dynamoid 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/.travis.yml +4 -0
  2. data/Gemfile +3 -2
  3. data/Gemfile.lock +40 -45
  4. data/README.markdown +55 -25
  5. data/Rakefile +31 -0
  6. data/VERSION +1 -1
  7. data/doc/Dynamoid.html +58 -42
  8. data/doc/Dynamoid/Adapter.html +666 -179
  9. data/doc/Dynamoid/Adapter/AwsSdk.html +752 -236
  10. data/doc/Dynamoid/Associations.html +28 -21
  11. data/doc/Dynamoid/Associations/Association.html +102 -49
  12. data/doc/Dynamoid/Associations/BelongsTo.html +28 -25
  13. data/doc/Dynamoid/Associations/ClassMethods.html +95 -52
  14. data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +28 -25
  15. data/doc/Dynamoid/Associations/HasMany.html +28 -25
  16. data/doc/Dynamoid/Associations/HasOne.html +28 -25
  17. data/doc/Dynamoid/Associations/ManyAssociation.html +138 -94
  18. data/doc/Dynamoid/Associations/SingleAssociation.html +67 -38
  19. data/doc/Dynamoid/Components.html +60 -22
  20. data/doc/Dynamoid/Config.html +61 -44
  21. data/doc/Dynamoid/Config/Options.html +90 -61
  22. data/doc/Dynamoid/Criteria.html +28 -21
  23. data/doc/Dynamoid/Criteria/Chain.html +508 -100
  24. data/doc/Dynamoid/Criteria/ClassMethods.html +26 -19
  25. data/doc/Dynamoid/Dirty.html +424 -0
  26. data/doc/Dynamoid/Dirty/ClassMethods.html +174 -0
  27. data/doc/Dynamoid/Document.html +451 -84
  28. data/doc/Dynamoid/Document/ClassMethods.html +281 -102
  29. data/doc/Dynamoid/Errors.html +29 -22
  30. data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +141 -0
  31. data/doc/Dynamoid/Errors/DocumentNotValid.html +36 -25
  32. data/doc/Dynamoid/Errors/Error.html +27 -20
  33. data/doc/Dynamoid/Errors/InvalidField.html +27 -19
  34. data/doc/Dynamoid/Errors/InvalidQuery.html +131 -0
  35. data/doc/Dynamoid/Errors/MissingRangeKey.html +27 -19
  36. data/doc/Dynamoid/Fields.html +94 -77
  37. data/doc/Dynamoid/Fields/ClassMethods.html +166 -37
  38. data/doc/Dynamoid/Finders.html +28 -21
  39. data/doc/Dynamoid/Finders/ClassMethods.html +505 -78
  40. data/doc/Dynamoid/IdentityMap.html +492 -0
  41. data/doc/Dynamoid/IdentityMap/ClassMethods.html +534 -0
  42. data/doc/Dynamoid/Indexes.html +41 -28
  43. data/doc/Dynamoid/Indexes/ClassMethods.html +45 -29
  44. data/doc/Dynamoid/Indexes/Index.html +100 -62
  45. data/doc/Dynamoid/Middleware.html +115 -0
  46. data/doc/Dynamoid/Middleware/IdentityMap.html +264 -0
  47. data/doc/Dynamoid/Persistence.html +326 -85
  48. data/doc/Dynamoid/Persistence/ClassMethods.html +275 -109
  49. data/doc/Dynamoid/Validations.html +47 -31
  50. data/doc/_index.html +116 -71
  51. data/doc/class_list.html +13 -7
  52. data/doc/css/full_list.css +4 -2
  53. data/doc/css/style.css +60 -44
  54. data/doc/file.LICENSE.html +26 -19
  55. data/doc/file.README.html +152 -48
  56. data/doc/file_list.html +14 -8
  57. data/doc/frames.html +20 -5
  58. data/doc/index.html +152 -48
  59. data/doc/js/app.js +52 -43
  60. data/doc/js/full_list.js +14 -9
  61. data/doc/js/jquery.js +4 -16
  62. data/doc/method_list.html +446 -540
  63. data/doc/top-level-namespace.html +27 -20
  64. data/{Dynamoid.gemspec → dynamoid.gemspec} +21 -8
  65. data/lib/dynamoid/adapter.rb +11 -10
  66. data/lib/dynamoid/adapter/aws_sdk.rb +40 -19
  67. data/lib/dynamoid/components.rb +2 -1
  68. data/lib/dynamoid/criteria/chain.rb +29 -11
  69. data/lib/dynamoid/dirty.rb +6 -0
  70. data/lib/dynamoid/document.rb +34 -19
  71. data/lib/dynamoid/fields.rb +36 -30
  72. data/lib/dynamoid/finders.rb +7 -5
  73. data/lib/dynamoid/persistence.rb +37 -10
  74. data/spec/app/models/address.rb +2 -0
  75. data/spec/app/models/camel_case.rb +10 -0
  76. data/spec/app/models/car.rb +6 -0
  77. data/spec/app/models/nuclear_submarine.rb +5 -0
  78. data/spec/app/models/subscription.rb +2 -2
  79. data/spec/app/models/vehicle.rb +7 -0
  80. data/spec/dynamoid/adapter/aws_sdk_spec.rb +20 -11
  81. data/spec/dynamoid/adapter_spec.rb +67 -82
  82. data/spec/dynamoid/associations/association_spec.rb +30 -30
  83. data/spec/dynamoid/criteria/chain_spec.rb +56 -9
  84. data/spec/dynamoid/criteria_spec.rb +3 -0
  85. data/spec/dynamoid/dirty_spec.rb +8 -0
  86. data/spec/dynamoid/document_spec.rb +109 -47
  87. data/spec/dynamoid/fields_spec.rb +32 -3
  88. data/spec/dynamoid/finders_spec.rb +12 -0
  89. data/spec/dynamoid/persistence_spec.rb +73 -8
  90. data/spec/spec_helper.rb +1 -0
  91. data/spec/support/with_partitioning.rb +15 -0
  92. metadata +22 -9
