dynomite 1.2.7 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +17 -2
- data/CHANGELOG.md +21 -0
- data/Gemfile +1 -5
- data/LICENSE.txt +22 -0
- data/README.md +6 -190
- data/Rakefile +13 -1
- data/dynomite.gemspec +9 -2
- data/exe/dynomite +14 -0
- data/lib/dynomite/associations/association.rb +126 -0
- data/lib/dynomite/associations/belongs_to.rb +35 -0
- data/lib/dynomite/associations/has_and_belongs_to_many.rb +19 -0
- data/lib/dynomite/associations/has_many.rb +19 -0
- data/lib/dynomite/associations/has_one.rb +19 -0
- data/lib/dynomite/associations/many_association.rb +257 -0
- data/lib/dynomite/associations/single_association.rb +157 -0
- data/lib/dynomite/associations.rb +248 -0
- data/lib/dynomite/autoloader.rb +25 -0
- data/lib/dynomite/cli.rb +48 -0
- data/lib/dynomite/client.rb +118 -0
- data/lib/dynomite/command.rb +89 -0
- data/lib/dynomite/completer/script.rb +6 -0
- data/lib/dynomite/completer/script.sh +10 -0
- data/lib/dynomite/completer.rb +159 -0
- data/lib/dynomite/config.rb +39 -0
- data/lib/dynomite/core.rb +18 -19
- data/lib/dynomite/engine.rb +15 -0
- data/lib/dynomite/erb.rb +5 -3
- data/lib/dynomite/error.rb +12 -0
- data/lib/dynomite/help/completion.md +20 -0
- data/lib/dynomite/help/completion_script.md +3 -0
- data/lib/dynomite/help/migrate.md +3 -0
- data/lib/dynomite/help.rb +9 -0
- data/lib/dynomite/install.rb +4 -0
- data/lib/dynomite/item/abstract.rb +15 -0
- data/lib/dynomite/item/components.rb +33 -0
- data/lib/dynomite/item/dsl.rb +101 -0
- data/lib/dynomite/item/id.rb +41 -0
- data/lib/dynomite/item/indexes/finder.rb +58 -0
- data/lib/dynomite/item/indexes/index.rb +21 -0
- data/lib/dynomite/item/indexes/primary_index.rb +18 -0
- data/lib/dynomite/item/indexes.rb +25 -0
- data/lib/dynomite/item/locking.rb +53 -0
- data/lib/dynomite/item/magic_fields.rb +66 -0
- data/lib/dynomite/item/primary_key.rb +85 -0
- data/lib/dynomite/item/query/delegates.rb +28 -0
- data/lib/dynomite/item/query/params/base.rb +42 -0
- data/lib/dynomite/item/query/params/expression_attribute.rb +79 -0
- data/lib/dynomite/item/query/params/filter.rb +41 -0
- data/lib/dynomite/item/query/params/function/attribute_exists.rb +21 -0
- data/lib/dynomite/item/query/params/function/attribute_type.rb +30 -0
- data/lib/dynomite/item/query/params/function/base.rb +33 -0
- data/lib/dynomite/item/query/params/function/begins_with.rb +32 -0
- data/lib/dynomite/item/query/params/function/contains.rb +7 -0
- data/lib/dynomite/item/query/params/function/size_fn.rb +37 -0
- data/lib/dynomite/item/query/params/helpers.rb +94 -0
- data/lib/dynomite/item/query/params/key_condition.rb +34 -0
- data/lib/dynomite/item/query/params.rb +115 -0
- data/lib/dynomite/item/query/partiql/executer.rb +72 -0
- data/lib/dynomite/item/query/partiql.rb +67 -0
- data/lib/dynomite/item/query/relation/chain.rb +125 -0
- data/lib/dynomite/item/query/relation/comparision_expression.rb +21 -0
- data/lib/dynomite/item/query/relation/comparision_map.rb +19 -0
- data/lib/dynomite/item/query/relation/delete.rb +38 -0
- data/lib/dynomite/item/query/relation/ids.rb +21 -0
- data/lib/dynomite/item/query/relation/math.rb +19 -0
- data/lib/dynomite/item/query/relation/where_field.rb +32 -0
- data/lib/dynomite/item/query/relation/where_group.rb +78 -0
- data/lib/dynomite/item/query/relation.rb +127 -0
- data/lib/dynomite/item/query.rb +7 -0
- data/lib/dynomite/item/read/find.rb +196 -0
- data/lib/dynomite/item/read/find_with_event.rb +42 -0
- data/lib/dynomite/item/read.rb +90 -0
- data/lib/dynomite/item/sti.rb +43 -0
- data/lib/dynomite/item/table_namespace.rb +43 -0
- data/lib/dynomite/item/typecaster.rb +106 -0
- data/lib/dynomite/item/waiter_methods.rb +18 -0
- data/lib/dynomite/item/write/base.rb +15 -0
- data/lib/dynomite/item/write/delete_item.rb +14 -0
- data/lib/dynomite/item/write/put_item.rb +99 -0
- data/lib/dynomite/item/write/update_item.rb +73 -0
- data/lib/dynomite/item/write.rb +204 -0
- data/lib/dynomite/item.rb +113 -286
- data/lib/dynomite/migration/dsl/accessor.rb +19 -0
- data/lib/dynomite/migration/dsl/index/base.rb +42 -0
- data/lib/dynomite/migration/dsl/index/gsi.rb +59 -0
- data/lib/dynomite/migration/dsl/index/lsi.rb +27 -0
- data/lib/dynomite/migration/dsl/index.rb +72 -0
- data/lib/dynomite/migration/dsl/primary_key.rb +62 -0
- data/lib/dynomite/migration/dsl/provisioned_throughput.rb +38 -0
- data/lib/dynomite/migration/dsl.rb +89 -142
- data/lib/dynomite/migration/file_info.rb +28 -0
- data/lib/dynomite/migration/generator.rb +30 -16
- data/lib/dynomite/migration/helpers.rb +7 -0
- data/lib/dynomite/migration/internal/migrate/create_schema_migrations.rb +17 -0
- data/lib/dynomite/migration/internal/models/schema_migration.rb +6 -0
- data/lib/dynomite/migration/runner.rb +179 -0
- data/lib/dynomite/migration/templates/create_table.rb +7 -23
- data/lib/dynomite/migration/templates/delete_table.rb +7 -0
- data/lib/dynomite/migration/templates/update_table.rb +3 -18
- data/lib/dynomite/migration.rb +53 -10
- data/lib/dynomite/reserved_words.rb +13 -3
- data/lib/dynomite/seed.rb +13 -0
- data/lib/dynomite/types.rb +22 -0
- data/lib/dynomite/version.rb +1 -1
- data/lib/dynomite/waiter.rb +40 -0
- data/lib/dynomite.rb +11 -17
- data/lib/generators/application_item/application_item_generator.rb +30 -0
- data/lib/generators/application_item/templates/application_item.rb.tt +4 -0
- data/lib/jets/commands/dynamodb_command.rb +29 -0
- data/lib/jets/commands/help/generate.md +33 -0
- data/lib/jets/commands/help/migrate.md +3 -0
- metadata +201 -17
- data/docs/migrations/long-example.rb +0 -127
- data/docs/migrations/short-example.rb +0 -40
- data/lib/dynomite/db_config.rb +0 -121
- data/lib/dynomite/errors.rb +0 -15
- data/lib/dynomite/log.rb +0 -15
- data/lib/dynomite/migration/common.rb +0 -86
- data/lib/dynomite/migration/dsl/base_secondary_index.rb +0 -73
- data/lib/dynomite/migration/dsl/global_secondary_index.rb +0 -4
- data/lib/dynomite/migration/dsl/local_secondary_index.rb +0 -8
- data/lib/dynomite/migration/executor.rb +0 -38
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Common methods to the *SecondaryIndex classes that handle gsi and lsi methods
|
|
2
|
+
# as well a the Dsl class that handles create_table and update_table methods.
|
|
3
|
+
class Dynomite::Migration::Dsl
|
|
4
|
+
module PrimaryKey
|
|
5
|
+
include Dynomite::Types
|
|
6
|
+
|
|
7
|
+
# http://docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Types/KeySchemaElement.html
|
|
8
|
+
# partition_key is required
|
|
9
|
+
attr_reader :partition_key_identifier
|
|
10
|
+
def partition_key(identifier)
|
|
11
|
+
identifier = identifier.to_s
|
|
12
|
+
@partition_key_identifier = identifier # for later use. useful for conventional_index_name
|
|
13
|
+
adjust_schema_and_attributes(identifier, "HASH")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# sort_key is optional
|
|
17
|
+
attr_reader :sort_key_identifier
|
|
18
|
+
def sort_key(identifier)
|
|
19
|
+
identifier = identifier.to_s
|
|
20
|
+
@sort_key_identifier = identifier # for later use. useful for conventional_index_name
|
|
21
|
+
adjust_schema_and_attributes(identifier, "RANGE")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Use class variable to share across all instances of GlobalSecondaryIndex
|
|
25
|
+
# Note: Even though dynomite merges attribute defintions correctly for
|
|
26
|
+
# multiple indexes, DynamoDB does not allow creating multiple indexes
|
|
27
|
+
# at the same time. Example error:
|
|
28
|
+
# Unable to update table: Subscriber limit exceeded: Only 1 online index can be created or deleted simultaneously per table
|
|
29
|
+
# Leaving the logic in place in case AWS changes this in the future.
|
|
30
|
+
|
|
31
|
+
# Parameters:
|
|
32
|
+
# identifier: "id:string" or "id"
|
|
33
|
+
# key_type: "HASH" OR "RANGE"
|
|
34
|
+
#
|
|
35
|
+
# Adjusts the parameters for create_table to add the
|
|
36
|
+
# partition_key and sort_key
|
|
37
|
+
def adjust_schema_and_attributes(identifier, key_type)
|
|
38
|
+
name, attribute_type = identifier.split(':')
|
|
39
|
+
attribute_type ||= "string" # default to string
|
|
40
|
+
|
|
41
|
+
partition_key = {
|
|
42
|
+
attribute_name: name,
|
|
43
|
+
key_type: key_type.upcase
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if partition_key[:key_type] == "RANGE"
|
|
47
|
+
@key_schema << partition_key unless @key_schema.include?(partition_key)
|
|
48
|
+
else # HASH - add to beginning
|
|
49
|
+
@key_schema.unshift(partition_key) unless @key_schema.include?(partition_key)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
attribute_definition = {
|
|
53
|
+
attribute_name: name,
|
|
54
|
+
attribute_type: type_map(attribute_type)
|
|
55
|
+
}
|
|
56
|
+
unless @attribute_definitions.include?(attribute_definition)
|
|
57
|
+
@attribute_definitions << attribute_definition
|
|
58
|
+
end
|
|
59
|
+
@attribute_definitions
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
class Dynomite::Migration::Dsl
|
|
2
|
+
module ProvisionedThroughput
|
|
3
|
+
def billing_mode(v)
|
|
4
|
+
@billing_mode = v
|
|
5
|
+
@provisioned_throughput = nil if @billing_mode.to_s.upcase == "PAY_PER_REQUEST"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# t.provisioned_throughput(1) # both
|
|
9
|
+
# t.provisioned_throughput(1,1) # read, write
|
|
10
|
+
# t.provisioned_throughput({
|
|
11
|
+
# read_capacity_units: 1,
|
|
12
|
+
# write_capacity_units: 1
|
|
13
|
+
# }
|
|
14
|
+
def provisioned_throughput(*args)
|
|
15
|
+
if args.size == 0 # reader method
|
|
16
|
+
@provisioned_throughput # early return
|
|
17
|
+
elsif args.first.is_a?(Hash)
|
|
18
|
+
# @provisioned_throughput_set_called useful for update_table
|
|
19
|
+
# only provide a provisioned_throughput settings if explicitly called for update_table
|
|
20
|
+
@provisioned_throughput_set_called = true
|
|
21
|
+
# Case:
|
|
22
|
+
# provisioned_throughput(
|
|
23
|
+
# read_capacity_units: 1,
|
|
24
|
+
# write_capacity_units: 1
|
|
25
|
+
# )
|
|
26
|
+
@provisioned_throughput = arg.first # set directly
|
|
27
|
+
else # assume parameter is an Integer or [Integer, Integer]
|
|
28
|
+
# Case: provisioned_throughput(1)
|
|
29
|
+
# Case: provisioned_throughput(1, 1)
|
|
30
|
+
read_capacity_units, write_capacity_units = args
|
|
31
|
+
@provisioned_throughput = {
|
|
32
|
+
read_capacity_units: read_capacity_units,
|
|
33
|
+
write_capacity_units: write_capacity_units || read_capacity_units,
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -1,35 +1,27 @@
|
|
|
1
1
|
class Dynomite::Migration
|
|
2
2
|
class Dsl
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
autoload :GlobalSecondaryIndex, "dynomite/migration/dsl/global_secondary_index"
|
|
14
|
-
|
|
15
|
-
include Dynomite::DbConfig
|
|
16
|
-
include Common
|
|
17
|
-
|
|
18
|
-
attr_accessor(*ATTRIBUTES)
|
|
19
|
-
|
|
3
|
+
extend Accessor
|
|
4
|
+
include Dynomite::Client
|
|
5
|
+
include ProvisionedThroughput
|
|
6
|
+
include PrimaryKey
|
|
7
|
+
include Index
|
|
8
|
+
include Helpers
|
|
9
|
+
|
|
10
|
+
attr_accessor :attribute_definitions,
|
|
11
|
+
:key_schema,
|
|
12
|
+
:table_name
|
|
20
13
|
def initialize(method_name, table_name, &block)
|
|
21
14
|
@method_name = method_name
|
|
22
15
|
@table_name = table_name
|
|
23
16
|
@block = block
|
|
24
17
|
|
|
25
|
-
# Dsl fills in
|
|
18
|
+
# Dsl fills in atttributes in as methods are called within the block
|
|
19
|
+
# when parition_key and sort_key are called.
|
|
26
20
|
# Attributes for both create_table and updated_table:
|
|
27
|
-
@billing_mode = 'PROVISIONED'
|
|
28
21
|
@attribute_definitions = []
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
22
|
+
# dont set billing_mode for update_table. otherwise creating an index can set billing_mode to PAY_PER_REQUEST without user knowing
|
|
23
|
+
@billing_mode = "PAY_PER_REQUEST" if @method_name == :create_table
|
|
24
|
+
@provisioned_throughput = nil
|
|
33
25
|
|
|
34
26
|
# Attributes for create_table only:
|
|
35
27
|
@key_schema = []
|
|
@@ -39,35 +31,10 @@ class Dynomite::Migration
|
|
|
39
31
|
@lsi_indexes = []
|
|
40
32
|
end
|
|
41
33
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def billing_mode(mode = nil)
|
|
45
|
-
return @billing_mode if mode.nil?
|
|
46
|
-
|
|
47
|
-
@billing_mode = mode.to_s.upcase
|
|
34
|
+
def namespaced_table_name
|
|
35
|
+
table_name_with_namespace(table_name)
|
|
48
36
|
end
|
|
49
37
|
|
|
50
|
-
# t.gsi(:create) do |i|
|
|
51
|
-
# i.partition_key "category:string"
|
|
52
|
-
# i.sort_key "created_at:string" # optional
|
|
53
|
-
# end
|
|
54
|
-
def gsi(action=:create, index_name=nil, &block)
|
|
55
|
-
gsi_index = GlobalSecondaryIndex.new(action, index_name, &block)
|
|
56
|
-
@gsi_indexes << gsi_index # store @gsi_index for the parent Dsl to use
|
|
57
|
-
end
|
|
58
|
-
alias_method :global_secondary_index, :gsi
|
|
59
|
-
|
|
60
|
-
# t.lsi(:create) do |i|
|
|
61
|
-
# i.partition_key "category:string"
|
|
62
|
-
# i.sort_key "created_at:string" # optional
|
|
63
|
-
# end
|
|
64
|
-
def lsi(action=:create, index_name=nil, &block)
|
|
65
|
-
# dont need action create but have it to keep the lsi and gsi method consistent
|
|
66
|
-
lsi_index = LocalSecondaryIndex.new(index_name, &block)
|
|
67
|
-
@lsi_indexes << lsi_index # store @lsi_index for the parent Dsl to use
|
|
68
|
-
end
|
|
69
|
-
alias_method :local_secondary_index, :lsi
|
|
70
|
-
|
|
71
38
|
def evaluate
|
|
72
39
|
return if @evaluated
|
|
73
40
|
@block.call(self) if @block
|
|
@@ -79,136 +46,116 @@ class Dynomite::Migration
|
|
|
79
46
|
# executor
|
|
80
47
|
def params
|
|
81
48
|
evaluate # lazy evaluation: wait until as long as possible before evaluating code block
|
|
82
|
-
|
|
83
|
-
# Not using send because think its clearer in this case
|
|
84
|
-
case @method_name
|
|
85
|
-
when :create_table
|
|
86
|
-
params_create_table
|
|
87
|
-
when :update_table
|
|
88
|
-
params_update_table
|
|
89
|
-
end
|
|
49
|
+
send "params_#{@method_name}" # IE: params_create_table, params_update_table, params_delete_table
|
|
90
50
|
end
|
|
91
51
|
|
|
52
|
+
# https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#create_table-instance_method
|
|
92
53
|
def params_create_table
|
|
93
|
-
merge_lsi_attribute_definitions!
|
|
94
|
-
merge_gsi_attribute_definitions!
|
|
95
|
-
|
|
96
54
|
params = {
|
|
55
|
+
billing_mode: @billing_mode.to_s.upcase,
|
|
97
56
|
table_name: namespaced_table_name,
|
|
98
57
|
key_schema: @key_schema,
|
|
99
|
-
|
|
100
|
-
|
|
58
|
+
provisioned_throughput: @provisioned_throughput,
|
|
59
|
+
tags: @tags, # only for create_table
|
|
101
60
|
}
|
|
61
|
+
params.reject! { |k,v| v.blank? }
|
|
102
62
|
|
|
103
|
-
params[:provisioned_throughput] = @provisioned_throughput if @billing_mode == 'PROVISIONED'
|
|
104
63
|
params[:local_secondary_indexes] = lsi_secondary_index_creates unless @lsi_indexes.empty?
|
|
105
64
|
params[:global_secondary_indexes] = gsi_secondary_index_creates unless @gsi_indexes.empty?
|
|
65
|
+
params[:attribute_definitions] = attribute_definitions
|
|
66
|
+
params.merge!(common_params)
|
|
106
67
|
params
|
|
107
68
|
end
|
|
108
69
|
|
|
70
|
+
# https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#update_table-instance_method
|
|
71
|
+
dsl_accessor :replica_updates
|
|
109
72
|
def params_update_table
|
|
110
|
-
merge_gsi_attribute_definitions!
|
|
111
|
-
|
|
112
73
|
params = {
|
|
74
|
+
billing_mode: @billing_mode.to_s.upcase,
|
|
113
75
|
table_name: namespaced_table_name,
|
|
114
|
-
attribute_definitions: @attribute_definitions,
|
|
115
|
-
billing_mode: @billing_mode
|
|
116
76
|
# update table take values only some values for the "parent" table
|
|
117
77
|
# no key_schema, update_table does not handle key_schema for the "parent" table
|
|
78
|
+
replica_updates: @replica_updates, # only for update_table
|
|
118
79
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
params[:
|
|
80
|
+
params.reject! { |k,v| v.blank? }
|
|
81
|
+
|
|
82
|
+
# only set "parent" table provisioned_throughput if user actually invoked it in the dsl
|
|
83
|
+
params[:provisioned_throughput] = @provisioned_throughput if @provisioned_throughput_set_called
|
|
84
|
+
params[:global_secondary_index_updates] = global_secondary_index_updates unless @gsi_indexes.empty?
|
|
85
|
+
params[:attribute_definitions] = attribute_definitions
|
|
125
86
|
params
|
|
126
87
|
end
|
|
127
88
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
# attribute_definitions from it.
|
|
131
|
-
def merge_lsi_attribute_definitions!
|
|
132
|
-
lsi = @lsi_indexes.first # DynamoDB only supports adding one index at a time anyway. The reason @lsi_indexes is an Array is because we're sharing the same class code for LSI and GSI
|
|
133
|
-
if lsi
|
|
134
|
-
lsi.evaluate # force early evaluate since we need the params to
|
|
135
|
-
# add: gsi_attribute_definitions + lsi_attrs
|
|
136
|
-
lsi_attrs = lsi.attribute_definitions
|
|
137
|
-
end
|
|
138
|
-
all_attrs = if lsi_attrs
|
|
139
|
-
@attribute_definitions + lsi_attrs
|
|
140
|
-
else
|
|
141
|
-
@attribute_definitions
|
|
142
|
-
end
|
|
143
|
-
@attribute_definitions = all_attrs.uniq
|
|
89
|
+
def params_delete_table
|
|
90
|
+
{ table_name: namespaced_table_name }
|
|
144
91
|
end
|
|
145
92
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
93
|
+
def tags(values=nil)
|
|
94
|
+
if values.nil?
|
|
95
|
+
@tags
|
|
96
|
+
else
|
|
97
|
+
if values.is_a?(Hash)
|
|
98
|
+
@tags = values.map do |key,value|
|
|
99
|
+
{key: key.to_s, value: value.to_s}
|
|
100
|
+
end
|
|
101
|
+
else
|
|
102
|
+
@tags = values
|
|
103
|
+
end
|
|
155
104
|
end
|
|
156
105
|
end
|
|
157
106
|
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
107
|
+
# @attribute_definitions only hold the partition_key and sort_key attributes
|
|
108
|
+
# We'll also added the attributes from: 1. lsi index 2. gsi indexes 3. existing attributes for update table
|
|
109
|
+
def attribute_definitions
|
|
110
|
+
# Goes through all the lsi_indexes that have been built up in memory.
|
|
111
|
+
# Find the lsi object that creates an index and then grab the attribute_definitions from it.
|
|
112
|
+
# All lsi indexes are create. There is no update or delete for lsi indexes.
|
|
113
|
+
@lsi_indexes.each do |lsi|
|
|
114
|
+
lsi.attribute_definitions.each do |definition|
|
|
115
|
+
@attribute_definitions << definition unless @attribute_definitions.include?(definition)
|
|
116
|
+
end
|
|
167
117
|
end
|
|
168
|
-
end
|
|
169
118
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
gsi = @gsi_indexes.find { |i| i.action == :create }
|
|
177
|
-
if gsi
|
|
178
|
-
gsi.evaluate # force early evaluate since we need the params to
|
|
179
|
-
# add: gsi_attribute_definitions + gsi_attrs
|
|
180
|
-
gsi_attrs = gsi.attribute_definitions
|
|
119
|
+
# Goes through all the gsi_indexes that have been built up in memory.
|
|
120
|
+
# Find the gsi object that creates an index and then grab the attribute_definitions from it.
|
|
121
|
+
@gsi_indexes.select { |i| i.action == :create }.each do |gsi|
|
|
122
|
+
gsi.attribute_definitions.each do |definition|
|
|
123
|
+
@attribute_definitions << definition unless @attribute_definitions.include?(definition)
|
|
124
|
+
end
|
|
181
125
|
end
|
|
182
126
|
|
|
183
127
|
# Merge existing attributes for update table
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
128
|
+
if @method_name == :update_table
|
|
129
|
+
existing_attributes = desc_table(namespaced_table_name).attribute_definitions
|
|
130
|
+
existing_attributes.each do |attribute_definition|
|
|
131
|
+
definition = attribute_definition.to_h
|
|
132
|
+
@attribute_definitions << definition unless @attribute_definitions.include?(definition)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
187
135
|
|
|
188
|
-
|
|
189
|
-
@attribute_definitions = all_attrs
|
|
136
|
+
@attribute_definitions
|
|
190
137
|
end
|
|
191
138
|
|
|
192
|
-
|
|
193
|
-
#
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
end
|
|
139
|
+
dsl_accessor :stream_specification, :sse_specification
|
|
140
|
+
# common to create_table and update_table
|
|
141
|
+
def common_params
|
|
142
|
+
params = {
|
|
143
|
+
stream_specification: @stream_specification,
|
|
144
|
+
sse_specification: @sse_specification,
|
|
145
|
+
deletion_protection_enabled: deletion_protection_enabled_value,
|
|
146
|
+
}
|
|
147
|
+
params.reject! { |k,v| v.blank? }
|
|
202
148
|
end
|
|
203
149
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
return @gsi_attribute_definitions if @gsi_attribute_definitions
|
|
150
|
+
def deletion_protection_enabled(value=true)
|
|
151
|
+
@deletion_protection_enabled = value
|
|
152
|
+
end
|
|
153
|
+
alias deletion_protection deletion_protection_enabled
|
|
209
154
|
|
|
210
|
-
|
|
211
|
-
|
|
155
|
+
# To avoid name conflict with DSL t.deletion_protection_enabled
|
|
156
|
+
def deletion_protection_enabled_value
|
|
157
|
+
default = Dynomite.config.migration.deletion_protection_enabled
|
|
158
|
+
@deletion_protection_enabled.nil? ? default : @deletion_protection_enabled
|
|
212
159
|
end
|
|
213
160
|
end
|
|
214
161
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class Dynomite::Migration
|
|
2
|
+
class FileInfo
|
|
3
|
+
attr_reader :path
|
|
4
|
+
def initialize(path)
|
|
5
|
+
@path = path
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def pretty_path
|
|
9
|
+
@path.sub(/^\.\//,'') # remove leading ./
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def migration_class
|
|
13
|
+
filename = File.basename(@path, '.rb')
|
|
14
|
+
filename = filename.sub(/\d+[-_]/, '') # strip leading timestsamp
|
|
15
|
+
filename.camelize.constantize
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def version
|
|
19
|
+
filename = File.basename(@path, '.rb')
|
|
20
|
+
md = filename.match(/(\d+)[-_]/)
|
|
21
|
+
md[1].to_i
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.all_files
|
|
25
|
+
Dir.glob("#{Dynomite.root}/dynamodb/migrate/*").to_a.sort
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -3,8 +3,6 @@ require "active_support/core_ext/string"
|
|
|
3
3
|
class Dynomite::Migration
|
|
4
4
|
# jets dynamodb:generate posts --partition-key id:string
|
|
5
5
|
class Generator
|
|
6
|
-
include Dynomite::DbConfig
|
|
7
|
-
|
|
8
6
|
attr_reader :migration_name, :table_name
|
|
9
7
|
def initialize(migration_name, options)
|
|
10
8
|
@migration_name = migration_name
|
|
@@ -12,21 +10,28 @@ class Dynomite::Migration
|
|
|
12
10
|
end
|
|
13
11
|
|
|
14
12
|
def generate
|
|
15
|
-
puts "Generating migration
|
|
16
|
-
return if
|
|
13
|
+
puts "Generating migration" unless @options[:quiet]
|
|
14
|
+
return if ENV['NOOP']
|
|
17
15
|
create_migration
|
|
18
16
|
end
|
|
19
17
|
|
|
20
18
|
def create_migration
|
|
21
19
|
FileUtils.mkdir_p(File.dirname(migration_path))
|
|
22
20
|
IO.write(migration_path, migration_code)
|
|
23
|
-
|
|
24
|
-
puts "
|
|
21
|
+
pretty_migration_path = migration_path.sub(/^\.\//,'') # remove leading ./
|
|
22
|
+
puts "Migration file created: #{pretty_migration_path}\nTo run:\n\n"
|
|
23
|
+
command = File.basename($0)
|
|
24
|
+
if command == "jets"
|
|
25
|
+
puts " #{command} dynamodb:migrate"
|
|
26
|
+
else
|
|
27
|
+
puts " #{command} migrate"
|
|
28
|
+
end
|
|
29
|
+
puts
|
|
25
30
|
end
|
|
26
31
|
|
|
27
32
|
def migration_code
|
|
28
|
-
path = File.expand_path("../templates/#{
|
|
29
|
-
|
|
33
|
+
path = File.expand_path("../templates/#{action}.rb", __FILE__)
|
|
34
|
+
Dynomite::Erb.result(path,
|
|
30
35
|
migration_class_name: migration_class_name,
|
|
31
36
|
table_name: table_name,
|
|
32
37
|
partition_key: @options[:partition_key],
|
|
@@ -35,30 +40,39 @@ class Dynomite::Migration
|
|
|
35
40
|
)
|
|
36
41
|
end
|
|
37
42
|
|
|
38
|
-
def
|
|
39
|
-
|
|
43
|
+
def action
|
|
44
|
+
# optoins[:table_action] is old and deprecated
|
|
45
|
+
action = @options[:action] || @options[:table_action] || conventional_action
|
|
46
|
+
case action
|
|
47
|
+
when /create/
|
|
48
|
+
"create_table"
|
|
49
|
+
when /delete/
|
|
50
|
+
"delete_table"
|
|
51
|
+
else
|
|
52
|
+
"update_table" # default and fallback
|
|
53
|
+
end
|
|
40
54
|
end
|
|
41
55
|
|
|
42
|
-
def
|
|
43
|
-
@migration_name.
|
|
56
|
+
def conventional_action
|
|
57
|
+
@migration_name.split("_").first
|
|
44
58
|
end
|
|
45
59
|
|
|
46
60
|
def table_name
|
|
47
|
-
@options[:table_name] || conventional_table_name
|
|
61
|
+
@options[:table_name] || conventional_table_name || "TABLE_NAME"
|
|
48
62
|
end
|
|
49
63
|
|
|
50
64
|
# create_posts => posts
|
|
51
65
|
# update_posts => posts
|
|
52
66
|
def conventional_table_name
|
|
53
|
-
@migration_name.sub(/^(create|update)_/, '')
|
|
67
|
+
@migration_name.sub(/^(create|update|delete)_/, '')
|
|
54
68
|
end
|
|
55
69
|
|
|
56
70
|
def migration_class_name
|
|
57
|
-
"#{@migration_name}
|
|
71
|
+
"#{@migration_name}".camelize # doesnt include timestamp
|
|
58
72
|
end
|
|
59
73
|
|
|
60
74
|
def migration_path
|
|
61
|
-
"#{Dynomite.
|
|
75
|
+
"#{Dynomite.root}/dynamodb/migrate/#{timestamp}-#{@migration_name}.rb"
|
|
62
76
|
end
|
|
63
77
|
|
|
64
78
|
def timestamp
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class CreateSchemaMigrations < Dynomite::Migration
|
|
2
|
+
include Dynomite::Client
|
|
3
|
+
|
|
4
|
+
def up
|
|
5
|
+
create_table :schema_migrations do |t|
|
|
6
|
+
t.partition_key "version:number" # required
|
|
7
|
+
t.billing_mode "PAY_PER_REQUEST"
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def table_exist?(full_table_name)
|
|
12
|
+
client.describe_table(table_name: full_table_name)
|
|
13
|
+
true
|
|
14
|
+
rescue Aws::DynamoDB::Errors::ResourceNotFoundException
|
|
15
|
+
false
|
|
16
|
+
end
|
|
17
|
+
end
|