ocean-dynamo 1.6.1 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75ca78788e4c6fede73f78af4d7c8730e9f868198cd95f8905094f9e0032e45d
4
- data.tar.gz: 798dc05815ecb753dcbe7062ecff1906108cde3ea498a25c53c0c4cea6588985
3
+ metadata.gz: a7ade2e3ad29ce511cb3537e6d800280da158c8a1eeb676ac767b0489c7c25d1
4
+ data.tar.gz: d1f727f3fcf58637e9888eeffcb3a4120b5107a79c400b7ae845936bd2f8eab7
5
5
  SHA512:
6
- metadata.gz: 99a4b8a30c990f58440f15245c90e3fd66aff7484d197a40dc48af85972bd2066858e8b4720a3273a35ee779300234e79d9ca79d21517c41f855441dc7ca2b71
7
- data.tar.gz: 1e8df34da4547b6d00108a844b73c195ba25334866cc2f3f44016de9216ced945e67e59e20097590b19e96a2ec7fa5e439b217dd82ccb591d6c0bd414c387910
6
+ metadata.gz: 7938d1e380cb4f93fa99682cc667f29480c73ee3dcb99e06f74b5fd8092c4f91f03039831e3391112f1c11d3d9f6f11a0a1e57b0c2343e59c3889bb435df2a89
7
+ data.tar.gz: 15eb31c9595bbabe5feed8474bb75b69139393dfeb262202ee5416162c66de998cc954558132b6c2589ebea4afc46a01d072ede7b08edaddef6eeaf4a80b5fc6
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- == ocean-dynamo
1
+ # ocean-dynamo
2
2
 
3
3
  OceanDynamo is a massively scalable Amazon DynamoDB near drop-in replacement for
4
4
  ActiveRecord.