@@ -8,13 +8,13 @@
8
8
 
9
9
  <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
10
10
 
11
-
11
+
12
12
 
13
13
  <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
14
14
 
15
15
  <script type="text/javascript" charset="utf-8" src="js/full_list.js"></script>
16
16
 
17
-
17
+
18
18
  <base id="base_target" target="_parent" />
19
19
  </head>
20
20
  <body>
@@ -28,22 +28,28 @@
28
28
  <h1 id="full_list_header">File List</h1>
29
29
  <div id="nav">
30
30
 
31
- <a target="_self" href="class_list.html">Classes</a>
31
+ <span><a target="_self" href="class_list.html">
32
+ Classes
33
+ </a></span>
32
34
 
33
- <a target="_self" href="method_list.html">Methods</a>
35
+ <span><a target="_self" href="method_list.html">
36
+ Methods
37
+ </a></span>
34
38
 
35
- <a target="_self" href="file_list.html">Files</a>
39
+ <span><a target="_self" href="file_list.html">
40
+ Files
41
+ </a></span>
36
42
 
37
43
  </div>
38
44
  <div id="search">Search: <input type="text" /></div>
39
45
 
40
- <ul id="full_list" class="files">
46
+ <ul id="full_list" class="file">
41
47
 
42
48
 
43
- <li class="r1"><a href="index.html" title="README">README</a></li>
49
+ <li class="r1"><span class="object_link"><a href="index.html" title="README">README</a></a></li>
44
50
 
45
51
 
46
- <li class="r2"><a href="file.LICENSE.html" title="LICENSE">LICENSE</a></li>
52
+ <li class="r2"><span class="object_link"><a href="file.LICENSE.html" title="LICENSE">LICENSE</a></a></li>
47
53
 
48
54
 
49
55
  </ul>
@@ -4,10 +4,25 @@
4
4
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
5
  <head>
6
6
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7
- <title>Documentation by YARD 0.7.5</title>
7
+ <title>Documentation by YARD 0.8.6.1</title>
8
8
  </head>
