dynamoid-moda 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +15 -0
  2. data/.document +5 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +7 -0
  5. data/Gemfile +24 -0
  6. data/Gemfile.lock +118 -0
  7. data/Gemfile_activemodel4 +24 -0
  8. data/Gemfile_activemodel4.lock +88 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.markdown +360 -0
  11. data/Rakefile +93 -0
  12. data/VERSION +1 -0
  13. data/doc/.nojekyll +0 -0
  14. data/doc/Dynamoid.html +328 -0
  15. data/doc/Dynamoid/Adapter.html +1872 -0
  16. data/doc/Dynamoid/Adapter/AwsSdk.html +2101 -0
  17. data/doc/Dynamoid/Adapter/Local.html +1574 -0
  18. data/doc/Dynamoid/Associations.html +138 -0
  19. data/doc/Dynamoid/Associations/Association.html +847 -0
  20. data/doc/Dynamoid/Associations/BelongsTo.html +161 -0
  21. data/doc/Dynamoid/Associations/ClassMethods.html +766 -0
  22. data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +167 -0
  23. data/doc/Dynamoid/Associations/HasMany.html +167 -0
  24. data/doc/Dynamoid/Associations/HasOne.html +161 -0
  25. data/doc/Dynamoid/Associations/ManyAssociation.html +1684 -0
  26. data/doc/Dynamoid/Associations/SingleAssociation.html +627 -0
  27. data/doc/Dynamoid/Components.html +242 -0
  28. data/doc/Dynamoid/Config.html +412 -0
  29. data/doc/Dynamoid/Config/Options.html +638 -0
  30. data/doc/Dynamoid/Criteria.html +138 -0
  31. data/doc/Dynamoid/Criteria/Chain.html +1471 -0
  32. data/doc/Dynamoid/Criteria/ClassMethods.html +105 -0
  33. data/doc/Dynamoid/Dirty.html +424 -0
  34. data/doc/Dynamoid/Dirty/ClassMethods.html +174 -0
  35. data/doc/Dynamoid/Document.html +1033 -0
  36. data/doc/Dynamoid/Document/ClassMethods.html +1116 -0
  37. data/doc/Dynamoid/Errors.html +125 -0
  38. data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +141 -0
  39. data/doc/Dynamoid/Errors/DocumentNotValid.html +221 -0
  40. data/doc/Dynamoid/Errors/Error.html +137 -0
  41. data/doc/Dynamoid/Errors/InvalidField.html +141 -0
  42. data/doc/Dynamoid/Errors/InvalidQuery.html +131 -0
  43. data/doc/Dynamoid/Errors/MissingRangeKey.html +141 -0
  44. data/doc/Dynamoid/Fields.html +686 -0
  45. data/doc/Dynamoid/Fields/ClassMethods.html +438 -0
  46. data/doc/Dynamoid/Finders.html +135 -0
  47. data/doc/Dynamoid/Finders/ClassMethods.html +943 -0
  48. data/doc/Dynamoid/IdentityMap.html +492 -0
  49. data/doc/Dynamoid/IdentityMap/ClassMethods.html +534 -0
  50. data/doc/Dynamoid/Indexes.html +321 -0
  51. data/doc/Dynamoid/Indexes/ClassMethods.html +369 -0
  52. data/doc/Dynamoid/Indexes/Index.html +1142 -0
  53. data/doc/Dynamoid/Middleware.html +115 -0
  54. data/doc/Dynamoid/Middleware/IdentityMap.html +264 -0
  55. data/doc/Dynamoid/Persistence.html +892 -0
  56. data/doc/Dynamoid/Persistence/ClassMethods.html +836 -0
  57. data/doc/Dynamoid/Validations.html +415 -0
  58. data/doc/_index.html +506 -0
  59. data/doc/class_list.html +53 -0
  60. data/doc/css/common.css +1 -0
  61. data/doc/css/full_list.css +57 -0
  62. data/doc/css/style.css +338 -0
  63. data/doc/file.LICENSE.html +73 -0
  64. data/doc/file.README.html +416 -0
  65. data/doc/file_list.html +58 -0
  66. data/doc/frames.html +28 -0
  67. data/doc/index.html +416 -0
  68. data/doc/js/app.js +214 -0
  69. data/doc/js/full_list.js +178 -0
  70. data/doc/js/jquery.js +4 -0
  71. data/doc/method_list.html +1144 -0
  72. data/doc/top-level-namespace.html +112 -0
  73. data/dynamoid-moda.gemspec +210 -0
  74. data/dynamoid.gemspec +208 -0
  75. data/lib/dynamoid.rb +46 -0
  76. data/lib/dynamoid/adapter.rb +267 -0
  77. data/lib/dynamoid/adapter/aws_sdk.rb +309 -0
  78. data/lib/dynamoid/associations.rb +106 -0
  79. data/lib/dynamoid/associations/association.rb +105 -0
  80. data/lib/dynamoid/associations/belongs_to.rb +44 -0
  81. data/lib/dynamoid/associations/has_and_belongs_to_many.rb +40 -0
  82. data/lib/dynamoid/associations/has_many.rb +39 -0
  83. data/lib/dynamoid/associations/has_one.rb +39 -0
  84. data/lib/dynamoid/associations/many_association.rb +191 -0
  85. data/lib/dynamoid/associations/single_association.rb +69 -0
  86. data/lib/dynamoid/components.rb +37 -0
  87. data/lib/dynamoid/config.rb +57 -0
  88. data/lib/dynamoid/config/options.rb +78 -0
  89. data/lib/dynamoid/criteria.rb +29 -0
  90. data/lib/dynamoid/criteria/chain.rb +326 -0
  91. data/lib/dynamoid/dirty.rb +47 -0
  92. data/lib/dynamoid/document.rb +199 -0
  93. data/lib/dynamoid/errors.rb +28 -0
  94. data/lib/dynamoid/fields.rb +138 -0
  95. data/lib/dynamoid/finders.rb +133 -0
  96. data/lib/dynamoid/identity_map.rb +96 -0
  97. data/lib/dynamoid/indexes.rb +69 -0
  98. data/lib/dynamoid/indexes/index.rb +103 -0
  99. data/lib/dynamoid/middleware/identity_map.rb +16 -0
  100. data/lib/dynamoid/persistence.rb +292 -0
  101. data/lib/dynamoid/validations.rb +36 -0
  102. data/spec/app/models/address.rb +13 -0
  103. data/spec/app/models/camel_case.rb +34 -0
  104. data/spec/app/models/car.rb +6 -0
  105. data/spec/app/models/magazine.rb +11 -0
  106. data/spec/app/models/message.rb +9 -0
  107. data/spec/app/models/nuclear_submarine.rb +5 -0
  108. data/spec/app/models/sponsor.rb +8 -0
  109. data/spec/app/models/subscription.rb +12 -0
  110. data/spec/app/models/tweet.rb +12 -0
  111. data/spec/app/models/user.rb +26 -0
  112. data/spec/app/models/vehicle.rb +7 -0
  113. data/spec/dynamoid/adapter/aws_sdk_spec.rb +376 -0
  114. data/spec/dynamoid/adapter_spec.rb +155 -0
  115. data/spec/dynamoid/associations/association_spec.rb +194 -0
  116. data/spec/dynamoid/associations/belongs_to_spec.rb +71 -0
  117. data/spec/dynamoid/associations/has_and_belongs_to_many_spec.rb +47 -0
  118. data/spec/dynamoid/associations/has_many_spec.rb +42 -0
  119. data/spec/dynamoid/associations/has_one_spec.rb +45 -0
  120. data/spec/dynamoid/associations_spec.rb +16 -0
  121. data/spec/dynamoid/config_spec.rb +27 -0
  122. data/spec/dynamoid/criteria/chain_spec.rb +210 -0
  123. data/spec/dynamoid/criteria_spec.rb +75 -0
  124. data/spec/dynamoid/dirty_spec.rb +57 -0
  125. data/spec/dynamoid/document_spec.rb +180 -0
  126. data/spec/dynamoid/fields_spec.rb +156 -0
  127. data/spec/dynamoid/finders_spec.rb +147 -0
  128. data/spec/dynamoid/identity_map_spec.rb +45 -0
  129. data/spec/dynamoid/indexes/index_spec.rb +104 -0
  130. data/spec/dynamoid/indexes_spec.rb +25 -0
  131. data/spec/dynamoid/persistence_spec.rb +301 -0
  132. data/spec/dynamoid/validations_spec.rb +36 -0
  133. data/spec/dynamoid_spec.rb +14 -0
  134. data/spec/spec_helper.rb +55 -0
  135. data/spec/support/with_partitioning.rb +15 -0
  136. metadata +363 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZDk3YjM5N2U2MDE0NDVjYzgyNjE4MzYyNWNjNzc2OWQ2NjE1YTEwMQ==
