dbee 2.0.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
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_relative '../fixtures/models'
12
+
13
+ describe Dbee::Schema do
14
+ def make_model(model_name)
15
+ raise "no model named '#{model_name}'" unless schema_config.key?(model_name)
16
+
17
+ Dbee::Model.make((schema_config[model_name] || {}).merge('name' => model_name))
18
+ end
19
+
20
+ let(:model_name) do
21
+ 'Theaters, Members, and Movies from DSL'
22
+ end
23
+ let(:schema_config) { yaml_fixture('models.yaml')[model_name] }
24
+
25
+ let(:demographics_model) { make_model('demographic') }
26
+ let(:members_model) { make_model('member') }
27
+ let(:movies_model) { make_model('movie') }
28
+ let(:phone_numbers_model) { make_model('phone_number') }
29
+ let(:theaters_model) { make_model('theater') }
30
+
31
+ let(:subject) { described_class.new(schema_config) }
32
+
33
+ describe '#expand_query_path' do
34
+ specify 'one model case' do
35
+ expect(subject.expand_query_path(members_model, Dbee::KeyPath.new('id'))).to eq []
36
+ end
37
+
38
+ specify 'two model case' do
39
+ expected_path = [[members_model.relationship_for_name('movies'), movies_model]]
40
+ expect(
41
+ subject.expand_query_path(members_model, Dbee::KeyPath.new('movies.id'))
42
+ ).to eq expected_path
43
+ end
44
+
45
+ it 'traverses aliased models' do
46
+ expected_path = [
47
+ [members_model.relationship_for_name('demos'), demographics_model],
48
+ [demographics_model.relationship_for_name('phone_numbers'), phone_numbers_model]
49
+ ]
50
+
51
+ expect(
52
+ subject.expand_query_path(members_model, Dbee::KeyPath.new('demos.phone_numbers.id'))
53
+ ).to eq expected_path
54
+ end
55
+
56
+ it 'raises an error given an unknown relationship' do
57
+ expect do
58
+ subject.expand_query_path(theaters_model, Dbee::KeyPath.new('demographics.id'))
59
+ end.to raise_error("model 'theater' does not have a 'demographics' relationship")
60
+ end
61
+ end
62
+ end
data/spec/dbee_spec.rb CHANGED
@@ -13,59 +13,39 @@ require 'fixtures/models'
13
13
  describe Dbee do
14
14
  describe '#sql' do
15
15
  let(:provider) { Dbee::Providers::NullProvider.new }
16
-
17
- let(:model_hash) do
18
- {
19
- name: 'something'
20
- }
21
- end
22
-
23
- let(:model) { Dbee::Model.make(model_hash) }
24
-
25
16
  let(:query_hash) do
26
17
  {
18
+ from: 'my_model',
27
19
  fields: [
28
20
  { key_path: :a }
29
21
  ]
30
22
  }
31
23
  end
32
-
33
24
  let(:query) { Dbee::Query.make(query_hash) }
25
+ let(:schema) { Dbee::Schema.new({}) }
34
26
 
35
- it 'accepts a hash as a model and passes a Model instance to provider#sql' do
36
- expect(provider).to receive(:sql).with(model, query)
37
-
38
- described_class.sql(model_hash, query, provider)
39
- end
40
-
41
- it 'accepts a Dbee::Model instance as a model and passes a Model instance to provider#sql' do
42
- expect(provider).to receive(:sql).with(model, query)
27
+ it 'accepts a query hash and a Schema and passes them into provider#sql' do
28
+ expect(provider).to receive(:sql).with(schema, query)
43
29
 
44
- described_class.sql(model, query, provider)
30
+ described_class.sql(schema, query_hash, provider)
45
31
  end
46
32
 
47
- it 'accepts a Dbee::Base constant as a model and passes a Model instance to provider#sql' do
48
- model_constant = Models::Theater
49
-
50
- expect(provider).to receive(:sql).with(model_constant.to_model(query.key_chain), query)
51
-
52
- described_class.sql(model_constant, query, provider)
33
+ it 'does not allow a nil schema' do
34
+ expect do
35
+ described_class.sql(nil, query, provider)
36
+ end.to raise_error ArgumentError, /schema or model is required/
53
37
  end
54
38
 
