gotime-cassandra_object 4.1.0 → 4.2.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.
- data/README.rdoc +9 -1
- data/gotime-cassandra_object.gemspec +1 -1
- data/lib/cassandra_object/base.rb +1 -2
- data/lib/cassandra_object/log_subscriber.rb +17 -25
- data/lib/cassandra_object/{batches.rb → scope/batches.rb} +5 -8
- data/lib/cassandra_object/scope/finder_methods.rb +47 -0
- data/lib/cassandra_object/scope/query_methods.rb +79 -0
- data/lib/cassandra_object/scope.rb +48 -0
- data/lib/cassandra_object/scoping.rb +19 -0
- data/lib/gotime-cassandra_object.rb +2 -2
- data/test/unit/log_subscriber_test.rb +6 -0
- data/test/unit/{batches_test.rb → scope/batches_test.rb} +0 -0
- data/test/unit/{finder_methods_test.rb → scope/finder_methods_test.rb} +0 -0
- data/test/unit/scope/query_methods_test.rb +12 -0
- data/test/unit/scoping_test.rb +7 -0
- metadata +12 -6
- data/lib/cassandra_object/finder_methods.rb +0 -68
data/README.rdoc
CHANGED
@@ -61,4 +61,12 @@ Cassandra Object has equivalent methods as ActiveRecord:
|
|
61
61
|
...
|
62
62
|
end
|
63
63
|
|
64
|
-
|
64
|
+
== Scoping
|
65
|
+
|
66
|
+
Some lightweight scoping features are available:
|
67
|
+
|
68
|
+
Widget.where('color' => 'red')
|
69
|
+
Widget.select(['name', 'color'])
|
70
|
+
Widget.limit(10)
|
71
|
+
|
72
|
+
|
@@ -31,9 +31,7 @@ module CassandraObject
|
|
31
31
|
include Connection
|
32
32
|
include Identity
|
33
33
|
include Inspect
|
34
|
-
include FinderMethods
|
35
34
|
include Persistence
|
36
|
-
include Batches
|
37
35
|
include AttributeMethods
|
38
36
|
include Validations
|
39
37
|
include AttributeMethods::Dirty
|
@@ -43,6 +41,7 @@ module CassandraObject
|
|
43
41
|
include Callbacks, ActiveModel::Observing
|
44
42
|
include Timestamps
|
45
43
|
include Savepoints
|
44
|
+
include Scoping
|
46
45
|
|
47
46
|
include Serialization
|
48
47
|
|
@@ -1,37 +1,29 @@
|
|
1
1
|
module CassandraObject
|
2
2
|
class LogSubscriber < ActiveSupport::LogSubscriber
|
3
|
-
def
|
4
|
-
|
5
|
-
|
6
|
-
debug " #{name} (#{event.payload[:keys].size}) #{event.payload[:keys].join(" ")}"
|
7
|
-
end
|
8
|
-
|
9
|
-
def remove(event)
|
10
|
-
name = '%s remove (%.1fms)' % [event.payload[:column_family], event.duration]
|
11
|
-
|
12
|
-
message = " #{name} #{event.payload[:key]}"
|
13
|
-
message << " #{Array(event.payload[:attributes]).inspect}" if event.payload[:attributes]
|
14
|
-
|
15
|
-
debug message
|
3
|
+
def initialize
|
4
|
+
super
|
5
|
+
@odd_or_even = false
|
16
6
|
end
|
17
7
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
8
|
+
def cql(event)
|
9
|
+
payload = event.payload
|
10
|
+
name = '%s (%.1fms)' % [payload[:name], event.duration]
|
11
|
+
cql = payload[:cql].squeeze(' ')
|
23
12
|
|
24
|
-
|
25
|
-
|
13
|
+
if odd?
|
14
|
+
name = color(name, CYAN, true)
|
15
|
+
cql = color(cql, nil, true)
|
16
|
+
else
|
17
|
+
name = color(name, MAGENTA, true)
|
18
|
+
end
|
26
19
|
|
27
|
-
debug " #{name} #{
|
20
|
+
debug " #{name} #{cql}"
|
28
21
|
end
|
29
22
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
debug " #{name} (#{event.payload[:count]}) '#{event.payload[:start]}' => '#{event.payload[:finish]}'"
|
23
|
+
def odd?
|
24
|
+
@odd_or_even = !@odd_or_even
|
34
25
|
end
|
35
26
|
end
|
36
27
|
end
|
28
|
+
|
37
29
|
CassandraObject::LogSubscriber.attach_to :cassandra_object
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module CassandraObject
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
module ClassMethods
|
2
|
+
class Scope
|
3
|
+
module Batches
|
6
4
|
def find_each(options = {})
|
7
5
|
find_in_batches(options) do |records|
|
8
6
|
records.each { |record| yield record }
|
@@ -13,8 +11,8 @@ module CassandraObject
|
|
13
11
|
batch_size = options.delete(:batch_size) || 1000
|
14
12
|
start_key = nil
|
15
13
|
|
16
|
-
|
17
|
-
records =
|
14
|
+
scope = limit(batch_size + 1)
|
15
|
+
records = scope.to_a
|
18
16
|
|
19
17
|
while records.any?
|
20
18
|
if records.size > batch_size
|
@@ -26,8 +24,7 @@ module CassandraObject
|
|
26
24
|
yield records
|
27
25
|
break if next_record.nil?
|
28
26
|
|
29
|
-
|
30
|
-
records = instantiate_from_cql statement, next_record.id
|
27
|
+
records = scope.where("KEY >= #{next_record.id}").to_a
|
31
28
|
end
|
32
29
|
end
|
33
30
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
class Scope
|
3
|
+
module FinderMethods
|
4
|
+
def find(ids)
|
5
|
+
if ids.is_a?(Array)
|
6
|
+
find_some(ids)
|
7
|
+
else
|
8
|
+
find_one(ids)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def find_by_id(ids)
|
13
|
+
find(ids)
|
14
|
+
rescue CassandraObject::RecordNotFound
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def all
|
19
|
+
to_a
|
20
|
+
end
|
21
|
+
|
22
|
+
def first
|
23
|
+
limit(1).to_a.first
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def find_one(id)
|
28
|
+
if id.blank?
|
29
|
+
raise CassandraObject::RecordNotFound, "Couldn't find #{self.name} with key #{id.inspect}"
|
30
|
+
elsif record = where('KEY' => id).first
|
31
|
+
record
|
32
|
+
else
|
33
|
+
raise CassandraObject::RecordNotFound
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_some(ids)
|
38
|
+
ids = ids.flatten
|
39
|
+
return [] if ids.empty?
|
40
|
+
|
41
|
+
ids = ids.compact.map(&:to_s).uniq
|
42
|
+
|
43
|
+
where("KEY in (#{ids * ','})").to_a
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
class Scope
|
3
|
+
module QueryMethods
|
4
|
+
def select!(value)
|
5
|
+
self.select_values += Array.wrap(value)
|
6
|
+
self
|
7
|
+
end
|
8
|
+
|
9
|
+
def select(value)
|
10
|
+
clone.select! value
|
11
|
+
end
|
12
|
+
|
13
|
+
def where!(*values)
|
14
|
+
self.where_values += values.flatten
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def where(*values)
|
19
|
+
clone.where! values
|
20
|
+
end
|
21
|
+
|
22
|
+
def limit!(value)
|
23
|
+
self.limit_value = value
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def limit(value)
|
28
|
+
clone.limit! value
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_a
|
32
|
+
statement = [
|
33
|
+
"select #{select_string} from #{klass.column_family}",
|
34
|
+
where_string,
|
35
|
+
limit_string
|
36
|
+
].delete_if(&:blank?) * ' '
|
37
|
+
|
38
|
+
instantiate_from_cql(statement)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def select_string
|
43
|
+
if select_values.any?
|
44
|
+
select_values * ','
|
45
|
+
else
|
46
|
+
'*'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def where_string
|
51
|
+
if where_values.any?
|
52
|
+
wheres = []
|
53
|
+
|
54
|
+
where_values.map do |where_value|
|
55
|
+
if where_value.is_a?(String)
|
56
|
+
wheres << where_value
|
57
|
+
elsif where_value.is_a?(Hash)
|
58
|
+
where_value.each do |column, value|
|
59
|
+
wheres << "#{column} = #{value}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
"WHERE #{wheres * ' AND '}"
|
65
|
+
else
|
66
|
+
''
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def limit_string
|
71
|
+
if limit_value
|
72
|
+
"limit #{limit_value}"
|
73
|
+
else
|
74
|
+
""
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'cassandra_object/scope/batches'
|
2
|
+
require 'cassandra_object/scope/finder_methods'
|
3
|
+
require 'cassandra_object/scope/query_methods'
|
4
|
+
|
5
|
+
module CassandraObject
|
6
|
+
class Scope
|
7
|
+
include Batches, FinderMethods, QueryMethods
|
8
|
+
|
9
|
+
attr_accessor :klass
|
10
|
+
attr_accessor :limit_value, :select_values, :where_values
|
11
|
+
|
12
|
+
def initialize(klass)
|
13
|
+
@klass = klass
|
14
|
+
|
15
|
+
@limit_value = nil
|
16
|
+
@select_values = []
|
17
|
+
@where_values = []
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def method_missing(method_name, *args, &block)
|
22
|
+
if klass.respond_to?(method_name)
|
23
|
+
klass.send(method_name, *args, &block)
|
24
|
+
elsif Array.method_defined?(method_name)
|
25
|
+
to_a.send(method_name, *args, &block)
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def instantiate_from_cql(cql_string, *args)
|
32
|
+
results = []
|
33
|
+
klass.execute_cql(cql_string, *args).fetch do |cql_row|
|
34
|
+
results << instantiate_cql_row(cql_row)
|
35
|
+
end
|
36
|
+
results.compact!
|
37
|
+
results
|
38
|
+
end
|
39
|
+
|
40
|
+
def instantiate_cql_row(cql_row)
|
41
|
+
attributes = cql_row.to_hash
|
42
|
+
key = attributes.delete('KEY')
|
43
|
+
if attributes.any?
|
44
|
+
instantiate(key, attributes)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
module Scoping
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
singleton_class.class_eval do
|
7
|
+
delegate :find, :find_by_id, :first, :all, to: :scope
|
8
|
+
delegate :find_each, :find_in_batches, to: :scope
|
9
|
+
delegate :select, :where, to: :scope
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def scope
|
15
|
+
Scope.new(self)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -15,10 +15,10 @@ module CassandraObject
|
|
15
15
|
autoload :Identity
|
16
16
|
autoload :Inspect
|
17
17
|
autoload :Serialization
|
18
|
-
autoload :Batches
|
19
|
-
autoload :FinderMethods
|
20
18
|
autoload :Savepoints
|
21
19
|
autoload :Schema
|
20
|
+
autoload :Scope
|
21
|
+
autoload :Scoping
|
22
22
|
autoload :Timestamps
|
23
23
|
autoload :Type
|
24
24
|
|
File without changes
|
File without changes
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CassandraObject::QueryMethodsTest < CassandraObject::TestCase
|
4
|
+
test "select" do
|
5
|
+
issue = Issue.create title: 'foo', description: 'bar'
|
6
|
+
|
7
|
+
issue = Issue.select(:title).find(issue.id)
|
8
|
+
|
9
|
+
assert_equal 'foo', issue.title
|
10
|
+
assert_nil issue.description
|
11
|
+
end
|
12
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gotime-cassandra_object
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-08-
|
13
|
+
date: 2012-08-14 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activemodel
|
@@ -98,7 +98,6 @@ files:
|
|
98
98
|
- lib/cassandra_object/attribute_methods/primary_key.rb
|
99
99
|
- lib/cassandra_object/attribute_methods/typecasting.rb
|
100
100
|
- lib/cassandra_object/base.rb
|
101
|
-
- lib/cassandra_object/batches.rb
|
102
101
|
- lib/cassandra_object/belongs_to.rb
|
103
102
|
- lib/cassandra_object/belongs_to/association.rb
|
104
103
|
- lib/cassandra_object/belongs_to/builder.rb
|
@@ -106,7 +105,6 @@ files:
|
|
106
105
|
- lib/cassandra_object/callbacks.rb
|
107
106
|
- lib/cassandra_object/connection.rb
|
108
107
|
- lib/cassandra_object/errors.rb
|
109
|
-
- lib/cassandra_object/finder_methods.rb
|
110
108
|
- lib/cassandra_object/identity.rb
|
111
109
|
- lib/cassandra_object/inspect.rb
|
112
110
|
- lib/cassandra_object/log_subscriber.rb
|
@@ -114,6 +112,11 @@ files:
|
|
114
112
|
- lib/cassandra_object/railtie.rb
|
115
113
|
- lib/cassandra_object/savepoints.rb
|
116
114
|
- lib/cassandra_object/schema.rb
|
115
|
+
- lib/cassandra_object/scope.rb
|
116
|
+
- lib/cassandra_object/scope/batches.rb
|
117
|
+
- lib/cassandra_object/scope/finder_methods.rb
|
118
|
+
- lib/cassandra_object/scope/query_methods.rb
|
119
|
+
- lib/cassandra_object/scoping.rb
|
117
120
|
- lib/cassandra_object/serialization.rb
|
118
121
|
- lib/cassandra_object/tasks/ks.rake
|
119
122
|
- lib/cassandra_object/timestamps.rb
|
@@ -142,15 +145,18 @@ files:
|
|
142
145
|
- test/unit/attribute_methods/typecasting_test.rb
|
143
146
|
- test/unit/attribute_methods_test.rb
|
144
147
|
- test/unit/base_test.rb
|
145
|
-
- test/unit/batches_test.rb
|
146
148
|
- test/unit/belongs_to_test.rb
|
147
149
|
- test/unit/callbacks_test.rb
|
148
150
|
- test/unit/connection_test.rb
|
149
|
-
- test/unit/finder_methods_test.rb
|
150
151
|
- test/unit/identity_test.rb
|
151
152
|
- test/unit/inspect_test.rb
|
153
|
+
- test/unit/log_subscriber_test.rb
|
152
154
|
- test/unit/persistence_test.rb
|
153
155
|
- test/unit/savepoints_test.rb
|
156
|
+
- test/unit/scope/batches_test.rb
|
157
|
+
- test/unit/scope/finder_methods_test.rb
|
158
|
+
- test/unit/scope/query_methods_test.rb
|
159
|
+
- test/unit/scoping_test.rb
|
154
160
|
- test/unit/timestamps_test.rb
|
155
161
|
- test/unit/types/array_type_test.rb
|
156
162
|
- test/unit/types/base_type_test.rb
|
@@ -1,68 +0,0 @@
|
|
1
|
-
module CassandraObject
|
2
|
-
module FinderMethods
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
module ClassMethods
|
6
|
-
def find(ids)
|
7
|
-
if ids.is_a?(Array)
|
8
|
-
find_some(ids)
|
9
|
-
else
|
10
|
-
find_one(ids)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def find_by_id(ids)
|
15
|
-
find(ids)
|
16
|
-
rescue CassandraObject::RecordNotFound
|
17
|
-
nil
|
18
|
-
end
|
19
|
-
|
20
|
-
def all
|
21
|
-
instantiate_from_cql "select * from #{column_family}"
|
22
|
-
end
|
23
|
-
|
24
|
-
def first(options = {})
|
25
|
-
instantiate_from_cql("select * from #{column_family} limit 1").first
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def instantiate_from_cql(cql_string, *args)
|
31
|
-
results = []
|
32
|
-
execute_cql(cql_string, *args).fetch do |cql_row|
|
33
|
-
results << instantiate_cql_row(cql_row)
|
34
|
-
end
|
35
|
-
results.compact!
|
36
|
-
results
|
37
|
-
end
|
38
|
-
|
39
|
-
def instantiate_cql_row(cql_row)
|
40
|
-
attributes = cql_row.to_hash
|
41
|
-
key = attributes.delete('KEY')
|
42
|
-
if attributes.any?
|
43
|
-
instantiate(key, attributes)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def find_one(id)
|
48
|
-
if id.blank?
|
49
|
-
raise CassandraObject::RecordNotFound, "Couldn't find #{self.name} with key #{id.inspect}"
|
50
|
-
elsif record = instantiate_from_cql("select * from #{column_family} where KEY = ? limit 1", id).first
|
51
|
-
record
|
52
|
-
else
|
53
|
-
raise CassandraObject::RecordNotFound
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def find_some(ids)
|
58
|
-
ids = ids.flatten
|
59
|
-
return [] if ids.empty?
|
60
|
-
|
61
|
-
ids = ids.compact.map(&:to_s).uniq
|
62
|
-
|
63
|
-
statement = "select * from #{column_family} where KEY in (#{Array.new(ids.size, '?') * ','})"
|
64
|
-
instantiate_from_cql statement, *ids
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|