cassandro 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  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