9
- <frameset cols="20%,*">
10
- <frame name="list" src="class_list.html" />
11
- <frame name="main" src="index.html" />
12
- </frameset>
9
+ <script type="text/javascript" charset="utf-8">
10
+ window.onload = function() {
11
+ var match = window.location.hash.match(/^#!(.+)/);
12
+ var name = 'index.html';
13
+ if (match) {
14
+ name = unescape(match[1]);
15
+ }
16
+ document.writeln('<frameset cols="20%,*">' +
17
+ '<frame name="list" src="class_list.html" />' +
18
+ '<frame name="main" src="' + name + '" />' +
19
+ '</frameset>');
20
+ }
21
+ </script>
22
+ <noscript>
23
+ <frameset cols="20%,*">
24
+ <frame name="list" src="class_list.html" />
25
+ <frame name="main" src="index.html" />
26
+ </frameset>
27
+ </noscript>
13
28
  </html>
@@ -6,19 +6,21 @@
6
6
  <title>
7
7
  File: README
8
8
 
9
- &mdash; Documentation by YARD 0.7.5
9
+ &mdash; Documentation by YARD 0.8.6.1
10
10
 
11
11
  </title>
12
12
 
13
- <link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
14
14
 
15
- <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
16
16
 
17
17
  <script type="text/javascript" charset="utf-8">
18
+ hasFrames = window.top.frames.main ? true : false;
18
19
  relpath = '';
19
- if (relpath != '') relpath += '/';
20
+ framesUrl = "frames.html#!" + escape(window.location.href);
20
21
  </script>
21
22
 
23
+
22
24
  <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
23
25
 
24
26
  <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
@@ -26,37 +28,46 @@
26
28
 
27
29
  </head>
28
30
  <body>
29
- <script type="text/javascript" charset="utf-8">
30
- if (window.top.frames.main) document.body.className = 'frames';
31
- </script>
32
-
33
31
  <div id="header">
34
32
  <div id="menu">
35
33
 
36
- <a href="_index.html" title="Index">Index</a> &raquo;
34
+ <a href="_index.html">Index</a> &raquo;
37
35
  <span class="title">File: README</span>
38
36
 
39
-
37
+
40
38
  <div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
41
39
  </div>
42
40
 
43
41
  <div id="search">
44
42
 
45
- <a id="class_list_link" href="#">Class List</a>
43
+ <a class="full_list_link" id="class_list_link"
44
+ href="class_list.html">
45
+ Class List
46
+ </a>
46
47
 
47
- <a id="method_list_link" href="#">Method List</a>
48
+ <a class="full_list_link" id="method_list_link"
49
+ href="method_list.html">
50
+ Method List
51
+ </a>
48
52
 
49
- <a id="file_list_link" href="#">File List</a>
53
+ <a class="full_list_link" id="file_list_link"
54
+ href="file_list.html">
55
+ File List
56
+ </a>
50
57
 
51
58
  </div>
52
59
  <div class="clear"></div>
53
60
  </div>
54
-
61
+
55
62
  <iframe id="search_frame"></iframe>
56
-
63
+
57
64
  <div id="content"><div id='filecontents'><h1>Dynamoid</h1>
58
65
 
59
- <p>Dynamoid is an ORM for Amazon's DynamoDB for Ruby applications. It provides similar functionality to ActiveRecord and improves on Amazon's existing <a href="http://docs.amazonwebservices.com/AWSRubySDK/latest/AWS/Record/HashModel.html">HashModel</a> by providing better searching tools, native association support, and a local adapter for offline development.</p>
66
+ <p>Dynamoid is an ORM for Amazon's DynamoDB for Ruby applications. It
67
+ provides similar functionality to ActiveRecord and improves on
68
+ Amazon's existing
69
+ <a href="http://docs.amazonwebservices.com/AWSRubySDK/latest/AWS/Record/HashModel.html">HashModel</a>
70
+ by providing better searching tools and native association support.</p>
60
71
 
61
72
  <p>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.</p>
62
73
 
@@ -66,23 +77,81 @@
66
77
 
67
78
  <p>Installing Dynamoid is pretty simple. First include the Gem in your Gemfile:</p>
68
79
 
69
- <pre class="code ruby"><code><span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>dynamoid</span><span class='tstring_end'>'</span></span>
80
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>dynamoid</span><span class='tstring_end'>'</span></span>
81
+ </code></pre>
82
+
83
+ <h2>Prerequisities</h2>
84
+
85
+ <p>Dynamoid depends on the aws-sdk, and this is tested on the current version of aws-sdk (1.6.9), rails 3.2.8.
86
+ Hence the configuration as needed for aws to work will be dealt with by aws setup.</p>
87
+
88
+ <p>Here are the steps to setup aws-sdk.</p>
89
+
90
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>aws-sdk</span><span class='tstring_end'>'</span></span>
91
+ </code></pre>
92
+
93
+ <p>(or) include the aws-sdk in your Gemfile.</p>
94
+
95
+ <p><a href="https://github.com/amazonwebservices/aws-sdk-for-ruby">Refer this link for aws setup</a></p>
96
+
97
+ <ol>
98
+ <li>Just like the config/database.yml this file requires an entry for each environment, create config/aws.yml as follows:</li>
99
+ </ol>
100
+
101
+ <p>Fill in your AWS Access Key ID and Secret Access Key</p>
102
+
103
+ <pre class="code ruby"><code class="ruby">
104
+
105
+ development:
106
+ access_key_id: REPLACE_WITH_ACCESS_KEY_ID
107
+ secret_access_key: REPLACE_WITH_SECRET_ACCESS_KEY
108
+ dynamo_db_endpoint: dynamodb.ap-southeast-1.amazonaws.com
109
+
110
+ test:
111
+ &lt;&lt;: *development
112
+
113
+ production:
114
+ &lt;&lt;: *development
115
+
70
116
  </code></pre>
71
117
 
72
- <p>Then you need to initialize it 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):</p>
118
+ <p>(or)</p>
119
+
120
+ <ol>
121
+ <li>Create config/initializers/aws.rb as follows:</li>
122
+ </ol>
73
123
 
