cassandro 1.2.0 → 2.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0120288029f77b9b0c1f5decbf83dd3aa28ee3f6
4
- data.tar.gz: 3f50c226fb664ccbd79eb2e95b6c638b0a0caaf0
3
+ metadata.gz: 3ca78baede197271950dd4171393ec32c9f3698f
4
+ data.tar.gz: 59a76cb0577d8b8293a1925d5ca071c889d61cbb
5
5
  SHA512:
6
- metadata.gz: 734ad77b4020a932713e66d2618815798c14b850a0243fd3f36c2d621dcaaec4b4d937f7c4a66c624dc13c653618039c55534bb2d904c7c28569bd6587aac153
7
- data.tar.gz: 97d3d021c5808aa343988e8781beaee4327756fe52a7a68304caed7e1b8657dc0446b2981a42de502a9b8b8e8a6329bf0f398ab487b26857cf303c529d4a7b8b
6
+ metadata.gz: 7b0810673c9631f7e60e0e9b7e4796b579c4c1b8b943f76f7dc0890a631f2b5fd0fbd08ca507d0abfaad198697206167ef6fcd84451123b759ca52d96abd6c2e
7
+ data.tar.gz: a5f4d40a976c593e3e6b149cf28573955b5e60381c24d2c4b8a04a92afcba110e3787784db5c127600bac5e9da7335a72c6ba0be7db021d8a8792509139f84b5
data/.gems CHANGED
@@ -1 +1 @@
1
- cassandra-driver -v 1.2
1
+ cassandra-driver -v 2.1.3
File without changes
data/README.md CHANGED
@@ -1,329 +1,56 @@
1
1
  # Cassandro [![Gem Version](https://badge.fury.io/rb/cassandro.svg)](http://badge.fury.io/rb/cassandro)
2
2
 
