Class: Dynamini::TestClient
- Inherits:
-
Object
- Object
- Dynamini::TestClient
- Defined in:
- lib/dynamini/test_client.rb
Overview
In-memory database client for test purposes.
Instance Attribute Summary collapse
-
#data ⇒ Object
readonly
Returns the value of attribute data.
-
#hash_key_attr ⇒ Object
readonly
Returns the value of attribute hash_key_attr.
-
#range_key_attr ⇒ Object
readonly
Returns the value of attribute range_key_attr.
-
#secondary_index ⇒ Object
readonly
Returns the value of attribute secondary_index.
Instance Method Summary collapse
- #apply_filter_options(parent, args, start_val, end_val) ⇒ Object
-
#batch_get_item(args = {}) ⇒ Object
No range key support - use query instead.
-
#batch_write_item(request_options) ⇒ Object
TODO add range key support for delete, not currently implemented batch_operations.batch_delete.
- #delete_item(args = {}) ⇒ Object
- #determine_hash_and_range(args) ⇒ Object
- #get_item(args = {}) ⇒ Object
- #get_last_evaluated_key(secondary_index_name, items, records) ⇒ Object
- #get_secondary_hash_key(index) ⇒ Object
- #get_secondary_range_key(index) ⇒ Object
- #get_table(table_name) ⇒ Object
- #index_of_start_key(args, records) ⇒ Object
-
#initialize(hash_key_attr, range_key_attr = nil, secondary_index = nil) ⇒ TestClient
constructor
A new instance of TestClient.
- #limit_scanned_records(limit, records, start_index) ⇒ Object
- #primary_index_insertion(hash_key_value, range_key_value, updates, table) ⇒ Object
- #primary_only_hash_insertion(hash_key_value, updates, table) ⇒ Object
- #primary_with_range_insertion(hash_key_value, range_key_value, updates, table) ⇒ Object
- #query(args = {}) ⇒ Object
- #range_key_limits(tokens) ⇒ Object
- #range_key_query(args, tokens) ⇒ Object
- #reset ⇒ Object
- #scan(args = {}) ⇒ Object
- #secondary_index_query(args = {}, tokens) ⇒ Object
- #sort_records(records, index, args, start_val, end_val) ⇒ Object
- #sort_scanned_records!(records, secondary_index_name) ⇒ Object
- #update_item(args = {}) ⇒ Object
Constructor Details
#initialize(hash_key_attr, range_key_attr = nil, secondary_index = nil) ⇒ TestClient
Returns a new instance of TestClient.
10 11 12 13 14 15 |
# File 'lib/dynamini/test_client.rb', line 10 def initialize(hash_key_attr, range_key_attr = nil, secondary_index=nil) @data = {} @hash_key_attr = hash_key_attr @range_key_attr = range_key_attr @secondary_index = secondary_index end |
Instance Attribute Details
#data ⇒ Object (readonly)
Returns the value of attribute data.
8 9 10 |
# File 'lib/dynamini/test_client.rb', line 8 def data @data end |
#hash_key_attr ⇒ Object (readonly)
Returns the value of attribute hash_key_attr.
8 9 10 |
# File 'lib/dynamini/test_client.rb', line 8 def hash_key_attr @hash_key_attr end |
#range_key_attr ⇒ Object (readonly)
Returns the value of attribute range_key_attr.
8 9 10 |
# File 'lib/dynamini/test_client.rb', line 8 def range_key_attr @range_key_attr end |
#secondary_index ⇒ Object (readonly)
Returns the value of attribute secondary_index.
8 9 10 |
# File 'lib/dynamini/test_client.rb', line 8 def secondary_index @secondary_index end |
Instance Method Details
#apply_filter_options(parent, args, start_val, end_val) ⇒ Object
203 204 205 206 207 208 209 210 |
# File 'lib/dynamini/test_client.rb', line 203 def (parent, args, start_val, end_val) records = parent.values records = records.select { |record| record[@range_key_attr] >= start_val.to_f } if start_val records = records.select { |record| record[@range_key_attr] <= end_val.to_f } if end_val records = records.sort! { |a, b| b[@range_key_attr] <=> a[@range_key_attr] } if args[:scan_index_forward] == false records = records[0...args[:limit]] if args[:limit] records end |
#batch_get_item(args = {}) ⇒ Object
No range key support - use query instead.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/dynamini/test_client.rb', line 71 def batch_get_item(args = {}) responses = {} args[:request_items].each do |table_name, get_request| responses[table_name] = [] ids = get_request[:keys].flat_map(&:values) raise 'Aws::DynamoDB::Errors::ValidationException: Provided list of item keys contains duplicates' if ids.length != ids.uniq.length get_request[:keys].each do |key_hash| item = get_table(table_name)[key_hash.values.first] responses[table_name] << item unless item.nil? end end OpenStruct.new(responses: responses) end |
#batch_write_item(request_options) ⇒ Object
TODO add range key support for delete, not currently implemented batch_operations.batch_delete
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/dynamini/test_client.rb', line 136 def batch_write_item() [:request_items].each do |table_name, requests| table = get_table(table_name) requests.each do |request_hash| if request_hash[:put_request] item = request_hash[:put_request][:item].symbolize_keys hash_key_value = item[hash_key_attr] if range_key_attr.present? range_key_value = item[range_key_attr] table[hash_key_value] = {} if table[hash_key_value].nil? table[hash_key_value][range_key_value] = item else table[hash_key_value] = item end else item = request_hash[:delete_request][:key] id = item[hash_key_attr] table.delete(id) end end end end |
#delete_item(args = {}) ⇒ Object
161 162 163 |
# File 'lib/dynamini/test_client.rb', line 161 def delete_item(args = {}) get_table(args[:table_name]).delete(args[:key][hash_key_attr]) end |
#determine_hash_and_range(args) ⇒ Object
185 186 187 188 189 190 191 192 |
# File 'lib/dynamini/test_client.rb', line 185 def determine_hash_and_range(args) if args[:index_name] index = secondary_index[args[:index_name].to_s] [index[:hash_key_name].to_s, index[:range_key_name].to_s] else [@hash_key_attr.to_s, @range_key_attr.to_s] end end |
#get_item(args = {}) ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/dynamini/test_client.rb', line 58 def get_item(args = {}) table = get_table(args[:table_name]) hash_key_value = args[:key][hash_key_attr] range_key_value = args[:key][range_key_attr] attributes_hash = table[hash_key_value] attributes_hash = attributes_hash[range_key_value] if attributes_hash && range_key_value OpenStruct.new(item: (attributes_hash ? attributes_hash.deep_dup : nil)) end |
#get_last_evaluated_key(secondary_index_name, items, records) ⇒ Object
124 125 126 127 128 129 130 131 132 133 |
# File 'lib/dynamini/test_client.rb', line 124 def get_last_evaluated_key(secondary_index_name, items, records) if records.length > 0 && items.last != records.last index = secondary_index[secondary_index_name] if index { get_secondary_hash_key(index).to_s => items.last[get_secondary_hash_key(index)] } else { hash_key_attr.to_s => items.last[hash_key_attr] } end end end |
#get_secondary_hash_key(index) ⇒ Object
243 244 245 |
# File 'lib/dynamini/test_client.rb', line 243 def get_secondary_hash_key(index) index[:hash_key_name] == @hash_key_attr ? index[:hash_key_name] : index[:hash_key_name].to_s end |
#get_secondary_range_key(index) ⇒ Object
247 248 249 |
# File 'lib/dynamini/test_client.rb', line 247 def get_secondary_range_key(index) index[:range_key_name] == @range_key_attr ? index[:range_key_name] : index[:range_key_name].to_s end |
#get_table(table_name) ⇒ Object
17 18 19 |
# File 'lib/dynamini/test_client.rb', line 17 def get_table(table_name) @data[table_name] ||= {} end |
#index_of_start_key(args, records) ⇒ Object
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/dynamini/test_client.rb', line 103 def index_of_start_key(args, records) if args[:exclusive_start_key] sec_index = secondary_index && secondary_index[args[:secondary_index_name]] start_index = records.index do |r| if sec_index r[get_secondary_hash_key(sec_index)] == args[:exclusive_start_key].values[0] else r[hash_key_attr] == args[:exclusive_start_key].values[0] end end start_index || 0 else 0 end end |
#limit_scanned_records(limit, records, start_index) ⇒ Object
119 120 121 122 |
# File 'lib/dynamini/test_client.rb', line 119 def limit_scanned_records(limit, records, start_index) end_index = limit ? start_index + limit - 1 : -1 records[start_index..end_index] end |
#primary_index_insertion(hash_key_value, range_key_value, updates, table) ⇒ Object
36 37 38 39 40 41 42 |
# File 'lib/dynamini/test_client.rb', line 36 def primary_index_insertion(hash_key_value, range_key_value, updates, table) if range_key_value primary_with_range_insertion(hash_key_value, range_key_value, updates, table) else primary_only_hash_insertion(hash_key_value, updates, table) end end |
#primary_only_hash_insertion(hash_key_value, updates, table) ⇒ Object
54 55 56 |
# File 'lib/dynamini/test_client.rb', line 54 def primary_only_hash_insertion(hash_key_value, updates, table) table[hash_key_value] ? table[hash_key_value].merge!(updates) : table[hash_key_value] = updates end |
#primary_with_range_insertion(hash_key_value, range_key_value, updates, table) ⇒ Object
44 45 46 47 48 49 50 51 52 |
# File 'lib/dynamini/test_client.rb', line 44 def primary_with_range_insertion(hash_key_value, range_key_value, updates, table) updates.merge!(range_key_attr => range_key_value) if table[hash_key_value] && table[hash_key_value][range_key_value] table[hash_key_value][range_key_value].merge! updates else table[hash_key_value] ||= {} table[hash_key_value][range_key_value] = updates end end |
#query(args = {}) ⇒ Object
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/dynamini/test_client.rb', line 165 def query(args = {}) # Possible key condition structures: # "foo = val" # "foo = val AND bar <= val2" # "foo = val AND bar >= val2" # "foo = val AND bar BETWEEN val2 AND val3" attr_placeholders = args[:expression_attribute_values].merge(args[:expression_attribute_names]) attr_placeholders.each { |symbol, value| args[:key_condition_expression].gsub!(symbol, value.to_s) } tokens = args[:key_condition_expression].split(/\s+/) hash_key_name, range_key_name = determine_hash_and_range(args) inspect_for_correct_keys?(tokens, hash_key_name, range_key_name) args[:index_name] ? secondary_index_query(args, tokens) : range_key_query(args, tokens) end |
#range_key_limits(tokens) ⇒ Object
194 195 196 197 198 199 200 201 |
# File 'lib/dynamini/test_client.rb', line 194 def range_key_limits(tokens) case tokens[5] when ">=" then [tokens[6], nil] when "<=" then [nil, tokens[6]] when "BETWEEN" then [tokens[6], tokens[8]] else [nil, nil] end end |
#range_key_query(args, tokens) ⇒ Object
212 213 214 215 216 217 218 219 220 221 |
# File 'lib/dynamini/test_client.rb', line 212 def range_key_query(args, tokens) start_val, end_val = range_key_limits(tokens) hash_key = hash_key_value(args).is_a?(Integer) ? tokens[2].to_i : tokens[2] parent = get_table(args[:table_name])[hash_key] return OpenStruct.new(items: []) unless parent selected = (parent, args, start_val, end_val) OpenStruct.new(items: selected) end |
#reset ⇒ Object
251 252 253 |
# File 'lib/dynamini/test_client.rb', line 251 def reset @data = {} end |
#scan(args = {}) ⇒ Object
87 88 89 90 91 92 93 94 |
# File 'lib/dynamini/test_client.rb', line 87 def scan(args = {}) records = get_table(args[:table_name]).values sort_scanned_records!(records, args[:secondary_index_name]) if args[:secondary_index_name] start_index = index_of_start_key(args, records) items = limit_scanned_records(args[:limit], records, start_index) last_evaluated_key = get_last_evaluated_key(args[:secondary_index_name], items, records) OpenStruct.new({items: items, last_evaluated_key: last_evaluated_key}) end |
#secondary_index_query(args = {}, tokens) ⇒ Object
223 224 225 226 227 228 229 230 231 |
# File 'lib/dynamini/test_client.rb', line 223 def secondary_index_query(args = {}, tokens) start_val, end_val = range_key_limits(tokens) index = secondary_index[args[:index_name].to_s] table = get_table(args[:table_name]) records = @range_key_attr ? get_values(table) : table.values selected = sort_records(records, index, args, start_val, end_val) OpenStruct.new(items: selected) end |
#sort_records(records, index, args, start_val, end_val) ⇒ Object
233 234 235 236 237 238 239 240 241 |
# File 'lib/dynamini/test_client.rb', line 233 def sort_records(records, index, args, start_val, end_val) records = records.select { |record| record[get_secondary_hash_key(index)] == hash_key_value(args) } records = records.select { |record| record[get_secondary_range_key(index)] >= start_val.to_f } if start_val records = records.select { |record| record[get_secondary_range_key(index)] <= end_val.to_f } if end_val records = records.sort { |a, b| a[get_secondary_range_key(index)] <=> b[get_secondary_range_key(index)] } records = records.reverse if args[:scan_index_forward] == false records = records[0...args[:limit]] if args[:limit] records end |
#sort_scanned_records!(records, secondary_index_name) ⇒ Object
96 97 98 99 100 101 |
# File 'lib/dynamini/test_client.rb', line 96 def sort_scanned_records!(records, secondary_index_name) index = secondary_index[secondary_index_name] records.sort! do |a, b| a[get_secondary_hash_key(index)] <=> b[get_secondary_hash_key(index)] end end |
#update_item(args = {}) ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/dynamini/test_client.rb', line 21 def update_item(args = {}) table = get_table(args[:table_name]) keys = args[:key] hash_key_value = keys[hash_key_attr] range_key_value = keys[range_key_attr] updates = flatten_attribute_updates(args).merge( hash_key_attr => hash_key_value ) primary_index_insertion(hash_key_value, range_key_value, updates, table) if hash_key_value end |