dbee-active_record 2.1.0.pre.alpha.1 → 2.3.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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +84 -0
- data/.rubocop.yml +4 -18
- data/.tool-versions +1 -0
- data/CHANGELOG.md +19 -1
- data/Guardfile +2 -1
- data/README.md +4 -4
- data/dbee-active_record.gemspec +11 -13
- data/lib/dbee/providers/active_record_provider/expression_builder.rb +81 -59
- data/lib/dbee/providers/active_record_provider/maker.rb +37 -0
- data/lib/dbee/providers/active_record_provider/{expression_builder → makers}/constraint.rb +1 -1
- data/lib/dbee/providers/active_record_provider/{expression_builder → makers}/order.rb +1 -1
- data/lib/dbee/providers/active_record_provider/{expression_builder → makers}/select.rb +13 -3
- data/lib/dbee/providers/active_record_provider/{expression_builder → makers}/where.rb +27 -7
- data/lib/dbee/providers/active_record_provider/version.rb +1 -1
- data/lib/dbee/providers/active_record_provider.rb +3 -3
- data/spec/db_helper.rb +7 -3
- data/spec/dbee/providers/active_record_provider/expression_builder_spec.rb +90 -0
- data/spec/dbee/providers/active_record_provider/makers/where_spec.rb +260 -0
- data/spec/dbee/providers/active_record_provider_spec.rb +15 -18
- data/spec/fixtures/active_record_snapshots/five_table_query.yaml +1 -0
- data/spec/fixtures/active_record_snapshots/multiple_same_table_query_with_static_constraints.yaml +1 -0
- data/spec/fixtures/active_record_snapshots/one_table_empty_query.yaml +11 -0
- data/spec/fixtures/active_record_snapshots/one_table_query.yaml +1 -0
- data/spec/fixtures/active_record_snapshots/one_table_query_with_ascending_sort.yaml +1 -0
- data/spec/fixtures/active_record_snapshots/one_table_query_with_descending_sort.yaml +1 -0
- data/spec/fixtures/active_record_snapshots/one_table_query_with_filters.yaml +1 -0
- data/spec/fixtures/active_record_snapshots/one_table_query_with_limit.yaml +1 -0
- data/spec/fixtures/active_record_snapshots/one_table_query_with_multiple_sorts.yaml +1 -0
- data/spec/fixtures/active_record_snapshots/partitioner_example_1_query.yaml +1 -0
- data/spec/fixtures/active_record_snapshots/partitioner_example_2_query.yaml +1 -0
- data/spec/fixtures/active_record_snapshots/reverse_polymorphic_query.yaml +1 -0
- data/spec/fixtures/active_record_snapshots/two_table_query.yaml +6 -0
- data/spec/fixtures/active_record_snapshots/two_table_query_with_aggregation.yaml +1 -0
- data/spec/fixtures/active_record_snapshots/two_table_query_with_pivoting.yaml +1 -0
- data/spec/fixtures/models.yaml +110 -102
- data/spec/spec_helper.rb +13 -2
- metadata +108 -27
- data/.travis.yml +0 -31
data/spec/db_helper.rb
CHANGED
@@ -106,6 +106,8 @@ def load_schema
|
|
106
106
|
t.timestamps
|
107
107
|
end
|
108
108
|
|
109
|
+
add_index :fields, %i[section key], unique: true
|
110
|
+
|
109
111
|
create_table :patients do |t|
|
110
112
|
t.column :first, :string
|
111
113
|
t.column :middle, :string
|
@@ -114,14 +116,16 @@ def load_schema
|
|
114
116
|
end
|
115
117
|
|
116
118
|
create_table :patient_field_values do |t|
|
117
|
-
t.column :patient_id, :integer
|
118
|
-
t.column :field_id, :integer
|
119
|
+
t.column :patient_id, :integer, foreign_key: true
|
120
|
+
t.column :field_id, :integer, foreign_key: true
|
119
121
|
t.column :value, :string
|
120
122
|
t.timestamps
|
121
123
|
end
|
122
124
|
|
125
|
+
add_index :patient_field_values, %i[patient_id field_id], unique: true
|
126
|
+
|
123
127
|
create_table :patient_payments do |t|
|
124
|
-
t.column :patient_id, :integer
|
128
|
+
t.column :patient_id, :integer, foreign_key: true
|
125
129
|
t.column :amount, :decimal
|
126
130
|
t.timestamps
|
127
131
|
end
|
@@ -0,0 +1,90 @@
|
|
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(:schema) { Dbee::Schema.new(models['Patients']) }
|
15
|
+
let(:alias_maker) { Dbee::Providers::ActiveRecordProvider::SafeAliasMaker.new }
|
16
|
+
|
17
|
+
let(:empty_query) { Dbee::Query.make(from: :patients) }
|
18
|
+
|
19
|
+
let(:id_and_average_query) do
|
20
|
+
Dbee::Query.make(
|
21
|
+
from: :patients,
|
22
|
+
fields: [
|
23
|
+
{
|
24
|
+
key_path: :id,
|
25
|
+
display: 'ID #'
|
26
|
+
},
|
27
|
+
{
|
28
|
+
key_path: 'patient_payments.amount',
|
29
|
+
display: 'Ave Payment',
|
30
|
+
aggregator: :ave
|
31
|
+
}
|
32
|
+
],
|
33
|
+
sorters: [
|
34
|
+
{
|
35
|
+
key_path: :id
|
36
|
+
}
|
37
|
+
],
|
38
|
+
filters: [
|
39
|
+
{
|
40
|
+
key_path: :id,
|
41
|
+
value: 123
|
42
|
+
}
|
43
|
+
]
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
let(:first_and_count_query) do
|
48
|
+
Dbee::Query.make(
|
49
|
+
from: :patients,
|
50
|
+
fields: [
|
51
|
+
{
|
52
|
+
key_path: :first,
|
53
|
+
display: 'First Name'
|
54
|
+
},
|
55
|
+
{
|
56
|
+
key_path: 'patient_payments.amount',
|
57
|
+
display: 'Number of Payments',
|
58
|
+
aggregator: :count
|
59
|
+
}
|
60
|
+
]
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
subject { described_class.new(schema, alias_maker, alias_maker) }
|
65
|
+
|
66
|
+
before(:all) do
|
67
|
+
connect_to_db(:sqlite)
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#to_sql' do
|
71
|
+
specify 'when called with no fields, then called with fields removes star select' do
|
72
|
+
expect(subject.to_sql(empty_query)).to include('*')
|
73
|
+
expect(subject.to_sql(id_and_average_query)).not_to include('*')
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'with aggregation' do
|
77
|
+
it 'generates the same sql when called multiple times' do
|
78
|
+
first_sql = subject.to_sql(id_and_average_query)
|
79
|
+
second_sql = subject.to_sql(id_and_average_query)
|
80
|
+
|
81
|
+
expect(first_sql).to eq(second_sql)
|
82
|
+
|
83
|
+
third_sql = subject.to_sql(first_and_count_query)
|
84
|
+
fourth_sql = subject.to_sql(first_and_count_query)
|
85
|
+
|
86
|
+
expect(third_sql).to eq(fourth_sql)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
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
|
@@ -11,22 +11,19 @@ require 'spec_helper'
|
|
11
11
|
require 'db_helper'
|
12
12
|
|
13
13
|
describe Dbee::Providers::ActiveRecordProvider do
|
14
|
-
let(:models) { yaml_fixture('models.yaml') }
|
15
|
-
|
16
14
|
describe '#sql' do
|
17
15
|
before(:all) do
|
18
16
|
connect_to_db(:sqlite)
|
19
17
|
end
|
20
18
|
|
21
19
|
it 'errors when joining tables with no constraints' do
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
{ name: :logins }
|
26
|
-
]
|
20
|
+
schema_hash = {
|
21
|
+
users: { relationships: { logins: nil } },
|
22
|
+
logins: nil
|
27
23
|
}
|
28
24
|
|
29
25
|
query_hash = {
|
26
|
+
from: :users,
|
30
27
|
fields: [
|
31
28
|
{ key_path: 'id' },
|
32
29
|
{ key_path: 'logins.id' }
|
@@ -34,11 +31,11 @@ describe Dbee::Providers::ActiveRecordProvider do
|
|
34
31
|
}
|
35
32
|
|
36
33
|
query = Dbee::Query.make(query_hash)
|
37
|
-
|
34
|
+
schema = Dbee::Schema.new(schema_hash)
|
38
35
|
|
39
36
|
error_class = Dbee::Providers::ActiveRecordProvider::ExpressionBuilder::MissingConstraintError
|
40
37
|
|
41
|
-
expect { described_class.new.sql(
|
38
|
+
expect { described_class.new.sql(schema, query) }.to raise_error(error_class)
|
42
39
|
end
|
43
40
|
end
|
44
41
|
|
@@ -57,12 +54,13 @@ describe Dbee::Providers::ActiveRecordProvider do
|
|
57
54
|
yaml_fixture_files('active_record_snapshots').each_pair do |filename, snapshot|
|
58
55
|
specify File.basename(filename) do
|
59
56
|
model_name = snapshot['model_name']
|
57
|
+
|
60
58
|
query = Dbee::Query.make(snapshot['query'])
|
61
|
-
|
59
|
+
schema = Dbee::Schema.new(models[model_name])
|
62
60
|
|
63
61
|
expected_5_sql = snapshot[key].to_s.chomp.tr("\n", ' ')
|
64
62
|
expected_6_sql = expected_5_sql.gsub(' ', ' ').gsub("'t'", '1').gsub("'f'", '0')
|
65
|
-
actual_sql = described_class.new(readable: readable).sql(
|
63
|
+
actual_sql = described_class.new(readable: readable).sql(schema, query)
|
66
64
|
|
67
65
|
error_msg = <<~ERROR_MSG
|
68
66
|
Expected 5 SQL: #{expected_5_sql}
|
@@ -95,9 +93,9 @@ describe Dbee::Providers::ActiveRecordProvider do
|
|
95
93
|
specify File.basename(filename) do
|
96
94
|
model_name = snapshot['model_name']
|
97
95
|
query = Dbee::Query.make(snapshot['query'])
|
98
|
-
|
96
|
+
schema = Dbee::Schema.new(models[model_name])
|
99
97
|
|
100
|
-
sql = described_class.new(readable: readable).sql(
|
98
|
+
sql = described_class.new(readable: readable).sql(schema, query)
|
101
99
|
|
102
100
|
expect { ActiveRecord::Base.connection.execute(sql) }.to_not raise_error
|
103
101
|
end
|
@@ -128,10 +126,10 @@ describe Dbee::Providers::ActiveRecordProvider do
|
|
128
126
|
|
129
127
|
let(:snapshot) { yaml_file_read(*snapshot_path) }
|
130
128
|
let(:query) { Dbee::Query.make(snapshot['query']) }
|
131
|
-
let(:
|
129
|
+
let(:schema) { Dbee::Schema.new(models['Patients']) }
|
132
130
|
|
133
131
|
it 'pivots table rows into columns' do
|
134
|
-
sql = described_class.new.sql(
|
132
|
+
sql = described_class.new.sql(schema, query)
|
135
133
|
|
136
134
|
results = ActiveRecord::Base.connection.execute(sql)
|
137
135
|
|
@@ -173,11 +171,10 @@ describe Dbee::Providers::ActiveRecordProvider do
|
|
173
171
|
|
174
172
|
let(:snapshot) { yaml_file_read(*snapshot_path) }
|
175
173
|
let(:query) { Dbee::Query.make(snapshot['query']) }
|
176
|
-
let(:
|
174
|
+
let(:schema) { Dbee::Schema.new(models['Patients']) }
|
177
175
|
|
178
176
|
it 'executes correct SQL aggregate functions' do
|
179
|
-
sql
|
180
|
-
|
177
|
+
sql = described_class.new.sql(schema, query)
|
181
178
|
results = ActiveRecord::Base.connection.execute(sql)
|
182
179
|
|
183
180
|
expect(results[0]).to include(
|
@@ -0,0 +1,11 @@
|
|
1
|
+
model_name: Patients
|
2
|
+
query:
|
3
|
+
from: patients
|
4
|
+
sqlite_readable: |+
|
5
|
+
SELECT "patients".* FROM "patients" "patients"
|
6
|
+
sqlite_not_readable: |+
|
7
|
+
SELECT "t0".* FROM "patients" "t0"
|
8
|
+
mysql_readable: |+
|
9
|
+
SELECT `patients`.* FROM `patients` `patients`
|
10
|
+
mysql_not_readable: |+
|
11
|
+
SELECT `t0`.* FROM `patients` `t0`
|
@@ -1,11 +1,13 @@
|
|
1
1
|
model_name: Theaters, Members, and Movies
|
2
2
|
query:
|
3
|
+
from: theaters
|
3
4
|
fields:
|
4
5
|
- key_path: id
|
5
6
|
- key_path: name
|
6
7
|
- key_path: members.id
|
7
8
|
- key_path: members.account_number
|
8
9
|
limit: 12
|
10
|
+
offset: 25
|
9
11
|
sqlite_readable: |+
|
10
12
|
SELECT
|
11
13
|
"theaters"."id" AS 'id',
|
@@ -15,6 +17,7 @@ sqlite_readable: |+
|
|
15
17
|
FROM "theaters" "theaters"
|
16
18
|
LEFT OUTER JOIN "members" "members" ON "members"."tid" = "theaters"."id" AND "members"."partition" = "theaters"."partition"
|
17
19
|
LIMIT 12
|
20
|
+
OFFSET 25
|
18
21
|
sqlite_not_readable: |+
|
19
22
|
SELECT
|
20
23
|
"t0"."id" AS 'c0',
|
@@ -24,6 +27,7 @@ sqlite_not_readable: |+
|
|
24
27
|
FROM "theaters" "t0"
|
25
28
|
LEFT OUTER JOIN "members" "t1" ON "t1"."tid" = "t0"."id" AND "t1"."partition" = "t0"."partition"
|
26
29
|
LIMIT 12
|
30
|
+
OFFSET 25
|
27
31
|
mysql_readable: |+
|
28
32
|
SELECT
|
29
33
|
`theaters`.`id` AS 'id',
|
@@ -33,6 +37,7 @@ mysql_readable: |+
|
|
33
37
|
FROM `theaters` `theaters`
|
34
38
|
LEFT OUTER JOIN `members` `members` ON `members`.`tid` = `theaters`.`id` AND `members`.`partition` = `theaters`.`partition`
|
35
39
|
LIMIT 12
|
40
|
+
OFFSET 25
|
36
41
|
mysql_not_readable: |+
|
37
42
|
SELECT
|
38
43
|
`t0`.`id` AS 'c0',
|
@@ -42,3 +47,4 @@ mysql_not_readable: |+
|
|
42
47
|
FROM `theaters` `t0`
|
43
48
|
LEFT OUTER JOIN `members` `t1` ON `t1`.`tid` = `t0`.`id` AND `t1`.`partition` = `t0`.`partition`
|
44
49
|
LIMIT 12
|
50
|
+
OFFSET 25
|