74
- <pre class="code ruby"><code> <span class='const'>Dynamoid</span><span class='period'>.</span><span class='id identifier rubyid_configure'>configure</span> <span class='kw'>do</span> <span class='op'>|</span><span class='id identifier rubyid_config'>config</span><span class='op'>|</span>
75
- <span class='id identifier rubyid_config'>config</span><span class='period'>.</span><span class='id identifier rubyid_adapter'>adapter</span> <span class='op'>=</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>local</span><span class='tstring_end'>'</span></span> <span class='comment'># This adapter allows offline development without connecting to the DynamoDB servers. Data is *NOT* persisted.
76
- </span> <span class='comment'># config.adapter = 'aws_sdk' # This adapter establishes a connection to the DynamoDB servers using Amazon's own AWS gem.
77
- </span> <span class='comment'># config.access_key = 'access_key' # If connecting to DynamoDB, your access key is required.
78
- </span> <span class='comment'># config.secret_key = 'secret_key' # So is your secret key.
124
+ <pre class="code ruby"><code class="ruby">
125
+ <span class='comment'>#Additionally include any of the dynamodb paramters as needed.
126
+ </span><span class='comment'>#(eg: if you would like to change the dynamodb endpoint, then add the parameter in
127
+ </span><span class='comment'># in the file aws.yml or aws.rb
128
+ </span>
129
+ <span class='const'>AWS</span><span class='period'>.</span><span class='id identifier rubyid_config'>config</span><span class='lparen'>(</span><span class='lbrace'>{</span>
130
+ <span class='symbol'>:access_key_id</span> <span class='op'>=&gt;</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>REPLACE_WITH_ACCESS_KEY_ID</span><span class='tstring_end'>'</span></span><span class='comma'>,</span>
131
+ <span class='symbol'>:secret_access_key</span> <span class='op'>=&gt;</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>REPLACE_WITH_SECRET_ACCESS_KEY</span><span class='tstring_end'>'</span></span><span class='comma'>,</span>
132
+ <span class='symbol'>:dynamo_db_endpoint</span> <span class='op'>=&gt;</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>dynamodb.ap-southeast-1.amazonaws.com</span><span class='tstring_end'>'</span></span>
133
+ <span class='rbrace'>}</span><span class='rparen'>)</span>
134
+
135
+
136
+ </code></pre>
137
+
138
+ <p>For a full list of the DDB regions, you can go
139
+ <a href="http://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region">here</a>.</p>
140
+
141
+ <p>Refer to the documentation of the AWS module at the below link for all of the configuration options supported by DynamoDB.</p>
142
+
143
+ <p><a href="http://docs.amazonwebservices.com/AWSRubySDK/latest/frames.html#!http%3A//docs.amazonwebservices.com/AWSRubySDK/latest/AWS.html">Module AWS</a></p>
144
+
145
+ <p>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):</p>
146
+
147
+ <pre class="code ruby"><code class="ruby"> <span class='const'>Dynamoid</span><span class='period'>.</span><span class='id identifier rubyid_configure'>configure</span> <span class='kw'>do</span> <span class='op'>|</span><span class='id identifier rubyid_config'>config</span><span class='op'>|</span>
148
+ <span class='id identifier rubyid_config'>config</span><span class='period'>.</span><span class='id identifier rubyid_adapter'>adapter</span> <span class='op'>=</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>aws_sdk</span><span class='tstring_end'>'</span></span> <span class='comment'># This adapter establishes a connection to the DynamoDB servers using Amazon's own AWS gem.
79
149
  </span> <span class='id identifier rubyid_config'>config</span><span class='period'>.</span><span class='id identifier rubyid_namespace'>namespace</span> <span class='op'>=</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>dynamoid_app_development</span><span class='tstring_end'>&quot;</span></span> <span class='comment'># To namespace tables created by Dynamoid from other tables you might have.
80
150
  </span> <span class='id identifier rubyid_config'>config</span><span class='period'>.</span><span class='id identifier rubyid_warn_on_scan'>warn_on_scan</span> <span class='op'>=</span> <span class='kw'>true</span> <span class='comment'># Output a warning to the logger when you perform a scan rather than a query on a table.
81
151
  </span> <span class='id identifier rubyid_config'>config</span><span class='period'>.</span><span class='id identifier rubyid_partitioning'>partitioning</span> <span class='op'>=</span> <span class='kw'>true</span> <span class='comment'># Spread writes randomly across the database. See &quot;partitioning&quot; below for more.
82
152
  </span> <span class='id identifier rubyid_config'>config</span><span class='period'>.</span><span class='id identifier rubyid_partition_size'>partition_size</span> <span class='op'>=</span> <span class='int'>200</span> <span class='comment'># Determine the key space size that writes are randomly spread across.
