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 CHANGED
@@ -61,4 +61,12 @@ Cassandra Object has equivalent methods as ActiveRecord:
61
61
  ...
62
62
  end
63
63
 
64
- CQL is currently not supported
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
+
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'gotime-cassandra_object'
5
- s.version = '4.1.0'
5
+ s.version = '4.2.0'
6
6
  s.description = 'Cassandra ActiveModel'
7
7
  s.summary = 'Cassandra ActiveModel'
8
8
  s.authors = ["Michael Koziarski", "gotime"]
@@ -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 multi_get(event)
4
- name = '%s multi_get (%.1fms)' % [event.payload[:column_family], event.duration]
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 truncate(event)
19
- name = '%s truncate (%.1fms)' % [event.payload[:column_family], event.duration]
20
-
21
- debug " #{name} #{event.payload[:column_family]}"
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
- def insert(event)
25
- name = '%s insert (%.1fms)' % [event.payload[:column_family], event.duration]
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} #{event.payload[:key]} #{event.payload[:attributes].inspect}"
20
+ debug " #{name} #{cql}"
28
21
  end
29
22
 
30
- def get_range(event)
31
- name = '%s get_range (%.1fms)' % [event.payload[:column_family], event.duration]
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
- module Batches
3
- extend ActiveSupport::Concern
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
- statement = "select * from #{column_family} limit #{batch_size + 1}"
17
- records = instantiate_from_cql statement
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
- statement = "SELECT * FROM #{column_family} WHERE KEY >= ? LIMIT #{batch_size + 1}"
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
 
@@ -0,0 +1,6 @@
1
+ require "test_helper"
2
+ require "active_support/log_subscriber/test_helper"
3
+
4
+ class CassandraObject::LogSubscriberTest < CassandraObject::TestCase
5
+ include ActiveSupport::LogSubscriber::TestHelper
6
+ end
@@ -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
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class CassandraObject::ScopingTest < CassandraObject::TestCase
4
+ test "scope" do
5
+ assert_kind_of CassandraObject::Scope, Issue.scope
6
+ end
7
+ 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.1.0
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 00:00:00.000000000 Z
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