55
- it 'accepts a Dbee::Query instance as a query and passes a Query instance to provider#sql' do
56
- model = Models::Theater.to_model(query.key_chain)
57
-
58
- expect(provider).to receive(:sql).with(model, query)
59
-
60
- described_class.sql(model, query, provider)
39
+ it 'does not allow a nil query' do
40
+ expect do
41
+ described_class.sql(schema, nil, provider)
42
+ end.to raise_error ArgumentError, /query is required/
61
43
  end
62
44
 
63
- it 'accepts a hash as a query and passes a Query instance to provider#sql' do
64
- model = Models::Theater.to_model(query.key_chain)
65
-
66
- expect(provider).to receive(:sql).with(model, query)
67
-
68
- described_class.sql(model, query_hash, provider)
45
+ it 'does not allow a nil provider' do
46
+ expect do
47
+ described_class.sql(schema, query, nil)
48
+ end.to raise_error ArgumentError, /provider is required/
69
49
  end
70
50
  end
71
51
  end
@@ -1,4 +1,4 @@
1
- Theaters, Members, and Movies:
1
+ Theaters, Members, and Movies Tree Based:
2
2
  name: theater
3
3
  table: theaters
4
4
  models:
@@ -119,7 +119,217 @@ Theaters, Members, and Movies:
119
119
  - type: static
120
120
  name: genre
121
121
  value: comedy
122
+
123
+ # Note that since converting from the tree does not have as much context as
124
+ # converting from the DSL, the resulting graph is a bit different.
125
+ Theaters, Members, and Movies from Tree:
126
+ theater:
127
+ table: theaters
128
+ relationships:
129
+ members:
130
+ constraints:
131
+ - type: reference
132
+ parent: id
133
+ name: tid
134
+ - type: reference
135
+ parent: partition
136
+ name: partition
137
+ parent_theater:
138
+ constraints:
139
+ - type: reference
140
+ name: id
141
+ parent: parent_theater_id
142
+ members:
143
+ relationships:
144
+ demos:
145
+ constraints:
146
+ - type: reference
147
+ parent: id
148
+ name: member_id
149
+ movies:
150
+ constraints:
151
+ - type: reference
152
+ parent: id
153
+ name: member_id
154
+ favorite_comic_movies:
155
+ constraints:
156
+ - type: reference
157
+ parent: id
158
+ name: member_id
159
+ - type: static
160
+ name: genre
161
+ value: comic
162
+ favorite_mystery_movies:
163
+ constraints:
164
+ - type: reference
165
+ parent: id
166
+ name: member_id
167
+ - type: static
168
+ name: genre
169
+ value: mystery
170
+ favorite_comedy_movies:
171
+ constraints:
172
+ - type: reference
173
+ parent: id
174
+ name: member_id
175
+ - type: static
176
+ name: genre
177
+ value: comedy
178
+ demos:
179
+ table: demographics
180
+ relationships:
181
+ phone_numbers:
182
+ constraints:
183
+ - type: reference
184
+ parent: id
185
+ name: demographic_id
186
+ phone_numbers:
187
+ movies:
188
+ favorite_comic_movies:
189
+ table: movies
190
+ favorite_mystery_movies:
191
+ table: movies
192
+ favorite_comedy_movies:
193
+ table: movies
194
+ parent_theater:
195
+ table: theaters
196
+ relationships:
197
+ members:
198
+ constraints:
199
+ - type: reference
200
+ parent: id
201
+ name: tid
202
+ - type: reference
203
+ parent: partition
204
+ name: partition
205
+
206
+ Theaters, Members, and Movies from DSL:
207
+ theater:
208
+ table: theaters
209
+ relationships:
210
+ members:
211
+ model: member
212
+ constraints:
213
+ - type: reference
214
+ parent: id
215
+ name: tid
216
+ - type: reference
217
+ parent: partition
218
+ name: partition
219
+ parent_theater:
220
+ model: theater
221
+ constraints:
222
+ - type: reference
223
+ name: id
224
+ parent: parent_theater_id
225
+ member:
226
+ table: members
227
+ relationships:
228
+ movies:
229
+ model: movie
230
+ constraints:
231
+ - type: reference
232
+ parent: id
233
+ name: member_id
234
+ demos:
235
+ model: demographic
236
+ constraints:
237
+ - type: reference
238
+ parent: id
239
+ name: member_id
240
+ favorite_comic_movies:
241
+ model: movie
242
+ constraints:
243
+ - type: reference
244
+ parent: id
245
+ name: member_id
246
+ - type: static
247
+ name: genre
248
+ value: comic
249
+ favorite_mystery_movies:
250
+ model: movie
251
+ constraints:
252
+ - type: reference
253
+ parent: id
254
+ name: member_id
255
+ - type: static
256
+ name: genre
257
+ value: mystery
258
+ favorite_comedy_movies:
259
+ model: movie
260
+ constraints:
261
+ - type: reference
262
+ parent: id
263
+ name: member_id
264
+ - type: static
265
+ name: genre
266
+ value: comedy
267
+ demographic:
268
+ table: demographics
269
+ relationships:
270
+ phone_numbers:
271
+ model: phone_number
272
+ constraints:
273
+ - type: reference
274
+ parent: id
275
+ name: demographic_id
276
+ phone_number:
277
+ table: phone_numbers
278
+ movie:
279
+ table: movies
280
+
122
281
  Readme:
282
+ practice:
283
+ table: practices
284
+ relationships:
285
+ patients:
286
+ model: patient
287
+ constraints:
288
+ - type: reference
289
+ name: practice_id
290
+ parent: id
291
+ patient:
292
+ table: patients
293
+ relationships:
294
+ notes:
295
+ model: note
296
+ constraints:
297
+ - type: reference
298
+ name: patient_id
299
+ parent: id
300
+ work_phone_number:
301
+ model: phone_number
302
+ constraints:
303
+ - type: reference
304
+ name: patient_id
305
+ parent: id
306
+ - type: static
307
+ name: phone_number_type
308
+ value: work
309
+ cell_phone_number:
310
+ model: phone_number
311
+ constraints:
312
+ - type: reference
313
+ name: patient_id
314
+ parent: id
315
+ - type: static
316
+ name: phone_number_type
317
+ value: cell
318
+ fax_phone_number:
319
+ model: phone_number
320
+ constraints:
321
+ - type: reference
322
+ name: patient_id
323
+ parent: id
324
+ - type: static
325
+ name: phone_number_type
326
+ value: fax
327
+ note:
328
+ table: notes
329
+ phone_number:
330
+ table: phones
331
+
332
+ Readme Tree Based:
123
333
  name: practice
124
334
  table: practices
125
335
  models:
@@ -161,63 +371,51 @@ Readme:
161
371
  - type: static
162
372
  name: phone_number_type
163
373
  value: fax
374
+
164
375
  Cycle Example:
165
- name: a
166
- table: as
167
- models:
168
- - name: b1
169
- table: bs
170
- models:
171
- - name: c
172
- table: cs
173
- models:
174
- - name: a
175
- table: as
176
- - name: d
177
- table: ds
178
- models:
179
- - name: a
180
- table: as
181
- - name: b2
182
- table: bs
183
- models:
184
- - name: c
185
- table: cs
186
- models:
187
- - name: a
188
- table: as
189
- - name: d
190
- table: ds
191
- models:
192
- - name: a
193
- table: as
194
- models:
195
- - name: b1
196
- table: bs
197
- models:
198
- - name: c
199
- table: cs
376
+ a:
377
+ table: as
378
+ relationships:
379
+ b1:
380
+ model: b
381
+ b2:
382
+ model: b
383
+ b:
384
+ table: bs
385
+ relationships:
386
+ c:
387
+ d:
388
+ c:
389
+ table: cs
390
+ relationships:
391
+ a:
392
+ d:
393
+ table: ds
394
+ relationships:
395
+ a:
200
396
 
201
397
  Partitioner Example 1:
202
- name: dog
203
- table: animals
204
- partitioners:
205
- - name: type
206
- value: Dog
207
- - name: deleted
208
- value: false
398
+ dog:
399
+ table: animals
400
+ partitioners:
401
+ - name: type
402
+ value: Dog
403
+ - name: deleted
404
+ value: false
209
405
 
210
406
  Partitioner Example 2:
211
- name: owner
212
- table: owners
213
- models:
214
- - name: dogs
215
- table: animals
216
- constraints:
217
- - name: owner_id
218
- parent: id
219
- partitioners:
220
- - name: type
221
- value: Dog
222
- - name: deleted
223
- value: false
407
+ owner:
408
+ table: owners
409
+ relationships:
410
+ dogs:
411
+ model: dog
412
+ constraints:
413
+ - name: owner_id
414
+ parent: id
415
+ dog:
416
+ table: animals
417
+ partitioners:
418
+ - name: type
419
+ value: Dog
420
+ - name: deleted
421
+ value: false