83
153
  </span> <span class='id identifier rubyid_config'>config</span><span class='period'>.</span><span class='id identifier rubyid_read_capacity'>read_capacity</span> <span class='op'>=</span> <span class='int'>100</span> <span class='comment'># Read capacity for your tables
84
154
  </span> <span class='id identifier rubyid_config'>config</span><span class='period'>.</span><span class='id identifier rubyid_write_capacity'>write_capacity</span> <span class='op'>=</span> <span class='int'>20</span> <span class='comment'># Write capacity for your tables
85
- </span> <span class='id identifier rubyid_config'>config</span><span class='period'>.</span><span class='id identifier rubyid_endpoint'>endpoint</span> <span class='op'>=</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>dynamodb.us-east-1.amazonaws.com</span><span class='tstring_end'>'</span></span> <span class='comment'># Set the regional endpoint
86
155
  </span> <span class='kw'>end</span>
87
156
 
88
157
  </code></pre>
@@ -93,7 +162,7 @@
93
162
 
94
163
  <p>You <em>must</em> include <code>Dynamoid::Document</code> in every Dynamoid model.</p>
95
164
 
96
- <pre class="code ruby"><code><span class='kw'>class</span> <span class='const'>User</span>
165
+ <pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>User</span>
97
166
  <span class='id identifier rubyid_include'>include</span> <span class='const'>Dynamoid</span><span class='op'>::</span><span class='const'>Document</span>
98
167
 
99
168
  <span class='kw'>end</span>
@@ -103,7 +172,7 @@
103
172
 
104
173
  <p>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.</p>
105
174
 
106
- <pre class="code ruby"><code><span class='kw'>class</span> <span class='const'>User</span>
175
+ <pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>User</span>
107
176
  <span class='id identifier rubyid_include'>include</span> <span class='const'>Dynamoid</span><span class='op'>::</span><span class='const'>Document</span>
108
177
 
109
178
  <span class='id identifier rubyid_table'>table</span> <span class='symbol'>:name</span> <span class='op'>=&gt;</span> <span class='symbol'>:awesome_users</span><span class='comma'>,</span> <span class='symbol'>:key</span> <span class='op'>=&gt;</span> <span class='symbol'>:user_id</span><span class='comma'>,</span> <span class='symbol'>:read_capacity</span> <span class='op'>=&gt;</span> <span class='int'>400</span><span class='comma'>,</span> <span class='symbol'>:write_capacity</span> <span class='op'>=&gt;</span> <span class='int'>400</span>
@@ -116,9 +185,9 @@
116
185
 
117
186
  <p>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.</p>
118
187
 
119
- <p>By default, fields are assumed to be of type <code>:string</code>. But you can also use <code>:integer</code>, <code>:float</code>, <code>:set</code>, <code>:array</code>, <code>:datetime</code>, and <code>:serialized</code>. You get magic columns of id (string), created_at (datetime), and updated_at (datetime) for free.</p>
188
+ <p>By default, fields are assumed to be of type <code>:string</code>. But you can also use <code>:integer</code>, <code>:float</code>, <code>:set</code>, <code>:array</code>, <code>:datetime</code>, <code>:boolean</code>, and <code>:serialized</code>. You get magic columns of id (string), created_at (datetime), and updated_at (datetime) for free.</p>
120
189
 
121
- <pre class="code ruby"><code><span class='kw'>class</span> <span class='const'>User</span>
190
+ <pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>User</span>
122
191
  <span class='id identifier rubyid_include'>include</span> <span class='const'>Dynamoid</span><span class='op'>::</span><span class='const'>Document</span>
123
192
 
124
193
  <span class='id identifier rubyid_field'>field</span> <span class='symbol'>:name</span>
@@ -135,14 +204,14 @@
135
204
 
136
205
  <p>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 <code>:range =&gt; true</code>. 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.</p>
137
206
 
138
- <pre class="code ruby"><code>class User
207
+ <pre class="code ruby"><code class="ruby">class User
139
208
  include Dynamoid::Document
140
209
 
141
210
  ...
142
211
 
143
- index :name
144
- index :email
145
- index [:name, :email]
212
+ index :name
213
+ index :email
214
+ index [:name, :email]
146
215
  index :created_at, :range =&gt; true
147
216
  index :name, :range_key =&gt; :joined_at
148
217
 
@@ -155,7 +224,7 @@ end
155
224
 
156
225
  <p>The only supported associations (so far) are <code>has_many</code>, <code>has_one</code>, <code>has_and_belongs_to_many</code>, and <code>belongs_to</code>. 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.</p>
157
226
 
158
- <pre class="code ruby"><code>class User
227
+ <pre class="code ruby"><code class="ruby">class User
159
228
  include Dynamoid::Document
160
229
 
161
230
  ...
@@ -185,7 +254,7 @@ end
185
254
 