@@ -9,7 +9,7 @@ but 5.1 will require a couple of changes.
9
9
  {<img src="https://badge.fury.io/rb/ocean-dynamo.png" alt="Gem Version" />}[http://badge.fury.io/rb/ocean-dynamo]
10
10
 
11
11
 
12
- === Features
12
+ ## Features
13
13
 
14
14
  As one important use case for OceanDynamo is to facilitate the conversion of SQL
15
15
  databases to no-SQL DynamoDB databases, it is important that the syntax and semantics
@@ -18,8 +18,8 @@ callbacks, exceptions and method chaining semantics. OceanDynamo follows this pa
18
18
  closely and is of course based on ActiveModel.
19
19
 
20
20
  The attribute and persistence layer of OceanDynamo is modeled on that of ActiveRecord:
21
- there's +save+, +save!+, +create+, +update+, +update!+, +update_attributes+, +find_each+,
22
- +destroy_all+, +delete_all+, +read_attribute+, +write_attribute+ and all the other
21
+ there's `save`, `save!`, `create`, `update`, `update!`, `update_attributes`, `find_each`,
22
+ `destroy_all`, `delete_all`, `read_attribute`, `write_attribute` and all the other
23
23
  methods you're used to. The design goal is always to implement as much of the ActiveRecord
24
24
  interface as possible, without compromising scalability. This makes the task of switching
25
25
  from SQL to no-SQL much easier.
@@ -34,22 +34,22 @@ with FactoryBot.
34
34
  OceanDynamo supports optimistic record locking via a combination of DynamoDB conditional
35
35
  writes and atomic updates. This is activated by default.
36
36
 
37
- === Current State
37
+ ## Current State
38
38
 
39
39
  * Secondary indices are now fully supported! See below for more information.
40
40
  * Version 2 of the AWS Ruby SDK is now used.
41
41
  * Work begun on association proxies, etc.
42
42
 
43
43
 
44
- === Future milestones
44
+ ## Future milestones
45
45
 
46
46
  * Direct support for the DynamoDB JSON attribute types for arrays and hashes
47
47
  * Collection proxies, to implement ActiveRecord-style method chaining, e.g.:
48
48
  <code>blog_entry.comments.build(body: "Cool!").save!</code>
49
- * The +has_and_belongs_to_many+ assocation.
49
+ * The `has_and_belongs_to_many` assocation.
50
50
 
51
51
 
52
- === Current use
52
+ ## Current use
53
53
 
54
54
  OceanDynamo is used as a central component in Ocean, a Rails framework and development,
55
55
  testing, and production pipeline for creating massively scalable HATEOAS microservice
@@ -59,15 +59,15 @@ SOAs in the cloud.
59
59
  However, OceanDynamo can of course also be used stand-alone.
60
60
 
61
61
 
62
- == Documentation
62
+ # Documentation
63
63
 
64
64
  * Ocean-dynamo gem on Rubygems: https://rubygems.org/gems/ocean-dynamo
65
65
  * Ocean-dynamo gem API: http://rubydoc.info/gems/ocean-dynamo/frames
66
- * Ocean-dynamo source and wiki: https://github.org/OceanDev/ocean-dynamo
66
+ * Ocean-dynamo source: https://gitlab.com/ocean-dev/ocean-dynamo
67
67
  * AWS DynamoDB Ruby SDK v2: http://docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB.html
68
68
 
69
69
 
70
- == Contributing
70
+ # Contributing
71
71
 
72
72
  Contributions are welcome. Fork in the usual way. OceanDynamo is developed using
73
73
  TDD: the specs are extensive and test coverage is very near to 100 percent. Pull requests
@@ -75,12 +75,12 @@ will not be considered unless all tests pass and coverage is equally high or hig
75
75
  All contributed code must therefore also be exhaustively tested.
76
76
 
77
77
 
78
- == Examples
78
+ # Examples
79
79
 
80
- === Basic syntax
80
+ ## Basic syntax
81
81
 
82
82
  The following example shows the basic syntax for declaring a DynamoDB-based schema.
83
-
83
+ ```
84
84
  class AsyncJob < OceanDynamo::Table
85
85
 
86
86
  dynamo_schema(:guid) do
@@ -104,24 +104,25 @@ The following example shows the basic syntax for declaring a DynamoDB-based sche
104
104
  end
105
105
 
106
106
  end
107
+ ```
107
108
 
108
- === Attributes
109
+ ## Attributes
109
110
 
110
- Each attribute has a name, a type (+:string+, +:integer+, +:float+, +:datetime+, +:boolean+,
111
- or +:serialized+) where +:string+ is the default. Each attribute also optionally has a default
112
- value, which can be a Proc. The hash key attribute is by default +:id+ (overridden as +:guid+ in
113
- the example above) and is a +:string+.
111
+ Each attribute has a name, a type (`:string`, `:integer`, `:float`, `:datetime`, `:boolean`,
112
+ or `:serialized`) where `:string` is the default. Each attribute also optionally has a default
113
+ value, which can be a Proc. The hash key attribute is by default `:id` (overridden as `:guid` in
114
+ the example above) and is a `:string`.
114
115
 
115
- The +:string+, +:integer+, +:float+ and +:datetime+ types can also store sets of their type.
116
+ The `:string`, `:integer`, `:float` and `:datetime` types can also store sets of their type.
116
117
  Sets are represented as arrays, may not contain duplicates and may not be empty.
117
118
 
118
- All attributes except the +:string+ type can take the value +nil+. Storing +nil+ for a string
119
+ All attributes except the `:string` type can take the value `nil`. Storing `nil` for a string
119
120
  value will return the empty string, <tt>""</tt>.
120
121
 
121
- === Schema args and options
122
-
123
- +dynamo_schema+ takes args and many options. Here's the full syntax:
122
+ ## Schema args and options
124
123
 
124
+ `dynamo_schema` takes args and many options. Here's the full syntax:
125
+ ```
125
126
  dynamo_schema(
126
127
  table_hash_key = :id, # The name of the hash key attribute
127
128
  table_range_key = nil, # The name of the range key attribute (or nil)
@@ -139,22 +140,23 @@ value will return the empty string, <tt>""</tt>.
139
140
  ...
140
141
  ...
141
142
  end
142
-
143
- Tip: you might want to use the following idiom when declaring a +dynamo_schema+. It is used everywhere in Ocean:
144
-
145
- dynamo_schema(:id, table_name_suffix: Api.basename_suffix,
146
- create: Rails.env != "production") do
143
+ ```
144
+ Tip: you might want to use the following idiom when declaring a `dynamo_schema`. It is used everywhere in Ocean:
145
+ ```
146
+ dynamo_schema(:id, table_name_suffix: Api.basename_suffix, create: true) do
147
147
  ...
148
148
  end
149
+ ```
150
+ This will auto-create the DynamoDB table in all environments and also add a
151
+ suffix to the table name in order to prevent collisions during tests.
152
+ Cf `Api.basename_suffix` in the `ocean-rails` gem for more information.
149
153
 
150
- This will auto-create the DynamoDB table in all environments except production, and it will also add a suffix to the table name in order to prevent tests from colliding. Cf +Api.basename_suffix+ in the +ocean-rails+ gem for more information.
151
-
152
- == +has_many+ and +belongs_to+
153
-
154
- === Example
154
+ # has_many and belongs_to
155
155
 
156
- The following example shows how to set up +has_many+ / +belongs_to+ relations:
156
+ ## Example
157
157
 
158
+ The following example shows how to set up `has_many` / `belongs_to` relations:
159
+ ```
158
160
  class Forum < OceanDynamo::Table
159
161
  dynamo_schema do
160
162
  attribute :name
@@ -179,38 +181,38 @@ The following example shows how to set up +has_many+ / +belongs_to+ relations:
179
181
  end
180
182
  belongs_to :topic, composite_key: true
181
183
  end
182
-
184
+ ```
183
185
  The only non-standard aspect of the above is <tt>composite_key: true</tt>, which
184
- is required as the Topic class itself has a +belongs_to+ relation and thus has
186
+ is required as the Topic class itself has a `belongs_to` relation and thus has
185
187
  a composite key. This must be declared in the child class as it needs to know
186
188
  how to retrieve its parent.
187
189
 
188
190
 
189
- === Restrictions
191
+ ## Restrictions
190
192
 
191
- Restrictions for +belongs_to+ tables:
192
- * The hash key must be specified and must not be +:id+.
193
+ Restrictions for `belongs_to` tables:
194
+ * The hash key must be specified and must not be `:id`.
193
195
  * The range key must not be specified at all.
194
- * +belongs_to+ can be specified only once in each class.
195
- * +belongs_to+ must be placed after the +dynamo_schema+ attribute block.
196
+ * `belongs_to` can be specified only once in each class.
197
+ * `belongs_to` must be placed after the `dynamo_schema` attribute block.
196
198
 
197
- Restrictions for +has_many+ tables:
198
- * +has_many+ must be placed after the +dynamo_schema+ attribute block.
199
+ Restrictions for `has_many` tables:
200
+ * `has_many` must be placed after the `dynamo_schema` attribute block.
199
201
 
200
- These restrictions allow OceanDynamo to implement the +has_many+ / +belongs_to+
202
+ These restrictions allow OceanDynamo to implement the `has_many` / `belongs_to`
201
203
  relation in a very efficient and massively scalable way.
202
204
 
203
205
 
204
- === Implementation
206
+ ## Implementation
205
207
 
206
- +belongs_to+ claims the range key and uses it to store its own id, which normally
208
+ `belongs_to` claims the range key and uses it to store its own id, which normally
207
209
  would be stored in the hash key attribute. Instead, the hash key attribute holds the
208
210
  id of the parent. We have thus reversed the roles of these two fields. As a result,
209
211
  all children store their parent id in the hash key, and their own id in the
210
212
  range key.
211
213
 
212
214
  This type of relation is even more efficient than its ActiveRecord counterpart as
213
- it uses only primary indices in both directions of the +has_many+ / +belongs_to+
215
+ it uses only primary indices in both directions of the `has_many` / `belongs_to`
214
216
  association. No scans.
215
217
 
216
218
  Furthermore, since DynamoDB has powerful primary index searches involving substrings
@@ -218,18 +220,18 @@ and matching, the fact that the range key is a string can be used to implement
218
220
  wildcard matching of additional attributes. This gives, amongst other things, the
219
221
  equivalent of an SQL GROUP BY request, again without requiring any secondary indices.
220
222
 
221
- It's our goal to use a similar technique to implement +has_and_belongs_to_many+ relations,
223
+ It's our goal to use a similar technique to implement `has_and_belongs_to_many` relations,
222
224
  which means that secondary indices won't be necessary for the vast majority of
223
225
  DynamoDB tables. This ultimately means reduced operational costs, as well as
224
226
  reduced complexity.
225
227
 
226
228
 
227
- == Secondary Indices
229
+ # Secondary Indices
228
230
 
229
- === Local Secondary Indices
231
+ ## Local Secondary Indices
230
232
 
231
233
  Up to five attributes can be declared as local secondary indices, in the following manner:
232
-
234
+ ```
233
235
  class Authentication < OceanDynamo::Table
234
236
  dynamo_schema(:username, :expires_at) do
235
237
  attribute :token, :string, local_secondary_index: true
@@ -239,10 +241,10 @@ Up to five attributes can be declared as local secondary indices, in the followi
239
241
  attribute :api_user_id, :string
240
242
  end
241
243
  end
242
-
243
- The items of the above table can be accessed by using the hash key +:username+ and
244
- the range key +:expires_at+. The +local_secondary_index+ declaration makes it possible
245
- to access items using the same hash key +:username+ but with +:token+ as an alternate
244
+ ```
245
+ The items of the above table can be accessed by using the hash key `:username` and
246
+ the range key `:expires_at`. The `local_secondary_index` declaration makes it possible
247
+ to access items using the same hash key `:username` but with `:token` as an alternate
246
248
  range key. Local secondary indices all use the same hash key as the primary index,
247
249
  substituting another attribute instead as the range key.
248
250
 
@@ -251,29 +253,29 @@ combination of keys. Secondary indices don't require the range key to be unique
251
253
  the same hash key. This means that secondary index searches always will return a
252
254
  collection.
253
255
 
254
- Local secondary indices are queried through +find_local_each+ and +find_local+.
256
+ Local secondary indices are queried through `find_local_each` and `find_local`.
255
257
  They take the same arguments; the former yields to a block for each item,
256
258
  the other returns all items in an array.
257
259
 
258
- The following finds all Authentications where +:username+ is "joe" and +:token+ is "quux":
259
-
260
+ The following finds all Authentications where `:username` is "joe" and `:token` is "quux":
261
+ ```
260
262
  Authentication.find_local(:username, "joe", :token, "=", "quux")
261
-
262
- This retrieves all Authentications belonging to Joe, sorted on +:token+:
263
-
263
+ ```
264
+ This retrieves all Authentications belonging to Joe, sorted on `:token`:
265
+ ```
264
266
  Authentication.find_local(:username, "joe", :token, ">=", "0")
265
-
267
+ ```
266
268
  The same thing but with the only the item with the highest token value:
267
-
269
+ ```
268
270
  Authentication.find_local(:username, "joe", :token, ">=", "0",
269
271
  scan_index_forward: false, limit: 1)
272
+ ```
270
273
 
274
+ ## Global Secondary Indices
271
275
 
272
- === Global Secondary Indices
273
-
274
- Global secondary indices are declared after all attributes, but still within the +do+
276
+ Global secondary indices are declared after all attributes, but still within the `do`
275
277
  block:
276
-
278
+ ```
277
279
  class Authentication < OceanDynamo::Table
278
280
  dynamo_schema(:username, :expires_at) do
279
281
  attribute :token, :string, local_secondary_index: true
@@ -287,41 +289,40 @@ block:
287
289
  global_secondary_index :expires_at, write_capacity_units: 50
288
290
  end
289
291
  end
290
-
291
- Each +global_secondary_index+ clause (there can be a maximum of 5 per table) takes
292
+ ```
293
+ Each `global_secondary_index` clause (there can be a maximum of 5 per table) takes
292
294
  the following arguments:
293
- * +hash_value+ (required),
294
- * +range_value+ (optional),
295
- * +:projection+ (default +:keys_only+, +:all+ for all attributes)
296
- * +:read_capacity_units+ (defaults to the table's read capacity, normally 10)
297
- * +:write_capacity_units+ (default to the table's write capacity, normally 5)
295
+ * `hash_value` (required),
296
+ * `range_value` (optional),
297
+ * `:projection` (default `:keys_only`, `:all` for all attributes)
298
+ * `:read_capacity_units` (defaults to the table's read capacity, normally 10)
299
+ * `:write_capacity_units` (default to the table's write capacity, normally 5)
298
300
 
299
- Global secondary indices are queried through +find_global_each+ and +find_global+.
301
+ Global secondary indices are queried through `find_global_each` and `find_global`.
300
302
  They take the same arguments; the former yields to a block for each item,
301
303
  the other returns all items in an array.
302
304
 
303
- The following finds all Authentications whose +:token+ is +"quux"+:
304
-
305
+ The following finds all Authentications whose `:token` is `"quux"`:
306
+ ```
305
307
  Authentication.find_global(:token, "quux")
306
-
307
- This retrieves all Authentications belonging to the user with the ID +"dfstw-ruyhdf-ewijf"+,
308
- sorted in ascending order of the +:expires_at+ attribute:
309
-
308
+ ```
309
+ This retrieves all Authentications belonging to the user with the ID `"dfstw-ruyhdf-ewijf"`,
310
+ sorted in ascending order of the `:expires_at` attribute:
311
+ ```
310
312
  Authentication.find_global(:api_user_id, "dfstw-ruyhdf-ewijf",
311
313
  :expires_at, ">=", 0)
312
-
313
- To get the highest +:expires_at+ record:
314
-
314
+ ```
315
+ To get the highest `:expires_at` record:
316
+ ```
315
317
  Authentication.find_global(:api_user_id, "dfstw-ruyhdf-ewijf",
316
318
  :expires_at, ">=", 0,
317
319
  scan_index_forward: false, limit: 1)
320
+ ```
318
321
 
319
-
320
- == Installation
322
+ # Installation
321
323
  ```
322
324
  gem install ocean-dynamo
323
325
  ```
324
-
325
326
  Ocean-dynamo relies on Aws.config to fetch configuration data. In Ocean, we use
326
327
  an init file similar to this one:
327
328
  ```
@@ -347,12 +348,12 @@ Aws.config.update(cfg)
347
348
  ```
348
349
  As you can see, this relies on ENV variables to choose from three different
349
350
  setups:
350
- #. If you're using discrete AWS credentials, set AWS_REGION, AWS_ACCESS_KEY_ID,
351
+ 1. If you're using discrete AWS credentials, set AWS_REGION, AWS_ACCESS_KEY_ID,
351
352
  and AWS_SECRET_ACCESS_KEY.
352
- #. If you're using localstack, provide AWS_DYNAMODB_ENDPOINT (http://localhost:4569).
353
- #. If you're using EC2 or ECS instance profile credentials, set only AWS_REGION.
353
+ 2. If you're using localstack, provide AWS_DYNAMODB_ENDPOINT (http://localhost:4569).
354
+ 3. If you're using EC2 or ECS instance profile credentials, set only AWS_REGION.
354
355
 
355
- == Running the specs
356
+ # Running the specs
356
357
 
357
358
  We're using localstack (https://github.com/localstack/localstack) for development
358
359
  and testing. Install (we use a Docker container) and run it. If you're using
@@ -360,18 +361,18 @@ ocean-dynamo with the Ocean Rails context, you can install and start it by
360
361
  following the instructions in the `ocean` repo.
361
362
 
362
363
  With localstack running, you should now be able to do
363
-
364
+ ```
364
365
  bundle exec rspec
365
-
366
+ ```
366
367
  All tests should pass.
367
368
 
368
- == Rails console
369
+ # Rails console
369
370
 
370
371
  The Rails console is available from the built-in dummy application:
371
-
372
+ ```
372
373
  cd spec/dummy
373
374
  rails console
374
-
375
+ ```
375
376
  This will, amongst other things, also create the CloudModel table if it doesn't already
376
377
  exist. On Amazon, this will take a little while. With DynamoDB Local, it's practically
377
378
  instant.
@@ -4,7 +4,7 @@ module OceanDynamo
4
4
  def self.included(base)
5
5
  base.extend(ClassMethods)
6
6
  end
7
-
7
+
8
8
 
9
9
  # ---------------------------------------------------------
10
10
  #
@@ -14,7 +14,7 @@ module OceanDynamo
14
14
 
15
15
  module ClassMethods
16
16
 
17
- def dynamo_schema(table_hash_key=:id,
17
+ def dynamo_schema(table_hash_key=:id,
18
18
  table_range_key=nil,
19
19
  table_name: compute_table_name,
20
20
  table_name_prefix: nil,
@@ -23,9 +23,10 @@ module OceanDynamo
23
23
  write_capacity_units: 5,
24
24
  connect: :late,
25
25
  create: false,
26
+ client: nil,
26
27
  **keywords,
27
28
  &block)
28
- self.dynamo_client = nil
29
+ self.dynamo_client = client
29
30
  self.dynamo_resource = nil
30
31
  self.dynamo_table = nil
31
32
  self.table_connected = false
@@ -131,7 +132,7 @@ module OceanDynamo
131
132
  #puts "Updating table #{table_full_name}"
132
133
  # attrs = table_attribute_definitions
133
134
  # active_attrs = []
134
- # dynamo_table.attribute_definitions.each do |k|
135
+ # dynamo_table.attribute_definitions.each do |k|
135
136
  # active_attrs << { attribute_name: k.attribute_name, attribute_type: k.attribute_type }
136
137
  # end
137
138
  # return false if active_attrs == attrs
@@ -149,7 +150,7 @@ module OceanDynamo
149
150
  attrs << { attribute_name: name, attribute_type: attribute_type(name) }
150
151
  end
151
152
  global_secondary_indexes.each do |index_name, data|
152
- data["keys"].each do |name|
153
+ data["keys"].each do |name|
153
154
  next if attrs.any? { |a| a[:attribute_name] == name }
154
155
  attrs << { attribute_name: name, attribute_type: attribute_type(name) }
155
156
  end
@@ -221,7 +222,7 @@ module OceanDynamo
221
222
  end
222
223
 
223
224
  end
224
-
225
+
225
226
 
226
227
  # ---------------------------------------------------------
227
228
  #
@@ -1,3 +1,3 @@
1
1
  module OceanDynamo
2
- VERSION = "1.6.1"
2
+ VERSION = "1.7.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ocean-dynamo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Bengtson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-28 00:00:00.000000000 Z
11
+ date: 2018-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk