activerecord-dbt 0.1.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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +921 -0
  4. data/Rakefile +5 -0
  5. data/lib/active_record/dbt/column/column.rb +84 -0
  6. data/lib/active_record/dbt/column/test.rb +61 -0
  7. data/lib/active_record/dbt/column/testable/accepted_values_testable.rb +59 -0
  8. data/lib/active_record/dbt/column/testable/not_null_testable.rb +23 -0
  9. data/lib/active_record/dbt/column/testable/relationships_testable.rb +49 -0
  10. data/lib/active_record/dbt/column/testable/unique_testable.rb +37 -0
  11. data/lib/active_record/dbt/config.rb +45 -0
  12. data/lib/active_record/dbt/configuration/data_sync.rb +15 -0
  13. data/lib/active_record/dbt/configuration/logger.rb +41 -0
  14. data/lib/active_record/dbt/configuration/parser.rb +15 -0
  15. data/lib/active_record/dbt/configuration/used_dbt_package.rb +25 -0
  16. data/lib/active_record/dbt/dbt_package/dbt_utils/table/testable/unique_combination_of_columns_testable.rb +42 -0
  17. data/lib/active_record/dbt/dbt_package/dbterd/column/testable/relationships_meta_relationship_type.rb +138 -0
  18. data/lib/active_record/dbt/factory/columns_factory.rb +31 -0
  19. data/lib/active_record/dbt/factory/model/staging_factory.rb +22 -0
  20. data/lib/active_record/dbt/factory/source_factory.rb +16 -0
  21. data/lib/active_record/dbt/factory/table_factory.rb +16 -0
  22. data/lib/active_record/dbt/factory/tables_factory.rb +15 -0
  23. data/lib/active_record/dbt/model/staging/base.rb +73 -0
  24. data/lib/active_record/dbt/model/staging/sql.rb +43 -0
  25. data/lib/active_record/dbt/model/staging/yml.rb +108 -0
  26. data/lib/active_record/dbt/railtie.rb +8 -0
  27. data/lib/active_record/dbt/source/yml.rb +37 -0
  28. data/lib/active_record/dbt/table/base.rb +16 -0
  29. data/lib/active_record/dbt/table/test.rb +19 -0
  30. data/lib/active_record/dbt/table/yml.rb +75 -0
  31. data/lib/active_record/dbt/version.rb +7 -0
  32. data/lib/active_record/dbt.rb +17 -0
  33. data/lib/generators/active_record/dbt/config/USAGE +9 -0
  34. data/lib/generators/active_record/dbt/config/config_generator.rb +30 -0
  35. data/lib/generators/active_record/dbt/config/templates/source_config.yml.tt +68 -0
  36. data/lib/generators/active_record/dbt/initializer/USAGE +8 -0
  37. data/lib/generators/active_record/dbt/initializer/initializer_generator.rb +15 -0
  38. data/lib/generators/active_record/dbt/initializer/templates/dbt.rb +10 -0
  39. data/lib/generators/active_record/dbt/source/USAGE +8 -0
  40. data/lib/generators/active_record/dbt/source/source_generator.rb +22 -0
  41. data/lib/generators/active_record/dbt/staging_model/USAGE +9 -0
  42. data/lib/generators/active_record/dbt/staging_model/staging_model_generator.rb +38 -0
  43. data/lib/generators/active_record/dbt/staging_model/templates/staging_model.sql.tt +29 -0
  44. data/lib/tasks/active_record/dbt_tasks.rake +6 -0
  45. metadata +133 -0