186
255
  <p>Dynamoid bakes in ActiveModel validations, just like ActiveRecord does.</p>
187
256
 
188
- <pre class="code ruby"><code>class User
257
+ <pre class="code ruby"><code class="ruby">class User
189
258
  include Dynamoid::Document
190
259
 
191
260
  ...
@@ -201,7 +270,7 @@ end
201
270
 
202
271
  <p>Dynamoid also employs ActiveModel callbacks. Right now, callbacks are defined on <code>save</code>, <code>update</code>, <code>destroy</code>, which allows you to do <code>before_</code> or <code>after_</code> any of those.</p>
203
272
 
204
- <pre class="code ruby"><code>class User
273
+ <pre class="code ruby"><code class="ruby">class User
205
274
  include Dynamoid::Document
206
275
 
207
276
  ...
@@ -218,19 +287,19 @@ end
218
287
 
219
288
  <p>Dynamoid's syntax is generally very similar to ActiveRecord's. Making new objects is simple:</p>
220
289
 
221
- <pre class="code ruby"><code><span class='id identifier rubyid_u'>u</span> <span class='op'>=</span> <span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='symbol'>:name</span> <span class='op'>=&gt;</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Josh</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span>
290
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_u'>u</span> <span class='op'>=</span> <span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='symbol'>:name</span> <span class='op'>=&gt;</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Josh</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span>
222
291
  <span class='id identifier rubyid_u'>u</span><span class='period'>.</span><span class='id identifier rubyid_email'>email</span> <span class='op'>=</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>josh@joshsymonds.com</span><span class='tstring_end'>'</span></span>
223
292
  <span class='id identifier rubyid_u'>u</span><span class='period'>.</span><span class='id identifier rubyid_save'>save</span>
224
293
  </code></pre>
225
294
 
226
295
  <p>Save forces persistence to the datastore: a unique ID is also assigned, but it is a string and not an auto-incrementing number.</p>
227
296
 
228
- <pre class="code ruby"><code><span class='id identifier rubyid_u'>u</span><span class='period'>.</span><span class='id identifier rubyid_id'>id</span> <span class='comment'># =&gt; &quot;3a9f7216-4726-4aea-9fbc-8554ae9292cb&quot;
297
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_u'>u</span><span class='period'>.</span><span class='id identifier rubyid_id'>id</span> <span class='comment'># =&gt; &quot;3a9f7216-4726-4aea-9fbc-8554ae9292cb&quot;
229
298
  </span></code></pre>
230
299
 
231
300
  <p>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:</p>
232
301
 
233
- <pre class="code ruby"><code><span class='id identifier rubyid_address'>address</span> <span class='op'>=</span> <span class='id identifier rubyid_u'>u</span><span class='period'>.</span><span class='id identifier rubyid_addresses'>addresses</span><span class='period'>.</span><span class='id identifier rubyid_create'>create</span>
302
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_address'>address</span> <span class='op'>=</span> <span class='id identifier rubyid_u'>u</span><span class='period'>.</span><span class='id identifier rubyid_addresses'>addresses</span><span class='period'>.</span><span class='id identifier rubyid_create'>create</span>
234
303
  <span class='id identifier rubyid_address'>address</span><span class='period'>.</span><span class='id identifier rubyid_city'>city</span> <span class='op'>=</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Chicago</span><span class='tstring_end'>'</span></span>
235
304
  <span class='id identifier rubyid_address'>address</span><span class='period'>.</span><span class='id identifier rubyid_save'>save</span>
236
305
  </code></pre>
@@ -239,28 +308,35 @@ end
239
308
 
240
309
  <p>Querying can be done in one of three ways:</p>
241
310
 
