dbee-active_record 2.0.3 → 2.1.2
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/.rubocop.yml +13 -12
- data/.ruby-version +1 -1
- data/.travis.yml +3 -10
- data/CHANGELOG.md +24 -1
- data/README.md +1 -1
- data/dbee-active_record.gemspec +17 -8
- data/exe/.gitkeep +0 -0
- data/lib/dbee/providers/active_record_provider/expression_builder.rb +55 -24
- data/lib/dbee/providers/active_record_provider/maker.rb +37 -0
- data/lib/dbee/providers/active_record_provider/{expression_builder/constraint_maker.rb → makers/constraint.rb} +12 -12
- data/lib/dbee/providers/active_record_provider/{expression_builder/order_maker.rb → makers/order.rb} +9 -9
- data/lib/dbee/providers/active_record_provider/makers/select.rb +81 -0
- data/lib/dbee/providers/active_record_provider/makers/where.rb +111 -0
- data/lib/dbee/providers/active_record_provider/version.rb +1 -1
- data/spec/db_helper.rb +134 -14
- data/spec/dbee/providers/active_record_provider/expression_builder_spec.rb +117 -0
- data/spec/dbee/providers/active_record_provider/makers/where_spec.rb +260 -0
- data/spec/dbee/providers/active_record_provider_spec.rb +101 -3
- data/spec/fixtures/active_record_snapshots/one_table_empty_query.yaml +10 -0
- data/spec/fixtures/active_record_snapshots/one_table_query_with_filters.yaml +24 -16
- data/spec/fixtures/active_record_snapshots/two_table_query_with_aggregation.yaml +71 -0
- data/spec/fixtures/active_record_snapshots/two_table_query_with_pivoting.yaml +88 -0
- data/spec/fixtures/models.yaml +20 -0
- data/spec/spec_helper.rb +5 -1
- metadata +51 -19
- data/lib/dbee/providers/active_record_provider/expression_builder/select_maker.rb +0 -33
- data/lib/dbee/providers/active_record_provider/expression_builder/where_maker.rb +0 -56
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
module Dbee
|
11
|
+
module Providers
|
12
|
+
class ActiveRecordProvider
|
13
|
+
module Makers # :nodoc: all
|
14
|
+
# Derives Arel#where predicates.
|
15
|
+
class Where
|
16
|
+
include Singleton
|
17
|
+
|
18
|
+
def make(filter, arel_column)
|
19
|
+
# If the filter has a value of nil, then simply return an IS (NOT) NULL predicate
|
20
|
+
return make_is_null_predicate(arel_column, filter.class) if filter.value.nil?
|
21
|
+
|
22
|
+
values = Array(filter.value).flatten
|
23
|
+
|
24
|
+
# This logic helps ensure that if a null exists that it translates to an IS NULL
|
25
|
+
# predicate and does not get put into an in or not_in clause.
|
26
|
+
predicates =
|
27
|
+
if values.include?(nil)
|
28
|
+
[make_is_null_predicate(arel_column, filter.class)]
|
29
|
+
else
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
|
33
|
+
predicates += make_predicates(filter, arel_column, values - [nil])
|
34
|
+
|
35
|
+
# Chain all predicates together
|
36
|
+
predicates.inject(predicates.shift) do |memo, predicate|
|
37
|
+
memo.or(predicate)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
FILTER_EVALUATORS = {
|
44
|
+
Query::Filters::Contains => ->(node, val) { node.matches("%#{val}%") },
|
45
|
+
Query::Filters::Equals => ->(node, val) { node.eq(val) },
|
46
|
+
Query::Filters::GreaterThan => ->(node, val) { node.gt(val) },
|
47
|
+
Query::Filters::GreaterThanOrEqualTo => ->(node, val) { node.gteq(val) },
|
48
|
+
Query::Filters::LessThan => ->(node, val) { node.lt(val) },
|
49
|
+
Query::Filters::LessThanOrEqualTo => ->(node, val) { node.lteq(val) },
|
50
|
+
Query::Filters::NotContain => ->(node, val) { node.does_not_match("%#{val}%") },
|
51
|
+
Query::Filters::NotEquals => ->(node, val) { node.not_eq(val) },
|
52
|
+
Query::Filters::NotStartWith => ->(node, val) { node.does_not_match("#{val}%") },
|
53
|
+
Query::Filters::StartsWith => ->(node, val) { node.matches("#{val}%") }
|
54
|
+
}.freeze
|
55
|
+
|
56
|
+
NULL_PREDICATE_MAP = {
|
57
|
+
Query::Filters::Contains => Query::Filters::Equals,
|
58
|
+
Query::Filters::Equals => Query::Filters::Equals,
|
59
|
+
Query::Filters::GreaterThan => Query::Filters::Equals,
|
60
|
+
Query::Filters::GreaterThanOrEqualTo => Query::Filters::Equals,
|
61
|
+
Query::Filters::LessThan => Query::Filters::Equals,
|
62
|
+
Query::Filters::LessThanOrEqualTo => Query::Filters::Equals,
|
63
|
+
Query::Filters::NotContain => Query::Filters::NotEquals,
|
64
|
+
Query::Filters::NotEquals => Query::Filters::NotEquals,
|
65
|
+
Query::Filters::NotStartWith => Query::Filters::NotEquals,
|
66
|
+
Query::Filters::StartsWith => Query::Filters::Equals
|
67
|
+
}.freeze
|
68
|
+
|
69
|
+
private_constant :FILTER_EVALUATORS, :NULL_PREDICATE_MAP
|
70
|
+
|
71
|
+
def make_predicates(filter, arel_column, values)
|
72
|
+
if use_in?(filter, values)
|
73
|
+
[arel_column.in(values)]
|
74
|
+
elsif use_not_in?(filter, values)
|
75
|
+
[arel_column.not_in(values)]
|
76
|
+
else
|
77
|
+
make_or_predicates(filter, arel_column, values)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def use_in?(filter, values)
|
82
|
+
filter.is_a?(Query::Filters::Equals) && values.length > 1
|
83
|
+
end
|
84
|
+
|
85
|
+
def use_not_in?(filter, values)
|
86
|
+
filter.is_a?(Query::Filters::NotEquals) && values.length > 1
|
87
|
+
end
|
88
|
+
|
89
|
+
def make_or_predicates(filter, arel_column, values)
|
90
|
+
values.map do |value|
|
91
|
+
make_predicate(arel_column, filter.class, value)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def make_predicate(arel_column, filter_class, value)
|
96
|
+
method = FILTER_EVALUATORS[filter_class]
|
97
|
+
|
98
|
+
raise ArgumentError, "cannot compile filter: #{filter}" unless method
|
99
|
+
|
100
|
+
method.call(arel_column, value)
|
101
|
+
end
|
102
|
+
|
103
|
+
def make_is_null_predicate(arel_column, requested_filter_class)
|
104
|
+
actual_filter_class = NULL_PREDICATE_MAP[requested_filter_class]
|
105
|
+
make_predicate(arel_column, actual_filter_class, nil)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/spec/db_helper.rb
CHANGED
@@ -10,6 +10,27 @@
|
|
10
10
|
# Enable logging using something like:
|
11
11
|
# ActiveRecord::Base.logger = Logger.new(STDERR)
|
12
12
|
|
13
|
+
class Field < ActiveRecord::Base
|
14
|
+
has_many :patient_field_values
|
15
|
+
end
|
16
|
+
|
17
|
+
class Patient < ActiveRecord::Base
|
18
|
+
has_many :patient_field_values
|
19
|
+
has_many :patient_payments
|
20
|
+
|
21
|
+
accepts_nested_attributes_for :patient_field_values
|
22
|
+
accepts_nested_attributes_for :patient_payments
|
23
|
+
end
|
24
|
+
|
25
|
+
class PatientFieldValue < ActiveRecord::Base
|
26
|
+
belongs_to :patient
|
27
|
+
belongs_to :field
|
28
|
+
end
|
29
|
+
|
30
|
+
class PatientPayment < ActiveRecord::Base
|
31
|
+
belongs_to :patient
|
32
|
+
end
|
33
|
+
|
13
34
|
def connect_to_db(name)
|
14
35
|
config = yaml_file_read('spec', 'config', 'database.yaml')[name.to_s]
|
15
36
|
ActiveRecord::Base.establish_connection(config)
|
@@ -17,39 +38,40 @@ end
|
|
17
38
|
|
18
39
|
def load_schema
|
19
40
|
ActiveRecord::Schema.define do
|
41
|
+
# Movie Theater Schema
|
20
42
|
create_table :theaters do |t|
|
21
|
-
t.column :name,
|
43
|
+
t.column :name, :string
|
22
44
|
t.column :partition, :string
|
23
|
-
t.column :active,
|
45
|
+
t.column :active, :boolean
|
24
46
|
t.column :inspected, :boolean
|
25
47
|
t.timestamps
|
26
48
|
end
|
27
49
|
|
28
50
|
create_table :members do |t|
|
29
|
-
t.column :tid,
|
51
|
+
t.column :tid, :integer
|
30
52
|
t.column :account_number, :string
|
31
|
-
t.column :partition,
|
53
|
+
t.column :partition, :string
|
32
54
|
t.timestamps
|
33
55
|
end
|
34
56
|
|
35
57
|
create_table :demographics do |t|
|
36
58
|
t.column :member_id, :integer
|
37
|
-
t.column :name,
|
59
|
+
t.column :name, :string
|
38
60
|
t.timestamps
|
39
61
|
end
|
40
62
|
|
41
63
|
create_table :phone_numbers do |t|
|
42
64
|
t.column :demographic_id, :integer
|
43
|
-
t.column :phone_type,
|
44
|
-
t.column :phone_number,
|
65
|
+
t.column :phone_type, :string
|
66
|
+
t.column :phone_number, :string
|
45
67
|
t.timestamps
|
46
68
|
end
|
47
69
|
|
48
70
|
create_table :movies do |t|
|
49
71
|
t.column :member_id, :integer
|
50
|
-
t.column :name,
|
51
|
-
t.column :genre,
|
52
|
-
t.column :favorite,
|
72
|
+
t.column :name, :string
|
73
|
+
t.column :genre, :string
|
74
|
+
t.column :favorite, :boolean, default: false, null: false
|
53
75
|
t.timestamps
|
54
76
|
end
|
55
77
|
|
@@ -60,10 +82,10 @@ def load_schema
|
|
60
82
|
|
61
83
|
create_table :animals do |t|
|
62
84
|
t.column :owner_id, :integer
|
63
|
-
t.column :toy_id,
|
64
|
-
t.column :type,
|
65
|
-
t.column :name,
|
66
|
-
t.column :deleted,
|
85
|
+
t.column :toy_id, :integer
|
86
|
+
t.column :type, :string
|
87
|
+
t.column :name, :string
|
88
|
+
t.column :deleted, :boolean
|
67
89
|
t.timestamps
|
68
90
|
end
|
69
91
|
|
@@ -76,5 +98,103 @@ def load_schema
|
|
76
98
|
t.column :laser, :boolean
|
77
99
|
t.timestamps
|
78
100
|
end
|
101
|
+
|
102
|
+
# Patient Schema
|
103
|
+
create_table :fields do |t|
|
104
|
+
t.column :section, :string
|
105
|
+
t.column :key, :string
|
106
|
+
t.timestamps
|
107
|
+
end
|
108
|
+
|
109
|
+
add_index :fields, %i[section key], unique: true
|
110
|
+
|
111
|
+
create_table :patients do |t|
|
112
|
+
t.column :first, :string
|
113
|
+
t.column :middle, :string
|
114
|
+
t.column :last, :string
|
115
|
+
t.timestamps
|
116
|
+
end
|
117
|
+
|
118
|
+
create_table :patient_field_values do |t|
|
119
|
+
t.column :patient_id, :integer, foreign_key: true
|
120
|
+
t.column :field_id, :integer, foreign_key: true
|
121
|
+
t.column :value, :string
|
122
|
+
t.timestamps
|
123
|
+
end
|
124
|
+
|
125
|
+
add_index :patient_field_values, %i[patient_id field_id], unique: true
|
126
|
+
|
127
|
+
create_table :patient_payments do |t|
|
128
|
+
t.column :patient_id, :integer, foreign_key: true
|
129
|
+
t.column :amount, :decimal
|
130
|
+
t.timestamps
|
131
|
+
end
|
79
132
|
end
|
80
133
|
end
|
134
|
+
|
135
|
+
def load_data
|
136
|
+
demo_dob_field = Field.create!(section: 'demographics', key: 'dob')
|
137
|
+
demo_drivers_license_field = Field.create!(section: 'demographics', key: 'drivers_license')
|
138
|
+
demo_notes_field = Field.create!(section: 'demographics', key: 'notes')
|
139
|
+
|
140
|
+
contact_phone_number_field = Field.create!(section: 'contact', key: 'phone_number')
|
141
|
+
contact_notes_field = Field.create!(section: 'contact', key: 'notes')
|
142
|
+
|
143
|
+
Patient.create!(
|
144
|
+
first: 'Bozo',
|
145
|
+
middle: 'The',
|
146
|
+
last: 'Clown',
|
147
|
+
patient_field_values_attributes: [
|
148
|
+
{
|
149
|
+
field: demo_dob_field,
|
150
|
+
value: '1904-04-04'
|
151
|
+
},
|
152
|
+
{
|
153
|
+
field: demo_notes_field,
|
154
|
+
value: 'The patient is funny!'
|
155
|
+
},
|
156
|
+
{
|
157
|
+
field: demo_drivers_license_field,
|
158
|
+
value: '82-54-hut-hut-hike!'
|
159
|
+
},
|
160
|
+
{
|
161
|
+
field: contact_phone_number_field,
|
162
|
+
value: '555-555-5555'
|
163
|
+
},
|
164
|
+
{
|
165
|
+
field: contact_notes_field,
|
166
|
+
value: 'Do not call this patient at night!'
|
167
|
+
}
|
168
|
+
],
|
169
|
+
patient_payments_attributes: [
|
170
|
+
{ amount: 5 },
|
171
|
+
{ amount: 10 },
|
172
|
+
{ amount: 15 }
|
173
|
+
]
|
174
|
+
)
|
175
|
+
|
176
|
+
Patient.create!(
|
177
|
+
first: 'Frank',
|
178
|
+
last: 'Rizzo',
|
179
|
+
patient_payments_attributes: [
|
180
|
+
{ amount: 50 },
|
181
|
+
{ amount: 150 }
|
182
|
+
]
|
183
|
+
)
|
184
|
+
|
185
|
+
Patient.create!(
|
186
|
+
first: 'Bugs',
|
187
|
+
middle: 'The',
|
188
|
+
last: 'Bunny',
|
189
|
+
patient_field_values_attributes: [
|
190
|
+
{
|
191
|
+
field: demo_dob_field,
|
192
|
+
value: '2040-01-01'
|
193
|
+
},
|
194
|
+
{
|
195
|
+
field: contact_notes_field,
|
196
|
+
value: 'Call anytime!!'
|
197
|
+
}
|
198
|
+
]
|
199
|
+
)
|
200
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
require 'db_helper'
|
12
|
+
|
13
|
+
describe Dbee::Providers::ActiveRecordProvider::ExpressionBuilder do
|
14
|
+
let(:model) { Dbee::Model.make(models['Patients']) }
|
15
|
+
let(:alias_maker) { Dbee::Providers::ActiveRecordProvider::SafeAliasMaker.new }
|
16
|
+
|
17
|
+
let(:id_and_average_query) do
|
18
|
+
Dbee::Query.make(
|
19
|
+
fields: [
|
20
|
+
{
|
21
|
+
key_path: :id,
|
22
|
+
display: 'ID #'
|
23
|
+
},
|
24
|
+
{
|
25
|
+
key_path: 'patient_payments.amount',
|
26
|
+
display: 'Ave Payment',
|
27
|
+
aggregator: :ave
|
28
|
+
}
|
29
|
+
],
|
30
|
+
sorters: [
|
31
|
+
{
|
32
|
+
key_path: :id
|
33
|
+
}
|
34
|
+
],
|
35
|
+
filters: [
|
36
|
+
{
|
37
|
+
key_path: :id,
|
38
|
+
value: 123
|
39
|
+
}
|
40
|
+
]
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:first_and_count_query) do
|
45
|
+
Dbee::Query.make(
|
46
|
+
fields: [
|
47
|
+
{
|
48
|
+
key_path: :first,
|
49
|
+
display: 'First Name'
|
50
|
+
},
|
51
|
+
{
|
52
|
+
key_path: 'patient_payments.amount',
|
53
|
+
display: 'Number of Payments',
|
54
|
+
aggregator: :count
|
55
|
+
}
|
56
|
+
]
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
subject { described_class.new(model, alias_maker, alias_maker) }
|
61
|
+
|
62
|
+
before(:all) do
|
63
|
+
connect_to_db(:sqlite)
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#clear' do
|
67
|
+
it 'provides fluent interface (returns self)' do
|
68
|
+
expect(subject.clear).to eq(subject)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'resets selecting, grouping, sorting, and filtering' do
|
72
|
+
subject.add(id_and_average_query)
|
73
|
+
|
74
|
+
sql = subject.to_sql
|
75
|
+
|
76
|
+
expect(sql).not_to include('*')
|
77
|
+
expect(sql).to include('GROUP')
|
78
|
+
expect(sql).to include('WHERE')
|
79
|
+
expect(sql).to include('ORDER')
|
80
|
+
|
81
|
+
sql = subject.clear.to_sql
|
82
|
+
|
83
|
+
expect(sql).to include('*')
|
84
|
+
expect(sql).not_to include('GROUP')
|
85
|
+
expect(sql).not_to include('WHERE')
|
86
|
+
expect(sql).not_to include('ORDER')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#to_sql' do
|
91
|
+
specify 'when called with no fields, then called with fields removes star select' do
|
92
|
+
expect(subject.to_sql).to include('*')
|
93
|
+
|
94
|
+
subject.add(id_and_average_query)
|
95
|
+
|
96
|
+
expect(subject.to_sql).not_to include('*')
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'with aggregation' do
|
100
|
+
it 'generates the same sql when called multiple times' do
|
101
|
+
subject.add(id_and_average_query)
|
102
|
+
|
103
|
+
first_sql = subject.to_sql
|
104
|
+
second_sql = subject.to_sql
|
105
|
+
|
106
|
+
expect(first_sql).to eq(second_sql)
|
107
|
+
|
108
|
+
subject.add(first_and_count_query)
|
109
|
+
|
110
|
+
first_sql = subject.to_sql
|
111
|
+
second_sql = subject.to_sql
|
112
|
+
|
113
|
+
expect(first_sql).to eq(second_sql)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,260 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2020-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
require 'db_helper'
|
12
|
+
|
13
|
+
# rubocop:disable Layout/LineLength
|
14
|
+
# Disable the line length cop beause there are some lengthy 'expected' SQL strings in spec which
|
15
|
+
# cannot be shortened.
|
16
|
+
describe Dbee::Providers::ActiveRecordProvider::Makers::Where do
|
17
|
+
before(:all) { connect_to_db(:sqlite) }
|
18
|
+
|
19
|
+
let(:subject) { described_class.instance }
|
20
|
+
let(:column) { Arel::Table.new(:test)[:foo] }
|
21
|
+
|
22
|
+
describe 'equals' do
|
23
|
+
specify 'a string value' do
|
24
|
+
filter = Dbee::Query::Filters::Equals.new(key_path: :foo, value: 'bar')
|
25
|
+
expect(subject.make(filter, column).to_sql).to eq %q("test"."foo" = 'bar')
|
26
|
+
end
|
27
|
+
|
28
|
+
specify 'a null value' do
|
29
|
+
filter = Dbee::Query::Filters::Equals.new(key_path: :foo, value: nil)
|
30
|
+
expect(subject.make(filter, column).to_sql).to eq '"test"."foo" IS NULL'
|
31
|
+
end
|
32
|
+
|
33
|
+
specify 'a set with a null value' do
|
34
|
+
filter = Dbee::Query::Filters::Equals.new(key_path: :foo, value: ['a', nil, 'c'])
|
35
|
+
expected = %q[("test"."foo" IS NULL OR "test"."foo" IN ('a', 'c'))]
|
36
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
37
|
+
end
|
38
|
+
|
39
|
+
specify 'a set without a null value' do
|
40
|
+
filter = Dbee::Query::Filters::Equals.new(key_path: :foo, value: %w[a b c])
|
41
|
+
expect(subject.make(filter, column).to_sql).to eq %q["test"."foo" IN ('a', 'b', 'c')]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'not equals' do
|
46
|
+
specify 'a string value' do
|
47
|
+
filter = Dbee::Query::Filters::NotEquals.new(key_path: :foo, value: 'bar')
|
48
|
+
expect(subject.make(filter, column).to_sql).to eq %q("test"."foo" != 'bar')
|
49
|
+
end
|
50
|
+
|
51
|
+
specify 'a null value' do
|
52
|
+
filter = Dbee::Query::Filters::NotEquals.new(key_path: :foo, value: nil)
|
53
|
+
expect(subject.make(filter, column).to_sql).to eq '"test"."foo" IS NOT NULL'
|
54
|
+
end
|
55
|
+
|
56
|
+
specify 'a set with a null value' do
|
57
|
+
filter = Dbee::Query::Filters::NotEquals.new(key_path: :foo, value: ['a', nil, 'c'])
|
58
|
+
expected = %q[("test"."foo" IS NOT NULL OR "test"."foo" NOT IN ('a', 'c'))]
|
59
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
60
|
+
end
|
61
|
+
|
62
|
+
specify 'a set without a null value' do
|
63
|
+
filter = Dbee::Query::Filters::NotEquals.new(key_path: :foo, value: %w[a b c])
|
64
|
+
expect(subject.make(filter, column).to_sql).to eq %q["test"."foo" NOT IN ('a', 'b', 'c')]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'contains' do
|
69
|
+
specify 'a string value' do
|
70
|
+
filter = Dbee::Query::Filters::Contains.new(key_path: :foo, value: 'bar')
|
71
|
+
expect(subject.make(filter, column).to_sql).to eq %q("test"."foo" LIKE '%bar%')
|
72
|
+
end
|
73
|
+
|
74
|
+
specify 'a null value' do
|
75
|
+
filter = Dbee::Query::Filters::Contains.new(key_path: :foo, value: nil)
|
76
|
+
expect(subject.make(filter, column).to_sql).to eq '"test"."foo" IS NULL'
|
77
|
+
end
|
78
|
+
|
79
|
+
specify 'a set with a null value' do
|
80
|
+
filter = Dbee::Query::Filters::Contains.new(key_path: :foo, value: ['a', nil, 'c'])
|
81
|
+
expected = %q[(("test"."foo" IS NULL OR "test"."foo" LIKE '%a%') OR "test"."foo" LIKE '%c%')]
|
82
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
83
|
+
end
|
84
|
+
|
85
|
+
specify 'a set without a null value' do
|
86
|
+
filter = Dbee::Query::Filters::Contains.new(key_path: :foo, value: %w[a b c])
|
87
|
+
expected = %q[(("test"."foo" LIKE '%a%' OR "test"."foo" LIKE '%b%') OR "test"."foo" LIKE '%c%')]
|
88
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe 'not contains' do
|
93
|
+
specify 'a string value' do
|
94
|
+
filter = Dbee::Query::Filters::NotContain.new(key_path: :foo, value: 'bar')
|
95
|
+
expect(subject.make(filter, column).to_sql).to eq %q("test"."foo" NOT LIKE '%bar%')
|
96
|
+
end
|
97
|
+
|
98
|
+
specify 'a null value' do
|
99
|
+
filter = Dbee::Query::Filters::NotContain.new(key_path: :foo, value: nil)
|
100
|
+
expect(subject.make(filter, column).to_sql).to eq '"test"."foo" IS NOT NULL'
|
101
|
+
end
|
102
|
+
|
103
|
+
specify 'a set with a null value' do
|
104
|
+
filter = Dbee::Query::Filters::NotContain.new(key_path: :foo, value: ['a', nil, 'c'])
|
105
|
+
expected = %q[(("test"."foo" IS NOT NULL OR "test"."foo" NOT LIKE '%a%') OR "test"."foo" NOT LIKE '%c%')]
|
106
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
107
|
+
end
|
108
|
+
|
109
|
+
specify 'a set without a null value' do
|
110
|
+
filter = Dbee::Query::Filters::NotContain.new(key_path: :foo, value: %w[a b c])
|
111
|
+
expected = %q[(("test"."foo" NOT LIKE '%a%' OR "test"."foo" NOT LIKE '%b%') OR "test"."foo" NOT LIKE '%c%')]
|
112
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'starts with' do
|
117
|
+
specify 'a string value' do
|
118
|
+
filter = Dbee::Query::Filters::StartsWith.new(key_path: :foo, value: 'bar')
|
119
|
+
expect(subject.make(filter, column).to_sql).to eq %q("test"."foo" LIKE 'bar%')
|
120
|
+
end
|
121
|
+
|
122
|
+
specify 'a null value' do
|
123
|
+
filter = Dbee::Query::Filters::StartsWith.new(key_path: :foo, value: nil)
|
124
|
+
expect(subject.make(filter, column).to_sql).to eq '"test"."foo" IS NULL'
|
125
|
+
end
|
126
|
+
|
127
|
+
specify 'a set with a null value' do
|
128
|
+
filter = Dbee::Query::Filters::StartsWith.new(key_path: :foo, value: ['a', nil, 'c'])
|
129
|
+
expected = %q[(("test"."foo" IS NULL OR "test"."foo" LIKE 'a%') OR "test"."foo" LIKE 'c%')]
|
130
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
131
|
+
end
|
132
|
+
|
133
|
+
specify 'a set without a null value' do
|
134
|
+
filter = Dbee::Query::Filters::StartsWith.new(key_path: :foo, value: %w[a b c])
|
135
|
+
expected = %q[(("test"."foo" LIKE 'a%' OR "test"."foo" LIKE 'b%') OR "test"."foo" LIKE 'c%')]
|
136
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe 'not start with' do
|
141
|
+
specify 'a string value' do
|
142
|
+
filter = Dbee::Query::Filters::NotStartWith.new(key_path: :foo, value: 'bar')
|
143
|
+
expect(subject.make(filter, column).to_sql).to eq %q("test"."foo" NOT LIKE 'bar%')
|
144
|
+
end
|
145
|
+
|
146
|
+
specify 'a null value' do
|
147
|
+
filter = Dbee::Query::Filters::NotStartWith.new(key_path: :foo, value: nil)
|
148
|
+
expect(subject.make(filter, column).to_sql).to eq '"test"."foo" IS NOT NULL'
|
149
|
+
end
|
150
|
+
|
151
|
+
specify 'a set with a null value' do
|
152
|
+
filter = Dbee::Query::Filters::NotStartWith.new(key_path: :foo, value: ['a', nil, 'c'])
|
153
|
+
expected = %q[(("test"."foo" IS NOT NULL OR "test"."foo" NOT LIKE 'a%') OR "test"."foo" NOT LIKE 'c%')]
|
154
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
155
|
+
end
|
156
|
+
|
157
|
+
specify 'a set without a null value' do
|
158
|
+
filter = Dbee::Query::Filters::NotStartWith.new(key_path: :foo, value: %w[a b c])
|
159
|
+
expected = %q[(("test"."foo" NOT LIKE 'a%' OR "test"."foo" NOT LIKE 'b%') OR "test"."foo" NOT LIKE 'c%')]
|
160
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe 'greater than' do
|
165
|
+
specify 'a string value' do
|
166
|
+
filter = Dbee::Query::Filters::GreaterThan.new(key_path: :foo, value: 'bar')
|
167
|
+
expect(subject.make(filter, column).to_sql).to eq %q("test"."foo" > 'bar')
|
168
|
+
end
|
169
|
+
|
170
|
+
specify 'a null value' do
|
171
|
+
filter = Dbee::Query::Filters::GreaterThan.new(key_path: :foo, value: nil)
|
172
|
+
expect(subject.make(filter, column).to_sql).to eq '"test"."foo" IS NULL'
|
173
|
+
end
|
174
|
+
|
175
|
+
specify 'a set with a null value' do
|
176
|
+
filter = Dbee::Query::Filters::GreaterThan.new(key_path: :foo, value: ['a', nil, 'c'])
|
177
|
+
expected = %q[(("test"."foo" IS NULL OR "test"."foo" > 'a') OR "test"."foo" > 'c')]
|
178
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
179
|
+
end
|
180
|
+
|
181
|
+
specify 'a set without a null value' do
|
182
|
+
filter = Dbee::Query::Filters::GreaterThan.new(key_path: :foo, value: %w[a b c])
|
183
|
+
expected = %q[(("test"."foo" > 'a' OR "test"."foo" > 'b') OR "test"."foo" > 'c')]
|
184
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe 'greater than or equal to' do
|
189
|
+
specify 'a string value' do
|
190
|
+
filter = Dbee::Query::Filters::GreaterThanOrEqualTo.new(key_path: :foo, value: 'bar')
|
191
|
+
expect(subject.make(filter, column).to_sql).to eq %q("test"."foo" >= 'bar')
|
192
|
+
end
|
193
|
+
|
194
|
+
specify 'a null value' do
|
195
|
+
filter = Dbee::Query::Filters::GreaterThanOrEqualTo.new(key_path: :foo, value: nil)
|
196
|
+
expect(subject.make(filter, column).to_sql).to eq '"test"."foo" IS NULL'
|
197
|
+
end
|
198
|
+
|
199
|
+
specify 'a set with a null value' do
|
200
|
+
filter = Dbee::Query::Filters::GreaterThanOrEqualTo.new(key_path: :foo, value: ['a', nil, 'c'])
|
201
|
+
expected = %q[(("test"."foo" IS NULL OR "test"."foo" >= 'a') OR "test"."foo" >= 'c')]
|
202
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
203
|
+
end
|
204
|
+
|
205
|
+
specify 'a set without a null value' do
|
206
|
+
filter = Dbee::Query::Filters::GreaterThanOrEqualTo.new(key_path: :foo, value: %w[a b c])
|
207
|
+
expected = %q[(("test"."foo" >= 'a' OR "test"."foo" >= 'b') OR "test"."foo" >= 'c')]
|
208
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe 'less than' do
|
213
|
+
specify 'a string value' do
|
214
|
+
filter = Dbee::Query::Filters::LessThan.new(key_path: :foo, value: 'bar')
|
215
|
+
expect(subject.make(filter, column).to_sql).to eq %q("test"."foo" < 'bar')
|
216
|
+
end
|
217
|
+
|
218
|
+
specify 'a null value' do
|
219
|
+
filter = Dbee::Query::Filters::LessThan.new(key_path: :foo, value: nil)
|
220
|
+
expect(subject.make(filter, column).to_sql).to eq '"test"."foo" IS NULL'
|
221
|
+
end
|
222
|
+
|
223
|
+
specify 'a set with a null value' do
|
224
|
+
filter = Dbee::Query::Filters::LessThan.new(key_path: :foo, value: ['a', nil, 'c'])
|
225
|
+
expected = %q[(("test"."foo" IS NULL OR "test"."foo" < 'a') OR "test"."foo" < 'c')]
|
226
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
227
|
+
end
|
228
|
+
|
229
|
+
specify 'a set without a null value' do
|
230
|
+
filter = Dbee::Query::Filters::LessThan.new(key_path: :foo, value: %w[a b c])
|
231
|
+
expected = %q[(("test"."foo" < 'a' OR "test"."foo" < 'b') OR "test"."foo" < 'c')]
|
232
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
describe 'less than or equal to' do
|
237
|
+
specify 'a string value' do
|
238
|
+
filter = Dbee::Query::Filters::LessThanOrEqualTo.new(key_path: :foo, value: 'bar')
|
239
|
+
expect(subject.make(filter, column).to_sql).to eq %q("test"."foo" <= 'bar')
|
240
|
+
end
|
241
|
+
|
242
|
+
specify 'a null value' do
|
243
|
+
filter = Dbee::Query::Filters::LessThanOrEqualTo.new(key_path: :foo, value: nil)
|
244
|
+
expect(subject.make(filter, column).to_sql).to eq '"test"."foo" IS NULL'
|
245
|
+
end
|
246
|
+
|
247
|
+
specify 'a set with a null value' do
|
248
|
+
filter = Dbee::Query::Filters::LessThanOrEqualTo.new(key_path: :foo, value: ['a', nil, 'c'])
|
249
|
+
expected = %q[(("test"."foo" IS NULL OR "test"."foo" <= 'a') OR "test"."foo" <= 'c')]
|
250
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
251
|
+
end
|
252
|
+
|
253
|
+
specify 'a set without a null value' do
|
254
|
+
filter = Dbee::Query::Filters::LessThanOrEqualTo.new(key_path: :foo, value: %w[a b c])
|
255
|
+
expected = %q[(("test"."foo" <= 'a' OR "test"."foo" <= 'b') OR "test"."foo" <= 'c')]
|
256
|
+
expect(subject.make(filter, column).to_sql).to eq expected
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
# rubocop:enable Layout/LineLength
|