data/README.md ADDED
@@ -0,0 +1,921 @@
1
+ # ActiveRecord::Dbt
2
+
3
+ `ActiveRecord::Dbt` generates dbt files from the information of the database connected via ActiveRecord.
4
+
5
+ Currently, it can generate `yaml` files for `sources` and `models` files for `staging`.
6
+
7
+ ## Installation
8
+
9
+ To install `activerecord-dbt`, add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'activerecord-dbt'
13
+ ```
14
+
15
+ Since it is only used in the development environment, it is recommended to add it to the development group:
16
+
17
+ ```ruby
18
+ group :development do
19
+ gem 'activerecord-dbt'
20
+ end
21
+ ```
22
+
23
+ Then run:
24
+
25
+ ```bash
26
+ $ bundle
27
+ ```
28
+
29
+ Alternatively, you can install it manually by running:
30
+
31
+ ```bash
32
+ $ gem install activerecord-dbt
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ### Configuration
38
+
39
+ #### ActiveRecord::Dbt Configuration
40
+
41
+ Create an initializer file for dbt:
42
+
43
+ ```bash
44
+ $ bin/rails generate active_record:dbt:initializer
45
+ ```
46
+
47
+ This will generate the `config/initializers/dbt.rb` file.
48
+
49
+ Configuration | Description
50
+ --------- | ---------
51
+ config_directory_path | The path to the directory where files generated by `bin/rails generate active_record:dbt:*` are stored. The default is `lib/dbt`.
52
+ export_directory_path | The path to the directory where configuration files are stored. The default is `doc/dbt`.
53
+ data_sync_delayed | Indicates whether there is a data delay. If set to `true`, `severity: warn` is applied to the `relationships` test. The default is `false`.
54
+ logger | The destination for log output. The default is `Logger.new('./log/active_record_dbt.log')`.
55
+ used_dbt_package_names | An array of `dbt` package names to use.
56
+
57
+ Example:
58
+
59
+ Adjust the settings according to your environment.
60
+
61
+ ```ruby
62
+ # frozen_string_literal: true
63
+
64
+ require 'active_record/dbt'
65
+
66
+ ActiveRecord::Dbt.configure do |c|
67
+ c.config_directory_path = 'lib/dbt'
68
+ c.export_directory_path = 'doc/dbt'
69
+ c.data_sync_delayed = false
70
+ c.used_dbt_package_names = [
71
+ 'dbt-labs/dbt_utils',
72
+ 'datnguye/dbterd'
73
+ ]
74
+ end
75
+
76
+ ```
77
+
78
+ #### Create Configuration Files
79
+
80
+ Create configuration files for dbt:
81
+
82
+ ```bash
83
+ $ bin/rails generate active_record:dbt:config
84
+ ```
85
+
86
+ This will create the following files.
87
+
88
+ File | Description
89
+ --------- | ---------
90
+ `#{config_directory_path}/source_config.yml` | Used to generate `#{export_directory_path}/src_#{source_name}.yml`.
91
+ `#{config_directory_path}/staging_model.sql.tt` | Used to generate `#{export_directory_path}/stg_#{source_name}__#{table_name}.sql`.
92
+
93
+ ### Generate dbt Source File
94
+
95
+ #### dbt Source Configuration
96
+
97
+ In the `#{config_directory_path}/source_config.yml` file, describe the properties you want to set for the source.
98
+ You can configure `sources`, `table_overrides`, `defaults`, and `table_descriptions` in this file.
99
+
100
+ The available properties for `sources` and `table_overrides` are detailed in [Source properties | dbt Developer Hub](https://docs.getdbt.com/reference/source-properties).
101
+
102
+ ##### sources
103
+
104
+ Set all properties except for `tables`.
105
+
106
+ Example:
107
+
108
+ ```yml
109
+ sources:
110
+ name: dummy
111
+ meta:
112
+ generated_by: activerecord-dbt
113
+ description: |-
114
+ Write a description of the 'dummy' source.
115
+ You can write multiple lines.
116
+
117
+ ```
118
+
119
+ ##### table_overrides
120
+
121
+ Set all properties for `tables` except for `name` and `description`.
122
+
123
+ Example:
124
+
125
+ ```yml
126
+ table_overrides:
127
+ users:
128
+ loaded_at_field: created_at
129
+ freshness:
130
+ warn_after:
131
+ count: 3
132
+ period: day
133
+ error_after:
134
+ count: 5
135
+ period: day
136
+ columns:
137
+ created_at:
138
+ tests:
139
+ - not_null:
140
+ where: 'id != 1'
141
+
142
+ ```
143
+
144
+ ##### defaults
145
+
146
+ Set default values for the `name` and `description` of `tables`.
147
+
148
+ In `logical_name` and `description` of `table_descriptions`, you can refer to the table name with `{{ table_name }}`.
149
+ In the `description` of `columns`, you can refer to the table name with `{{ table_name }}` and the column name with `{{ column_name }}`.
150
+
151
+ Example:
152
+
153
+ ```yml
154
+ defaults:
155
+ table_descriptions:
156
+ logical_name: Write a logical_name of the '{{ table_name }}' table.
157
+ columns:
158
+ description: Write a description of the '{{ table_name }}.{{ column_name }}' column.
159
+
160
+ ```
161
+
162
+ If nothing is set, it defaults to the following:
163
+
164
+ ```yml
165
+ defaults:
166
+ table_descriptions:
167
+ logical_name: Write a logical_name of the '{{ table_name }}' table.
168
+ columns:
169
+ description: Write a description of the '{{ table_name }}.{{ column_name }}' column.
170
+
171
+ ```
172
+
173
+ ##### table_descriptions
174
+
175
+ Set the `name` and `description` for `tables`.
176
+
177
+ Configuration | Description
178
+ --------- | ---------
179
+ logical_name | A title or one-line description to be output in the dbt `description`.
180
+ description | A detailed description of `logical_name` to be output in the dbt `description`.
181
+
182
+ Example:
183
+
184
+ ```yml
185
+ table_descriptions:
186
+ ar_internal_metadata:
187
+ logical_name: Internal Metadata
188
+ description: |-
189
+ By default Rails will store information about your Rails environment and schema
190
+ in an internal table named `ar_internal_metadata`.
191
+ columns:
192
+ key: Key
193
+ value: Value
194
+ created_at: Created At
195
+ updated_at: Updated At
196
+ schema_migrations:
197
+ logical_name: Schema Migrations
198
+ description: |-
199
+ Rails keeps track of which migrations have been committed to the database and
200
+ stores them in a neighboring table in that same database called `schema_migrations`.
201
+ columns:
202
+ version: The version number of the migration.
203
+
204
+ ```
205
+
206
+ ##### Example:
207
+
208
+ Adjust the settings according to your environment.
209
+
210
+ ```yml
211
+ sources:
212
+ name: dummy
213
+ meta:
214
+ generated_by: activerecord-dbt
215
+ description: |-
216
+ Write a description of the 'dummy' source.
217
+ You can write multiple lines.
218
+
219
+ table_overrides:
220
+ users:
221
+ loaded_at_field: created_at
222
+ freshness:
223
+ warn_after:
224
+ count: 3
225
+ period: day
226
+ error_after:
227
+ count: 5
228
+ period: day
229
+ columns:
230
+ created_at:
231
+ tests:
232
+ - not_null:
233
+ where: 'id != 1'
234
+
235
+ defaults:
236
+ table_descriptions:
237
+ logical_name: Write a logical_name of the '{{ table_name }}' table.
238
+ columns:
239
+ description: Write a description of the '{{ table_name }}.{{ column_name }}' column.
240
+
241
+ table_descriptions:
242
+ ar_internal_metadata:
243
+ logical_name: Internal Metadata
244
+ description: |-
245
+ By default Rails will store information about your Rails environment and schema
246
+ in an internal table named `ar_internal_metadata`.
247
+ columns:
248
+ key: Key
249
+ value: Value
250
+ created_at: Created At
251
+ updated_at: Updated At
252
+ schema_migrations:
253
+ logical_name: Schema Migrations
254
+ description: |-
255
+ Rails keeps track of which migrations have been committed to the database and
256
+ stores them in a neighboring table in that same database called `schema_migrations`.
257
+ columns:
258
+ version: The version number of the migration.
259
+
260
+ ```
261
+
262
+ #### Generate `#{export_directory_path}/src_#{source_name}.yml`
263
+
264
+ Generate a source file for dbt:
265
+
266
+ ```bash
267
+ $ bin/rails generate active_record:dbt:source
268
+ ```
269
+
270
+ Generate `#{export_directory_path}/src_#{source_name}.yml`.
271
+
272
+ ##### Example:
273
+
274
+ > [!NOTE]
275
+ >
276
+ > The output will be as shown below. It is recommended to indent the YAML file with a tool of your choice.
277
+
278
+ ```yaml
279
+ ---
280
+ version: 2
281
+ sources:
282
+ - name: dummy
283
+ meta:
284
+ generated_by: activerecord-dbt
285
+ description: |-
286
+ Write a description of the 'dummy' source.
287
+ You can write multiple lines.
288
+ tables:
289
+ - name: ar_internal_metadata
290
+ description: |-
291
+ # Internal Metadata
292
+ By default Rails will store information about your Rails environment and schema
293
+ in an internal table named `ar_internal_metadata`.
294
+ columns:
295
+ - name: key
296
+ description: Key
297
+ meta:
298
+ column_type: string
299
+ tests:
300
+ - unique
301
+ - not_null
302
+ - name: value
303
+ description: Value
304
+ meta:
305
+ column_type: string
306
+ - name: created_at
307
+ description: Created At
308
+ meta:
309
+ column_type: datetime
310
+ tests:
311
+ - not_null
312
+ - name: updated_at
313
+ description: Updated At
314
+ meta:
315
+ column_type: datetime
316
+ tests:
317
+ - not_null
318
+ - name: companies
319
+ description: Write a logical_name of the 'companies' table.
320
+ columns:
321
+ - name: id
322
+ description: id
323
+ meta:
324
+ column_type: integer
325
+ tests:
326
+ - unique
327
+ - not_null
328
+ - name: name
329
+ description: Write a description of the 'companies.name' column.
330
+ meta:
331
+ column_type: string
332
+ tests:
333
+ - not_null
334
+ - name: establishment_date
335
+ description: Write a description of the 'companies.establishment_date' column.
336
+ meta:
337
+ column_type: string
338
+ - name: average_age
339
+ description: Write a description of the 'companies.average_age' column.
340
+ meta:
341
+ column_type: float
342
+ - name: published
343
+ description: Write a description of the 'companies.published' column.
344
+ meta:
345
+ column_type: boolean
346
+ tests:
347
+ - not_null
348
+ - accepted_values:
349
+ values:
350
+ - true
351
+ - false
352
+ quote: false
353
+ - name: created_at
354
+ description: Created At
355
+ meta:
356
+ column_type: datetime
357
+ tests:
358
+ - not_null
359
+ - name: updated_at
360
+ description: Updated At
361
+ meta:
362
+ column_type: datetime
363
+ tests:
364
+ - not_null
365
+ - name: posts
366
+ description: Post
367
+ columns:
368
+ - name: id
369
+ description: ID
370
+ meta:
371
+ column_type: integer
372
+ tests:
373
+ - unique
374
+ - not_null
375
+ - name: user_id
376
+ description: User
377
+ meta:
378
+ column_type: integer
379
+ tests:
380
+ - not_null
381
+ - relationships:
382
+ to: source('dummy', 'users')
383
+ field: id
384
+ meta:
385
+ relationship_type: many-to-one
386
+ - name: title
387
+ description: Title
388
+ meta:
389
+ column_type: string
390
+ - name: content
391
+ description: Content
392
+ meta:
393
+ column_type: text
394
+ - name: created_at
395
+ description: Post Created At
396
+ meta:
397
+ column_type: datetime
398
+ tests:
399
+ - not_null
400
+ - name: updated_at
401
+ description: Post Updated At
402
+ meta:
403
+ column_type: datetime
404
+ tests:
405
+ - not_null
406
+ - name: status
407
+ description: Write a description of the 'posts.status' column.
408
+ meta:
409
+ column_type: integer
410
+ tests:
411
+ - accepted_values:
412
+ values:
413
+ - 0
414
+ - 1
415
+ - 2
416
+ quote: false
417
+ - name: posts_tags
418
+ description: Write a logical_name of the 'posts_tags' table.
419
+ tests:
420
+ - dbt_utils.unique_combination_of_columns:
421
+ combination_of_columns:
422
+ - post_id
423
+ - tag_id
424
+ columns:
425
+ - name: post_id
426
+ description: post_id
427
+ meta:
428
+ column_type: integer
429
+ tests:
430
+ - not_null
431
+ - relationships:
432
+ to: source('dummy', 'posts')
433
+ field: id
434
+ meta:
435
+ relationship_type: many-to-one
436
+ active_record_dbt_error:
437
+ class: NameError
438
+ message: uninitialized constant PostsTag
439
+ - name: tag_id
440
+ description: tag_id
441
+ meta:
442
+ column_type: integer
443
+ tests:
444
+ - not_null
445
+ - relationships:
446
+ to: source('dummy', 'tags')
447
+ field: id
448
+ meta:
449
+ relationship_type: many-to-one
450
+ active_record_dbt_error:
451
+ class: NameError
452
+ message: uninitialized constant PostsTag
453
+ - name: profiles
454
+ description: Write a logical_name of the 'profiles' table.
455
+ columns:
456
+ - name: id
457
+ description: id
458
+ meta:
459
+ column_type: integer
460
+ tests:
461
+ - unique
462
+ - not_null
463
+ - name: user_id
464
+ description: user_id
465
+ meta:
466
+ column_type: integer
467
+ tests:
468
+ - unique
469
+ - not_null
470
+ - relationships:
471
+ to: source('dummy', 'users')
472
+ field: id
473
+ meta:
474
+ relationship_type: one-to-one
475
+ - name: first_name
476
+ description: Write a description of the 'profiles.first_name' column.
477
+ meta:
478
+ column_type: string
479
+ tests:
480
+ - not_null
481
+ - name: last_name
482
+ description: Write a description of the 'profiles.last_name' column.
483
+ meta:
484
+ column_type: string
485
+ tests:
486
+ - not_null
487
+ - name: created_at
488
+ description: Created At
489
+ meta:
490
+ column_type: datetime
491
+ tests:
492
+ - not_null
493
+ - name: updated_at
494
+ description: Updated At
495
+ meta:
496
+ column_type: datetime
497
+ tests:
498
+ - not_null
499
+ - name: relationships
500
+ description: Write a logical_name of the 'relationships' table.
501
+ tests:
502
+ - dbt_utils.unique_combination_of_columns:
503
+ combination_of_columns:
504
+ - follower_id
505
+ - followed_id
506
+ columns:
507
+ - name: id
508
+ description: id
509
+ meta:
510
+ column_type: integer
511
+ tests:
512
+ - unique
513
+ - not_null
514
+ - name: follower_id
515
+ description: follower_id
516
+ meta:
517
+ column_type: integer
518
+ tests:
519
+ - not_null
520
+ - relationships:
521
+ to: source('dummy', 'users')
522
+ field: id
523
+ meta:
524
+ relationship_type: many-to-one
525
+ - name: followed_id
526
+ description: followed_id
527
+ meta:
528
+ column_type: integer
529
+ tests:
530
+ - not_null
531
+ - relationships:
532
+ to: source('dummy', 'users')
533
+ field: id
534
+ meta:
535
+ relationship_type: many-to-one
536
+ - name: created_at
537
+ description: Created At
538
+ meta:
539
+ column_type: datetime
540
+ tests:
541
+ - not_null
542
+ - name: updated_at
543
+ description: Updated At
544
+ meta:
545
+ column_type: datetime
546
+ tests:
547
+ - not_null
548
+ - name: schema_migrations
549
+ description: |-
550
+ # Schema Migrations
551
+ Rails keeps track of which migrations have been committed to the database and
552
+ stores them in a neighboring table in that same database called `schema_migrations`.
553
+ columns:
554
+ - name: version
555
+ description: The version number of the migration.
556
+ meta:
557
+ column_type: string
558
+ tests:
559
+ - unique
560
+ - not_null
561
+ - name: tags
562
+ description: Write a logical_name of the 'tags' table.
563
+ columns:
564
+ - name: id
565
+ description: id
566
+ meta:
567
+ column_type: integer
568
+ tests:
569
+ - unique
570
+ - not_null
571
+ - name: name
572
+ description: Write a description of the 'tags.name' column.
573
+ meta:
574
+ column_type: string
575
+ tests:
576
+ - unique
577
+ - not_null
578
+ - name: created_at
579
+ description: Created At
580
+ meta:
581
+ column_type: datetime
582
+ tests:
583
+ - not_null
584
+ - name: updated_at
585
+ description: Updated At
586
+ meta:
587
+ column_type: datetime
588
+ tests:
589
+ - not_null
590
+ - name: user_tags
591
+ description: Write a logical_name of the 'user_tags' table.
592
+ tests:
593
+ - dbt_utils.unique_combination_of_columns:
594
+ combination_of_columns:
595
+ - user_id
596
+ - tag_id
597
+ columns:
598
+ - name: id
599
+ description: id
600
+ meta:
601
+ column_type: integer
602
+ tests:
603
+ - unique
604
+ - not_null
605
+ - name: user_id
606
+ description: user_id
607
+ meta:
608
+ column_type: integer
609
+ tests:
610
+ - not_null
611
+ - relationships:
612
+ to: source('dummy', 'users')
613
+ field: id
614
+ meta:
615
+ relationship_type: many-to-one
616
+ - name: tag_id
617
+ description: tag_id
618
+ meta:
619
+ column_type: integer
620
+ tests:
621
+ - not_null
622
+ - relationships:
623
+ to: source('dummy', 'tags')
624
+ field: id
625
+ meta:
626
+ relationship_type: many-to-one
627
+ - name: created_at
628
+ description: Created At
629
+ meta:
630
+ column_type: datetime
631
+ tests:
632
+ - not_null
633
+ - name: updated_at
634
+ description: Updated At
635
+ meta:
636
+ column_type: datetime
637
+ tests:
638
+ - not_null
639
+ - name: users
640
+ description: User
641
+ loaded_at_field: created_at
642
+ freshness:
643
+ warn_after:
644
+ count: 3
645
+ period: day
646
+ error_after:
647
+ count: 5
648
+ period: day
649
+ columns:
650
+ - name: id
651
+ description: ID
652
+ meta:
653
+ column_type: integer
654
+ tests:
655
+ - unique
656
+ - not_null
657
+ - name: created_at
658
+ description: User Created At
659
+ meta:
660
+ column_type: datetime
661
+ tests:
662
+ - not_null:
663
+ where: id != 1
664
+ - name: updated_at
665
+ description: User Updated At
666
+ meta:
667
+ column_type: datetime
668
+ tests:
669
+ - not_null
670
+ - name: company_id
671
+ description: company_id
672
+ meta:
673
+ column_type: integer
674
+ tests:
675
+ - relationships:
676
+ to: source('dummy', 'companies')
677
+ field: id
678
+ meta:
679
+ relationship_type: many-to-one
680
+
681
+ ```
682
+
683
+ ### Generate dbt Staging Files
684
+
685
+ #### dbt Staging Configuration
686
+
687
+ In the `#{config_directory_path}/staging_model.sql.tt` file, write the SQL template for the `staging` model you want to create.
688
+ You can use `sql.source_name`, `sql.table_name`, `sql.select_column_names`, `sql.primary_key_eql_id?`, and `sql.rename_primary_id` within this file.
689
+
690
+ Example:
691
+
692
+ ```sql
693
+ with
694
+
695
+ source as (
696
+
697
+ select * from {{ source('<%= sql.source_name %>', '<%= sql.table_name %>') }}
698
+
699
+ ),
700
+
701
+ renamed as (
702
+
703
+ select
704
+
705
+ <%- sql.select_column_names.each_with_index do |(column_type, columns), column_type_index| -%>
706
+ -- <%= column_type %>
707
+ <%- columns.each_with_index do |column, column_index| -%>
708
+ <%- is_rename_primary_id = sql.primary_key_eql_id? && sql.primary_key?(column.name) -%>
709
+ <%- is_last_column = column_type_index == sql.select_column_names.size - 1 && column_index == columns.size - 1 -%>
710
+ <%= is_rename_primary_id ? "id as #{sql.rename_primary_id}" : column.name %><% unless is_last_column -%>,<%- end %>
711
+ <%- if column_type_index != sql.select_column_names.size - 1 && column_index == columns.size - 1 -%>
712
+
713
+ <%- end -%>
714
+ <%- end -%>
715
+ <%- end -%>
716
+
717
+ from source
718
+
719
+ )
720
+
721
+ select * from renamed
722
+
723
+ ```
724
+
725
+ Different Pattern:
726
+
727
+ ```sql
728
+ #standardSQL
729
+
730
+ with source as (
731
+ select
732
+ <%- if sql.primary_key_eql_id? -%>
733
+ id as <%= sql.rename_primary_id %>
734
+ , * except(id)
735
+ <%- else -%>
736
+ *
737
+ <%- end -%>
738
+ from {{ source('<%= sql.source_name %>', '<%= sql.table_name %>') }}
739
+ )
740
+
741
+ , final as (
742
+ select
743
+ <%- sql.select_column_names.each_with_index do |(column_type, columns), column_type_index| -%>
744
+ -- <%= column_type %>
745
+ <%- columns.each_with_index do |column, column_index| -%>
746
+ <% unless column_type_index == 0 && column_index == 0 -%>, <%- end %><%= (sql.primary_key_eql_id? && sql.primary_key?(column.name) ? sql.rename_primary_id : column.name) %>
747
+ <%- if column_type_index != sql.select_column_names.size - 1 && column_index == columns.size - 1 -%>
748
+
749
+ <%- end -%>
750
+ <%- end -%>
751
+ <%- end -%>
752
+ from source
753
+ )
754
+
755
+ select
756
+ *
757
+ from final
758
+
759
+ ```
760
+
761
+ #### Generate dbt Staging Files
762
+
763
+ Generate staging model files for dbt:
764
+
765
+ ```bash
766
+ $ bin/rails generate active_record:dbt:staging_model TABLE_NAME
767
+ ```
768
+
769
+ Generate staging model files for dbt that reference the specified `TABLE_NAME`.
770
+
771
+ File | Description
772
+ --------- | ---------
773
+ `#{export_directory_path}/stg_#{source_name}__#{table_name}.sql` | Staging model file for dbt.
774
+ `#{export_directory_path}/stg_#{source_name}__#{table_name}.yml` | Staging model documentation file for dbt.
775
+
776
+ Example:
777
+
778
+ ```bash
779
+ $ bin/rails generate active_record:dbt:staging_model profiles
780
+ ```
781
+
782
+ ##### Generate `#{export_directory_path}/stg_#{source_name}__#{table_name}.sql`
783
+
784
+ Example:
785
+
786
+ ```sql
787
+ with
788
+
789
+ source as (
790
+
791
+ select * from {{ source('dummy', 'profiles') }}
792
+
793
+ ),
794
+
795
+ renamed as (
796
+
797
+ select
798
+
799
+ -- ids
800
+ id as profile_id,
801
+ user_id,
802
+
803
+ -- strings
804
+ first_name,
805
+ last_name,
806
+
807
+ -- datetimes
808
+ created_at,
809
+ updated_at
810
+
811
+ from source
812
+
813
+ )
814
+
815
+ select * from renamed
816
+
817
+ ```
818
+
819
+ Different Pattern:
820
+
821
+ ```sql
822
+ #standardSQL
823
+
824
+ with source as (
825
+ select
826
+ id as profile_id
827
+ , * except(id)
828
+ from {{ source('dummy', 'profiles') }}
829
+ )
830
+
831
+ , final as (
832
+ select
833
+ -- ids
834
+ profile_id
835
+ , user_id
836
+
837
+ -- strings
838
+ , first_name
839
+ , last_name
840
+
841
+ -- datetimes
842
+ , created_at
843
+ , updated_at
844
+ from source
845
+ )
846
+
847
+ select
848
+ *
849
+ from final
850
+
851
+ ```
852
+
853
+ ##### Generate `#{export_directory_path}/stg_#{source_name}__#{table_name}.yml`
854
+
855
+ Example:
856
+
857
+ ```yaml
858
+ ---
859
+ version: 2
860
+ models:
861
+ - name: stg_dummy__profiles
862
+ description: Write a logical_name of the 'profiles' table.
863
+ columns:
864
+ - name: profile_id
865
+ description: profile_id
866
+ meta:
867
+ column_type: integer
868
+ tests:
869
+ - unique
870
+ - not_null
871
+ - relationships:
872
+ to: source('dummy', 'profiles')
873
+ field: id
874
+ meta:
875
+ relationship_type: one-to-one
876
+ - name: user_id
877
+ description: user_id
878
+ meta:
879
+ column_type: integer
880
+ tests:
881
+ - unique
882
+ - not_null
883
+ - relationships:
884
+ to: source('dummy', 'users')
885
+ field: id
886
+ meta:
887
+ relationship_type: one-to-one
888
+ - name: first_name
889
+ description: Write a description of the 'profiles.first_name' column.
890
+ meta:
891
+ column_type: string
892
+ tests:
893
+ - not_null
894
+ - name: last_name
895
+ description: Write a description of the 'profiles.last_name' column.
896
+ meta:
897
+ column_type: string
898
+ tests:
899
+ - not_null
900
+ - name: created_at
901
+ description: Created At
902
+ meta:
903
+ column_type: datetime
904
+ tests:
905
+ - not_null
906
+ - name: updated_at
907
+ description: Updated At
908
+ meta:
909
+ column_type: datetime
910
+ tests:
911
+ - not_null
912
+
913
+ ```
914
+
915
+ ## Contributing
916
+
917
+ Contribution directions go here.
918
+
919
+ ## License
920
+
921
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).