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
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'statement'
|
2
|
+
require_relative 'execution'
|
3
|
+
require_relative 'logging'
|
4
|
+
|
5
|
+
module Cassie::Statements
|
6
|
+
module Core
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
include Statement
|
11
|
+
include Execution
|
12
|
+
include Logging
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(params={})
|
16
|
+
params.each do |attr, value|
|
17
|
+
self.public_send("#{attr}=", value)
|
18
|
+
end
|
19
|
+
|
20
|
+
super()
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,9 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require_relative 'batches'
|
4
|
-
|
5
|
-
module Cassie::Queries::Statement
|
6
|
-
module Batches
|
1
|
+
module Cassie::Statements::Execution
|
2
|
+
module BatchedFetching
|
7
3
|
extend ::ActiveSupport::Concern
|
8
4
|
|
9
5
|
included do
|
@@ -54,10 +50,10 @@ module Cassie::Queries::Statement
|
|
54
50
|
def fetch_in_batches(opts={})
|
55
51
|
opts[:batch_size] ||= 1000
|
56
52
|
|
57
|
-
#
|
58
|
-
# rather than waiting until the firt iteration is executed
|
59
|
-
#
|
60
|
-
#
|
53
|
+
# spawn the new query as soon as the enumerable is created
|
54
|
+
# rather than waiting until the firt iteration is executed.
|
55
|
+
# The client could mutate the object between these moments,
|
56
|
+
# however we don't want to spawn twice if a block isn't passed.
|
61
57
|
paged_query = opts.delete(:_paged_query) || self.clone
|
62
58
|
|
63
59
|
return to_enum(:fetch_in_batches, opts.merge(_paged_query: paged_query)) unless block_given?
|
@@ -87,7 +83,7 @@ module Cassie::Queries::Statement
|
|
87
83
|
private
|
88
84
|
|
89
85
|
def page_size_changed_error(original_size)
|
90
|
-
Cassie::
|
86
|
+
Cassie::Statements::Statement::Invalid.new("Page size is no longer valid. It was #{original_size} when the batch was started, and is now #{self.page_size}. Continuing would cause unexpected results.")
|
91
87
|
end
|
92
88
|
end
|
93
89
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Cassie::Statements::Execution
|
2
|
+
module Deserialization
|
3
|
+
|
4
|
+
protected
|
5
|
+
|
6
|
+
def build_result(row)
|
7
|
+
# Default implementation builds
|
8
|
+
# a struct with the row data for
|
9
|
+
# more convenient data access
|
10
|
+
Struct.new(*row.keys.map(&:to_sym)).new(*row.values)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,19 +1,15 @@
|
|
1
|
-
|
2
|
-
require_relative 'loading'
|
3
|
-
require_relative 'batches'
|
1
|
+
class Cassie::Statements::RecordNotFound < StandardError; end
|
4
2
|
|
5
|
-
|
3
|
+
module Cassie::Statements::Execution
|
4
|
+
require_relative 'batched_fetching'
|
5
|
+
require_relative 'deserialization'
|
6
6
|
|
7
|
-
module Cassie::Queries::Statement
|
8
7
|
module Fetching
|
9
8
|
extend ActiveSupport::Concern
|
10
9
|
|
11
10
|
included do
|
12
|
-
include
|
13
|
-
include
|
14
|
-
#TODO: should this be loaded from instrumentation
|
15
|
-
# by using notifications when fetching is loaded?
|
16
|
-
include Cassie::Queries::Instrumentation::Loading
|
11
|
+
include BatchedFetching
|
12
|
+
include Deserialization
|
17
13
|
end
|
18
14
|
|
19
15
|
# Returns array of rows or empty array
|
@@ -27,7 +23,7 @@ module Cassie::Queries::Statement
|
|
27
23
|
end
|
28
24
|
|
29
25
|
execute
|
30
|
-
result
|
26
|
+
result
|
31
27
|
end
|
32
28
|
|
33
29
|
# Returns first result or nil
|
@@ -38,15 +34,8 @@ module Cassie::Queries::Statement
|
|
38
34
|
# query.fetch_first(id: 2)
|
39
35
|
# => nil
|
40
36
|
def fetch_first(args={})
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
fetch(args).first
|
45
|
-
ensure
|
46
|
-
if old_limit
|
47
|
-
@limit = old_limit
|
48
|
-
else
|
49
|
-
remove_instance_variable(:@limit)
|
37
|
+
with_limit(1) do
|
38
|
+
fetch(args).first
|
50
39
|
end
|
51
40
|
end
|
52
41
|
|
@@ -58,7 +47,7 @@ module Cassie::Queries::Statement
|
|
58
47
|
# query.fetch_first!(id: 2)
|
59
48
|
# RecordNotFound: RecordNotFound
|
60
49
|
def fetch_first!(args={})
|
61
|
-
fetch_first || raise(Cassie::
|
50
|
+
fetch_first || raise(Cassie::Statements::RecordNotFound.new('CQL row does not exist'))
|
62
51
|
end
|
63
52
|
end
|
64
53
|
end
|
data/lib/cassie/{queries/instrumentation/execution.rb → statements/execution/instrumentation.rb}
RENAMED
@@ -1,5 +1,5 @@
|
|
1
|
-
module Cassie::
|
2
|
-
module
|
1
|
+
module Cassie::Statements::Execution
|
2
|
+
module Instrumentation
|
3
3
|
|
4
4
|
def execute
|
5
5
|
instrumenter.instrument("cassie.cql.execution") do |payload|
|
@@ -9,6 +9,10 @@ module Cassie::Queries::Instrumentation
|
|
9
9
|
execution_val
|
10
10
|
end
|
11
11
|
end
|
12
|
+
|
13
|
+
def instrumenter
|
14
|
+
Cassie::Statements.instrumenter
|
15
|
+
end
|
12
16
|
end
|
13
17
|
end
|
14
18
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative 'simple_policy'
|
2
|
+
|
3
|
+
module Cassie::Statements::Execution::PartitionLinking
|
4
|
+
class CursoringPolicy < SimplePolicy
|
5
|
+
|
6
|
+
def prepare_execution
|
7
|
+
super
|
8
|
+
# We are changing to the next partition
|
9
|
+
# so, reset the max cursor to start at the top
|
10
|
+
# execution.max_cursor = nil
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# Note: currently supports only natural linking
|
2
|
+
# that is in the same direction as the clustering order
|
3
|
+
module Cassie::Statements::Execution::PartitionLinking
|
4
|
+
module PolicyMethods
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
attr_reader :identifier, :direction, :range, :peeking_execution, :execution
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(executed, identifier, direction, range)
|
12
|
+
@peeking_execution = executed
|
13
|
+
@identifier = identifier
|
14
|
+
@direction = direction
|
15
|
+
@range = range
|
16
|
+
end
|
17
|
+
|
18
|
+
def link
|
19
|
+
if end_of_partition? && partition_available?
|
20
|
+
prepare_execution
|
21
|
+
execution.execute
|
22
|
+
combine_results
|
23
|
+
else
|
24
|
+
peeking_execution.result
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def prepare_execution
|
29
|
+
@execution = peeking_execution.clone
|
30
|
+
change_partition
|
31
|
+
adjust_limit
|
32
|
+
execution
|
33
|
+
end
|
34
|
+
|
35
|
+
def end_of_partition?
|
36
|
+
!peeking_execution.result.peeked_row
|
37
|
+
rescue NoMethodError => ex
|
38
|
+
message = "Results aren't available for linking. Did you forget to call `execute`?" if peeking_execution.result.nil?
|
39
|
+
message ||= "Peeking not enabled. To link partitions, peeking must be included in the execution. Did you forget to call `link_partitions`?"
|
40
|
+
raise ArgumentError, message
|
41
|
+
end
|
42
|
+
|
43
|
+
def partition_available?
|
44
|
+
if ascending?
|
45
|
+
# |0| |1| |2| |3|
|
46
|
+
# |X| |✓| |✓| |✓| |X|
|
47
|
+
current_key < last_key && current_key >= first_key
|
48
|
+
else
|
49
|
+
# |0| |1| |2| |3|
|
50
|
+
# |X| |✓| |✓| |✓| |X|
|
51
|
+
current_key > first_key && current_key <= last_key
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def first_key
|
58
|
+
eval_opt(range.first, peeking_execution)
|
59
|
+
end
|
60
|
+
|
61
|
+
def last_key
|
62
|
+
eval_opt(range.last, peeking_execution)
|
63
|
+
end
|
64
|
+
|
65
|
+
def change_partition
|
66
|
+
_partition = if ascending?
|
67
|
+
# explicitly pass key to keep policy subclass
|
68
|
+
# interface clear and consistent
|
69
|
+
next_key(current_key)
|
70
|
+
else
|
71
|
+
# explicitly pass key to keep policy subclass
|
72
|
+
# interface clear and consistent
|
73
|
+
previous_key(current_key)
|
74
|
+
end
|
75
|
+
if _partition < first_key || _partition > last_key
|
76
|
+
logger.warn("[WARN] linking to partition that is outside of ranges defined. #{_partition} outside of (#{first_key}..#{last_key}). This could result in unexpected records being returned.")
|
77
|
+
end
|
78
|
+
|
79
|
+
# define object singleton method to
|
80
|
+
# override getter for partition key
|
81
|
+
# returning the partion that needs to be linked
|
82
|
+
execution.define_singleton_method(identifier) do
|
83
|
+
_partition
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def adjust_limit
|
88
|
+
execution.limit = execution.limit - peeked_rows.count
|
89
|
+
end
|
90
|
+
|
91
|
+
def current_key
|
92
|
+
peeking_execution.send(identifier)
|
93
|
+
end
|
94
|
+
|
95
|
+
def combine_results
|
96
|
+
rows = combine_rows(peeked_rows.to_a , execution_rows.to_a)
|
97
|
+
execution.result.define_singleton_method(:rows) do
|
98
|
+
rows
|
99
|
+
end
|
100
|
+
execution.result
|
101
|
+
end
|
102
|
+
|
103
|
+
def ascending?
|
104
|
+
[:ascending, :asc, :ASC].include? direction
|
105
|
+
end
|
106
|
+
|
107
|
+
def peeked_rows
|
108
|
+
peeking_execution.result.rows
|
109
|
+
end
|
110
|
+
|
111
|
+
def execution_rows
|
112
|
+
execution.result.rows
|
113
|
+
end
|
114
|
+
|
115
|
+
def logger
|
116
|
+
Cassie::Statements.logger
|
117
|
+
end
|
118
|
+
|
119
|
+
def eval_opt(value, _source=source)
|
120
|
+
case value
|
121
|
+
when Symbol
|
122
|
+
_source.send(value)
|
123
|
+
else
|
124
|
+
value
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'policy_methods'
|
2
|
+
|
3
|
+
module Cassie::Statements::Execution::PartitionLinking
|
4
|
+
class SimplePolicy
|
5
|
+
include PolicyMethods
|
6
|
+
|
7
|
+
def combine_rows(rows_a, rows_b)
|
8
|
+
rows_a + rows_b
|
9
|
+
end
|
10
|
+
|
11
|
+
def next_key(current_key)
|
12
|
+
current_key + 1
|
13
|
+
end
|
14
|
+
|
15
|
+
def previous_key(current_key)
|
16
|
+
current_key - 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Cassie::Statements::Execution
|
2
|
+
module PartitionLinking
|
3
|
+
require_relative 'partition_linking/simple_policy'
|
4
|
+
require_relative 'partition_linking/cursoring_policy'
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def link_partitions(*args)
|
10
|
+
include Peeking
|
11
|
+
self.partition_linker_args = args
|
12
|
+
end
|
13
|
+
|
14
|
+
def partition_linker=(val)
|
15
|
+
@partition_linker = val
|
16
|
+
end
|
17
|
+
|
18
|
+
def partition_linker
|
19
|
+
@partition_linker || SimplePolicy
|
20
|
+
end
|
21
|
+
|
22
|
+
def partition_linker_args=(val)
|
23
|
+
@partition_linker_args = val
|
24
|
+
end
|
25
|
+
|
26
|
+
def partition_linker_args
|
27
|
+
@partition_linker_args if defined?(@partition_linker_args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def execute
|
32
|
+
success = super
|
33
|
+
if success && partition_linker?
|
34
|
+
@result = build_partition_linker.link
|
35
|
+
result.success?
|
36
|
+
else
|
37
|
+
success
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_partition_linker
|
42
|
+
self.class.partition_linker.new(self, *self.class.partition_linker_args)
|
43
|
+
end
|
44
|
+
|
45
|
+
def partition_linker?
|
46
|
+
!!self.class.partition_linker_args
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Cassie::Statements::Execution
|
2
|
+
module Peeking
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
@result_class = Cassie::Statements::Results::PeekingResult
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute
|
10
|
+
assert_limit
|
11
|
+
with_limit(limit + 1) { super }
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def result_opts
|
17
|
+
super.merge(limit: limit - 1)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def assert_limit
|
23
|
+
if limit.nil?
|
24
|
+
raise ArgumentError, "Cassie Peeking is enabled, but the statement limit is `nil`. A limit is required to peek at the next result. Did you accidentally set `Cassie::Statements.limit = nil` instead of disabling the limit for only a specific query?"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Cassie::Statements::Results
|
2
|
+
require_relative 'querying'
|
3
|
+
require_relative 'peeking'
|
4
|
+
|
5
|
+
class CursoredResult < Result
|
6
|
+
include Querying
|
7
|
+
include Peeking
|
8
|
+
|
9
|
+
attr_reader :max_cursor_key
|
10
|
+
|
11
|
+
def after_initialize(opts)
|
12
|
+
super
|
13
|
+
@max_cursor_key = opts[:max_cursor_key]
|
14
|
+
|
15
|
+
define_singleton_method "next_max_#{max_cursor_key}" do
|
16
|
+
next_max_cursor
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def next_max_cursor
|
21
|
+
if peeked_row
|
22
|
+
peeked_row[max_cursor_key]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Cassie::Statements::Results
|
2
|
+
module Instrumentation
|
3
|
+
|
4
|
+
protected
|
5
|
+
|
6
|
+
def records
|
7
|
+
instrumenter.instrument("cassie.deserialize") do |payload|
|
8
|
+
records = super
|
9
|
+
payload[:count] = records.count if records.respond_to?(:count)
|
10
|
+
records
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def instrumenter
|
15
|
+
Cassie::Statements.instrumenter
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Cassie::Statements::Results
|
2
|
+
module Modification
|
3
|
+
|
4
|
+
def success?
|
5
|
+
# when using conditional update, the server will respond
|
6
|
+
# with a result-set containing a special result named "[applied]".
|
7
|
+
return false if rows.first && rows.first["[applied]"] == false
|
8
|
+
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Cassie::Statements::Results
|
2
|
+
module Peeking
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
attr_reader :limit
|
7
|
+
attr_reader :peeked_row
|
8
|
+
end
|
9
|
+
|
10
|
+
def peeked_result
|
11
|
+
return @peeked_result if defined?(@peeked_result)
|
12
|
+
|
13
|
+
@peeked_result = if peeked_row
|
14
|
+
each_deserializer.call(peeked_row)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def after_initialize(opts={})
|
21
|
+
super
|
22
|
+
@limit = opts[:limit]
|
23
|
+
extract_peeked_rows_after(limit)
|
24
|
+
end
|
25
|
+
|
26
|
+
def extract_peeked_rows_after(limit)
|
27
|
+
peeked_count = rows.count - limit
|
28
|
+
@peeked_row = case
|
29
|
+
when peeked_count == 1
|
30
|
+
raw_rows.delete_at(-1)
|
31
|
+
when peeked_count <= 0
|
32
|
+
nil
|
33
|
+
else
|
34
|
+
raise "More than one row was peeked at. Please report this Cassie issue: https://github.com/eprothro/cassie/issues."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def raw_rows
|
39
|
+
__getobj__.instance_variable_get(:@rows)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Cassie::Statements::Results
|
2
|
+
require_relative 'instrumentation'
|
3
|
+
|
4
|
+
module Querying
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
# enumerate on domain specific models
|
9
|
+
# not on underlying Cassandra::Result rows
|
10
|
+
#
|
11
|
+
# e.g. include? should compare against the
|
12
|
+
# deserialized objects, not the underlying
|
13
|
+
# row hashes.
|
14
|
+
include Enumerable
|
15
|
+
include Instrumentation
|
16
|
+
|
17
|
+
attr_reader :deserializer
|
18
|
+
attr_reader :each_deserializer
|
19
|
+
end
|
20
|
+
|
21
|
+
def after_initialize(opts)
|
22
|
+
super
|
23
|
+
@each_deserializer = opts[:each_deserializer]
|
24
|
+
@deserializer = opts[:deserializer]
|
25
|
+
ensure_deserialization
|
26
|
+
end
|
27
|
+
|
28
|
+
# Deserialize each row into domain objects
|
29
|
+
#
|
30
|
+
# note: __object__.each is aliased
|
31
|
+
# as rows and each_row.
|
32
|
+
def each(&block)
|
33
|
+
if block_given?
|
34
|
+
records.each(&block)
|
35
|
+
self
|
36
|
+
else
|
37
|
+
records.each
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def success?
|
42
|
+
# an empty query is still successful
|
43
|
+
return true if __getobj__.empty?
|
44
|
+
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def records
|
51
|
+
@records ||= deserializer.call(rows)
|
52
|
+
end
|
53
|
+
|
54
|
+
def ensure_deserialization
|
55
|
+
@deserializer ||= method(each_deserializer ? :map_deserialize : :pass_through_deserialize)
|
56
|
+
end
|
57
|
+
|
58
|
+
def pass_through_deserialize(hashes)
|
59
|
+
hashes
|
60
|
+
end
|
61
|
+
|
62
|
+
def map_deserialize(hashes)
|
63
|
+
hashes.map{|hash| each_deserializer.call(hash) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Cassie::Statements::Results
|
2
|
+
require_relative 'core'
|
3
|
+
|
4
|
+
class Result < SimpleDelegator
|
5
|
+
# __obj__ is Cassandra::Result, which is enumerable
|
6
|
+
include Core
|
7
|
+
|
8
|
+
def initialize(obj, opts={})
|
9
|
+
super(obj)
|
10
|
+
after_initialize(opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
# Result will be the superclass
|
16
|
+
# of concrete result classes
|
17
|
+
# so any overrides defined in subclasses
|
18
|
+
# or modules included in subclasses
|
19
|
+
# will get called first
|
20
|
+
def after_initialize(opts)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Cassie::Statements
|
4
|
+
module Results
|
5
|
+
require_relative 'results/result'
|
6
|
+
require_relative 'results/modification_result'
|
7
|
+
require_relative 'results/query_result'
|
8
|
+
require_relative 'results/peeking_result'
|
9
|
+
require_relative 'results/cursored_result'
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|