242
- <pre class="code ruby"><code><span class='const'>Address</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span><span class='lparen'>(</span><span class='id identifier rubyid_address'>address</span><span class='period'>.</span><span class='id identifier rubyid_id'>id</span><span class='rparen'>)</span> <span class='comment'># Find directly by ID.
311
+ <pre class="code ruby"><code class="ruby"><span class='const'>Address</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span><span class='lparen'>(</span><span class='id identifier rubyid_address'>address</span><span class='period'>.</span><span class='id identifier rubyid_id'>id</span><span class='rparen'>)</span> <span class='comment'># Find directly by ID.
243
312
  </span><span class='const'>Address</span><span class='period'>.</span><span class='id identifier rubyid_where'>where</span><span class='lparen'>(</span><span class='symbol'>:city</span> <span class='op'>=&gt;</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Chicago</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span> <span class='comment'># Find by any number of matching criteria... though presently only &quot;where&quot; is supported.
244
313
  </span><span class='const'>Address</span><span class='period'>.</span><span class='id identifier rubyid_find_by_city'>find_by_city</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Chicago</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span> <span class='comment'># The same as above, but using ActiveRecord's older syntax.
245
314
  </span></code></pre>
246
315
 
247
316
  <p>And you can also query on associations:</p>
248
317
 
249
- <pre class="code ruby"><code><span class='id identifier rubyid_u'>u</span><span class='period'>.</span><span class='id identifier rubyid_addresses'>addresses</span><span class='period'>.</span><span class='id identifier rubyid_where'>where</span><span class='lparen'>(</span><span class='symbol'>:city</span> <span class='op'>=&gt;</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Chicago</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span>
318
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_u'>u</span><span class='period'>.</span><span class='id identifier rubyid_addresses'>addresses</span><span class='period'>.</span><span class='id identifier rubyid_where'>where</span><span class='lparen'>(</span><span class='symbol'>:city</span> <span class='op'>=&gt;</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Chicago</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span>
250
319
  </code></pre>
251
320
 
252
321
  <p>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.</p>
253
322
 
254
323
  <p>You can also limit returned results, or select a record from which to start, to support pagination:</p>
255
324
 
256
- <pre class="code ruby"><code><span class='const'>Address</span><span class='period'>.</span><span class='id identifier rubyid_limit'>limit</span><span class='lparen'>(</span><span class='int'>5</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_start'>start</span><span class='lparen'>(</span><span class='id identifier rubyid_address'>address</span><span class='rparen'>)</span> <span class='comment'># Only 5 addresses.
325
+ <pre class="code ruby"><code class="ruby"><span class='const'>Address</span><span class='period'>.</span><span class='id identifier rubyid_limit'>limit</span><span class='lparen'>(</span><span class='int'>5</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_start'>start</span><span class='lparen'>(</span><span class='id identifier rubyid_address'>address</span><span class='rparen'>)</span> <span class='comment'># Only 5 addresses.
326
+ </span></code></pre>
327
+
328
+ <p>For large queries that return many rows, Dynamoid can use AWS' support for requesting documents in batches:</p>
329
+
330
+ <pre class="code ruby"><code class="ruby"><span class='comment'>#Do some maintenance on the entire table without flooding DynamoDB
331
+ </span><span class='const'>Address</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span><span class='lparen'>(</span><span class='label'>batch_size:</span> <span class='int'>100</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_each'>each</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_address'>address</span><span class='op'>|</span> <span class='id identifier rubyid_address'>address</span><span class='period'>.</span><span class='id identifier rubyid_do_some_work'>do_some_work</span><span class='semicolon'>;</span> <span class='id identifier rubyid_sleep'>sleep</span><span class='lparen'>(</span><span class='float'>0.01</span><span class='rparen'>)</span> <span class='rbrace'>}</span>
332
+ <span class='const'>Address</span><span class='period'>.</span><span class='id identifier rubyid_limit'>limit</span><span class='lparen'>(</span><span class='int'>10_000</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_batch'>batch</span><span class='lparen'>(</span><span class='int'>100</span><span class='rparen'>)</span><span class='period'>.</span> <span class='id identifier rubyid_each'>each</span> <span class='lbrace'>{</span> <span class='id identifier rubyid_…'>…</span> <span class='rbrace'>}</span> <span class='comment'>#batch specified as part of a chain
257
333
  </span></code></pre>
258
334
 
259
335
  <h3>Consistent Reads</h3>
260
336
 
261
337
  <p>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.</p>
262
338
 
263
- <pre class="code ruby"><code><span class='const'>Address</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span><span class='lparen'>(</span><span class='id identifier rubyid_address'>address</span><span class='period'>.</span><span class='id identifier rubyid_id'>id</span><span class='comma'>,</span> <span class='symbol'>:consistent_read</span> <span class='op'>=&gt;</span> <span class='kw'>true</span><span class='rparen'>)</span> <span class='comment'># Find an address, ensure the read is consistent.
339
+ <pre class="code ruby"><code class="ruby"><span class='const'>Address</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span><span class='lparen'>(</span><span class='id identifier rubyid_address'>address</span><span class='period'>.</span><span class='id identifier rubyid_id'>id</span><span class='comma'>,</span> <span class='symbol'>:consistent_read</span> <span class='op'>=&gt;</span> <span class='kw'>true</span><span class='rparen'>)</span> <span class='comment'># Find an address, ensure the read is consistent.
264
340
  </span><span class='const'>Address</span><span class='period'>.</span><span class='id identifier rubyid_where'>where</span><span class='lparen'>(</span><span class='symbol'>:city</span> <span class='op'>=&gt;</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Chicago</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_consistent'>consistent</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span> <span class='comment'># Find all addresses where the city is Chicago, with a consistent read.
265
341
  </span></code></pre>
266
342
 
@@ -268,7 +344,7 @@ end
268
344
 
269
345
  <p>If you have a range index, Dynamoid provides a number of additional other convenience methods to make your life a little easier:</p>
270
346
 
271
- <pre class="code ruby"><code><span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_where'>where</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>created_at.gt</span><span class='tstring_end'>&quot;</span></span> <span class='op'>=&gt;</span> <span class='const'>DateTime</span><span class='period'>.</span><span class='id identifier rubyid_now'>now</span> <span class='op'>-</span> <span class='int'>1</span><span class='period'>.</span><span class='id identifier rubyid_day'>day</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span>
347
+ <pre class="code ruby"><code class="ruby"><span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_where'>where</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>created_at.gt</span><span class='tstring_end'>&quot;</span></span> <span class='op'>=&gt;</span> <span class='const'>DateTime</span><span class='period'>.</span><span class='id identifier rubyid_now'>now</span> <span class='op'>-</span> <span class='int'>1</span><span class='period'>.</span><span class='id identifier rubyid_day'>day</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span>
272
348
  <span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_where'>where</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>created_at.lt</span><span class='tstring_end'>&quot;</span></span> <span class='op'>=&gt;</span> <span class='const'>DateTime</span><span class='period'>.</span><span class='id identifier rubyid_now'>now</span> <span class='op'>-</span> <span class='int'>1</span><span class='period'>.</span><span class='id identifier rubyid_day'>day</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span>
273
349
  </code></pre>
274
350
 
@@ -282,6 +358,23 @@ end
282
358
 
283
359
  <p>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.</p>
284
360
 
361
+ <h2>Concurrency</h2>
362
+
363
+ <p>Dynamoid supports basic, ActiveRecord-like optimistic locking on save operations. Simply add a <code>lock_version</code> column to your table like so: </p>
364
+
365
+ <pre class="code ruby"><code class="ruby">class MyTable
366
+ ...
367
+
368
+ field :lock_version, :integer
369
+
370
+ ...
371
+ end
372
+ </code></pre>
373
+
374
+ <p>In this example, all saves to <code>MyTable</code> will raise an <code>AWS::DynamoDB::Errors::ConditionalCheckFailedException</code> 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. </p>
375
+
376
+ <p>Calls to <code>update</code> and <code>update!</code> also increment the <code>lock_version</code>, 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, <code>update</code> is useful &amp; 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. </p>
377
+
285
378
  <h2>Credits</h2>
286
379
 
287
380
  <p>Dynamoid borrows code, structure, and even its name very liberally from the truly amazing <a href="https://github.com/mongoid/mongoid">Mongoid</a>. 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.</p>
@@ -289,23 +382,34 @@ end
289
382
  <p>Also, without contributors the project wouldn't be nearly as awesome. So many thanks to:</p>
290
383
 
291
384
  <ul>
385
+ <li><a href="https://github.com/loganb">Logan Bowers</a></li>
386
+ <li><a href="https://github.com/luxx">Lane LaRue</a></li>
387
+ <li><a href="https://github.com/cheneveld">Craig Heneveld</a></li>
292
388
  <li><a href="https://github.com/ananthakumaran">Anantha Kumaran</a></li>
293
389
  <li><a href="https://github.com/jasondew">Jason Dew</a></li>
390
+ <li><a href="https://github.com/luisantonioa">Luis Arias</a></li>
391
+ <li><a href="https://github.com/stefanneculai">Stefan Neculai</a></li>
294
392
  </ul>
295
393
 
296
394
  <h2>Running the tests</h2>
297
395
 
298
- <p>The tests can be run in the simple predictable way with <code>rake</code>. However, if you provide environment variables for ACCESS_KEY and SECRET_KEY, the tests will use the aws_sdk adapter rather than the local adapter: <code>ACCESS_KEY=&lt;accesskey&gt; SECRET_KEY=&lt;secretkey&gt; rake</code>. Keep in mind this takes much, much longer than the local tests.</p>
396
+ <p>Running the tests is fairly simple. In one window, run <code>fake_dynamo --port 4567</code>, and in the other, use <code>rake</code>.</p>
299
397
 
300
398
  <h2>Copyright</h2>
301
399
 
302
- <p>Copyright (c) 2012 Josh Symonds. See LICENSE.txt for further details.</p>
400
+ <p>Copyright (c) 2012 Josh Symonds.</p>
401
+
402
+ <p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), 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:</p>
403
+
404
+ <p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>
405
+
406
+ <p>THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, 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.</p>
303
407
  </div></div>
304
-
408
+
305
409
  <div id="footer">
306
- Generated on Thu Apr 26 01:26:24 2012 by
410
+ Generated on Thu Jun 27 21:59:09 2013 by
307
411
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
308
- 0.7.5 (ruby-1.9.3).
412
+ 0.8.6.1 (ruby-1.9.3).
309
413
  </div>
310
414
 
311
415
  </body>