3
- Cassandro is a small Ruby ORM for Apache Cassandra 2.0 and CQL 3.0. Cassandro uses the new Datastax Ruby Driver (official driver).
3
+ Cassandro is a small Ruby ORM for Apache Cassandra 2.0 and CQL 3.0. Cassandro uses the new [Datastax Ruby Driver](https://github.com/datastax/ruby-driver)
4
4
 
5
5
  ## Install
6
6
 
7
7
  `gem install cassandro`
8
8
 
9
- ## Basic Cassandro
9
+ ## Changelog
10
10
 
11
- Connecting to Cassandra DB: `Cassandro.connect(Hash options)`. For full list of options visit [Ruby Driver Documentation](http://datastax.github.io/ruby-driver/api/#cluster-class_method)
11
+ ### v2.0
12
+ * Support `cassandra-driver` >= 2.0
13
+ * Allow registering indexes in model's definition
14
+ * Add `Model#ttl` method
12
15
 
13
- ```ruby
14
- Cassandro.connect(
15
- hosts: ['127.0.0.1'],
16
- keyspace: 'some_keyspace'
17
- )
18
- ```
19
-
20
- Creating a new keyspace. For full details of keyspace creation visit [CLI keyspace](http://www.datastax.com/documentation/cassandra/2.0/cassandra/reference/referenceStorage_r.html)
21
-
22
- ```ruby
23
- # < 1.0.0
24
- Cassandro.create_keyspace('new_keyspace', 'SimpleStrategy', 1)
25
-
26
- # >= 1.0.0, allow more options
27
- Cassandro.create_keyspace('new_keyspace', {
28
- replication: {
29
- class: 'NetworkTopologyStrategy',
30
- dc_1: 2,
31
- dc_2: 2
32
- },
33
- durable_writes: true
34
- })
35
- ```
36
-
37
- Select keyspace outside `#connect`
38
-
39
- ```ruby
40
- Cassandro.use('keyspace_name')
41
- ```
42
-
43
- Create table.
44
- ```ruby
45
- table = <<-TABLEDEF
46
- CREATE TABLE IF NOT EXISTS users (
47
- email VARCHAR,
48
- first_name VARCHAR,
49
- age INT,
50
- created_at TIMESTAMP,
51
- PRIMARY KEY(email,created_at)
52
- )
53
- TABLEDEF
54
-
55
- Cassandro.execute(table)
56
- ```
57
-
58
- Execute queries.
59
- ```ruby
60
- result = Cassandro.execute("SELECT * FROM table_name;")
61
- ```
62
-
63
- Using Driver directly.
64
- ```ruby
65
- statement = Cassandro.client.prepare("SELECT * FROM table_name WHERE colname = ?;")
66
- result = Cassandro.client.execute(statement, id)
67
- ```
68
-
69
- ## Cassandro::Model
70
-
71
- ### Creating model
72
- Creating new model: make you class inherits form `Cassandro::Model`
73
-
74
- ```ruby
75
- class User < Cassandro::Model
76
- end
77
- ```
78
-
79
- Specifying table name using the method `table(table_name)`:
80
-
81
- ```ruby
82
- class User < Cassandro::Model
83
-
84
- table 'users'
85
- end
86
- ```
16
+ ### v1.2
17
+ * TTL
18
+ * Model-wide TTL
19
+ * Single record TTL
20
+ * Support `:set` datatype
21
+ * Ignore columns not definied on model
87
22
 
88
- Adding attributes using the method `attribute(name, type, options)`:
23
+ ## Example
89
24
 
90
25
  ```ruby
91
- class User < Cassandro::Model
92
-
93
- attribute :email, :text
94
- attribute :first_name, :text
95
- attribute :age, :integer
96
- attribute :created_at, :datetime
97
- end
98
- ```
99
-
100
- types: :uuid, :text, :integer, :float, :timestamp, :datetime
101
-
102
- Setting the primary key using the method `primary_key(pk_name | Array)`:
103
-
104
- ```ruby
105
- class User < Cassandro::Model
106
-
107
- primary_key [:email, :created_at]
108
-
109
- end
110
-
111
- ```
112
-
113
- Setting unique field using the method `unique(field | Array)`:
114
-
115
- ```ruby
116
- class User < Cassandro::Model
117
-
118
- unique :email
119
- end
120
- ```
121
-
122
-
123
- ### Setting TTL to a model
124
-
125
- ```Ruby
126
- class Person < Cassandro::Model
127
- table :people
128
- ttl 60
129
- end
130
- ```
131
- This will make all the instances of the People class will have a Time To Live of `60` seconds in the database.
132
-
133
- Creating a single record with a given TTL:
134
-
135
- ```Ruby
136
- class Person < Cassandro::Model
137
- table :people
138
- attribute :first_name, :text
139
- attribute :last_name, :text
140
- end
141
-
142
- Person.create_with_ttl(20, :first_name => "Eddie", :last_name => "Vedder")
143
- ```
144
-
145
- This will create a record in the `people` table with a TTL of `20` seconds. It doesn't matter if the model has a different TTL set, this will override that TTL for _this record only_
146
-
147
-
148
- __A complete example__
149
-
150
- ```ruby
151
- class User < Cassandro::Model
152
-
153
- table 'users'
154
-
26
+ class Developer < Cassandro::Model
27
+ table :developers
28
+
155
29
  attribute :email, :text
156
- attribute :first_name, :text
157
- attribute :age, :integer
158
- attribute :created_at, :datetime
30
+ attribute :repos, :integer
31
+ attribute :nickname, :text
159
32
 
160
- primary_key [:email, :created_at]
161
-
162
- unique :email
163
- end
164
- ```
165
-
166
- ### Interacting
167
-
168
- Creating a new row:
169
-
170
- ```ruby
171
- user = User.create(email: 'test1@example.com', first_name: 'Test', age: 30, created_at: DateTime.now)
172
- => #<User:0x00000001b9dc40
173
- @attributes=
174
- {:email=>"test1@example.com",
175
- :first_name=>"Test",
176
- :age=>30,
177
- :created_at=>
178
- #<DateTime: 2014-11-03T11:34:47-03:00 ((2456965j,52487s,201385585n),-10800s,2299161j)>},
179
- @errors={},
180
- @insert_statement=
181
- #<Cassandra::Statements::Prepared:0xdcd4f8 @cql=" INSERT INTO users(email,first_name,age,created_at)\n VALUES(?,?,?,?)\n IF NOT EXISTS\n">,
182
- @persisted=true>
183
-
184
- ```
185
-
186
- Find:
187
-
188
- ```ruby
189
- User[email: 'test1@example.com']
190
- => #<User:0x00000001cc59d8
191
- @attributes=
192
- {:email=>"test1@example.com",
193
- :created_at=>2014-11-03 11:34:47 -0300,
194
- :age=>30,
195
- :first_name=>"Test"},
196
- @errors={},
197
- @persisted=true>
198
-
199
- User.where('email','test1@example.com')
200
- => #<User:0x00000001cc59d8
201
- @attributes=
202
- {:email=>"test1@example.com",
203
- :created_at=>2014-11-03 11:34:47 -0300,
204
- :age=>30,
205
- :first_name=>"Test"},
206
- @errors={},
207
- @persisted=true>
208
-
209
- ```
210
-
211
- ```ruby
212
- User.all
213
- => [#<User:0x00000002bc75f8
214
- @attributes=
215
- {:email=>"test@example.com",
216
- :created_at=>2014-11-03 11:30:52 -0300,
217
- :age=>30,
218
- :first_name=>"Test"},
219
- @errors={},
220
- @persisted=true>,
221
- #<User:0x00000002bc6b30
222
- @attributes=
223
- {:email=>"test1@example.com",
224
- :created_at=>2014-11-03 11:34:47 -0300,
225
- :age=>30,
226
- :first_name=>"Test"},
227
- @errors={},
228
- @persisted=true>]
229
- ```
230
-
231
- ```ruby
232
- User.query('created_at > ?', Time.now.to_i)
233
- => #<Cassandra::Result:0x1fcb254 @rows=[{"email"=>"test@example.com", "created_at"=>2014-11-03 11:30:52 -0300, "age"=>30, "first_name"=>"Test"}, {"email"=>"test1@example.com", "created_at"=>2014-11-03 11:34:47 -0300, "age"=>30, "first_name"=>"Test"}] @last_page=true>
234
- ```
235
-
236
- Count:
237
-
238
- ```ruby
239
- User.count('email', 'test@example.com')
240
- => 1
241
- ```
242
-
243
- Checking errors:
244
- ```ruby
245
- user = User.create(email: 'test1@example.com', first_name: 'Test', age: 30, created_at: DateTime.now)
246
- => #<User:0x00000001dc7a48
247
- @attributes=
248
- {:email=>"test1@example.com",
249
- :first_name=>"Test",
250
- :age=>30,
251
- :created_at=>
252
- #<DateTime: 2014-11-03T11:36:40-03:00 ((2456965j,52600s,972972939n),-10800s,2299161j)>},
253
- @errors={:unique=>"user_not_unique"},
254
- @persisted=false>
255
-
256
- user.persisted?
257
- => false
258
- user.errors
259
- => {:unique=>"user_not_unique"}
260
-
261
- ```
262
-
263
- ## Migrations
264
-
265
- Define your migrations by extending from `Cassandro::Migration`
266
-
267
- ```ruby
268
- class UserMigration < Cassandro::Migration
269
- version 1
270
-
271
- def up
272
- execute <<-TABLEDEF
273
- CREATE TABLE users (
274
- id UUID,
275
- first_name VARCHAR,
276
- last_name VARCHAR,
277
- email VARCHAR,
278
- PRIMARY KEY(id, email)
279
- )
280
- TABLEDEF
281
- end
282
-
283
- def down
284
- execute <<-QUERY
285
- DROP TABLE users;
286
- QUERY
287
- end
33
+ primary_key [:id, :repos]
34
+
35
+ index :nickname
288
36
  end
289
37
 
290
- class UserGenderMigration < Cassandro::Migration
291
-
292
- version 2
38
+ Cassandro.connect(hosts: ['127.0.0.1'], keyspace: 'little_cassandro')
293
39
 
294
- def up
295
- execute <<-TABLEUPDATE
296
- ALTER TABLE users ADD gender VARCHAR
297
- TABLEUPDATE
298
- end
299
-
300
- def down
301
- execute <<-QUERY
302
- ALTER TABLE users DROP gender
303
- QUERY
304
- end
305
- end
40
+ Developer.create(email: 'developer@dev.com', repos: 10, nickname: 'cassandro')
306
41
  ```
307
42
 
308
- Then use `Cassandro::Migrator` to run your migrations
309
-
310
- ```ruby
311
- Cassandro.connect(hosts: ['127.0.0.1'], keyspace: 'some_keyspace')
43
+ ## Documentation
312
44
 
313
- migrator = Cassandro::Migrator.new('./path/to/migrations', Logger.new(STDOUT))
314
-
315
- migrator.migrate!(:up) #migrates to last version
316
- migrator.migrate!(:down) #apply all downgrades
317
-
318
- migrator.migrate!(:up, 2) #migrates up to version 2
319
- migrator.migrate!(:down, 1) #migrates down to version 1
320
- ```
45
+ * [Getting Started](docs/getting_started.md)
46
+ * [Migrations](docs/migrations.md)
47
+ * [Modeling](docs/modeling.md)
48
+ * [Querying](docs/querying.md)
49
+ * [Advanced Features](docs/advanced_features.md)
321
50
 
322
51
  ## TODO
323
52
 
324
- * Support Index
325
- * Better queries
326
- * Better documentation
53
+ * Improve querying
327
54
 
328
55
  ## How to collaborate
329
56
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "cassandro"
5
- s.version = "1.2.0"
5
+ s.version = "2.0.0"
6
6
  s.summary = "Ruby ORM for Apache Cassandra"
7
7
  s.license = "MIT"
8
8
  s.description = "Lightweight Apache Cassandra ORM for Ruby"
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.email = ["orazile@gmail.com", "leonardomateo@gmail.com"]
11
11
  s.homepage = "https://github.com/tarolandia/cassandro"
12
12
  s.require_paths = ["lib"]
13
- s.add_dependency "cassandra-driver", '~> 1.2', '>= 1.0.0'
13
+ s.add_dependency "cassandra-driver", '~> 2.1.3', '>= 2.0.0'
14
14
  s.add_development_dependency "protest", '~> 0.5', '>= 0.5.3'
15
15
  s.add_development_dependency "rack-test", '~> 0.6', '>= 0.6.3'
16
16
 
@@ -0,0 +1,59 @@
1
+ ## TTL
2
+
3
+ ### Setting TTL to a model
4
+
5
+ ```Ruby
6
+ class Person < Cassandro::Model
7
+ table :people
8
+ ttl 60
9
+ end
10
+ ```
11
+ This will make all the instances of the People class will have a Time To Live of `60` seconds in the database.
12
+
13
+ ### Creating a single record with a given TTL:
14
+
15
+ ```Ruby
16
+ class Person < Cassandro::Model
17
+ table :people
18
+ attribute :first_name, :text
19
+ attribute :last_name, :text
20
+ end
21
+
22
+ Person.create_with_ttl(20, :first_name => "Eddie", :last_name => "Vedder")
23
+ ```
24
+
25
+ This will create a record in the `people` table with a TTL of `20` seconds. It doesn't matter if the model has a different TTL set, this will override that TTL for _this record only_
26
+
27
+ ### Getting TTL
28
+
29
+ After creating a record with a TTL you can use method `Model#ttl` to get the value.
30
+
31
+ ```Ruby
32
+ person = Person.create_with_ttl(20, :first_name => "John", :last_name => "Lennon")
33
+
34
+ person.ttl # => 20
35
+
36
+ # ...
37
+
38
+ person.ttl # => 18
39
+ ```
40
+
41
+ ### Enabling Soft Delete
42
+
43
+
44
+ ```Ruby
45
+ class Person < Cassandro::Model
46
+ include Cassandro::SoftDelete
47
+
48
+ table :people
49
+ end
50
+ ```
51
+
52
+ This will add an attribute `:delete` to your model. Next time you use `Model#destroy` your data will not be deleted from database but marked as deleted. You can then use `Model#restore` to unmark it.
53
+
54
+ Data marked as deleted is not included within `Model#all` method by default. In order to include deleted records you have to send a boolean parameter to `all`.
55
+
56
+ ```ruby
57
+ Person.all # => list all but deleted
58
+ Person.all(true) # => list all, deleted included
59
+ ```
@@ -0,0 +1,70 @@
1
+ # Getting Started with Cassandro ORM
2
+
3
+ ## Connection
4
+
5
+ Connecting to Cassandra DB: `Cassandro.connect(Hash options)`.
6
+
7
+ ```ruby
8
+ # Connect
9
+ Cassandro.connect(hosts: ['192.168.2.100', '192.168.2.101'])
10
+
11
+ # Connect specifying keyspace
12
+ Cassandro.connect(hosts: ['192.168.2.100', '192.168.2.101'], keyspace: 'some_keyspace')
13
+ ```
14
+
15
+ _For full list of options visit [Ruby Driver Documentation](http://datastax.github.io/ruby-driver/api/#cluster-class_method)_
16
+
17
+ ## Keyspace
18
+
19
+ ### Create Keyspace
20
+
21
+ ```ruby
22
+ Cassandro.create_keyspace('new_keyspace', {
23
+ replication: {
24
+ class: 'NetworkTopologyStrategy',
25
+ dc_1: 2,
26
+ dc_2: 2
27
+ },
28
+ durable_writes: true
29
+ })
30
+ ```
31
+
32
+ _For full details of keyspace creation visit [CLI keyspace](http://www.datastax.com/documentation/cassandra/2.0/cassandra/reference/referenceStorage_r.html)_
33
+
34
+
35
+ ### Select keyspace
36
+
37
+ ```ruby
38
+ Cassandro.use('keyspace_name')
39
+ ```
40
+
41
+ ## Execute
42
+
43
+ ### Execute queries
44
+ ```ruby
45
+ result = Cassandro.execute("SELECT * FROM table_name;")
46
+ ```
47
+ ### Create table
48
+ ```ruby
49
+ table = <<-TABLEDEF
50
+ CREATE TABLE IF NOT EXISTS users (
51
+ email VARCHAR,
52
+ first_name VARCHAR,
53
+ age INT,
54
+ created_at TIMESTAMP,
55
+ PRIMARY KEY(email,created_at)
56
+ )
57
+ TABLEDEF
58
+
59
+ Cassandro.execute(table)
60
+ ```
61
+
62
+ ## Cassandra Client
63
+
64
+ Cassandro provides access to `cassandra-driver` instance through `Cassandro.client`
65
+
66
+ ### Using Driver directly
67
+ ```ruby
68
+ statement = Cassandro.client.prepare("SELECT * FROM table_name WHERE colname = ?;")
69
+ result = Cassandro.client.execute(statement, id)
70
+ ```
@@ -0,0 +1,60 @@
1
+ ## Migrations
2
+
3
+ Define your migrations by extending from `Cassandro::Migration`
4
+
5
+ ```ruby
6
+ class UserMigration < Cassandro::Migration
7
+ version 1
8
+
9
+ def up
10
+ execute <<-TABLEDEF
11
+ CREATE TABLE users (
12
+ id UUID,
13
+ first_name VARCHAR,
14
+ last_name VARCHAR,
15
+ email VARCHAR,
16
+ PRIMARY KEY(id, email)
17
+ )
18
+ TABLEDEF
19
+ end
20
+
21
+ def down
22
+ execute <<-QUERY
23
+ DROP TABLE users;
24
+ QUERY
25
+ end
26
+ end
27
+
28
+ class UserGenderMigration < Cassandro::Migration
29
+
30
+ version 2
31
+
32
+ def up
33
+ execute <<-TABLEUPDATE
34
+ ALTER TABLE users ADD gender VARCHAR
35
+ TABLEUPDATE
36
+ end
37
+
38
+ def down
39
+ execute <<-QUERY
40
+ ALTER TABLE users DROP gender
41
+ QUERY
42
+ end
43
+ end
44
+ ```
45
+
46
+ Then use `Cassandro::Migrator` to run your migrations
47
+
48
+ ```ruby
49
+ Cassandro.connect(hosts: ['127.0.0.1'], keyspace: 'some_keyspace')
50
+
51
+ migrator = Cassandro::Migrator.new('./path/to/migrations', Logger.new(STDOUT))
52
+
53
+ migrator.migrate!(:up) #migrates to last version
54
+ migrator.migrate!(:down) #apply all downgrades
55
+
56
+ migrator.migrate!(:up, 2) #migrates up to version 2
57
+ migrator.migrate!(:down, 1) #migrates down to version 1
58
+ ```
59
+
60
+
@@ -0,0 +1,93 @@
1
+ ## Cassandro::Model
2
+
3
+ ### Creating model
4
+
5
+ #### Creating new model
6
+
7
+ Make you class inherits form `Cassandro::Model`
8
+
9
+ ```ruby
10
+ class User < Cassandro::Model
11
+ end
12
+ ```
13
+ #### Table name
14
+
15
+ Specify table name using the method `table(table_name)`:
16
+
17
+ ```ruby
18
+ class User < Cassandro::Model
19
+
20
+ table 'users'
21
+ end
22
+ ```
23
+
24
+ #### Attributes
25
+
26
+ Add attributes using the method `attribute(name, type, options)`:
27
+
28
+ ```ruby
29
+ class User < Cassandro::Model
30
+
31
+ attribute :email, :text
32
+ attribute :first_name, :text
33
+ attribute :age, :integer
34
+ attribute :created_at, :datetime
35
+ end
36
+ ```
37
+
38
+ Types: `:uuid`, `:text`, `:integer`, `:float`, `:timestamp`, `:datetime`, `:set`
39
+
40
+ #### Primary Key
41
+
42
+ Set the primary key using the method `primary_key(pk_name | Array)`:
43
+
44
+ ```ruby
45
+ class User < Cassandro::Model
46
+
47
+ primary_key [:email, :created_at]
48
+
49
+ end
50
+
51
+ ```
52
+
53
+ #### Unique
54
+
55
+ Set unique fields using the method `unique(field | Array)`:
56
+
57
+ ```ruby
58
+ class User < Cassandro::Model
59
+
60
+ unique :email
61
+ end
62
+ ```
63
+
64
+ #### Index
65
+
66
+ Set indexes using the method `index(field | Array)`. Note registering indexes in your model is only a refence.
67
+
68
+ ```ruby
69
+ class User < Cassandro::Model
70
+
71
+ index :age
72
+ end
73
+ ```
74
+
75
+ #### A complete example
76
+
77
+ ```ruby
78
+ class User < Cassandro::Model
79
+
80
+ table 'users'
81
+
82
+ attribute :email, :text
83
+ attribute :first_name, :text
84
+ attribute :age, :integer
85
+ attribute :created_at, :datetime
86
+
87
+ primary_key [:email, :created_at]
88
+
89
+ unique :email
90
+
91
+ index :age
92
+ end
93
+ ```
@@ -0,0 +1,120 @@
1
+ ## Querying
2
+
3
+ ```ruby
4
+ class User < Cassandro::Model
5
+ table :users
6
+
7
+ attribute :email, :text
8
+ attribute :first_name, :text
9
+ attribute :age, :integer
10
+ attribute :created_at, :datetime
11
+
12
+ primary_key :email
13
+
14
+ index :first_name
15
+ end
16
+ ```
17
+
18
+ ### Creating a new row:
19
+
20
+ ```ruby
21
+ user = User.create(email: 'test1@example.com', first_name: 'Test', age: 30, created_at: DateTime.now)
22
+ => #<User:0x00000001b9dc40 ... @persisted=true>
23
+
24
+ ```
25
+
26
+ ### Updating attributes
27
+
28
+ #### Using `#save`
29
+
30
+ ```ruby
31
+ user.age = 31
32
+ user.save
33
+ => true
34
+ ```
35
+
36
+ #### Using `#update_attributes`
37
+
38
+ ```ruby
39
+ user.update_attributes(first_name: 'Test 1', age: 31)
40
+ => true
41
+ ```
42
+
43
+ ### Selecting records
44
+
45
+ #### Find
46
+
47
+ ```ruby
48
+ User[email: 'test1@example.com']
49
+ => #<User:0x00000001cc59d8 ... @persisted=true>
50
+ ```
51
+ ```ruby
52
+ User[email: 'test1@example.com', first_name: 'No Test']
53
+ => nil
54
+ ```
55
+
56
+ #### Find all
57
+
58
+ ```ruby
59
+ User.all
60
+ => [#<User:0x00000001cc59d8 ... @persisted=true>, #<User:0x00000001cc59d9 ... @persisted=true>, ...]
61
+ ```
62
+ #### Where / Query
63
+
64
+ ```ruby
65
+ User.where('first_name','Test 1')
66
+ => [#<User:0x00000001cc59d8 ... @persisted=true>]
67
+ ```
68
+
69
+ ```ruby
70
+ User.query('first_name = ?', 'Test')
71
+ => [#<User:0x00000001cc59d8 ... @persisted=true>, ...]
72
+ ```
73
+
74
+ #### Count:
75
+
76
+ ```ruby
77
+ User.count('email', 'test@example.com')
78
+ => 1
79
+
80
+ User.count
81
+ => 2
82
+ ```
83
+
84
+ ### Deleting
85
+
86
+ #### Destroy
87
+
88
+ ```ruby
89
+ user = User[email: 'test1@example.com']
90
+ user.destroy
91
+ ```
92
+
93
+ #### Destroy All (truncate table)
94
+
95
+ ```ruby
96
+ User.destroy_all
97
+ ```
98
+
99
+ ### Checking errors:
100
+
101
+ ```ruby
102
+ user = User.create(email: 'test1@example.com', first_name: 'Test', age: 30, created_at: DateTime.now)
103
+ => #<User:0x00000001dc7a48
104
+ @attributes=
105
+ {:email=>"test1@example.com",
106
+ :first_name=>"Test",
107
+ :age=>30,
108
+ :created_at=>
109
+ #<DateTime: 2014-11-03T11:36:40-03:00 ((2456965j,52600s,972972939n),-10800s,2299161j)>},
110
+ @errors={:unique=>"user_not_unique"},
111
+ @persisted=false>
112
+
113
+ user.persisted?
114
+ => false
115
+ user.errors
116
+ => {:unique=>"user_not_unique"}
117
+
118
+ ```
119
+
120
+
@@ -71,3 +71,12 @@ module Cassandro
71
71
  end
72
72
  end
73
73
  end
74
+
75
+ # Patch: Make params_metadata public for Prepared Statements
76
+ module Cassandra
77
+ module Statements
78
+ class Prepared
79
+ attr_reader :params_metadata
80
+ end
81
+ end
82
+ end
@@ -70,7 +70,7 @@ module Cassandro
70
70
 
71
71
  begin
72
72
  st = Cassandro.client.prepare(query)
73
- Cassandro.client.execute(st, *native_attributes(attrs))
73
+ Cassandro.client.execute(st, arguments: native_attributes(attrs))
74
74
  @attributes.merge!(attrs)
75
75
  true
76
76
  rescue Exception => e
@@ -101,7 +101,7 @@ module Cassandro
101
101
  st = self.statement_for(:insert, :insert_check => insert_check)
102
102
 
103
103
  begin
104
- r = Cassandro.client.execute(st, *self.native_attributes)
104
+ r = Cassandro.client.execute(st, arguments: self.native_attributes)
105
105
  raise ModelException.new('not_applied') unless !insert_check || (insert_check && r.first["[applied]"])
106
106
  @persisted = true
107
107
  rescue => e
@@ -119,11 +119,21 @@ module Cassandro
119
119
  Cassandro.execute(query)
120
120
  end
121
121
 
122
+ def ttl
123
+ query = <<-QUERY
124
+ SELECT TTL(#{@attributes.keys.last}) FROM #{self.class.table_name}
125
+ WHERE #{self.class.pk.flatten.map { |k| "#{k.to_s} = #{self.class.cast_as(k, @attributes[k])}" }.join(' AND ')}
126
+ QUERY
127
+ result = Cassandro.execute(query)
128
+ result.any? ? result.first.values.first : nil
129
+ end
130
+
122
131
  def self.table(name)
123
132
  self.table_name = name.to_s
124
133
  end
125
134
 
126
135
  def self.attribute(name, type = String, options = {})
136
+ return if attributes.include?(name)
127
137
  attributes << name
128
138
  casts[name] = type
129
139
 
@@ -138,17 +148,25 @@ module Cassandro
138
148
 
139
149
  def self.primary_key(keys)
140
150
  if keys.is_a?(Array)
141
- pk.push(*keys)
151
+ pk.merge(keys)
142
152
  else
143
- pk << keys
153
+ pk.add(keys)
144
154
  end
145
155
  end
146
156
 
147
157
  def self.unique(keys)
148
158
  if keys.is_a?(Array)
149
- uniques.push(*keys)
159
+ uniques.merge(keys)
150
160
  else
151
- uniques << keys
161
+ uniques.add(keys)
162
+ end
163
+ end
164
+
165
+ def self.index(keys)
166
+ if keys.is_a?(Array)
167
+ indexes.merge(keys)
168
+ else
169
+ indexes.add(keys)
152
170
  end
153
171
  end
154
172
 
@@ -170,7 +188,7 @@ module Cassandro
170
188
  QUERY
171
189
 
172
190
  st = Cassandro.client.prepare(query)
173
- result = Cassandro.client.execute(st, *values)
191
+ result = Cassandro.client.execute(st, arguments: values)
174
192
 
175
193
  return nil unless result.any?
176
194
 
@@ -184,6 +202,16 @@ module Cassandro
184
202
  model
185
203
  end
186
204
 
205
+ def self.create_with_ttl(seconds, attrs = {})
206
+ old_ttl = self.options[:ttl]
207
+ self.options[:ttl] = seconds.to_i
208
+
209
+ result = self.create(attrs)
210
+
211
+ old_ttl ? self.options[:ttl] = old_ttl : self.options.delete(:ttl)
212
+ result
213
+ end
214
+
187
215
  def self.all
188
216
  query = "SELECT * FROM #{self.table_name}"
189
217
 
@@ -202,7 +230,7 @@ module Cassandro
202
230
  query = "SELECT * FROM #{table_name} WHERE #{key} = ? ALLOW FILTERING"
203
231
 
204
232
  st = Cassandro.client.prepare(query)
205
- rows = Cassandro.client.execute(st, value)
233
+ rows = Cassandro.client.execute(st, arguments: [value])
206
234
 
207
235
  rows.each do |result|
208
236
  results << new(result, true)
@@ -218,7 +246,7 @@ module Cassandro
218
246
  key = key.to_sym
219
247
  query << " WHERE #{key} = ? ALLOW FILTERING"
220
248
  st = Cassandro.client.prepare(query)
221
- results = Cassandro.client.execute(st, value)
249
+ results = Cassandro.client.execute(st, arguments: [value])
222
250
  else
223
251
  results = Cassandro.client.execute(query)
224
252
  end
@@ -237,9 +265,18 @@ module Cassandro
237
265
  end
238
266
 
239
267
  def self.query(where, *values)
268
+ results = []
269
+
240
270
  query = "SELECT * FROM #{table_name} WHERE #{where} ALLOW FILTERING"
241
271
  st = Cassandro.client.prepare(query)
242
- Cassandro.client.execute(st, *values)
272
+ rows = Cassandro.client.execute(st, arguments: values)
273
+
274
+
275
+ rows.each do |result|
276
+ results << new(result, true)
277
+ end
278
+
279
+ results
243
280
  end
244
281
 
245
282
  protected
@@ -248,7 +285,7 @@ module Cassandro
248
285
  end
249
286
 
250
287
  def self.pk
251
- @pk ||= []
288
+ @pk ||= Set.new
252
289
  end
253
290
 
254
291
  def self.table_name
@@ -264,7 +301,11 @@ module Cassandro
264
301
  end
265
302
 
266
303
  def self.uniques
267
- @unique ||= []
304
+ @unique ||= Set.new
305
+ end
306
+
307
+ def self.indexes
308
+ @indexes ||= Set.new
268
309
  end
269
310
 
270
311
  def self.uniqueness_defined?
@@ -298,16 +339,6 @@ module Cassandro
298
339
  self.options[:ttl] = seconds.to_i
299
340
  end
300
341
 
301
- def self.create_with_ttl(seconds, attrs = {})
302
- old_ttl = self.options[:ttl]
303
- self.options[:ttl] = seconds.to_i
304
-
305
- result = self.create(attrs)
306
-
307
- old_ttl ? self.options[:ttl] = old_ttl : self.options.delete(:ttl)
308
- result
309
- end
310
-
311
342
  def statement_for(operation, options = {})
312
343
  case operation
313
344
  when :insert
@@ -44,6 +44,28 @@ Protest.describe "Cassandro Model" do
44
44
  assert Test.uniqueness_defined?
45
45
  end
46
46
 
47
+ test "adds index" do
48
+ class Test < Cassandro::Model
49
+ index :test_col_2
50
+ end
51
+
52
+ assert Test.indexes.include?(:test_col_2)
53
+ end
54
+
55
+ test "adds multiple indexes" do
56
+ class Test < Cassandro::Model
57
+ attribute :test_col_3, :text
58
+ attribute :test_col_4, :text
59
+ attribute :test_col_5, :text
60
+
61
+ index :test_col_3
62
+ index [:test_col_4, :test_col_5]
63
+ end
64
+ assert Test.indexes.include?(:test_col_3)
65
+ assert Test.indexes.include?(:test_col_4)
66
+ assert Test.indexes.include?(:test_col_5)
67
+ end
68
+
47
69
  test "allows setting and getting attributes" do
48
70
  uuid = SecureRandom.uuid
49
71
  test = Test.new(test_col_1: uuid, test_col_2: 'test_value_2')
@@ -159,7 +181,7 @@ Protest.describe "Cassandro Model" do
159
181
  Test.create(test_col_1: uuid, test_col_2: 'test_value_2')
160
182
 
161
183
  tests = Test[uuid]
162
- assert_equal false, tests.respond_to?("test_col_3")
184
+ assert_equal false, tests.respond_to?("test_col_ignored")
163
185
  end
164
186
  end
165
187
 
@@ -247,5 +269,11 @@ Protest.describe "Cassandro Model" do
247
269
  assert results.first["ttl(address)"] > 0
248
270
  assert results.first["ttl(address)"] <= 30
249
271
  end
272
+
273
+ test "should get TTL" do
274
+ patient = Patient.create_with_ttl(20, :name => "Cassandro Get", :address => "cassandstreet", :age => 1)
275
+ assert patient.ttl > 0
276
+ assert patient.ttl <= 20
277
+ end
250
278
  end
251
279
  end
@@ -4,6 +4,9 @@ table = <<-TABLEDEF
4
4
  test_col_1 UUID,
5
5
  test_col_2 VARCHAR,
6
6
  test_col_3 VARCHAR,
7
+ test_col_4 VARCHAR,
8
+ test_col_5 VARCHAR,
9
+ test_col_ignored VARCHAR,
7
10
  PRIMARY KEY(test_col_1)
8
11
  )
9
12
  TABLEDEF
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cassandro
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lautaro Orazi
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-03-30 00:00:00.000000000 Z
12
+ date: 2015-04-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cassandra-driver
@@ -17,20 +17,20 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '1.2'
20
+ version: 2.1.3
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 1.0.0
23
+ version: 2.0.0
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
27
27
  requirements:
28
28
  - - "~>"
29
29
  - !ruby/object:Gem::Version
30
- version: '1.2'
30
+ version: 2.1.3
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 1.0.0
33
+ version: 2.0.0
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: protest
36
36
  requirement: !ruby/object:Gem::Requirement
@@ -82,9 +82,14 @@ files:
82
82
  - ".gems"
83
83
  - ".gems-test"
84
84
  - ".gitignore"
85
- - LICENSE
85
+ - LICENSE.md
86
86
  - README.md
87
87
  - cassandro.gemspec
88
+ - docs/advanced_features.md
89
+ - docs/getting_started.md
90
+ - docs/migrations.md
91
+ - docs/modeling.md
92
+ - docs/querying.md
88
93
  - lib/cassandro.rb
89
94
  - lib/cassandro/core.rb
90
95
  - lib/cassandro/ext/migration.rb