476
475
put_attr_map[hash_key_name]
479
not_processed_predefined_attr_names = set()
480
for attr in schema.attribute_defs:
481
not_processed_predefined_attr_names.add(attr.name)
478
not_processed_predefined_attr_names = set(
479
schema.attribute_type_map.keys()
483
484
if expected_condition_map:
484
485
query_builder = [
485
"UPDATE \"", context.tenant, "\".\"", self.USER_TABLE_PREFIX,
486
put_request.table_name, "\" SET "]
486
'UPDATE "', context.tenant, '"."', self.USER_TABLE_PREFIX,
487
put_request.table_name, '" SET ']
488
489
dynamic_attr_names = []
489
490
dynamic_attr_values = []
490
492
for name, val in put_attr_map.iteritems():
491
493
if name in key_attr_names:
492
494
not_processed_predefined_attr_names.remove(name)
493
495
elif name in not_processed_predefined_attr_names:
494
496
query_builder += (
495
"\"", self.USER_COLUMN_PREFIX, name, "\"=", val, ","
497
'"', self.USER_COLUMN_PREFIX, name, '"=',
498
self._encode_predefined_attr_value(val), ","
497
500
not_processed_predefined_attr_names.remove(name)
501
504
self._encode_dynamic_attr_value(val)
504
query_builder.append("{")
505
dynamic_value_iter = iter(dynamic_attr_values)
506
for name in dynamic_attr_names:
508
"'", name, "':" + dynamic_value_iter.next(), ","
511
query_builder.append("}, ")
507
query_builder += (self.SYSTEM_COLUMN_ATTRS, "={")
508
if dynamic_attr_values:
509
dynamic_value_iter = iter(dynamic_attr_values)
510
for name in dynamic_attr_names:
512
"'", name, "':", dynamic_value_iter.next(), ","
515
query_builder.append("},")
513
517
for name in not_processed_predefined_attr_names:
514
518
query_builder += (
515
"\"", self.USER_COLUMN_PREFIX, name, "\"=null,"
519
'"', self.USER_COLUMN_PREFIX, name,
518
523
query_builder += (
519
524
self.SYSTEM_COLUMN_ATTR_TYPES, "={", types, "},",
520
525
self.SYSTEM_COLUMN_ATTR_EXIST, "={", exists, "},",
521
526
self.SYSTEM_COLUMN_HASH, "=", encoded_hash_key_value,
522
" WHERE ", self.USER_COLUMN_PREFIX, hash_key_name, "=",
527
' WHERE "', self.USER_COLUMN_PREFIX, hash_key_name, '"=',
523
528
encoded_hash_key_value
526
if key_attr_names == 2:
531
if len(key_attr_names) == 2:
527
532
range_key_name = key_attr_names[1]
528
533
encoded_range_key_value = self._encode_predefined_attr_value(
529
534
put_attr_map[range_key_name]
532
537
query_builder += (
533
" AND ", self.USER_COLUMN_PREFIX, range_key_name, "=",
538
' AND "', self.USER_COLUMN_PREFIX, range_key_name, '"=',
534
539
encoded_range_key_value
537
if_clause = self._conditions_as_string(expected_condition_map)
538
query_builder += (" IF ", if_clause)
540
self._execute_query("".join(query_builder), consistent=True)
542
if expected_condition_map:
543
query_builder.append(" IF ")
544
self._append_expected_conditions(
545
expected_condition_map, schema, query_builder
542
548
query_builder = [
543
"INSERT INTO \"", context.tenant, "\".\"",
544
self.USER_TABLE_PREFIX, put_request.table_name, "\" ("
549
'INSERT INTO "', context.tenant, '"."',
550
self.USER_TABLE_PREFIX, put_request.table_name, '" ('
547
553
dynamic_attr_names = []
616
627
@raise BackendInteractionException
618
query = "DELETE FROM \"{}\".\"{}{}\" WHERE ".format(
619
context.tenant, self.USER_TABLE_PREFIX, delete_request.table_name)
621
where = self._primary_key_as_string(delete_request.key_attribute_map)
630
'DELETE FROM "', context.tenant, '"."', self.USER_TABLE_PREFIX,
631
delete_request.table_name, '" WHERE '
634
query_builder.append(
635
self._primary_key_as_string(delete_request.key_attribute_map)
625
638
if expected_condition_map:
626
if_clause = self._conditions_as_string(expected_condition_map)
628
query += " IF " + if_clause
630
self._execute_query(query, consistent=True)
634
def _condition_as_string(self, attr, condition):
635
name = self.USER_COLUMN_PREFIX + attr
639
schema = self.describe_table(context, delete_request.table_name)
640
query_builder.append(" IF ")
641
self._append_expected_conditions(
642
expected_condition_map, schema, query_builder
645
result = self._execute_query("".join(query_builder), consistent=True)
647
return (result is None) or result[0]['[applied]']
649
def _compact_indexed_condition(self, cond_list):
650
left_condition = None
651
right_condition = None
652
exact_condition = None
656
for condition in cond_list:
657
if condition.type == models.IndexedCondition.CONDITION_TYPE_EQUAL:
658
if (exact_condition is not None and
659
condition.arg.value != exact_condition.arg.value):
661
exact_condition = condition
662
elif condition.is_left_border():
663
if left_condition is None:
664
left_condition = condition
665
elif condition.is_strict_border():
666
if condition.arg.value >= left_condition.arg.value:
667
left_condition = condition
669
if condition.arg.value > left_condition.arg.value:
670
left_condition = condition
671
elif condition.is_right_border():
672
if right_condition is None:
673
right_condition = condition
674
elif condition.is_strict():
675
if condition.arg.value <= right_condition.arg.value:
676
right_condition = condition
678
if condition.arg.value < right_condition.arg.value:
679
right_condition = condition
681
if exact_condition is not None:
682
if left_condition is not None:
683
if left_condition.is_strict():
684
if left_condition.arg.value >= exact_condition.arg.value:
687
if left_condition.arg.value > exact_condition.arg.value:
689
if right_condition is not None:
690
if right_condition.is_strict():
691
if right_condition.arg.value <= exact_condition.arg.value:
694
if right_condition.arg.value < exact_condition.arg.value:
696
return [exact_condition]
697
elif left_condition is not None:
698
if right_condition is not None:
699
if (left_condition.is_strict_border() or
700
right_condition.is_strict_border()):
701
if left_condition.arg.value >= right_condition.arg.value:
704
if left_condition.arg.value > right_condition.arg.value:
706
return [left_condition, right_condition]
708
return [left_condition]
710
assert right_condition is not None
712
return [right_condition]
714
def _append_indexed_condition(self, attr_name, condition, query_builder,
715
column_prefix=USER_COLUMN_PREFIX):
716
op = self.CONDITION_TO_OP[condition.type]
718
'"', column_prefix, attr_name, '"', op,
719
self._encode_predefined_attr_value(condition.arg)
722
def _append_hash_key_indexed_condition(
723
self, attr_name, condition, query_builder,
724
column_prefix=USER_COLUMN_PREFIX):
725
if condition.type == models.IndexedCondition.CONDITION_TYPE_EQUAL:
726
self._append_indexed_condition(
727
attr_name, condition, query_builder, column_prefix
730
op = self.CONDITION_TO_OP[condition.type]
732
'token("', column_prefix, attr_name, '")', op, "token(",
733
self._encode_predefined_attr_value(condition.arg), ")"
736
def _append_expected_conditions(self, expected_condition_map, schema,
738
init_length = len(query_builder)
740
for attr_name, cond_list in expected_condition_map.iteritems():
741
for condition in cond_list:
742
self._append_expected_condition(
743
attr_name, condition, query_builder,
744
attr_name in schema.attribute_type_map
746
query_builder.append(" AND ")
748
if len(query_builder) > init_length:
751
def _append_expected_condition(self, attr, condition, query_builder,
637
753
if condition.type == models.ExpectedCondition.CONDITION_TYPE_EXISTS:
638
754
if condition.arg:
639
return "\"{}\"={{\"{}\"}}".format(
640
self.SYSTEM_COLUMN_ATTR_EXIST, attr)
642
return "\"{}\"=null".format(name)
643
elif condition.type == models.IndexedCondition.CONDITION_TYPE_BETWEEN:
644
first, second = condition.arg
645
val1 = self._encode_predefined_attr_value(first)
646
val2 = self._encode_predefined_attr_value(second)
647
return " \"{}\" >= {} AND \"{}\" <= {}".format(
648
name, val1, name, val2)
649
elif (condition.type ==
650
models.IndexedCondition.CONDITION_TYPE_BEGINS_WITH):
651
first = condition.arg
652
second = first.value[:-1] + chr(ord(first.value[-1]) + 1)
653
second = models.AttributeValue(condition.arg.type, second)
654
val1 = self._encode_predefined_attr_value(first)
655
val2 = self._encode_predefined_attr_value(second)
656
return " \"{}\" >= {} AND \"{}\" < {}".format(
657
name, val1, name, val2)
756
self.SYSTEM_COLUMN_ATTR_EXIST, "={'", attr, "'}"
761
'"', self.USER_COLUMN_PREFIX, attr, '"=null'
765
self.SYSTEM_COLUMN_ATTRS, "['", attr, "']=null"
767
elif condition.type == models.ExpectedCondition.CONDITION_TYPE_EQUAL:
770
'"', self.USER_COLUMN_PREFIX, attr, '"=',
771
self._encode_predefined_attr_value(condition.arg)
775
self.SYSTEM_COLUMN_ATTRS, "['", attr, "']=",
776
self._encode_dynamic_attr_value(condition.arg)
659
op = self.CONDITION_TO_OP[condition.type]
660
return '"' + name + '"' + op + self._encode_predefined_attr_value(
664
def _conditions_as_string(self, condition_map):
665
return " AND ".join((self._condition_as_string(attr, cond)
667
in condition_map.iteritems()))
669
781
def _primary_key_as_string(self, key_map):
670
782
return " AND ".join((
711
823
where = self._primary_key_as_string(key_attribute_map)
713
query = "UPDATE \"{}\".\"{}{}\" SET {} WHERE {}".format(
714
context.tenant, self.USER_TABLE_PREFIX, table_name,
826
'UPDATE "', context.tenant, '"."', self.USER_TABLE_PREFIX,
827
table_name, '" SET ', set_clause, " WHERE ", where
718
830
if expected_condition_map:
719
if_clause = self._conditions_as_string(expected_condition_map)
720
query += " IF {}".format(if_clause)
722
self._execute_query(query, consistent=True)
831
query_builder.append(" IF ")
832
self._append_expected_conditions(
833
expected_condition_map, schema, query_builder
836
result = self._execute_query("".join(query_builder), consistent=True)
838
return (result is None) or result[0]['[applied]']
726
840
def _updates_as_string(self, schema, key_attribute_map, update_map):
727
predefined_attrs = [attr.name for attr in schema.attribute_defs]
729
841
set_clause = ", ".join({
730
self._update_as_string(attr, update, attr in predefined_attrs)
842
self._update_as_string(attr, update,
843
attr in schema.attribute_type_map)
731
844
for attr, update in update_map.iteritems()})
733
846
#update system_hash
889
1004
select_type = select_type or models.SelectType.all()
891
select = 'COUNT(*)' if select_type.is_count else '*'
893
1006
query_builder = [
894
"SELECT ", select, " FROM \"", context.tenant, "\".\"",
895
self.USER_TABLE_PREFIX, table_name, "\""
1007
"SELECT ", 'COUNT(*)' if select_type.is_count else '*', ' FROM "',
1008
context.tenant, '"."', self.USER_TABLE_PREFIX, table_name, '"'
898
indexed_condition_map = indexed_condition_map or {}
901
fixed_range_cond = None
903
1011
if exclusive_start_key:
904
if range_name in exclusive_start_key:
906
fixed_range_cond = self._fixed_range_condition(
907
range_name, indexed_condition_map,
910
indexed_condition_map[hash_name] = models.Condition.eq(
911
exclusive_start_key[hash_name])
914
token_cond = 'token(\"{}\")>token({})'.format(
915
self.USER_COLUMN_PREFIX + hash_name,
916
self._encode_predefined_attr_value(
917
exclusive_start_key[hash_name]))
919
if hash_name in indexed_condition_map:
920
del indexed_condition_map[hash_name]
922
where = self._conditions_as_string(indexed_condition_map)
926
where += ' AND ' + token_cond
932
where += ' AND ' + fixed_range_cond
934
where = fixed_range_cond
937
query_builder += (" WHERE ", where)
939
add_filtering, add_system_hash = self._add_filtering_and_sys_hash(
940
schema, indexed_condition_map)
943
hash_value = self._encode_predefined_attr_value(
944
indexed_condition_map[hash_name].arg
948
" AND \"", self.SYSTEM_COLUMN_HASH, "\"=", hash_value
1012
indexed_condition_map = indexed_condition_map or {}
1014
exclusive_hash_key_value = exclusive_start_key[hash_name]
1015
exclusive_range_key_value = exclusive_start_key.get(range_name,
1017
if exclusive_range_key_value:
1018
range_key_cond_list = indexed_condition_map.get(
1021
if range_key_cond_list is None:
1022
range_key_cond_list = []
1023
indexed_condition_map[range_name] = range_key_cond_list
1025
range_key_cond_list.append(
1026
models.IndexedCondition.lt(exclusive_range_key_value)
1027
if order_type == models.ORDER_TYPE_DESC else
1028
models.IndexedCondition.gt(exclusive_range_key_value)
1031
hash_key_cond_list = indexed_condition_map.get(
1034
if hash_key_cond_list is None:
1035
hash_key_cond_list = []
1036
indexed_condition_map[hash_name] = hash_key_cond_list
1038
hash_key_cond_list.append(
1039
models.IndexedCondition.eq(exclusive_hash_key_value)
1042
hash_key_cond_list = indexed_condition_map.get(
1045
if hash_key_cond_list is None:
1046
hash_key_cond_list = []
1047
indexed_condition_map[hash_name] = hash_key_cond_list
1049
hash_key_cond_list.append(
1050
models.IndexedCondition.lt(exclusive_hash_key_value)
1051
if order_type == models.ORDER_TYPE_DESC else
1052
models.IndexedCondition.gt(exclusive_hash_key_value)
1055
pre_condition_str = " WHERE "
1057
if indexed_condition_map:
1058
hash_cond_list = None
1059
for attr, cond_list in indexed_condition_map.iteritems():
1060
active_cond_list = self._compact_indexed_condition(cond_list)
1061
if active_cond_list is None:
1062
return models.SelectResult(count=0)
1064
if attr == hash_name:
1065
hash_cond_list = active_cond_list
1066
for active_cond in active_cond_list:
1067
query_builder.append(pre_condition_str)
1068
pre_condition_str = " AND "
1069
self._append_hash_key_indexed_condition(
1070
attr, active_cond, query_builder
1073
for active_cond in active_cond_list:
1074
query_builder.append(pre_condition_str)
1075
pre_condition_str = " AND "
1076
self._append_indexed_condition(
1077
attr, active_cond, query_builder
1080
if (hash_cond_list is not None and
1081
len(hash_cond_list) == 1 and
1082
hash_cond_list[0].type ==
1083
models.IndexedCondition.CONDITION_TYPE_EQUAL):
1084
query_builder.append(pre_condition_str)
1085
self._append_indexed_condition(
1086
self.SYSTEM_COLUMN_HASH, hash_cond_list[0],
1087
query_builder, column_prefix="")
1016
1152
last_evaluated_key=last_evaluated_key,
1019
def _fixed_range_condition(self, range_name,
1020
condition_map, exclusive_start_key):
1022
if range_name not in exclusive_start_key:
1027
if range_name in condition_map:
1028
condition = condition_map.pop(range_name)
1030
if condition.type == models.Condition.CONDITION_TYPE_EQUAL:
1031
condition_map[range_name] = condition
1034
elif condition.type in (
1035
models.IndexedCondition.CONDITION_TYPE_LESS,
1036
models.IndexedCondition.CONDITION_TYPE_LESS_OR_EQUAL
1039
right_cond = condition
1041
elif condition.type == (models.IndexedCondition.
1042
CONDITION_TYPE_BETWEEN):
1044
first, second = condition.arg
1046
right_cond = models.IndexedCondition.le(second)
1048
elif condition.type == (models.IndexedCondition.
1049
CONDITION_TYPE_BEGINS_WITH):
1051
first = condition.arg
1052
second_value = first.value[:-1] + chr(
1053
ord(first.value[-1]) + 1)
1054
second = models.AttributeValue(
1055
condition.arg.type, second_value)
1057
right_cond = models.IndexedCondition.lt(second)
1059
left_cond = models.IndexedCondition.gt(
1060
exclusive_start_key[range_name])
1062
fixed = self._condition_as_string(range_name, left_cond)
1065
fixed += ' AND ' + self._condition_as_string(
1066
range_name, right_cond)
1070
1155
def scan(self, context, table_name, condition_map, attributes_to_get=None,
1071
1156
limit=None, exclusive_start_key=None, consistent=False):
1161
1246
return filtered
1164
def _add_filtering_and_sys_hash(schema, condition_map={}):
1166
condition_map = condition_map or {}
1168
hash_name = schema.key_attributes[0]
1170
if hash_name in condition_map:
1171
assert (condition_map[hash_name].type
1172
== models.Condition.CONDITION_TYPE_EQUAL)
1175
range_name = schema.key_attributes[1]
1181
for key in condition_map.iterkeys()
1182
if key != hash_name and key != range_name
1185
non_pk_attrs_count = len(non_pk_attrs)
1187
if non_pk_attrs_count == 0:
1191
ind_def.attribute_to_index
1192
for ind_def in schema.index_defs
1195
has_one_indexed_eq = any(
1196
[(attr in indexed_attrs) and
1197
(condition_map[attr].type ==
1198
models.Condition.CONDITION_TYPE_EQUAL)
1199
for attr in non_pk_attrs])
1201
add_sys_hash = not has_one_indexed_eq
1202
add_filtering = non_pk_attrs_count > 1 or add_sys_hash
1204
return add_filtering, add_sys_hash
1206
def _conditions_satisfied(self, row, cond_map={}):
1207
cond_map = cond_map or {}
1208
return all([self._condition_satisfied(row.get(attr, None), cond)
1209
for attr, cond in cond_map.iteritems()])
1248
def _conditions_satisfied(self, row, cond_map=None):
1252
for attr_name, cond_list in cond_map.iteritems():
1253
for cond in cond_list:
1254
if not self._condition_satisfied(
1255
row.get(attr_name, None), cond):
1212
1260
def _condition_satisfied(attr_val, cond):