dbee 2.0.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6408442138aafff2ca06cd0161a5fd34a10270a773fb6bd90a9cde54c593b66
4
- data.tar.gz: 8dfb19dc5001ba6e7718cac33e0041eaef49747343a189138dd165f82b825bfb
3
+ metadata.gz: 2b8250c307ad60bdb8bc51e19fdb93b2c9eb3db0cccfb5daad0a2e621aab57cb
4
+ data.tar.gz: db66f66f4a56dd40bbaa347218d0827291c789733b9c3f7086ca416e85a09246
5
5
  SHA512:
6
- metadata.gz: d26d78a27695eb0c4ca15055ada5624c802d4f22c9d7a5fb110b940bcf1bdc56f1bdcb65f0c4754820439bf94fcc6ba029dd1f922c6e53f9a07698a862b5d897
7
- data.tar.gz: 5074fbbc002af0e8e7335a2a1e25bfbaa25923cdbc6171d177de5ebee6147236248f2d7efd86ca4d398ac2abf2b4a4873d49d2cd2a38bfde8cbf46fc6e8bc7b8
6
+ metadata.gz: '0085b06c34404de9b93b728713fd118189a2693920668685e66574c2bd23b8cb2009d0ab4a047dbbc8b4e7c69084a3ec595d1fa80aaf6de06bce023d5fff3d1a'
7
+ data.tar.gz: a295c963939ce9df84689bd3ab34852df111a7c57e685ac07abdb661498dc269fe85e661fae49b77826e43054030fb09c18fe7da648a1cdc78020024bac15a52
data/.gitignore CHANGED
@@ -4,3 +4,4 @@
4
4
  /coverage
5
5
  Gemfile.lock
6
6
  /pkg
7
+ .vscode
data/.rubocop.yml CHANGED
@@ -1,8 +1,15 @@
1
- Metrics/LineLength:
1
+ AllCops:
2
+ TargetRubyVersion: 2.5
3
+ NewCops: enable
4
+
5
+ Layout/LineLength:
2
6
  Max: 100
3
7
 
8
+ Metrics/AbcSize:
9
+ Max: 16
10
+
4
11
  Metrics/BlockLength:
5
- ExcludedMethods:
12
+ IgnoredMethods:
6
13
  - let
7
14
  - it
8
15
  - describe
@@ -10,14 +17,11 @@ Metrics/BlockLength:
10
17
  - specify
11
18
  - define
12
19
 
13
- Metrics/MethodLength:
14
- Max: 25
15
-
16
- AllCops:
17
- TargetRubyVersion: 2.3
18
-
19
- Metrics/AbcSize:
20
- Max: 16
20
+ Metrics/ParameterLists:
21
+ CountKeywordArgs: false
21
22
 
22
23
  Metrics/ClassLength:
23
24
  Max: 125
25
+
26
+ Metrics/MethodLength:
27
+ Max: 25
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6.3
1
+ 2.6.6
data/.travis.yml CHANGED
@@ -1,13 +1,13 @@
1
1
  env:
2
2
  global:
3
3
  - CC_TEST_REPORTER_ID=e7db23dad7560a076e48357331b0362db3741b62dbdd537bc30de27fa9cab69b
4
+ - DISABLE_RSPEC_FOCUS=true
4
5
  language: ruby
5
6
  rvm:
6
7
  # Build on the latest stable of all supported Rubies (https://www.ruby-lang.org/en/downloads/):
7
- - 2.3.8
8
- - 2.4.6
9
- - 2.5.5
10
- - 2.6.3
8
+ - 2.5.8
9
+ - 2.6.6
10
+ - 2.7.2
11
11
  cache: bundler
12
12
  before_script:
13
13
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
data/CHANGELOG.md CHANGED
@@ -1,3 +1,46 @@
1
+ # 3.0.0 (March 11th, 2021)
2
+
3
+ ### Additions
4
+
5
+ * Support for graph based models. This paves the way for representing more advanced features, such as sub-queries in a more clear way. Since graph based models are similar to DSL models, the hope is that they will be easier to work with and understand.
6
+
7
+ ### Breaking Changes
8
+
9
+ * The `to_model` method on `Dbee::Base` objects has been removed. Use `to_schema` instead.
10
+ * The `ancestors!` method on `Dbee::Model` has been removed. Use `Dbee::Schema#expand_query_path` instead.
11
+
12
+ # 2.1.1 (July 14th, 2020)
13
+
14
+ * Removed guard that ensured a query has at least one field to establish a more rational base-case.
15
+
16
+ # 2.1.0 (July 13th, 2020)
17
+
18
+ ### Additions:
19
+
20
+ * Added Dbee::Query::Field#aggregator (such as ave, min, max, sum, etc.)
21
+ * Added Dbee::Query::Field#filters (allows for doing select column filtering)
22
+
23
+ ### Changes:
24
+
25
+ * Bumped minimum Ruby version to 2.5
26
+
27
+ # 2.0.3 (January 7th, 2020)
28
+
29
+ ### Fixes:
30
+
31
+ * Constant resolution will now explicitly set inherit to false when calling `Object#const_defined?` and `Object#const_get`. This should equate to less false positives. For example:
32
+
33
+ ```ruby
34
+ class A; end
35
+
36
+ module B
37
+ class A; end
38
+ class C; end
39
+ end
40
+ ```
41
+
42
+ If `B::A` is the desired class, it would not be suitable to just declare an association on `A` as that would resolve explicitly to `::A`. It also means C cannot be auto-resolved without prefixing/sharing the namespace with parent association `A`.
43
+
1
44
  # 2.0.2 (November 7th, 2019)