5
+ data.tar.gz: !binary |-
6
+ Y2UwMzc1ZjJkOWIyNGUyNDg0NDBiZjZmYzU1NmJlNWM0NmM5NjEwNA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YjgxM2UxMjQ1NTg3OTJhOWYyM2RjNTNiNmVmMTNmMDIwOThkZmVkNGE5OGZi
10
+ NTdhMmMwN2JkYTJiZDdhYWI4OGIxMmQ3YmU3ZmRiN2EyYzI5YzgxMzdjOWQ3
11
+ YTk3YmI0NDY1MjIzZTY4MTJjZjM5YTM1MjU4NDQ2MGQ1Y2QyYTg=
12
+ data.tar.gz: !binary |-
13
+ MTFhNTA2OTYzOGNmZTkxNWU5ODZkN2U3NzA1OTFjOGEyMzM2NDM3NTcwMWRh
14
+ MmU1ZTk3MzY5OTg2M2I4OWZmZjExMTdkNzEzMTViYmNjNDk3ZWRhNTZhZjBk
15
+ ZmJjYjcxMGZmYjM2YmM3YjE2NjA4MTc3OWQ3ODc3OTBmZDA2N2Q=
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ gemfile:
3
+ - Gemfile
4
+ - Gemfile_activemodel4
5
+ ruby:
6
+ - 1.9.3
7
+ script: bundle exec rake unattended_spec
data/Gemfile ADDED
@@ -0,0 +1,24 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'activemodel'
4
+ gem 'tzinfo'
5
+ gem 'aws-sdk'
6
+
7
+ # Add dependencies required to use your gem here.
8
+ # Example:
9
+ # gem "activesupport", ">= 2.3.5"
10
+
11
+ # Add dependencies to develop your gem here.
12
+ # Include everything needed to run rake, tests, features, etc.
13
+ group :development do
14
+ gem "rake"
15
+ gem "rspec"
16
+ gem "bundler"
17
+ gem "jeweler"
18
+ gem "yard"
19
+ gem "redcarpet", '1.17.2'
20
+ gem 'github-markup'
21
+ gem 'pry'
22
+ gem 'fake_dynamo', '~>0.1.3'
23
+ gem "mocha", '0.10.0'
24
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,118 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ activemodel (4.0.2)
5
+ activesupport (= 4.0.2)
6
+ builder (~> 3.1.0)
7
+ activesupport (4.0.2)
8
+ i18n (~> 0.6, >= 0.6.4)
9
+ minitest (~> 4.2)
10
+ multi_json (~> 1.3)
11
+ thread_safe (~> 0.1)
12
+ tzinfo (~> 0.3.37)
13
+ addressable (2.3.5)
14
+ atomic (1.1.14)
15
+ aws-sdk (1.34.0)
16
+ json (~> 1.4)
17
+ nokogiri (>= 1.4.4)
18
+ uuidtools (~> 2.1)
19
+ builder (3.1.4)
20
+ coderay (1.1.0)
21
+ descendants_tracker (0.0.3)
22
+ diff-lcs (1.2.5)
23
+ fake_dynamo (0.1.3)
24
+ activesupport
25
+ json
26
+ sinatra
27
+ faraday (0.9.0)
28
+ multipart-post (>= 1.2, < 3)
29
+ git (1.2.6)
30
+ github-markup (1.0.1)
31
+ github_api (0.11.2)
32
+ addressable (~> 2.3)
33
+ descendants_tracker (~> 0.0.1)
34
+ faraday (~> 0.8, < 0.10)
35
+ hashie (>= 1.2)
36
+ multi_json (>= 1.7.5, < 2.0)
37
+ nokogiri (~> 1.6.0)
38
+ oauth2
39
+ hashie (2.0.5)
40
+ highline (1.6.20)
41
+ i18n (0.6.9)
42
+ jeweler (2.0.1)
43
+ builder
44
+ bundler (>= 1.0)
45
+ git (>= 1.2.5)
46
+ github_api
47
+ highline (>= 1.6.15)
48
+ nokogiri (>= 1.5.10)
49
+ rake
50
+ rdoc
51
+ json (1.8.1)
52
+ jwt (0.1.11)
53
+ multi_json (>= 1.5)
54
+ metaclass (0.0.2)
55
+ method_source (0.8.2)
56
+ mini_portile (0.5.2)
57
+ minitest (4.7.5)
58
+ mocha (0.10.0)
59
+ metaclass (~> 0.0.1)
60
+ multi_json (1.8.4)
61
+ multi_xml (0.5.5)
62
+ multipart-post (2.0.0)
63
+ nokogiri (1.6.1)
64
+ mini_portile (~> 0.5.0)
65
+ oauth2 (0.9.3)
66
+ faraday (>= 0.8, < 0.10)
67
+ jwt (~> 0.1.8)
68
+ multi_json (~> 1.3)
69
+ multi_xml (~> 0.5)
70
+ rack (~> 1.2)
71
+ pry (0.9.12.6)
72
+ coderay (~> 1.0)
73
+ method_source (~> 0.8)
74
+ slop (~> 3.4)
75
+ rack (1.5.2)
76
+ rack-protection (1.5.2)
77
+ rack
78
+ rake (10.1.1)
79
+ rdoc (4.1.1)
80
+ json (~> 1.4)
81
+ redcarpet (1.17.2)
82
+ rspec (2.14.1)
83
+ rspec-core (~> 2.14.0)
84
+ rspec-expectations (~> 2.14.0)
85
+ rspec-mocks (~> 2.14.0)
86
+ rspec-core (2.14.7)
87
+ rspec-expectations (2.14.5)
88
+ diff-lcs (>= 1.1.3, < 2.0)
89
+ rspec-mocks (2.14.5)
90
+ sinatra (1.4.4)
91
+ rack (~> 1.4)
92
+ rack-protection (~> 1.4)
93
+ tilt (~> 1.3, >= 1.3.4)
94
+ slop (3.4.7)
95
+ thread_safe (0.1.3)
96
+ atomic
97
+ tilt (1.4.1)
98
+ tzinfo (0.3.38)
99
+ uuidtools (2.1.4)
100
+ yard (0.8.7.3)
101
+
102
+ PLATFORMS
103
+ ruby
104
+
105
+ DEPENDENCIES
106
+ activemodel
107
+ aws-sdk
108
+ bundler
109
+ fake_dynamo (~> 0.1.3)
110
+ github-markup
111
+ jeweler
112
+ mocha (= 0.10.0)
113
+ pry
114
+ rake
115
+ redcarpet (= 1.17.2)
116
+ rspec
117
+ tzinfo
118
+ yard
@@ -0,0 +1,24 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'activemodel', '~>4.0.0'
4
+ gem 'tzinfo'
5
+ gem 'aws-sdk'
6
+
7
+ # Add dependencies required to use your gem here.
8
+ # Example:
9
+ # gem "activesupport", ">= 2.3.5"
10
+
11
+ # Add dependencies to develop your gem here.
12
+ # Include everything needed to run rake, tests, features, etc.
13
+ group :development do
14
+ gem "rake"
15
+ gem "rspec"
16
+ gem "bundler"
17
+ gem "jeweler"
18
+ gem "yard"
19
+ gem "redcarpet", '1.17.2'
20
+ gem 'github-markup'
21
+ gem 'pry'
22
+ gem 'fake_dynamo', '~>0.1.3'
23
+ gem "mocha", '0.10.0'
24
+ end
@@ -0,0 +1,88 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ activemodel (4.0.0)
5
+ activesupport (= 4.0.0)
6
+ builder (~> 3.1.0)
7
+ activesupport (4.0.0)
8
+ i18n (~> 0.6, >= 0.6.4)
9
+ minitest (~> 4.2)
10
+ multi_json (~> 1.3)
11
+ thread_safe (~> 0.1)
12
+ tzinfo (~> 0.3.37)
13
+ atomic (1.1.10)
14
+ aws-sdk (1.10.0)
15
+ json (~> 1.4)
16
+ nokogiri (>= 1.4.4)
17
+ uuidtools (~> 2.1)
18
+ builder (3.1.4)
19
+ coderay (1.0.9)
20
+ diff-lcs (1.2.4)
21
+ fake_dynamo (0.1.3)
22
+ activesupport
23
+ json
24
+ sinatra
25
+ git (1.2.5)
26
+ github-markup (0.7.5)
27
+ i18n (0.6.4)
28
+ jeweler (1.8.4)
29
+ bundler (~> 1.0)
30
+ git (>= 1.2.5)
31
+ rake
32
+ rdoc
33
+ json (1.8.0)
34
+ metaclass (0.0.1)
35
+ method_source (0.8.1)
36
+ minitest (4.7.5)
37
+ mocha (0.10.0)
38
+ metaclass (~> 0.0.1)
39
+ multi_json (1.7.7)
40
+ nokogiri (1.5.9)
41
+ pry (0.9.12.2)
42
+ coderay (~> 1.0.5)
43
+ method_source (~> 0.8)
44
+ slop (~> 3.4)
45
+ rack (1.5.2)
46
+ rack-protection (1.5.0)
47
+ rack
48
+ rake (10.0.4)
49
+ rdoc (4.0.1)
50
+ json (~> 1.4)
51
+ redcarpet (1.17.2)
52
+ rspec (2.13.0)
53
+ rspec-core (~> 2.13.0)
54
+ rspec-expectations (~> 2.13.0)
55
+ rspec-mocks (~> 2.13.0)
56
+ rspec-core (2.13.1)
57
+ rspec-expectations (2.13.0)
58
+ diff-lcs (>= 1.1.3, < 2.0)
59
+ rspec-mocks (2.13.1)
60
+ sinatra (1.4.2)
61
+ rack (~> 1.5, >= 1.5.2)
62
+ rack-protection (~> 1.4)
63
+ tilt (~> 1.3, >= 1.3.4)
64
+ slop (3.4.5)
65
+ thread_safe (0.1.0)
66
+ atomic
67
+ tilt (1.4.1)
68
+ tzinfo (0.3.37)
69
+ uuidtools (2.1.4)
70
+ yard (0.8.6.1)
71
+
72
+ PLATFORMS
73
+ ruby
74
+
75
+ DEPENDENCIES
76
+ activemodel (~> 4.0.0)
77
+ aws-sdk
78
+ bundler
79
+ fake_dynamo (~> 0.1.3)
80
+ github-markup
81
+ jeweler
82
+ mocha (= 0.10.0)
83
+ pry
84
+ rake
85
+ redcarpet (= 1.17.2)
86
+ rspec
87
+ tzinfo
88
+ yard
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Josh Symonds
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,360 @@
1
+ # Dynamoid
2
+
3
+ Dynamoid is an ORM for Amazon's DynamoDB for Ruby applications. It
4
+ provides similar functionality to ActiveRecord and improves on
5
+ Amazon's existing
6
+ [HashModel](http://docs.amazonwebservices.com/AWSRubySDK/latest/AWS/Record/HashModel.html)
7
+ by providing better searching tools and native association support.
8
+
9
+ DynamoDB is not like other document-based databases you might know, and is very different indeed from relational databases. It sacrifices anything beyond the simplest relational queries and transactional support to provide a fast, cost-efficient, and highly durable storage solution. If your database requires complicated relational queries and transaction support, then this modest Gem cannot provide them for you, and neither can DynamoDB. In those cases you would do better to look elsewhere for your database needs.
10
+
11
+ But if you want a fast, scalable, simple, easy-to-use database (and a Gem that supports it) then look no further!
12
+
13
+ ## Installation
14
+
15
+ Installing Dynamoid is pretty simple. First include the Gem in your Gemfile:
16
+
17
+ ```ruby
18
+ gem 'dynamoid'
19
+ ```
20
+ ## Prerequisities
21
+
22
+ Dynamoid depends on the aws-sdk, and this is tested on the current version of aws-sdk (1.6.9), rails 3.2.8.
23
+ Hence the configuration as needed for aws to work will be dealt with by aws setup.
24
+
25
+ Here are the steps to setup aws-sdk.
26
+
27
+ ```ruby
28
+ gem 'aws-sdk'
29
+ ```
30
+ (or) include the aws-sdk in your Gemfile.
31
+
32
+
33
+ [Refer this link for aws setup](https://github.com/amazonwebservices/aws-sdk-for-ruby)
34
+
35
+ 1. Just like the config/database.yml this file requires an entry for each environment, create config/aws.yml as follows:
36
+
37
+ Fill in your AWS Access Key ID and Secret Access Key
38
+
39
+ ```ruby
40
+
41
+
42
+ development:
43
+ access_key_id: REPLACE_WITH_ACCESS_KEY_ID
44
+ secret_access_key: REPLACE_WITH_SECRET_ACCESS_KEY
45
+ dynamo_db_endpoint: dynamodb.ap-southeast-1.amazonaws.com
46
+
47
+ test:
48
+ <<: *development
49
+
50
+ production:
51
+ <<: *development
52
+
53
+ ```
54
+
55
+ (or)
56
+
57
+
58
+ 2. Create config/initializers/aws.rb as follows:
59
+
60
+ ```ruby
61
+
62
+ #Additionally include any of the dynamodb paramters as needed.
63
+ #(eg: if you would like to change the dynamodb endpoint, then add the parameter in
64
+ # in the file aws.yml or aws.rb
65
+
66
+ AWS.config({
67
+ :access_key_id => 'REPLACE_WITH_ACCESS_KEY_ID',
68
+ :secret_access_key => 'REPLACE_WITH_SECRET_ACCESS_KEY',
69
+ :dynamo_db_endpoint => 'dynamodb.ap-southeast-1.amazonaws.com'
70
+ })
71
+
72
+
73
+ ```
74
+
75
+ For a full list of the DDB regions, you can go
76
+ [here](http://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region).
77
+
78
+
79
+ Refer to the documentation of the AWS module at the below link for all of the configuration options supported by DynamoDB.
80
+
81
+ [Module AWS](http://docs.amazonwebservices.com/AWSRubySDK/latest/frames.html#!http%3A//docs.amazonwebservices.com/AWSRubySDK/latest/AWS.html)
82
+
83
+ Then you need to initialize Dynamoid config to get it going. Put code similar to this somewhere (a Rails initializer would be a great place for this if you're using Rails):
84
+
85
+ ```ruby
86
+ Dynamoid.configure do |config|
87
+ config.adapter = 'aws_sdk' # This adapter establishes a connection to the DynamoDB servers using Amazon's own AWS gem.
88
+ config.namespace = "dynamoid_app_development" # To namespace tables created by Dynamoid from other tables you might have.
89
+ config.warn_on_scan = true # Output a warning to the logger when you perform a scan rather than a query on a table.
90
+ config.partitioning = true # Spread writes randomly across the database. See "partitioning" below for more.
91
+ config.partition_size = 200 # Determine the key space size that writes are randomly spread across.
92
+ config.read_capacity = 100 # Read capacity for your tables
93
+ config.write_capacity = 20 # Write capacity for your tables
94
+ end
95
+
96
+ ```
97
+
98
+ Once you have the configuration set up, you need to move on to making models.
99
+
100
+ ## Setup
101
+
102
+ You *must* include ```Dynamoid::Document``` in every Dynamoid model.
103
+
104
+ ```ruby
105
+ class User
106
+ include Dynamoid::Document
107
+
108
+ end
109
+ ```
110
+
111
+ ### Table
112
+
113
+ Dynamoid has some sensible defaults for you when you create a new table, including the table name and the primary key column. But you can change those if you like on table creation.
114
+
115
+ ```ruby
116
+ class User
117
+ include Dynamoid::Document
118
+
119
+ table :name => :awesome_users, :key => :user_id, :read_capacity => 400, :write_capacity => 400
120
+ end
121
+ ```
122
+
123
+ These fields will not change an existing table: so specifying a new read_capacity and write_capacity here only works correctly for entirely new tables. Similarly, while Dynamoid will look for a table named `awesome_users` in your namespace, it won't change any existing tables to use that name; and if it does find a table with the correct name, it won't change its hash key, which it expects will be user_id. If this table doesn't exist yet, however, Dynamoid will create it with these options.
124
+
125
+ ### Fields
126
+
127
+ You'll have to define all the fields on the model and the data type of each field. Every field on the object must be included here; if you miss any they'll be completely bypassed during DynamoDB's initialization and will not appear on the model objects.
128
+
129
+ By default, fields are assumed to be of type ```:string```. But you can also use ```:integer```, ```:float```, ```:set```, ```:array```, ```:datetime```, ```:boolean```, and ```:serialized```. You get magic columns of id (string), created_at (datetime), and updated_at (datetime) for free.
130
+
131
+ ```ruby
132
+ class User
133
+ include Dynamoid::Document
134
+
135
+ field :name
136
+ field :email
137
+ field :rank, :integer
138
+ field :number, :float
139
+ field :joined_at, :datetime
140
+ field :hash, :serialized
141
+
142
+ end
143
+ ```
144
+
145
+ ### Indexes
146
+
147
+ You can also define indexes on fields, combinations of fields, and one range field. Yes, only one range field: in DynamoDB tables can have at most one range index, so make good use of it! To make an index, just specify the fields you want it on, either single or in an array. If the entire index is a range, pass ```:range => true```. Otherwise, pass the attribute that will become the range key. The only range attributes you can use right now are integers, floats, and datetimes. If you pass a string as a range key likely DynamoDB will complain a lot.
148
+
149
+ ```ruby
150
+ class User
151
+ include Dynamoid::Document
152
+
153
+ ...
154
+
155
+ index :name
156
+ index :email
157
+ index [:name, :email]
158
+ index :created_at, :range => true
159
+ index :name, :range_key => :joined_at
160
+
161
+ end
162
+ ```
163
+
164
+ ### Associations
165
+
166
+ Just like in ActiveRecord (or your other favorite ORM), Dynamoid uses associations to create links between models.
167
+
168
+ The only supported associations (so far) are ```has_many```, ```has_one```, ```has_and_belongs_to_many```, and ```belongs_to```. Associations are very simple to create: just specify the type, the name, and then any options you'd like to pass to the association. If there's an inverse association either inferred or specified directly, Dynamoid will update both objects to point at each other.
169
+
170
+ ```ruby
171
+ class User
172
+ include Dynamoid::Document
173
+
174
+ ...
175
+
176
+ has_many :addresses
177
+ has_many :students, :class => User
178
+ belongs_to :teacher, :class_name => :user
179
+ belongs_to :group
180
+ has_one :role
181
+ has_and_belongs_to_many :friends, :inverse_of => :friending_users
182
+
183
+ end
184
+
185
+ class Address
186
+ include Dynamoid::Document
187
+
188
+ ...
189
+
190
+ belongs_to :address # Automatically links up with the user model
191
+
192
+ end
193
+ ```
194
+
195
+ Contrary to what you'd expect, association information is always contained on the object specifying the association, even if it seems like the association has a foreign key. This is a side effect of DynamoDB's structure: it's very difficult to find foreign keys without an index. Usually you won't find this to be a problem, but it does mean that association methods that build new models will not work correctly -- for example, ```user.addresses.new``` returns an address that is not associated to the user. We'll be correcting this soon.
196
+
197
+ ### Validations
198
+
199
+ Dynamoid bakes in ActiveModel validations, just like ActiveRecord does.
200
+
201
+ ```ruby
202
+ class User
203
+ include Dynamoid::Document
204
+
205
+ ...
206
+
207
+ validates_presence_of :name
208
+ validates_format_of :email, :with => /@/
209
+ end
210
+ ```
211
+
212
+ To see more usage and examples of ActiveModel validations, check out the [ActiveModel validation documentation](http://api.rubyonrails.org/classes/ActiveModel/Validations.html).
213
+
214
+ ### Callbacks
215
+
216
+ Dynamoid also employs ActiveModel callbacks. Right now, callbacks are defined on ```save```, ```update```, ```destroy```, which allows you to do ```before_``` or ```after_``` any of those.
217
+
218
+ ```ruby
219
+ class User
220
+ include Dynamoid::Document
221
+
222
+ ...
223
+
224
+ before_save :set_default_password
225
+ after_create :notify_friends
226
+ after_destroy :delete_addresses
227
+ end
228
+ ```
229
+
230
+ ## Usage
231
+
232
+ ### Object Creation
233
+
234
+ Dynamoid's syntax is generally very similar to ActiveRecord's. Making new objects is simple:
235
+
236
+ ```ruby
237
+ u = User.new(:name => 'Josh')
238
+ u.email = 'josh@joshsymonds.com'
239
+ u.save
240
+ ```
241
+
242
+ Save forces persistence to the datastore: a unique ID is also assigned, but it is a string and not an auto-incrementing number.
243
+
244
+ ```ruby
245
+ u.id # => "3a9f7216-4726-4aea-9fbc-8554ae9292cb"
246
+ ```
247
+
248
+ Along with persisting the model's attributes, indexes are automatically updated on save. To use associations, you use association methods very similar to ActiveRecord's:
249
+
250
+ ```ruby
251
+ address = u.addresses.create
252
+ address.city = 'Chicago'
253
+ address.save
254
+ ```
255
+
256
+ ### Querying
257
+
258
+ Querying can be done in one of three ways:
259
+
260
+ ```ruby
261
+ Address.find(address.id) # Find directly by ID.
262
+ Address.where(:city => 'Chicago').all # Find by any number of matching criteria... though presently only "where" is supported.
263
+ Address.find_by_city('Chicago') # The same as above, but using ActiveRecord's older syntax.
264
+ ```
265
+
266
+ And you can also query on associations:
267
+
268
+ ```ruby
269
+ u.addresses.where(:city => 'Chicago').all
270
+ ```
271
+
272
+ But keep in mind Dynamoid -- and document-based storage systems in general -- are not drop-in replacements for existing relational databases. The above query does not efficiently perform a conditional join, but instead finds all the user's addresses and naively filters them in Ruby. For large associations this is a performance hit compared to relational database engines.
273
+
274
+ You can also limit returned results, or select a record from which to start, to support pagination:
275
+
276
+ ```ruby
277
+ Address.limit(5).start(address) # Only 5 addresses.
278
+ ```
279
+
280
+ For large queries that return many rows, Dynamoid can use AWS' support for requesting documents in batches:
281
+
282
+ ```ruby
283
+ #Do some maintenance on the entire table without flooding DynamoDB
284
+ Address.all(batch_size: 100).each { |address| address.do_some_work; sleep(0.01) }
285
+ Address.limit(10_000).batch(100). each { … } #batch specified as part of a chain
286
+ ```
287
+
288
+ ### Consistent Reads
289
+
290
+ Querying supports consistent reading. By default, DynamoDB reads are eventually consistent: if you do a write and then a read immediately afterwards, the results of the previous write may not be reflected. If you need to do a consistent read (that is, you need to read the results of a write immediately) you can do so, but keep in mind that consistent reads are twice as expensive as regular reads for DynamoDB.
291
+
292
+ ```ruby
293
+ Address.find(address.id, :consistent_read => true) # Find an address, ensure the read is consistent.
294
+ Address.where(:city => 'Chicago').consistent.all # Find all addresses where the city is Chicago, with a consistent read.
295
+ ```
296
+
297
+ ### Range Finding
298
+
299
+ If you have a range index, Dynamoid provides a number of additional other convenience methods to make your life a little easier:
300
+
301
+ ```ruby
302
+ User.where("created_at.gt" => DateTime.now - 1.day).all
303
+ User.where("created_at.lt" => DateTime.now - 1.day).all
304
+ ```
305
+
306
+ It also supports .gte and .lte. Turning those into symbols and allowing a Rails SQL-style string syntax is in the works. You can only have one range argument per query, because of DynamoDB's inherent limitations, so use it sensibly!
307
+
308
+ ## Partitioning, Provisioning, and Performance
309
+
310
+ DynamoDB achieves much of its speed by relying on a random pattern of writes and reads: internally, hash keys are distributed across servers, and reading from two consecutive servers is much faster than reading from the same server twice. Of course, many of our applications request one key (like a commonly used role, a superuser, or a very popular product) much more frequently than other keys. In DynamoDB, this will result in lowered throughput and slower response times, and is a design pattern we should try to avoid.
311
+
312
+ Dynamoid attempts to obviate this problem transparently by employing a partitioning strategy to divide up keys randomly across DynamoDB's servers. Each ID is assigned an additional number (by default 0 to 199, but you can increase the partition size in Dynamoid's configuration) upon save; when read, all 200 hashes are retrieved simultaneously and the most recently updated one is returned to the application. This results in a significant net performance increase, and is usually invisible to the application itself. It does, however, bring up the important issue of provisioning your DynamoDB tables correctly.
313
+
314
+ When your read or write throughput exceed your table's allowed provisioning, DynamoDB will wait on connections until throughput is available again. This will appear as very, very slow requests and can be somewhat frustrating. Partitioning significantly increases the amount of throughput tables will experience; though DynamoDB will ignore keys that don't exist, if you have 20 partitioned keys representing one object, all will be retrieved every time the object is requested. Ensure that your tables are set up for this kind of throughput, or turn provisioning off, to make sure that DynamoDB doesn't throttle your requests.
315
+
316
+ ## Concurrency
317
+
318
+ Dynamoid supports basic, ActiveRecord-like optimistic locking on save operations. Simply add a `lock_version` column to your table like so:
319
+
320
+ ```ruby
321
+ class MyTable
322
+ ...
323
+
324
+ field :lock_version, :integer
325
+
326
+ ...
327
+ end
328
+ ```
329
+
330
+ In this example, all saves to `MyTable` will raise an `AWS::DynamoDB::Errors::ConditionalCheckFailedException` if a concurrent process loaded, edited, and saved the same row. Your code should trap this exception, reload the row (so that it will pick up the newest values), and try the save again.
331
+
332
+ Calls to `update` and `update!` also increment the `lock_version`, however they do not check the existing value. This guarantees that a update operation will raise an exception in a concurrent save operation, however a save operation will never cause an update to fail. Thus, `update` is useful & safe only for doing atomic operations (e.g. increment a value, add/remove from a set, etc), but should not be used in a read-modify-write pattern.
333
+
334
+ ## Credits
335
+
336
+ Dynamoid borrows code, structure, and even its name very liberally from the truly amazing [Mongoid](https://github.com/mongoid/mongoid). Without Mongoid to crib from none of this would have been possible, and I hope they don't mind me reusing their very awesome ideas to make DynamoDB just as accessible to the Ruby world as MongoDB.
337
+
338
+ Also, without contributors the project wouldn't be nearly as awesome. So many thanks to:
339
+
340
+ * [Logan Bowers](https://github.com/loganb)
341
+ * [Lane LaRue](https://github.com/luxx)
342
+ * [Craig Heneveld](https://github.com/cheneveld)
343
+ * [Anantha Kumaran](https://github.com/ananthakumaran)
344
+ * [Jason Dew](https://github.com/jasondew)
345
+ * [Luis Arias](https://github.com/luisantonioa)
346
+ * [Stefan Neculai](https://github.com/stefanneculai)
347
+
348
+ ## Running the tests
349
+
350
+ Running the tests is fairly simple. In one window, run `fake_dynamo --port 4567`, and in the other, use `rake`.
351
+
352
+ ## Copyright
353
+
354
+ Copyright (c) 2012 Josh Symonds.
355
+
356
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
357
+
358
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
359
+
360
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.