cassie 1.0.0.beta.17 → 1.0.0.beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/cassie +40 -15
- data/lib/cassie/configuration/templates/cassandra.yml +1 -2
- data/lib/cassie/connection.rb +3 -3
- data/lib/cassie/connection_handler/cluster.rb +1 -1
- data/lib/cassie/connection_handler/sessions.rb +1 -1
- data/lib/cassie/connection_handler.rb +4 -2
- data/lib/cassie/definition.rb +8 -0
- data/lib/cassie/modification.rb +9 -0
- data/lib/cassie/query.rb +3 -15
- data/lib/cassie/statements/README.md +710 -0
- data/lib/cassie/statements/core.rb +23 -0
- data/lib/cassie/{queries/statement/batches.rb → statements/execution/batched_fetching.rb} +7 -11
- data/lib/cassie/{queries/statement → statements/execution}/callbacks.rb +1 -1
- data/lib/cassie/{queries/statement → statements/execution}/consistency.rb +1 -1
- data/lib/cassie/statements/execution/deserialization.rb +13 -0
- data/lib/cassie/{queries/statement → statements/execution}/fetching.rb +10 -21
- data/lib/cassie/{queries/instrumentation/execution.rb → statements/execution/instrumentation.rb} +6 -2
- data/lib/cassie/statements/execution/partition_linking/cursoring_policy.rb +13 -0
- data/lib/cassie/statements/execution/partition_linking/policy_methods.rb +128 -0
- data/lib/cassie/statements/execution/partition_linking/simple_policy.rb +19 -0
- data/lib/cassie/statements/execution/partition_linking.rb +49 -0
- data/lib/cassie/statements/execution/peeking.rb +28 -0
- data/lib/cassie/statements/execution/results/core.rb +11 -0
- data/lib/cassie/statements/execution/results/cursored_result.rb +26 -0
- data/lib/cassie/statements/execution/results/instrumentation.rb +18 -0
- data/lib/cassie/statements/execution/results/modification.rb +12 -0
- data/lib/cassie/statements/execution/results/modification_result.rb +8 -0
- data/lib/cassie/statements/execution/results/peeking.rb +42 -0
- data/lib/cassie/statements/execution/results/peeking_result.rb +10 -0
- data/lib/cassie/statements/execution/results/query_result.rb +9 -0
- data/lib/cassie/statements/execution/results/querying.rb +66 -0
- data/lib/cassie/statements/execution/results/result.rb +23 -0
- data/lib/cassie/statements/execution/results.rb +12 -0
- data/lib/cassie/statements/execution.rb +69 -0
- data/lib/cassie/statements/instrumenting.rb +6 -0
- data/lib/cassie/{queries/logging/building_resources_event.rb → statements/logging/deserialize_event.rb} +4 -4
- data/lib/cassie/statements/logging/deserialize_subscriber.rb +19 -0
- data/lib/cassie/{queries/logging/cql_execution_event.rb → statements/logging/execute_event.rb} +8 -4
- data/lib/cassie/statements/logging/execute_subscriber.rb +19 -0
- data/lib/cassie/statements/logging.rb +12 -0
- data/lib/cassie/statements/modification.rb +14 -0
- data/lib/cassie/statements/query.rb +12 -0
- data/lib/cassie/statements/statement/assignment.rb +51 -0
- data/lib/cassie/statements/statement/assignments.rb +87 -0
- data/lib/cassie/{queries → statements}/statement/conditions.rb +1 -3
- data/lib/cassie/{queries → statements}/statement/deleting.rb +15 -12
- data/lib/cassie/{queries → statements}/statement/inserting.rb +13 -10
- data/lib/cassie/statements/statement/limiting.rb +89 -0
- data/lib/cassie/{queries → statements}/statement/mapping.rb +21 -41
- data/lib/cassie/{queries → statements}/statement/ordering.rb +1 -1
- data/lib/cassie/statements/statement/pagination/cursors.rb +112 -0
- data/lib/cassie/statements/statement/pagination.rb +19 -0
- data/lib/cassie/{queries → statements}/statement/preparation/cache.rb +1 -1
- data/lib/cassie/{queries → statements}/statement/preparation.rb +4 -5
- data/lib/cassie/statements/statement/relation.rb +68 -0
- data/lib/cassie/statements/statement/relations.rb +93 -0
- data/lib/cassie/statements/statement/selection.rb +86 -0
- data/lib/cassie/{queries → statements}/statement/updating.rb +9 -10
- data/lib/cassie/{queries → statements}/statement.rb +10 -20
- data/lib/cassie/statements.rb +9 -0
- data/lib/cassie/testing/fake/definition.rb +11 -0
- data/lib/cassie/testing/fake/modification.rb +11 -0
- data/lib/cassie/testing/fake/result.rb +15 -3
- data/lib/cassie/testing.rb +2 -0
- data/lib/cassie.rb +2 -0
- metadata +57 -34
- data/lib/cassie/queries/README.md +0 -458
- data/lib/cassie/queries/instrumentation/loading.rb +0 -15
- data/lib/cassie/queries/instrumentation.rb +0 -18
- data/lib/cassie/queries/logging/subscription.rb +0 -24
- data/lib/cassie/queries/logging.rb +0 -21
- data/lib/cassie/queries/statement/assignment.rb +0 -36
- data/lib/cassie/queries/statement/assignments.rb +0 -67
- data/lib/cassie/queries/statement/execution.rb +0 -45
- data/lib/cassie/queries/statement/limiting.rb +0 -36
- data/lib/cassie/queries/statement/loading.rb +0 -24
- data/lib/cassie/queries/statement/pagination/cursors.rb +0 -168
- data/lib/cassie/queries/statement/pagination/page_size.rb +0 -7
- data/lib/cassie/queries/statement/pagination.rb +0 -37
- data/lib/cassie/queries/statement/relation.rb +0 -74
- data/lib/cassie/queries/statement/relations.rb +0 -66
- data/lib/cassie/queries/statement/selection.rb +0 -63
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cassie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.beta.
|
4
|
+
version: 1.0.0.beta.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Prothro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cassandra-driver
|
@@ -123,45 +123,68 @@ files:
|
|
123
123
|
- lib/cassie/connection_handler/README.md
|
124
124
|
- lib/cassie/connection_handler/cluster.rb
|
125
125
|
- lib/cassie/connection_handler/sessions.rb
|
126
|
+
- lib/cassie/definition.rb
|
126
127
|
- lib/cassie/logger.rb
|
127
|
-
- lib/cassie/
|
128
|
-
- lib/cassie/queries/instrumentation.rb
|
129
|
-
- lib/cassie/queries/instrumentation/execution.rb
|
130
|
-
- lib/cassie/queries/instrumentation/loading.rb
|
131
|
-
- lib/cassie/queries/logging.rb
|
132
|
-
- lib/cassie/queries/logging/building_resources_event.rb
|
133
|
-
- lib/cassie/queries/logging/cql_execution_event.rb
|
134
|
-
- lib/cassie/queries/logging/subscription.rb
|
135
|
-
- lib/cassie/queries/statement.rb
|
136
|
-
- lib/cassie/queries/statement/assignment.rb
|
137
|
-
- lib/cassie/queries/statement/assignments.rb
|
138
|
-
- lib/cassie/queries/statement/batches.rb
|
139
|
-
- lib/cassie/queries/statement/callbacks.rb
|
140
|
-
- lib/cassie/queries/statement/conditions.rb
|
141
|
-
- lib/cassie/queries/statement/consistency.rb
|
142
|
-
- lib/cassie/queries/statement/deleting.rb
|
143
|
-
- lib/cassie/queries/statement/execution.rb
|
144
|
-
- lib/cassie/queries/statement/fetching.rb
|
145
|
-
- lib/cassie/queries/statement/inserting.rb
|
146
|
-
- lib/cassie/queries/statement/limiting.rb
|
147
|
-
- lib/cassie/queries/statement/loading.rb
|
148
|
-
- lib/cassie/queries/statement/mapping.rb
|
149
|
-
- lib/cassie/queries/statement/ordering.rb
|
150
|
-
- lib/cassie/queries/statement/pagination.rb
|
151
|
-
- lib/cassie/queries/statement/pagination/cursors.rb
|
152
|
-
- lib/cassie/queries/statement/pagination/page_size.rb
|
153
|
-
- lib/cassie/queries/statement/preparation.rb
|
154
|
-
- lib/cassie/queries/statement/preparation/cache.rb
|
155
|
-
- lib/cassie/queries/statement/relation.rb
|
156
|
-
- lib/cassie/queries/statement/relations.rb
|
157
|
-
- lib/cassie/queries/statement/selection.rb
|
158
|
-
- lib/cassie/queries/statement/updating.rb
|
128
|
+
- lib/cassie/modification.rb
|
159
129
|
- lib/cassie/query.rb
|
130
|
+
- lib/cassie/statements.rb
|
131
|
+
- lib/cassie/statements/README.md
|
132
|
+
- lib/cassie/statements/core.rb
|
133
|
+
- lib/cassie/statements/execution.rb
|
134
|
+
- lib/cassie/statements/execution/batched_fetching.rb
|
135
|
+
- lib/cassie/statements/execution/callbacks.rb
|
136
|
+
- lib/cassie/statements/execution/consistency.rb
|
137
|
+
- lib/cassie/statements/execution/deserialization.rb
|
138
|
+
- lib/cassie/statements/execution/fetching.rb
|
139
|
+
- lib/cassie/statements/execution/instrumentation.rb
|
140
|
+
- lib/cassie/statements/execution/partition_linking.rb
|
141
|
+
- lib/cassie/statements/execution/partition_linking/cursoring_policy.rb
|
142
|
+
- lib/cassie/statements/execution/partition_linking/policy_methods.rb
|
143
|
+
- lib/cassie/statements/execution/partition_linking/simple_policy.rb
|
144
|
+
- lib/cassie/statements/execution/peeking.rb
|
145
|
+
- lib/cassie/statements/execution/results.rb
|
146
|
+
- lib/cassie/statements/execution/results/core.rb
|
147
|
+
- lib/cassie/statements/execution/results/cursored_result.rb
|
148
|
+
- lib/cassie/statements/execution/results/instrumentation.rb
|
149
|
+
- lib/cassie/statements/execution/results/modification.rb
|
150
|
+
- lib/cassie/statements/execution/results/modification_result.rb
|
151
|
+
- lib/cassie/statements/execution/results/peeking.rb
|
152
|
+
- lib/cassie/statements/execution/results/peeking_result.rb
|
153
|
+
- lib/cassie/statements/execution/results/query_result.rb
|
154
|
+
- lib/cassie/statements/execution/results/querying.rb
|
155
|
+
- lib/cassie/statements/execution/results/result.rb
|
156
|
+
- lib/cassie/statements/instrumenting.rb
|
157
|
+
- lib/cassie/statements/logging.rb
|
158
|
+
- lib/cassie/statements/logging/deserialize_event.rb
|
159
|
+
- lib/cassie/statements/logging/deserialize_subscriber.rb
|
160
|
+
- lib/cassie/statements/logging/execute_event.rb
|
161
|
+
- lib/cassie/statements/logging/execute_subscriber.rb
|
162
|
+
- lib/cassie/statements/modification.rb
|
163
|
+
- lib/cassie/statements/query.rb
|
164
|
+
- lib/cassie/statements/statement.rb
|
165
|
+
- lib/cassie/statements/statement/assignment.rb
|
166
|
+
- lib/cassie/statements/statement/assignments.rb
|
167
|
+
- lib/cassie/statements/statement/conditions.rb
|
168
|
+
- lib/cassie/statements/statement/deleting.rb
|
169
|
+
- lib/cassie/statements/statement/inserting.rb
|
170
|
+
- lib/cassie/statements/statement/limiting.rb
|
171
|
+
- lib/cassie/statements/statement/mapping.rb
|
172
|
+
- lib/cassie/statements/statement/ordering.rb
|
173
|
+
- lib/cassie/statements/statement/pagination.rb
|
174
|
+
- lib/cassie/statements/statement/pagination/cursors.rb
|
175
|
+
- lib/cassie/statements/statement/preparation.rb
|
176
|
+
- lib/cassie/statements/statement/preparation/cache.rb
|
177
|
+
- lib/cassie/statements/statement/relation.rb
|
178
|
+
- lib/cassie/statements/statement/relations.rb
|
179
|
+
- lib/cassie/statements/statement/selection.rb
|
180
|
+
- lib/cassie/statements/statement/updating.rb
|
160
181
|
- lib/cassie/support.rb
|
161
182
|
- lib/cassie/support/command_runner.rb
|
162
183
|
- lib/cassie/testing.rb
|
163
184
|
- lib/cassie/testing/README.md
|
185
|
+
- lib/cassie/testing/fake/definition.rb
|
164
186
|
- lib/cassie/testing/fake/execution_info.rb
|
187
|
+
- lib/cassie/testing/fake/modification.rb
|
165
188
|
- lib/cassie/testing/fake/prepared_statement.rb
|
166
189
|
- lib/cassie/testing/fake/query.rb
|
167
190
|
- lib/cassie/testing/fake/result.rb
|
@@ -1,458 +0,0 @@
|
|
1
|
-
# Cassie Queries
|
2
|
-
|
3
|
-
`cassie` query classes aim to provide a query interface that is
|
4
|
-
|
5
|
-
* Easy to use
|
6
|
-
* Easy to understand (and thus maintain)
|
7
|
-
* Easy to test
|
8
|
-
* Works well with the data mapper design pattern
|
9
|
-
|
10
|
-
### Usage
|
11
|
-
|
12
|
-
You might expect to see class methods allowing queries to be built like such:
|
13
|
-
|
14
|
-
```
|
15
|
-
Cassie.insert(:users_by_username,
|
16
|
-
"id = #{some_id}",
|
17
|
-
username: some_username)
|
18
|
-
```
|
19
|
-
|
20
|
-
Queries defined on the fly like this tend to create debt for an application in the long term. They:
|
21
|
-
* create gaps in test coverage
|
22
|
-
* resist documentation
|
23
|
-
* resist refactoring
|
24
|
-
|
25
|
-
Application queries represent distinct application behavior, `cassie` queries are designed to help create query classes that are reusable, testable and maintainable (so you can sleep better at night).
|
26
|
-
|
27
|
-
```ruby
|
28
|
-
# Some PORO user model
|
29
|
-
user = User.new(username: username)
|
30
|
-
|
31
|
-
MyInsertionQuery.new.insert(user)
|
32
|
-
```
|
33
|
-
<pre><b>
|
34
|
-
(1.2ms) INSERT INTO users_by_username (id, username) VALUES (?, ?); [["uuid()", "eprothro"]]
|
35
|
-
</b></pre>
|
36
|
-
|
37
|
-
```ruby
|
38
|
-
class MyInsertionQuery < Cassie::Query
|
39
|
-
|
40
|
-
insert :users_by_username do |u|
|
41
|
-
u.id,
|
42
|
-
u.username
|
43
|
-
end
|
44
|
-
|
45
|
-
def id
|
46
|
-
"uuid()"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
```
|
50
|
-
|
51
|
-
CQL algebra is less complex than with SQL. So, rather than introducing a query abstraction layer (e.g. something like [arel](https://github.com/rails/arel)), `cassie` queries provide a lightweight CQL DSL to codify your CQL queries.
|
52
|
-
|
53
|
-
```sql
|
54
|
-
SELECT *
|
55
|
-
FROM posts_by_author_category
|
56
|
-
WHERE author_id = ?
|
57
|
-
AND category = ?
|
58
|
-
LIMIT 30;
|
59
|
-
```
|
60
|
-
```ruby
|
61
|
-
select :posts_by_author_category
|
62
|
-
where :author_id, :eq
|
63
|
-
where :category, :eq
|
64
|
-
limit 30
|
65
|
-
```
|
66
|
-
|
67
|
-
This maintains the clarity of your CQL, allowing you to be expressive, but still use additional features without having get crazy with string manipulation.
|
68
|
-
|
69
|
-
#### Dynamic term values
|
70
|
-
|
71
|
-
```ruby
|
72
|
-
select :posts_by_author
|
73
|
-
|
74
|
-
where :user_id, :eq
|
75
|
-
```
|
76
|
-
|
77
|
-
Defining a CQL relation in a cassie query (the "where") creates a setter and getter for that relation. This allows the term value to be set for a particular query instance.
|
78
|
-
|
79
|
-
```ruby
|
80
|
-
query.user_id = 123
|
81
|
-
query.fetch
|
82
|
-
=> [#<Struct user_id=123, id="some post id">]
|
83
|
-
```
|
84
|
-
|
85
|
-
<pre><b>
|
86
|
-
(2.9ms) SELECT * FROM posts_by_author WHERE user_id = ? LIMIT 1; [[123]]
|
87
|
-
</b></pre>
|
88
|
-
|
89
|
-
These methods are plain old attr_accessors, and may be overriden
|
90
|
-
|
91
|
-
```ruby
|
92
|
-
select :posts_by_author
|
93
|
-
|
94
|
-
where :user_id, :eq
|
95
|
-
|
96
|
-
def author=(user)
|
97
|
-
@user_id = user.id
|
98
|
-
end
|
99
|
-
```
|
100
|
-
|
101
|
-
```ruby
|
102
|
-
query.author = User.new(id: 123)
|
103
|
-
query.fetch
|
104
|
-
=> [#<Struct user_id=123, id="some post id">]
|
105
|
-
```
|
106
|
-
|
107
|
-
<pre><b>
|
108
|
-
(2.9ms) SELECT * FROM posts_by_author WHERE user_id = ? LIMIT 1; [[123]]
|
109
|
-
</b></pre>
|
110
|
-
|
111
|
-
A specific name can be provided for the setter/getter:
|
112
|
-
|
113
|
-
```ruby
|
114
|
-
select :posts_by_author
|
115
|
-
|
116
|
-
where :user_id, :eq, value: :author_id
|
117
|
-
```
|
118
|
-
|
119
|
-
```ruby
|
120
|
-
query.author_id = 123
|
121
|
-
query.fetch
|
122
|
-
=> [#<Struct user_id=123, id="some post id">]
|
123
|
-
```
|
124
|
-
|
125
|
-
<pre><b>
|
126
|
-
(2.9ms) SELECT * FROM posts_by_author WHERE user_id = ? LIMIT 1; [[123]]
|
127
|
-
</b></pre>
|
128
|
-
|
129
|
-
#### Conditional relations
|
130
|
-
|
131
|
-
```ruby
|
132
|
-
select :posts_by_author_category
|
133
|
-
|
134
|
-
where :author_id, :eq
|
135
|
-
where :category, :eq, if: "category.present?"
|
136
|
-
```
|
137
|
-
|
138
|
-
or
|
139
|
-
|
140
|
-
```ruby
|
141
|
-
select :posts_by_author_category
|
142
|
-
|
143
|
-
where :author_id, :eq
|
144
|
-
where :category, :eq, if: :filter_by_category?
|
145
|
-
|
146
|
-
def filter_by_category?
|
147
|
-
#true or false, as makes sense for your query
|
148
|
-
end
|
149
|
-
```
|
150
|
-
|
151
|
-
#### Consistency configuration
|
152
|
-
|
153
|
-
The [consistency level](http://datastax.github.io/ruby-driver/v2.1.6/api/cassandra/#consistencies-constant) for a query is determined by your `Cassie::configuration` by default, falling to back to the `Cassandra` default if none is given.
|
154
|
-
|
155
|
-
```ruby
|
156
|
-
Cassie.configuration[:consistency]
|
157
|
-
=> nil
|
158
|
-
|
159
|
-
Cassie.cluster.instance_variable_get(:@execution_options).consistency
|
160
|
-
=> :one
|
161
|
-
```
|
162
|
-
|
163
|
-
A Cassie::Query looks for a consistency level defined on the object, subclass, then base class levels. If one is found, it will override the `Cassandra` default when the query is executed.
|
164
|
-
|
165
|
-
```ruby
|
166
|
-
select :posts_by_author_category
|
167
|
-
|
168
|
-
where :author_id, :eq
|
169
|
-
where :category, :eq, if: :filter_by_category?
|
170
|
-
|
171
|
-
def filter_by_category?
|
172
|
-
#true or false, as makes sense for your query
|
173
|
-
end
|
174
|
-
|
175
|
-
def consistency
|
176
|
-
#dynamically determine a query object's consistency level
|
177
|
-
if filter_by_category?
|
178
|
-
:quorum
|
179
|
-
else
|
180
|
-
super
|
181
|
-
end
|
182
|
-
end
|
183
|
-
```
|
184
|
-
|
185
|
-
```ruby
|
186
|
-
select :posts_by_author_category
|
187
|
-
|
188
|
-
where :author_id, :eq
|
189
|
-
where :category, :eq
|
190
|
-
|
191
|
-
consistency :quorum
|
192
|
-
```
|
193
|
-
|
194
|
-
```ruby
|
195
|
-
# lib/tasks/interesting_task.rake
|
196
|
-
require_relative "interesting_worker"
|
197
|
-
|
198
|
-
task :interesting_task do
|
199
|
-
Cassandra::Query.consistency = :all
|
200
|
-
|
201
|
-
InterestingWorker.new.perform
|
202
|
-
end
|
203
|
-
```
|
204
|
-
|
205
|
-
#### Finders
|
206
|
-
|
207
|
-
To avoid confusion with ruby `Enumerable#find` and Rails' specific `find` functionality, Cassie::Query opts to use `fetch` and explict `fetch_first` or `fetch_first!` methods.
|
208
|
-
|
209
|
-
##### `fetch`
|
210
|
-
|
211
|
-
Executes the query; returns array of results.
|
212
|
-
|
213
|
-
```
|
214
|
-
UsersByResourceQuery.new.fetch(resource: some_resource)
|
215
|
-
=> [#<User id=:123, username=:eprothro>, #<User id=:456, username=:tenderlove>]
|
216
|
-
```
|
217
|
-
|
218
|
-
##### `fetch_first` and `fetch_first!`
|
219
|
-
|
220
|
-
Executes the query, temporarily limited to 1 result; returns a single result. Bang version raises if no result is found.
|
221
|
-
|
222
|
-
```
|
223
|
-
UsersByUsernameQuery.new.fetch_first(username: "eprothro").username
|
224
|
-
=> "eprothro"
|
225
|
-
```
|
226
|
-
|
227
|
-
```
|
228
|
-
UsersByUsernameQuery.new.fetch_first(username: "active record").username
|
229
|
-
Cassie::Queries::RecordNotFound: CQL row does not exist
|
230
|
-
```
|
231
|
-
|
232
|
-
##### Batching
|
233
|
-
|
234
|
-
Similar to [Rails Batching](http://guides.rubyonrails.org/v4.2/active_record_querying.html#retrieving-multiple-objects-in-batches), Cassie allows efficient batching of `SELECT` queries.
|
235
|
-
|
236
|
-
###### `fetch_each`
|
237
|
-
```
|
238
|
-
UsersQuery.new.fetch_each do |user|
|
239
|
-
# only 1000 queried and loaded at a time
|
240
|
-
end
|
241
|
-
```
|
242
|
-
|
243
|
-
```
|
244
|
-
UsersQuery.new.fetch_each(batch_size: 500) do |user|
|
245
|
-
# only 500 queried and loaded at a time
|
246
|
-
end
|
247
|
-
```
|
248
|
-
|
249
|
-
```
|
250
|
-
UsersQuery.new.fetch_each.with_index do |user, index|
|
251
|
-
# Enumerator chaining without a block
|
252
|
-
end
|
253
|
-
```
|
254
|
-
###### `fetch_in_batches`
|
255
|
-
```
|
256
|
-
UsersQuery.new.fetch_in_batches do |users_array|
|
257
|
-
# only 1000 queried and at a time
|
258
|
-
end
|
259
|
-
```
|
260
|
-
|
261
|
-
```
|
262
|
-
UsersQuery.new.fetch_in_batches(batch_size: 500) do |users_array|
|
263
|
-
# only 500 queried and at a time
|
264
|
-
end
|
265
|
-
```
|
266
|
-
|
267
|
-
```
|
268
|
-
UsersQuery.new.fetch_in_batches.with_index do |group, index|
|
269
|
-
# Enumerator chaining without a block
|
270
|
-
end
|
271
|
-
```
|
272
|
-
|
273
|
-
#### Object Mapping
|
274
|
-
For Selection Queries, resources are returned as structs by default for manipulation using accessor methods.
|
275
|
-
|
276
|
-
```ruby
|
277
|
-
UsersByUsernameQuery.new.fetch(username: "eprothro")
|
278
|
-
=> [#<Struct id=:123, username=:eprothro>]
|
279
|
-
|
280
|
-
UsersByUsernameQuery.new.fetch_first(username: "eprothro").username
|
281
|
-
=> "eprothro"
|
282
|
-
```
|
283
|
-
|
284
|
-
Most application will want to override `build_resource` to construct more useful domain objects
|
285
|
-
|
286
|
-
```
|
287
|
-
class UsersByUsernameQuery < Cassie::Query
|
288
|
-
|
289
|
-
select :users_by_username
|
290
|
-
|
291
|
-
where :username, :eq
|
292
|
-
|
293
|
-
def build_resource(row)
|
294
|
-
User.new(row)
|
295
|
-
end
|
296
|
-
end
|
297
|
-
```
|
298
|
-
|
299
|
-
```ruby
|
300
|
-
UsersByUsernameQuery.new.fetch_first(username: "eprothro")
|
301
|
-
=> #<User:0x007fedec219cd8 @id=123, @username="eprothro">
|
302
|
-
```
|
303
|
-
|
304
|
-
For Data Modification Queries (`insert`, `update`, `delete`), mapping binding values from a domain object is supported.
|
305
|
-
|
306
|
-
```ruby
|
307
|
-
class UpdateUserQuery < Cassandra::Query
|
308
|
-
|
309
|
-
update :users_by_id do |q|
|
310
|
-
q.set :phone
|
311
|
-
q.set :email
|
312
|
-
q.set :address
|
313
|
-
q.set :username
|
314
|
-
end
|
315
|
-
|
316
|
-
where :id, :eq
|
317
|
-
|
318
|
-
map_from :user
|
319
|
-
```
|
320
|
-
|
321
|
-
This allows a domain object to be passed to the modification method, where binding values will be retrieved from the object
|
322
|
-
|
323
|
-
```ruby
|
324
|
-
user
|
325
|
-
=> #<User:0x007ff8895ce660 @id=6539, @phone="+15555555555", @email="etp@example.com", @address=nil, @username= "etp">
|
326
|
-
UpdateUserQuery.new.update(user)
|
327
|
-
```
|
328
|
-
|
329
|
-
<pre><b>
|
330
|
-
(1.2ms) UPDATE users_by_id (phone, email, address, username) VALUES (?, ?, ?, ?) WHERE id = ?; [["+15555555555", "etp@example.com", nil, "etp", 6539]]
|
331
|
-
</b></pre>
|
332
|
-
|
333
|
-
|
334
|
-
#### Cursored paging
|
335
|
-
|
336
|
-
Read about [cursored pagination](https://www.google.com/webhp?q=cursored%20paging#safe=off&q=cursor+paging) if unfamiliar with concept and how it optimizes paging through frequently updated data sets and I/O bandwidth.
|
337
|
-
|
338
|
-
```ruby
|
339
|
-
class MyPagedQuery < Cassie::Query
|
340
|
-
|
341
|
-
select :events_by_user
|
342
|
-
|
343
|
-
where :user_id, :eq
|
344
|
-
|
345
|
-
max_cursor :event_id
|
346
|
-
since_cursor :event_id
|
347
|
-
end
|
348
|
-
```
|
349
|
-
|
350
|
-
```ruby
|
351
|
-
# Imagine a set of id's 100 decreasing to 1
|
352
|
-
# where the client already has 1-50 in memory.
|
353
|
-
|
354
|
-
q = MyPagedQuery.new(page_size: 25, user: current_user)
|
355
|
-
|
356
|
-
# fetch 100 - 76
|
357
|
-
page_1 = q.fetch(max_event_id: nil, since_event_id: 50)
|
358
|
-
q.next_max_event_id
|
359
|
-
# => 75
|
360
|
-
|
361
|
-
# fetch 75 - 51
|
362
|
-
page_2 = q.fetch(max_event_id: q.next_max_event_id, since_event_id: 50)
|
363
|
-
q.next_max_id
|
364
|
-
# => nil
|
365
|
-
```
|
366
|
-
|
367
|
-
The `cursor_by` helper can be used as shorthand for defining these relations for which you wish to use cursors.
|
368
|
-
```ruby
|
369
|
-
class MyPagedQuery < Cassie::Query
|
370
|
-
|
371
|
-
select :events_by_user
|
372
|
-
|
373
|
-
where :user_id, :eq
|
374
|
-
|
375
|
-
cursor_by :event_id
|
376
|
-
end
|
377
|
-
```
|
378
|
-
|
379
|
-
#### Prepared statements
|
380
|
-
|
381
|
-
A `Cassie::Query` will use prepared statements by default, cacheing prepared statements across all Cassie::Query objects, keyed by the bound CQL string.
|
382
|
-
|
383
|
-
|
384
|
-
To not use prepared statements for a particular query, disable the `.prepare` class option.
|
385
|
-
|
386
|
-
```ruby
|
387
|
-
class MySpecialQuery < Cassie::Query
|
388
|
-
|
389
|
-
select :users_by_some_value do
|
390
|
-
where :bucket
|
391
|
-
where :some_value, :in
|
392
|
-
end
|
393
|
-
|
394
|
-
# the length of `some_values` that will be passed in
|
395
|
-
# is highly variable, so we don't want to incur the
|
396
|
-
# cost of preparing a statement for each unique length
|
397
|
-
self.prepare = false
|
398
|
-
end
|
399
|
-
```
|
400
|
-
|
401
|
-
```ruby
|
402
|
-
query = MySpecialQuery.new
|
403
|
-
|
404
|
-
# will not prepare statement
|
405
|
-
set_1 = query.fetch([1, 2, 3])
|
406
|
-
# will not prepare statement
|
407
|
-
set_2 = query.fetch([7, 8, 9, 10, 11, 12])
|
408
|
-
```
|
409
|
-
|
410
|
-
#### Unbound statements
|
411
|
-
|
412
|
-
Cassie Query features are built around bound statements. However, we've tried to keep a simple ruby design in place to make custom behavior easier. If you want to override the assumption of bound statements, simply override `#statement`, returnign something that a `Cassandra::Session` can execute.
|
413
|
-
|
414
|
-
```ruby
|
415
|
-
class NotSureWhyIWouldDoThisButHereItIsQuery < Cassie::Query
|
416
|
-
def statement
|
417
|
-
"SELECT * FROM users WHERE id IN (1,2,3);"
|
418
|
-
end
|
419
|
-
end
|
420
|
-
```
|
421
|
-
|
422
|
-
#### Logging
|
423
|
-
|
424
|
-
Cassie Query objects use the Cassie logger unless overridden. This logs to STDOUT by default. Set any log stream you wish.
|
425
|
-
|
426
|
-
```ruby
|
427
|
-
Cassie.logger = my_app.config.logger
|
428
|
-
```
|
429
|
-
|
430
|
-
Set the log level to `debug` in order to log execution details.
|
431
|
-
|
432
|
-
```ruby
|
433
|
-
Cassie::Query.logger.level = Logger::DEBUG
|
434
|
-
```
|
435
|
-
|
436
|
-
#### Execution Time
|
437
|
-
|
438
|
-
Cassie Queries instrument execution time as `cassie.cql.execution` and logs a debug message.
|
439
|
-
|
440
|
-
```ruby
|
441
|
-
SelectUserByUsernameQuery.new('some_user').execute
|
442
|
-
(5.5ms) SELECT * FROM users_by_username WHERE username = ? LIMIT 1; ["some_user"] [LOCAL_ONE]
|
443
|
-
```
|
444
|
-
This measures the time to build the CQL query (statement and bindings), transmit the query to the cassandra coordinator, receive the result from the cassandra coordinator, and have the cassandra ruby driver build the ruby representation of the results. It does not include the time it takes for the Cassie Query to build its resource objects.
|
445
|
-
|
446
|
-
#### Resource Loading
|
447
|
-
|
448
|
-
Cassie Queries instrument resource building as `cassie.building_resources` and logs a debug message.
|
449
|
-
|
450
|
-
```ruby
|
451
|
-
SelectUserByUsernameQuery.new('some_user').fetch
|
452
|
-
(5.5ms) SELECT * FROM users_by_username WHERE username = ? LIMIT 1; ["some_user"] [LOCAL_ONE]
|
453
|
-
(0.2ms) 1 resource object built from Cassandra query result
|
454
|
-
```
|
455
|
-
|
456
|
-
This measures the time it takes Cassie to build the resource objects (e.g. your domain objects) and is in addition to the execution time.
|
457
|
-
|
458
|
-
> fetch time = `cassie.cql.execution` time + `cassie.building_resources` time
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module Cassie::Queries::Instrumentation
|
2
|
-
module Loading
|
3
|
-
|
4
|
-
protected
|
5
|
-
|
6
|
-
def build_resources(rows)
|
7
|
-
instrumenter.instrument("cassie.building_resources") do |payload|
|
8
|
-
payload[:count] = rows.count if rows.respond_to?(:count)
|
9
|
-
super
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require_relative 'instrumentation/execution'
|
2
|
-
require_relative 'instrumentation/loading'
|
3
|
-
|
4
|
-
module Cassie::Queries
|
5
|
-
module Instrumentation
|
6
|
-
extend ::ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
include Execution
|
10
|
-
end
|
11
|
-
|
12
|
-
protected
|
13
|
-
|
14
|
-
def instrumenter
|
15
|
-
ActiveSupport::Notifications
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require_relative 'cql_execution_event'
|
2
|
-
require_relative 'building_resources_event'
|
3
|
-
|
4
|
-
module Cassie::Queries::Logging
|
5
|
-
module Subscription
|
6
|
-
extend ::ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
ActiveSupport::Notifications.subscribe('cassie.cql.execution') do |*args|
|
10
|
-
# don't log if instrumentation failed
|
11
|
-
unless args.last[:exception]
|
12
|
-
logger.debug(CqlExecutionEvent.new(*args).message)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
ActiveSupport::Notifications.subscribe('cassie.building_resources') do |*args|
|
17
|
-
# don't log if instrumentation failed
|
18
|
-
unless args.last[:exception]
|
19
|
-
logger.debug(BuildingResourcesEvent.new(*args).message)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require_relative 'logging/subscription'
|
2
|
-
|
3
|
-
module Cassie::Queries
|
4
|
-
module Logging
|
5
|
-
extend ::ActiveSupport::Concern
|
6
|
-
|
7
|
-
included do
|
8
|
-
include Subscription
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
def logger
|
13
|
-
Cassie.logger
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def logger
|
18
|
-
self.class.logger
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
module Cassie::Queries::Statement
|
2
|
-
# set "username = ?", value: :username
|
3
|
-
# set "favs = favs + ?" value: "{ 'movie' : 'Cassablanca' }"
|
4
|
-
# set :username
|
5
|
-
class Assignment
|
6
|
-
# https://cassandra.apache.org/doc/cql3/CQL.html#updateStmt
|
7
|
-
|
8
|
-
attr_reader :identifier
|
9
|
-
|
10
|
-
def initialize(identifier, opts={})
|
11
|
-
if String === identifier
|
12
|
-
# custom assignment is being defined:
|
13
|
-
#
|
14
|
-
# `assign "username = ?", value: :username`
|
15
|
-
@cql = identifier
|
16
|
-
@custom = true
|
17
|
-
else
|
18
|
-
@identifier = identifier
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_insert_cql
|
23
|
-
return @cql if defined?(@cql)
|
24
|
-
identifier
|
25
|
-
end
|
26
|
-
|
27
|
-
def to_update_cql
|
28
|
-
return @cql if defined?(@cql)
|
29
|
-
"#{identifier} = ?"
|
30
|
-
end
|
31
|
-
|
32
|
-
def custom?
|
33
|
-
!!@custom
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|