extendi-cassandra_object 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.travis.yml +23 -0
- data/CHANGELOG +0 -0
- data/Gemfile +17 -0
- data/LICENSE +13 -0
- data/MIT-LICENSE +20 -0
- data/README.md +177 -0
- data/Rakefile +12 -0
- data/extendi-cassandra_object.gemspec +26 -0
- data/lib/cassandra_object.rb +73 -0
- data/lib/cassandra_object/adapters/abstract_adapter.rb +61 -0
- data/lib/cassandra_object/adapters/cassandra_adapter.rb +269 -0
- data/lib/cassandra_object/adapters/cassandra_schemaless_adapter.rb +306 -0
- data/lib/cassandra_object/attribute_methods.rb +96 -0
- data/lib/cassandra_object/attribute_methods/definition.rb +22 -0
- data/lib/cassandra_object/attribute_methods/dirty.rb +36 -0
- data/lib/cassandra_object/attribute_methods/primary_key.rb +25 -0
- data/lib/cassandra_object/attribute_methods/typecasting.rb +59 -0
- data/lib/cassandra_object/base.rb +33 -0
- data/lib/cassandra_object/base_schema.rb +11 -0
- data/lib/cassandra_object/base_schemaless.rb +11 -0
- data/lib/cassandra_object/base_schemaless_dynamic.rb +11 -0
- data/lib/cassandra_object/belongs_to.rb +63 -0
- data/lib/cassandra_object/belongs_to/association.rb +49 -0
- data/lib/cassandra_object/belongs_to/builder.rb +40 -0
- data/lib/cassandra_object/belongs_to/reflection.rb +30 -0
- data/lib/cassandra_object/callbacks.rb +29 -0
- data/lib/cassandra_object/core.rb +63 -0
- data/lib/cassandra_object/errors.rb +10 -0
- data/lib/cassandra_object/identity.rb +26 -0
- data/lib/cassandra_object/inspect.rb +25 -0
- data/lib/cassandra_object/log_subscriber.rb +44 -0
- data/lib/cassandra_object/model.rb +60 -0
- data/lib/cassandra_object/persistence.rb +203 -0
- data/lib/cassandra_object/railtie.rb +33 -0
- data/lib/cassandra_object/railties/controller_runtime.rb +45 -0
- data/lib/cassandra_object/schema.rb +83 -0
- data/lib/cassandra_object/schemaless.rb +83 -0
- data/lib/cassandra_object/scope.rb +86 -0
- data/lib/cassandra_object/scope/finder_methods.rb +54 -0
- data/lib/cassandra_object/scope/query_methods.rb +69 -0
- data/lib/cassandra_object/scoping.rb +27 -0
- data/lib/cassandra_object/serialization.rb +6 -0
- data/lib/cassandra_object/tasks/ks.rake +54 -0
- data/lib/cassandra_object/timestamps.rb +19 -0
- data/lib/cassandra_object/type.rb +16 -0
- data/lib/cassandra_object/types.rb +8 -0
- data/lib/cassandra_object/types/array_type.rb +16 -0
- data/lib/cassandra_object/types/base_type.rb +26 -0
- data/lib/cassandra_object/types/boolean_type.rb +20 -0
- data/lib/cassandra_object/types/date_type.rb +22 -0
- data/lib/cassandra_object/types/float_type.rb +16 -0
- data/lib/cassandra_object/types/integer_type.rb +20 -0
- data/lib/cassandra_object/types/json_type.rb +13 -0
- data/lib/cassandra_object/types/string_type.rb +19 -0
- data/lib/cassandra_object/types/time_type.rb +16 -0
- data/lib/cassandra_object/types/type_helper.rb +39 -0
- data/lib/cassandra_object/validations.rb +44 -0
- data/test/support/cassandra.rb +63 -0
- data/test/support/issue.rb +12 -0
- data/test/support/issue_dynamic.rb +12 -0
- data/test/support/issue_schema.rb +17 -0
- data/test/support/issue_schema_child.rb +17 -0
- data/test/support/issue_schema_father.rb +13 -0
- data/test/test_helper.rb +41 -0
- data/test/unit/active_model_test.rb +18 -0
- data/test/unit/adapters/adapter_test.rb +6 -0
- data/test/unit/attribute_methods/definition_test.rb +13 -0
- data/test/unit/attribute_methods/dirty_test.rb +72 -0
- data/test/unit/attribute_methods/primary_key_test.rb +26 -0
- data/test/unit/attribute_methods/typecasting_test.rb +119 -0
- data/test/unit/attribute_methods_test.rb +51 -0
- data/test/unit/base_test.rb +20 -0
- data/test/unit/belongs_to/reflection_test.rb +12 -0
- data/test/unit/belongs_to_test.rb +63 -0
- data/test/unit/callbacks_test.rb +46 -0
- data/test/unit/connection_test.rb +6 -0
- data/test/unit/connections/connections_test.rb +55 -0
- data/test/unit/core_test.rb +55 -0
- data/test/unit/identity_test.rb +26 -0
- data/test/unit/inspect_test.rb +26 -0
- data/test/unit/log_subscriber_test.rb +25 -0
- data/test/unit/persistence_schema_test.rb +156 -0
- data/test/unit/persistence_test.rb +266 -0
- data/test/unit/railties/controller_runtime_test.rb +48 -0
- data/test/unit/schema/tasks_test.rb +32 -0
- data/test/unit/schema_test.rb +115 -0
- data/test/unit/schemaless_test.rb +100 -0
- data/test/unit/scope/finder_methods_test.rb +117 -0
- data/test/unit/scope/query_methods_test.rb +32 -0
- data/test/unit/scoping_test.rb +7 -0
- data/test/unit/timestamps_test.rb +27 -0
- data/test/unit/types/array_type_test.rb +17 -0
- data/test/unit/types/base_type_test.rb +19 -0
- data/test/unit/types/boolean_type_test.rb +24 -0
- data/test/unit/types/date_type_test.rb +15 -0
- data/test/unit/types/float_type_test.rb +17 -0
- data/test/unit/types/integer_type_test.rb +19 -0
- data/test/unit/types/json_type_test.rb +23 -0
- data/test/unit/types/string_type_test.rb +25 -0
- data/test/unit/types/time_type_test.rb +14 -0
- data/test/unit/validations_test.rb +27 -0
- metadata +202 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
rake_tasks do
|
4
|
+
load 'cassandra_object/tasks/ks.rake'
|
5
|
+
end
|
6
|
+
|
7
|
+
initializer "cassandra_object.log_runtime" do |app|
|
8
|
+
ActiveSupport.on_load :cassandra_object do
|
9
|
+
pathname = Rails.root.join('config', 'cassandra.yml')
|
10
|
+
if pathname.exist?
|
11
|
+
config = YAML.load(pathname.read)
|
12
|
+
|
13
|
+
if config = config[Rails.env]
|
14
|
+
self.config = {
|
15
|
+
keyspace: config['keyspace'],
|
16
|
+
hosts: config['hosts'],
|
17
|
+
}
|
18
|
+
else
|
19
|
+
raise "Missing environment #{Rails.env} in cassandra.yml"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Expose database runtime to controller for logging.
|
26
|
+
initializer "cassandra_object.log_runtime" do |app|
|
27
|
+
require "cassandra_object/railties/controller_runtime"
|
28
|
+
ActiveSupport.on_load(:action_controller) do
|
29
|
+
include CassandraObject::Railties::ControllerRuntime
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'active_support/core_ext/module/attr_internal'
|
2
|
+
require 'cassandra_object/log_subscriber'
|
3
|
+
|
4
|
+
module CassandraObject
|
5
|
+
module Railties # :nodoc:
|
6
|
+
module ControllerRuntime #:nodoc:
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
module ClassMethods # :nodoc:
|
10
|
+
def log_process_action(payload)
|
11
|
+
messages, cassandra_object_runtime = super, payload[:cassandra_object_runtime]
|
12
|
+
if cassandra_object_runtime.to_i > 0
|
13
|
+
messages << ("CassandraObject: %.1fms" % cassandra_object_runtime.to_f)
|
14
|
+
end
|
15
|
+
messages
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
#private
|
20
|
+
|
21
|
+
attr_internal :cassandra_object_runtime
|
22
|
+
|
23
|
+
def process_action(action, *args)
|
24
|
+
# We also need to reset the runtime before each action
|
25
|
+
# because of queries in middleware or in cases we are streaming
|
26
|
+
# and it won't be cleaned up by the method below.
|
27
|
+
CassandraObject::LogSubscriber.reset_runtime
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def cleanup_view_runtime
|
32
|
+
runtime_before_render = CassandraObject::LogSubscriber.reset_runtime
|
33
|
+
runtime = super
|
34
|
+
runtime_after_render = CassandraObject::LogSubscriber.reset_runtime
|
35
|
+
self.cassandra_object_runtime = runtime_before_render + runtime_after_render
|
36
|
+
runtime - runtime_after_render
|
37
|
+
end
|
38
|
+
|
39
|
+
def append_info_to_payload(payload)
|
40
|
+
super
|
41
|
+
payload[:cassandra_object_runtime] = (cassandra_object_runtime || 0) + CassandraObject::LogSubscriber.reset_runtime
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'cassandra'
|
2
|
+
|
3
|
+
module CassandraObject
|
4
|
+
class Schema
|
5
|
+
|
6
|
+
class << self
|
7
|
+
DEFAULT_CREATE_KEYSPACE = {
|
8
|
+
'strategy_class' => 'SimpleStrategy',
|
9
|
+
'strategy_options' => 'replication_factor:1'
|
10
|
+
}
|
11
|
+
|
12
|
+
def create_keyspace(keyspace, options = nil)
|
13
|
+
stmt = "CREATE KEYSPACE #{keyspace} WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };"
|
14
|
+
|
15
|
+
options ||= {} #DEFAULT_CREATE_KEYSPACE
|
16
|
+
|
17
|
+
system_execute stmt #adapter.statement_with_options(stmt, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def drop_keyspace(keyspace, confirm = false)
|
21
|
+
if adapter.cassandra_version < 3
|
22
|
+
count = (system_execute "SELECT count(*) FROM schema_columnfamilies where keyspace_name = '#{keyspace}' ALLOW FILTERING;").rows.first['count']
|
23
|
+
else
|
24
|
+
count = (system_schema_execute "SELECT count(*) FROM tables where keyspace_name = '#{keyspace}';").rows.first['count']
|
25
|
+
end
|
26
|
+
if confirm || count == 0
|
27
|
+
system_execute "DROP KEYSPACE #{keyspace}"
|
28
|
+
else
|
29
|
+
raise "Cannot drop keyspace #{keyspace}. You must delete all tables before"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_column_family(column_family, options = {})
|
34
|
+
create_table column_family, options
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_table(table_name, options = {})
|
38
|
+
adapter.create_table table_name, options
|
39
|
+
end
|
40
|
+
|
41
|
+
def alter_column_family(column_family, instruction, options = {})
|
42
|
+
stmt = "ALTER TABLE #{column_family} #{instruction}"
|
43
|
+
keyspace_execute adapter.statement_with_options(stmt, options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def drop_column_family(column_family)
|
47
|
+
drop_table column_family
|
48
|
+
end
|
49
|
+
|
50
|
+
def drop_table(table_name, confirm = false)
|
51
|
+
adapter.drop_table table_name, confirm
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_index(column_family, column, index_name = nil)
|
55
|
+
stmt = "CREATE INDEX #{index_name.nil? ? '' : index_name} ON #{column_family} (#{column})"
|
56
|
+
keyspace_execute stmt
|
57
|
+
end
|
58
|
+
|
59
|
+
# If the index was not given a name during creation, the index name is <columnfamily_name>_<column_name>_idx.
|
60
|
+
def drop_index(index_name)
|
61
|
+
keyspace_execute "DROP INDEX #{index_name}"
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def adapter
|
67
|
+
@adapter ||= CassandraObject::Adapters::CassandraAdapter.new(CassandraObject::Base.config)
|
68
|
+
end
|
69
|
+
|
70
|
+
def keyspace_execute(cql)
|
71
|
+
adapter.schema_execute cql, CassandraObject::Base.config[:keyspace]
|
72
|
+
end
|
73
|
+
|
74
|
+
def system_schema_execute(cql)
|
75
|
+
adapter.schema_execute cql, 'system_schema'
|
76
|
+
end
|
77
|
+
|
78
|
+
def system_execute(cql)
|
79
|
+
adapter.schema_execute cql, 'system'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'cassandra'
|
2
|
+
|
3
|
+
module CassandraObject
|
4
|
+
class Schemaless
|
5
|
+
|
6
|
+
class << self
|
7
|
+
DEFAULT_CREATE_KEYSPACE = {
|
8
|
+
'strategy_class' => 'SimpleStrategy',
|
9
|
+
'strategy_options' => 'replication_factor:1'
|
10
|
+
}
|
11
|
+
|
12
|
+
def create_keyspace(keyspace, options = nil)
|
13
|
+
stmt = "CREATE KEYSPACE #{keyspace} WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };"
|
14
|
+
|
15
|
+
options ||= {} #DEFAULT_CREATE_KEYSPACE
|
16
|
+
|
17
|
+
system_execute stmt #adapter.statement_with_options(stmt, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def drop_keyspace(keyspace, confirm = false)
|
21
|
+
if adapter.cassandra_version < 3
|
22
|
+
count = (system_execute "SELECT count(*) FROM schema_columnfamilies where keyspace_name = '#{keyspace}' ALLOW FILTERING;").rows.first['count']
|
23
|
+
else
|
24
|
+
count = (system_schema_execute "SELECT count(*) FROM tables where keyspace_name = '#{keyspace}';").rows.first['count']
|
25
|
+
end
|
26
|
+
if confirm || count == 0
|
27
|
+
system_execute "DROP KEYSPACE #{keyspace}"
|
28
|
+
else
|
29
|
+
raise "Cannot drop keyspace #{keyspace}. You must delete all tables before"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_column_family(column_family, options = {})
|
34
|
+
create_table column_family, options
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_table(table_name, options = {})
|
38
|
+
adapter.create_table table_name, options
|
39
|
+
end
|
40
|
+
|
41
|
+
def alter_column_family(column_family, instruction, options = {})
|
42
|
+
stmt = "ALTER TABLE #{column_family} #{instruction}"
|
43
|
+
keyspace_execute adapter.statement_with_options(stmt, options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def drop_column_family(column_family)
|
47
|
+
drop_table column_family
|
48
|
+
end
|
49
|
+
|
50
|
+
def drop_table(table_name, confirm = false)
|
51
|
+
adapter.drop_table table_name, confirm
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_index(column_family, column, index_name = nil)
|
55
|
+
stmt = "CREATE INDEX #{index_name.nil? ? '' : index_name} ON #{column_family} (#{column})"
|
56
|
+
keyspace_execute stmt
|
57
|
+
end
|
58
|
+
|
59
|
+
# If the index was not given a name during creation, the index name is <columnfamily_name>_<column_name>_idx.
|
60
|
+
def drop_index(index_name)
|
61
|
+
keyspace_execute "DROP INDEX #{index_name}"
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def adapter
|
67
|
+
@adapter ||= CassandraObject::Adapters::CassandraSchemalessAdapter.new(CassandraObject::Base.config)
|
68
|
+
end
|
69
|
+
|
70
|
+
def keyspace_execute(cql)
|
71
|
+
adapter.schema_execute cql, CassandraObject::Base.config[:keyspace]
|
72
|
+
end
|
73
|
+
|
74
|
+
def system_schema_execute(cql)
|
75
|
+
adapter.schema_execute cql, 'system_schema'
|
76
|
+
end
|
77
|
+
|
78
|
+
def system_execute(cql)
|
79
|
+
adapter.schema_execute cql, 'system'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'cassandra_object/scope/finder_methods'
|
2
|
+
require 'cassandra_object/scope/query_methods'
|
3
|
+
|
4
|
+
module CassandraObject
|
5
|
+
class Scope
|
6
|
+
include FinderMethods, QueryMethods
|
7
|
+
|
8
|
+
attr_accessor :klass
|
9
|
+
attr_accessor :is_all, :limit_value, :select_values, :where_values, :id_values, :raw_response, :next_cursor
|
10
|
+
|
11
|
+
def initialize(klass)
|
12
|
+
@klass = klass
|
13
|
+
|
14
|
+
@is_all = false
|
15
|
+
@limit_value = nil
|
16
|
+
@raw_response = nil
|
17
|
+
@select_values = []
|
18
|
+
@id_values = []
|
19
|
+
@where_values = []
|
20
|
+
@next_cursor = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def scoping
|
26
|
+
previous, klass.current_scope = klass.current_scope, self
|
27
|
+
yield
|
28
|
+
ensure
|
29
|
+
klass.current_scope = previous
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def method_missing(method_name, *args, &block)
|
34
|
+
if klass.respond_to?(method_name)
|
35
|
+
scoping { klass.send(method_name, *args, &block) }
|
36
|
+
elsif Array.method_defined?(method_name)
|
37
|
+
to_a.send(method_name, *args, &block)
|
38
|
+
else
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def select_records
|
44
|
+
results = []
|
45
|
+
records = {}
|
46
|
+
new_next_cursor = nil
|
47
|
+
|
48
|
+
if self.schema_type == :standard
|
49
|
+
klass.adapter.select(self) do |key, attributes|
|
50
|
+
records[key] = attributes
|
51
|
+
end
|
52
|
+
else
|
53
|
+
if @is_all
|
54
|
+
pre = klass.adapter.pre_select(self, @limit_value, @next_cursor)
|
55
|
+
new_next_cursor = pre[:new_next_cursor]
|
56
|
+
return {results: [], next_cursor: new_next_cursor} if pre[:ids].empty? # fix last query all if ids is empty
|
57
|
+
self.id_values = pre[:ids]
|
58
|
+
end
|
59
|
+
|
60
|
+
resp = klass.adapter.select(self)
|
61
|
+
primary_key_column = klass.adapter.primary_key_column
|
62
|
+
resp.each do |cql_row|
|
63
|
+
key = cql_row[primary_key_column]
|
64
|
+
records[key] ||= {}
|
65
|
+
records[key][cql_row.values[1]] = cql_row.values[2]
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
# limit
|
70
|
+
records = records.first(@limit_value) if @limit_value.present?
|
71
|
+
records.each do |key, attributes|
|
72
|
+
if self.raw_response || self.schema_type == :dynamic_attributes
|
73
|
+
results << {key => attributes.values.compact.empty? ? attributes.keys : attributes}
|
74
|
+
else
|
75
|
+
results << klass.instantiate(key, attributes)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
results = results.reduce({}, :merge) if self.schema_type == :dynamic_attributes
|
79
|
+
if @is_all
|
80
|
+
return {results: results, next_cursor: new_next_cursor}
|
81
|
+
end
|
82
|
+
return results
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,54 @@
|
|
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 find_all_in_batches(next_cursor = nil)
|
19
|
+
obj = self.clone
|
20
|
+
obj.is_all = true
|
21
|
+
obj.next_cursor = next_cursor
|
22
|
+
obj.to_a
|
23
|
+
end
|
24
|
+
|
25
|
+
def first
|
26
|
+
return limit(1).find_all_in_batches[:results].first if self.schema_type == :dynamic_attributes || self.schema_type == :schemaless
|
27
|
+
limit(1).to_a.first
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def find_one(id)
|
33
|
+
if id.blank?
|
34
|
+
raise CassandraObject::RecordNotFound, "Couldn't find #{self.name} with key #{id.inspect}"
|
35
|
+
elsif self.schema_type == :dynamic_attributes
|
36
|
+
record = where_ids(id).to_a
|
37
|
+
raise CassandraObject::RecordNotFound if record.empty?
|
38
|
+
record
|
39
|
+
elsif record = where_ids(id)[0]
|
40
|
+
record
|
41
|
+
else
|
42
|
+
raise CassandraObject::RecordNotFound
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_some(ids)
|
47
|
+
ids = ids.flatten
|
48
|
+
return [] if ids.empty?
|
49
|
+
ids = ids.compact.map(&:to_s).uniq
|
50
|
+
where_ids(ids).to_a
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module CassandraObject
|
2
|
+
class Scope
|
3
|
+
module QueryMethods
|
4
|
+
|
5
|
+
def cql_response
|
6
|
+
cloned = self.clone
|
7
|
+
cloned.raw_response = true
|
8
|
+
cloned
|
9
|
+
end
|
10
|
+
|
11
|
+
def columns
|
12
|
+
cloned = self.clone
|
13
|
+
cloned.select_values = [:column1]
|
14
|
+
cloned.cql_response
|
15
|
+
end
|
16
|
+
|
17
|
+
def select!(*values)
|
18
|
+
self.select_values += values.flatten
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def select(*values, &block)
|
23
|
+
if block_given?
|
24
|
+
to_a.select(&block)
|
25
|
+
else
|
26
|
+
clone.select!(*values)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def where!(*values)
|
31
|
+
if values.flatten.size == 1
|
32
|
+
self.where_values += values.flatten
|
33
|
+
self.where_values << ''
|
34
|
+
else
|
35
|
+
self.where_values += values.flatten
|
36
|
+
end
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def where(*values)
|
41
|
+
clone.where! values
|
42
|
+
end
|
43
|
+
|
44
|
+
def where_ids!(*ids)
|
45
|
+
self.id_values += ids.flatten
|
46
|
+
self.id_values.compact if self.id_values.present?
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def where_ids(*ids)
|
51
|
+
clone.where_ids! ids
|
52
|
+
end
|
53
|
+
|
54
|
+
def limit!(value)
|
55
|
+
self.limit_value = value
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def limit(value)
|
60
|
+
clone.limit! value
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_a
|
64
|
+
select_records
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|