2
45
 
3
46
  ### Additions:
data/README.md CHANGED
@@ -20,7 +20,7 @@ Both of these solutions ended up closely coupling our domain data layer to ad-ho
20
20
 
21
21
  ## Installation
22
22
 
23
- This specific library is the core modeling component of the Dbee framework, but by itself, it not completely usable. You will need to provide a SQL generator which understands how to convert the data and query modeling to actual SQL. This library comes with a stub: Dbee::Providers::NullProvider, while the main reference implementation is split out into its own library: [dbee-active_record](https://github.com/bluemarblepayroll/dbee-active_record). Together these two libraries comprise a complete solution. Refer to the other library for more information on installation.
23
+ This specific library is the core modeling component of the Dbee framework, but by itself, it is not completely usable. You will need to provide a SQL generator which understands how to convert the data and query modeling to actual SQL. This library comes with a stub: Dbee::Providers::NullProvider, while the main reference implementation is split out into its own library: [dbee-active_record](https://github.com/bluemarblepayroll/dbee-active_record). Together these two libraries comprise a complete solution. Refer to the other library for more information on installation.
24
24
 
25
25
  To install through Rubygems:
26
26
 
@@ -189,49 +189,58 @@ The two code-first examples above should be technically equivalent.
189
189
  You can choose to alternatively describe your data model using configuration. The YAML below is equivalent to the Ruby sub-classes above:
190
190
 
191
191
  ````yaml
192
- name: practice
193
- models:
194
- - name: patients
195
- constraints:
196
- - type: reference
197
- name: practice_id
198
- parent: id
199
- models:
200
- - name: notes
201
- constraints:
202
- - type: reference
203
- name: patient_id
204
- parent: id
205
- - name: work_phone_number
206
- table: phones
207
- constraints:
208
- - type: reference
209
- name: patient_id
210
- parent: id
211
- - type: static
212
- name: phone_number_type
213
- value: work
214
- - name: cell_phone_number
215
- table: phones
216
- constraints:
217
- - type: reference
218
- name: patient_id
219
- parent: id
220
- - type: static
221
- name: phone_number_type
222
- value: cell
223
- - name: fax_phone_number
224
- table: phones
225
- constraints:
226
- - type: reference
227
- name: patient_id
228
- parent: id
229
- - type: static
230
- name: phone_number_type
231
- value: fax
192
+ practice:
193
+ table: practices
194
+ relationships:
195
+ patients:
196
+ model: patient
197
+ constraints:
198
+ - type: reference
199
+ name: practice_id
200
+ parent: id
201
+ patient:
202
+ table: patients
203
+ relationships:
204
+ notes:
205
+ model: note
206
+ constraints:
207
+ - type: reference
208
+ name: patient_id
209
+ parent: id
210
+ work_phone_number:
211
+ model: phone_number
212
+ constraints:
213
+ - type: reference
214
+ name: patient_id
215
+ parent: id
216
+ - type: static
217
+ name: phone_number_type
218
+ value: work
219
+ cell_phone_number:
220
+ model: phone_number
221
+ constraints:
222
+ - type: reference
223
+ name: patient_id
224
+ parent: id
225
+ - type: static
226
+ name: phone_number_type
227
+ value: cell
228
+ fax_phone_number:
229
+ model: phone_number
230
+ constraints:
231
+ - type: reference
232
+ name: patient_id
233
+ parent: id
234
+ - type: static
235
+ name: phone_number_type
236
+ value: fax
237
+ note:
238
+ table: notes
239
+ phone_number:
240
+ table: phones
232
241
  ````
233
242
 
234
- It is up to you to determine which modeling technique to use as both are equivalent. Technically speaking, the code-first DSL is nothing more than syntactic sugar on top of Dbee::Model.
243
+ It is up to you to determine which modeling technique to use as both are equivalent. Technically speaking, the code-first DSL is nothing more than syntactic sugar on top of `Dbee::Schema` and `Dbee::Model`. Also note that prior to version three of this project, a more hierarchical tree based model configuration was used. See [Tree Based Model Backward Compatibility](#tree-based-model-backward-compatibility) below for more information on this.
235
244
 
236
245
  #### Table Partitioning
237
246
 
@@ -275,6 +284,7 @@ Cats:
275
284
  The Query API (Dbee::Query) is a simplified and abstract way to model an SQL query. A Query has the following components:
276
285
 
277
286
  * fields (SELECT)
287
+ * from (FROM)
278
288
  * filters (WHERE)
279
289
  * sorters (ORDER BY)
280
290
  * limit (LIMIT/TAKE)
@@ -291,6 +301,7 @@ Get all practices:
291
301
 
292
302
  ````ruby
293
303
  query = {
304
+ from: 'practice',
294
305
  fields: [
295
306
  { key_path: 'id' },
296
307
  { key_path: 'active' },
@@ -303,6 +314,7 @@ Get all practices, limit to 10, and sort by name (descending) then id (ascending
303
314
 
304
315
  ````ruby
305
316
  query = {
317
+ from: 'practice',
306
318
  fields: [
307
319
  { key_path: 'id' },
308
320
  { key_path: 'active' },
@@ -320,6 +332,7 @@ Get top 5 active practices and patient whose name start with 'Sm':
320
332
 
321
333
  ````ruby
322
334
  query = {
335
+ from: 'practice',
323
336
  fields: [
324
337
  { key_path: 'name', display: 'Practice Name' },
325
338
  { key_path: 'patients.first', display: 'Patient First Name' },
@@ -338,6 +351,7 @@ Get practice IDs, patient IDs, names, and cell phone numbers that starts with '5
338
351
 
339
352
  ````ruby
340
353
  query = {
354
+ from: 'practice',
341
355
  fields: [
342
356
  { key_path: 'id', display: 'Practice ID #' },
343
357
  { key_path: 'patients.id', display: 'Patient ID #' },
@@ -363,6 +377,22 @@ You execute a Query against a Data Model, using a Provider. The sample provider
363
377
 
364
378
  Here are some sample executions based off the preceding examples:
365
379
 
380
+ ##### Base Case
381
+
382
+ If a query has no fields then it is implied you would like all fields on the root table. For example:
383
+
384
+ ````ruby
385
+ require 'dbee/providers/active_record_provider'
386
+
387
+ class Practice < Dbee::Base; end
388
+
389
+ provider = Dbee::Providers::ActiveRecordProvider.new
390
+ query = { from: 'practice' }
391
+ sql = Dbee.sql(Practice, query, provider)
392
+ ````
393
+
394
+ It equivalent to saying: `SELECT practices.* FROM practices`. This helps to establish a deterministic base-case: it returns the same implicit columns that is independent of sql joins (sorters and/or filters may require sql joins.)
395
+
366
396
  ##### Code-First Execution
367
397
 
368
398
  ````ruby
@@ -373,6 +403,7 @@ class Practice < Dbee::Base; end
373
403
  provider = Dbee::Providers::ActiveRecordProvider.new
374
404
 
375
405
  query = {
406
+ from: 'practice',
376
407
  fields: [
377
408
  { key_path: 'id' },
378
409
  { key_path: 'active' },
@@ -391,10 +422,11 @@ require 'dbee/providers/active_record_provider'
391
422
  provider = Dbee::Providers::ActiveRecordProvider.new
392
423
 
393
424
  model = {
394
- name: :practice
425
+ practice: { table: 'practices' }
395
426
  }
396
427
 
397
428
  query = {
429
+ from: 'practice',
398
430
  fields: [
399
431
  { key_path: 'id' },
400
432
  { key_path: 'active' },
@@ -407,7 +439,189 @@ sql = Dbee.sql(model, query, provider)
407
439
 
408
440
  The above examples showed how to use a plugin provider, see the plugin provider's documentation for more information about its options and use.
409
441
 
442
+ #### Aggregation
443
+
444
+ Fields can be configured to use aggregation by setting its `aggregator` attribute. For example, say we wanted to count the number of patients per practice:
445
+
446
+ **Data Model**:
447
+
448
+ ````yaml
449
+ practice:
450
+ table: practices
451
+ relationships:
452
+ patients:
453
+ model: patient
454
+ constraints:
455
+ - type: reference
456
+ name: practice_id
457
+ parent: id
458
+ patient:
459
+ table: patients
460
+ ````
461
+
462
+ **Query**:
463
+
464
+ ````ruby
465
+ query = {
466
+ from: 'practice',
467
+ fields: [
468
+ {
469
+ key_path: 'id',
470
+ display: 'Practice ID #',
471
+ },
472
+ {
473
+ key_path: 'name',
474
+ display: 'Practice Name',
475
+ },
476
+ {
477
+ key_path: 'patients.id',
478
+ display: 'Total Patients',
479
+ aggregator: :count
480
+ },
481
+ ]
482
+ ````
483
+
484
+ An example of a materialized result would be something akin to:
485
+
486
+ Practice ID # | Practice Name | Total Patients
487
+ ------------- | --------------- | --------------
488
+ 1 | Families Choice | 293
489
+ 2 | Awesome Choice | 2305
490
+ 3 | Best Value | 1200
491
+
492
+ A complete list of aggregator values can be found by inspecting the `Dbee::Query::Field::Aggregator` constant.
493
+
494
+ #### Field/Column Level Filtering & Pivoting
495
+
496
+ Fields can also have filters which provide post-filtering (on the select-level instead of at query-level.) This can be used in conjunction with aggregate functions to provide pivoting. For example:
497
+
498
+ **Data/Schema Example**:
499
+
500
+ patients:
501
+
502
+ id | first | last
503
+ -- | ----- | -----
504
+ 1 | frank | rizzo
505
+
506
+ patient_fields:
507
+
508
+ id | patient_id | key | value
509
+ -- | ---------- | --------------- | -----
510
+ 1 | 1 | dob | 1900-01-01
511
+ 2 | 1 | drivers_license | ABC123
512
+
513
+ **Model Configuration**:
514
+
515
+ ````yaml
516
+ patients:
517
+ relationships:
518
+ - patient_fields:
519
+ constraints:
520
+ - type: reference
521
+ parent: id
522
+ name: patient_id
523
+ patient_fields:
524
+ ````
525
+
526
+ **Query**:
527
+
528
+ ````ruby
529
+ query = {
530
+ from: 'patients',
531
+ fields: [
532
+ {
533
+ key_path: 'id',
534
+ display: 'ID #'
535
+ },
536
+ {
537
+ key_path: 'first',
538
+ display: 'First Name'
539
+ },
540
+ {
541
+ aggregator: :max,
542
+ key_path: 'patient_fields.value',
543
+ display: 'Date of Birth',
544
+ filters: [
545
+ {
546
+ key_path: 'patient_fields.key',
547
+ value: 'dob'
548
+ }
549
+ ]
550
+ },
551
+ {
552
+ aggregator: :max,
553
+ key_path: 'patient_fields.value',
554
+ display: 'Drivers License #',
555
+ filters: [
556
+ {
557
+ key_path: 'patient_fields.key',
558
+ value: 'drivers_license'
559
+ }
560
+ ]
561
+ }
562
+ }
563
+ }
564
+ ````
565
+
566
+ Executing the query above against the data and model would yield:
567
+
568
+ ID # | First Name | Date of Birth | Drivers License #
569
+ -- | ---------- | ------------- | -----------------
570
+ 1 | frank | 1900-01-01 | ABC123
571
+
572
+ ## Tree Based Model Backward Compatibility
573
+
574
+ In version three of this gem, the representation of configuration based models was changed to be more of a graph structure than the previous tree structure. For backwards compatibility, it is still possible to pass this older tree based structure as the first argument `Dbee.sql`. The practices example would be represented this way in the old structure:
575
+
576
+ ````yaml
577
+ # Deprecated tree based model configuration:
578
+ name: practice
579
+ table: practices
580
+ models:
581
+ - name: patients
582
+ constraints:
583
+ - type: reference
584
+ name: practice_id
585
+ parent: id
586
+ models:
587
+ - name: notes
588
+ constraints:
589
+ - type: reference
590
+ name: patient_id
591
+ parent: id
592
+ - name: work_phone_number
593
+ table: phones
594
+ constraints:
595
+ - type: reference
596
+ name: patient_id
597
+ parent: id
598
+ - type: static
599
+ name: phone_number_type
600
+ value: work
601
+ - name: cell_phone_number
602
+ table: phones
603
+ constraints:
604
+ - type: reference
605
+ name: patient_id
606
+ parent: id
607
+ - type: static
608
+ name: phone_number_type
609
+ value: cell
610
+ - name: fax_phone_number
611
+ table: phones
612
+ constraints:
613
+ - type: reference
614
+ name: patient_id
615
+ parent: id
616
+ - type: static
617
+ name: phone_number_type
618
+ value: fax
619
+ ````
410
620
 
621
+ Also note to further maintain backwards compatibility, queries issued against
622
+ tree based models do not need the "from" attribute to be defined. This is
623
+ because the from/starting point of the query can be inferred as the model at
624
+ the root of the tree.
411
625
  ## Contributing
412
626
 
413
627
  ### Development Environment Configuration