chrono_model 1.2.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +19 -20
  3. data/README.md +62 -40
  4. data/lib/active_record/connection_adapters/chronomodel_adapter.rb +17 -11
  5. data/lib/active_record/tasks/chronomodel_database_tasks.rb +64 -23
  6. data/lib/chrono_model/adapter/ddl.rb +168 -153
  7. data/lib/chrono_model/adapter/indexes.rb +99 -94
  8. data/lib/chrono_model/adapter/migrations.rb +81 -104
  9. data/lib/chrono_model/adapter/migrations_modules/legacy.rb +41 -0
  10. data/lib/chrono_model/adapter/migrations_modules/stable.rb +41 -0
  11. data/lib/chrono_model/adapter/tsrange.rb +20 -5
  12. data/lib/chrono_model/adapter/upgrade.rb +89 -91
  13. data/lib/chrono_model/adapter.rb +64 -31
  14. data/lib/chrono_model/chrono.rb +17 -0
  15. data/lib/chrono_model/conversions.rb +15 -9
  16. data/lib/chrono_model/db_console.rb +9 -0
  17. data/lib/chrono_model/json.rb +9 -6
  18. data/lib/chrono_model/patches/as_of_time_holder.rb +2 -2
  19. data/lib/chrono_model/patches/as_of_time_relation.rb +2 -2
  20. data/lib/chrono_model/patches/association.rb +15 -12
  21. data/lib/chrono_model/patches/batches.rb +17 -0
  22. data/lib/chrono_model/patches/db_console.rb +20 -4
  23. data/lib/chrono_model/patches/join_node.rb +4 -4
  24. data/lib/chrono_model/patches/preloader.rb +41 -11
  25. data/lib/chrono_model/patches/relation.rb +53 -8
  26. data/lib/chrono_model/patches.rb +3 -1
  27. data/lib/chrono_model/railtie.rb +29 -24
  28. data/lib/chrono_model/time_gate.rb +3 -3
  29. data/lib/chrono_model/time_machine/history_model.rb +65 -31
  30. data/lib/chrono_model/time_machine/time_query.rb +65 -49
  31. data/lib/chrono_model/time_machine/timeline.rb +52 -28
  32. data/lib/chrono_model/time_machine.rb +66 -25
  33. data/lib/chrono_model/utilities.rb +3 -3
  34. data/lib/chrono_model/version.rb +3 -1
  35. data/lib/chrono_model.rb +31 -36
  36. metadata +39 -136
  37. data/.gitignore +0 -21
  38. data/.rspec +0 -2
  39. data/.travis.yml +0 -41
  40. data/Gemfile +0 -4
  41. data/README.sql +0 -161
  42. data/Rakefile +0 -25
  43. data/chrono_model.gemspec +0 -33
  44. data/gemfiles/rails_5.0.gemfile +0 -6
  45. data/gemfiles/rails_5.1.gemfile +0 -6
  46. data/gemfiles/rails_5.2.gemfile +0 -6
  47. data/spec/aruba/dbconsole_spec.rb +0 -25
  48. data/spec/aruba/fixtures/database_with_default_username_and_password.yml +0 -14
  49. data/spec/aruba/fixtures/database_without_username_and_password.yml +0 -11
  50. data/spec/aruba/fixtures/empty_structure.sql +0 -27
  51. data/spec/aruba/fixtures/migrations/56/20160812190335_create_impressions.rb +0 -10
  52. data/spec/aruba/fixtures/migrations/56/20171115195229_add_temporal_extension_to_impressions.rb +0 -10
  53. data/spec/aruba/fixtures/railsapp/config/application.rb +0 -17
  54. data/spec/aruba/fixtures/railsapp/config/boot.rb +0 -5
  55. data/spec/aruba/fixtures/railsapp/config/environments/development.rb +0 -38
  56. data/spec/aruba/migrations_spec.rb +0 -48
  57. data/spec/aruba/rake_task_spec.rb +0 -71
  58. data/spec/chrono_model/adapter/base_spec.rb +0 -157
  59. data/spec/chrono_model/adapter/ddl_spec.rb +0 -243
  60. data/spec/chrono_model/adapter/indexes_spec.rb +0 -72
  61. data/spec/chrono_model/adapter/migrations_spec.rb +0 -312
  62. data/spec/chrono_model/conversions_spec.rb +0 -43
  63. data/spec/chrono_model/history_models_spec.rb +0 -32
  64. data/spec/chrono_model/json_ops_spec.rb +0 -59
  65. data/spec/chrono_model/time_machine/as_of_spec.rb +0 -188
  66. data/spec/chrono_model/time_machine/changes_spec.rb +0 -50
  67. data/spec/chrono_model/time_machine/counter_cache_race_spec.rb +0 -46
  68. data/spec/chrono_model/time_machine/default_scope_spec.rb +0 -37
  69. data/spec/chrono_model/time_machine/history_spec.rb +0 -104
  70. data/spec/chrono_model/time_machine/keep_cool_spec.rb +0 -27
  71. data/spec/chrono_model/time_machine/manipulations_spec.rb +0 -84
  72. data/spec/chrono_model/time_machine/model_identification_spec.rb +0 -46
  73. data/spec/chrono_model/time_machine/sequence_spec.rb +0 -74
  74. data/spec/chrono_model/time_machine/sti_spec.rb +0 -100
  75. data/spec/chrono_model/time_machine/time_query_spec.rb +0 -261
  76. data/spec/chrono_model/time_machine/timeline_spec.rb +0 -63
  77. data/spec/chrono_model/time_machine/timestamps_spec.rb +0 -43
  78. data/spec/chrono_model/time_machine/transactions_spec.rb +0 -69
  79. data/spec/config.travis.yml +0 -5
  80. data/spec/config.yml.example +0 -9
  81. data/spec/spec_helper.rb +0 -33
  82. data/spec/support/adapter/helpers.rb +0 -53
  83. data/spec/support/adapter/structure.rb +0 -44
  84. data/spec/support/aruba.rb +0 -44
  85. data/spec/support/connection.rb +0 -70
  86. data/spec/support/matchers/base.rb +0 -56
  87. data/spec/support/matchers/column.rb +0 -99
  88. data/spec/support/matchers/function.rb +0 -79
  89. data/spec/support/matchers/index.rb +0 -69
  90. data/spec/support/matchers/schema.rb +0 -39
  91. data/spec/support/matchers/table.rb +0 -275
  92. data/spec/support/time_machine/helpers.rb +0 -47
  93. data/spec/support/time_machine/structure.rb +0 -111
  94. data/sql/json_ops.sql +0 -56
  95. data/sql/uninstall-json_ops.sql +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa9d6f8ee80241092713836e372cf3cb568639e403511ba2c48ba33275f6c1a8
4
- data.tar.gz: '055794bce8014501e3eea0a180abe04278f1aba62015d3f5b98d75499c6faba1'
3
+ metadata.gz: e9dc931f360178771e212906ec3a02d1ff49ffc2393b457a7f531b101bc1e8ce
4
+ data.tar.gz: 7606b75d5eaf453e0d0f90c760607af50bdf862744f7048cc2c8061f41018bc5
5
5
  SHA512:
6
- metadata.gz: 380cbab091ab178aea031fee4e8343797a5e461e98b233a8c732b7cc0f9bd584497fa3b1bcc8703f6d8b74b972aeed2a257f6aba9ca7a2d932b4e72e7c211506
7
- data.tar.gz: c601c91ce05f426aef3c75b37ba9920170666523abff9b219ab09816e6c17f42146131d5ffcc89d233d5d7ec94d6ac5592e6a8160dd8207b9a48c3ff51feb629
6
+ metadata.gz: e64bea647172199e03703f0f4be8538d48276a8cb02fedb2309a68913ed6dad910d01f9ed4498fe345119ff1a12e25a0dda16f2b5976a0cb1b587dc4548eef4a
7
+ data.tar.gz: e326f5fce5a0fc94df9e23618840edb6baeaf307e85bbb3449fad7540cd85863be533caca5e30d073fc880a2759ce21ceed74f471dbba4959ead30e9ce43e5b5
data/LICENSE CHANGED
@@ -1,24 +1,23 @@
1
- Copyright (c) 2012-2014 Marcello Barnaba <m.barnaba@ifad.org>
2
- Copyright (c) 2012-2014 Peter J. Brindisi <p.brindisi@ifad.org>
3
- Copyright (c) 2012-2014 IFAD
4
-
5
1
  MIT License
6
2
 
7
- Permission is hereby granted, free of charge, to any person obtaining
8
- a copy of this software and associated documentation files (the
9
- "Software"), to deal in the Software without restriction, including
10
- without limitation the rights to use, copy, modify, merge, publish,
11
- distribute, sublicense, and/or sell copies of the Software, and to
12
- permit persons to whom the Software is furnished to do so, subject to
13
- the following conditions:
3
+ Copyright (c) 2012-2022 Marcello Barnaba <m.barnaba@ifad.org>
4
+ Copyright (c) 2012-2022 Peter J. Brindisi <p.brindisi@ifad.org>
5
+ Copyright (c) 2012-2022 IFAD
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
14
13
 
15
- The above copyright notice and this permission notice shall be
16
- included in all copies or substantial portions of the Software.
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
17
16
 
18
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
data/README.md CHANGED
@@ -1,12 +1,13 @@
1
1
  # Temporal database system on PostgreSQL using [updatable views][pg-updatable-views], [table inheritance][pg-table-inheritance] and [INSTEAD OF triggers][pg-instead-of-triggers].
2
2
 
3
3
  [![Build Status][build-status-badge]][build-status]
4
+ [![Legacy Build Status][legacy-build-status-badge]][build-status]
4
5
  [![Code Climate][code-analysis-badge]][code-analysis]
5
6
  [![Test Coverage][test-coverage-badge]][test-coverage]
6
7
  [![Gem Version][gem-version-badge]][gem-version]
7
8
  [![Inlinedocs][docs-analysis-badge]][docs-analysis]
8
9
 
9
- ![{A Delorean that we all love}][delorean-image]
10
+ ![A Delorean that we all love][delorean-image]
10
11
 
11
12
  ChronoModel implements what Oracle sells as "Flashback Queries", with standard
12
13
  SQL on free PostgreSQL. Academically speaking, ChronoModel implements a
@@ -62,8 +63,8 @@ All timestamps are _forcibly_ stored in as UTC, bypassing the
62
63
 
63
64
  ## Requirements
64
65
 
65
- * Ruby >= 2.3
66
- * Active Record >= 5.0. See the [detailed supported versions matrix on travis](https://travis-ci.org/ifad/chronomodel)
66
+ * Ruby >= 2.2.2
67
+ * Active Record >= 5.0. See the [detailed supported versions matrix on Ruby GitHub Actions workflows](https://github.com/ifad/chronomodel/blob/master/.github/workflows)
67
68
  * PostgreSQL >= 9.4 (legacy support for 9.3)
68
69
  * The `btree_gist` PostgreSQL extension
69
70
 
@@ -96,6 +97,13 @@ development:
96
97
  username: ...
97
98
  ```
98
99
 
100
+ Configure Active Record in your `config/application.rb` to use the `:sql` schema
101
+ format:
102
+
103
+ ```rb
104
+ config.active_record.schema_format = :sql
105
+ ```
106
+
99
107
  ## Schema creation
100
108
 
101
109
  ChronoModel hooks all `ActiveRecord::Migration` methods to make them temporal
@@ -141,7 +149,7 @@ validity from midnight, January 1st, 1 CE. You can set a specific validity with
141
149
  the `:validity` option:
142
150
 
143
151
  ```ruby
144
- change_table :your_table, :temporal => true, :copy_data => true, :validity => '1977-01-01'
152
+ change_table :your_table, temporal: true, copy_data: true, validity: '1977-01-01'
145
153
  ```
146
154
 
147
155
  Please note that `change_table` requires you to use *old_style* `up` and
@@ -156,9 +164,9 @@ history.
156
164
  You can also choose which fields are to be journaled, passing the following
157
165
  options to `create_table`:
158
166
 
159
- * `:journal => %w( fld1 fld2 .. .. )` - record changes in the history only when changing specified fields
160
- * `:no_journal => %w( fld1 fld2 .. )` - do not record changes to the specified fields
161
- * `:full_journal => true` - record changes to *all* fields, including `updated_at`.
167
+ * `journal: %w( fld1 fld2 .. .. )` - record changes in the history only when changing specified fields
168
+ * `no_journal: %w( fld1 fld2 .. )` - do not record changes to the specified fields
169
+ * `full_journal: true` - record changes to *all* fields, including `updated_at`.
162
170
 
163
171
  These options are stored as JSON in the [COMMENT][pg-comment] area of the
164
172
  public view, alongside with the ChronoModel version that created them.
@@ -195,7 +203,7 @@ to your `create_table`. Example:
195
203
  Include the `ChronoModel::TimeMachine` module in your model.
196
204
 
197
205
  ```ruby
198
- module Country < ActiveRecord::Base
206
+ class Country < ActiveRecord::Base
199
207
  include ChronoModel::TimeMachine
200
208
 
201
209
  has_many :compositions
@@ -334,7 +342,7 @@ ChronoModel::Json.create
334
342
  ## Caveats
335
343
 
336
344
  * Rails 4+ support requires disabling tsrange parsing support, as it
337
- [is broken][r4-tsrange-broken] and [incomplete][r4-tsrange-incomplete]
345
+ [is broken][r4-tsrange-broken] and [incomplete][r4-tsrange-incomplete]
338
346
  as of now, mainly due to a [design clash with ruby][pg-tsrange-and-ruby].
339
347
 
340
348
  * The triggers and temporal indexes cannot be saved in schema.rb. The AR
@@ -345,14 +353,24 @@ ChronoModel::Json.create
345
353
  `db:structure:load`.
346
354
  Two helper tasks are also added, `db:data:dump` and `db:data:load`.
347
355
 
348
- * The choice of using subqueries instead of [Common Table Expressions]
349
- [pg-ctes] was dictated by the fact that CTEs [currently act as an
350
- optimization fence][pg-cte-optimization-fence].
356
+ * The choice of using subqueries instead of [Common Table Expressions][pg-ctes]
357
+ was dictated by the fact that CTEs [currently act as an optimization
358
+ fence][pg-cte-optimization-fence].
351
359
  If it will be possible [to opt-out of the fence][pg-cte-opt-out-fence]
352
360
  in the future, they will be probably be used again as they were [in the
353
361
  past][cm-cte-impl], because the resulting queries were more readable,
354
362
  and do not inhibit using `.from()` on the `AR::Relation`.
355
363
 
364
+ * Foreign keys are not supported. [See issue #174][gh-issue-174]
365
+
366
+ * There may be unexpected results when combining eager loading and joins.
367
+ [See issue #186][gh-issue-186]
368
+
369
+ * Global ID ignores historical objects. [See issue #192][gh-issue-192]
370
+
371
+ * Different historical objects are considered the identical. [See issue
372
+ #206][gh-issue-206]
373
+
356
374
 
357
375
  ## Contributing
358
376
 
@@ -376,41 +394,41 @@ while using it in many important projects.
376
394
  This software is Made in Italy :it: :smile:.
377
395
 
378
396
 
379
- [build-status]: https://travis-ci.org/ifad/chronomodel
380
- [build-status-badge]: https://travis-ci.org/ifad/chronomodel.svg
381
- [code-analysis]: https://codeclimate.com/github/ifad/chronomodel
382
- [code-analysis-badge]: https://codeclimate.com/github/ifad/chronomodel.svg
383
- [docs-analysis]: http://inch-ci.org/github/ifad/chronomodel
384
- [docs-analysis-badge]: http://inch-ci.org/github/ifad/chronomodel.svg?branch=master
397
+ [build-status]: https://github.com/ifad/chronomodel/actions
398
+ [build-status-badge]: https://github.com/ifad/chronomodel/actions/workflows/ruby.yml/badge.svg
399
+ [code-analysis]: https://codeclimate.com/github/ifad/chronomodel/maintainability
400
+ [code-analysis-badge]: https://api.codeclimate.com/v1/badges/cdee7327938dc2eaff99/maintainability
401
+ [docs-analysis]: https://inch-ci.org/github/ifad/chronomodel
402
+ [docs-analysis-badge]: https://inch-ci.org/github/ifad/chronomodel.svg?branch=master
385
403
  [gem-version]: https://rubygems.org/gems/chrono_model
386
404
  [gem-version-badge]: https://badge.fury.io/rb/chrono_model.svg
405
+ [legacy-build-status-badge]: https://github.com/ifad/chronomodel/actions/workflows/legacy_ruby.yml/badge.svg
387
406
  [test-coverage]: https://codeclimate.com/github/ifad/chronomodel
388
407
  [test-coverage-badge]: https://codeclimate.com/github/ifad/chronomodel/badges/coverage.svg
389
408
 
390
409
  [delorean-image]: https://i.imgur.com/DD77F4s.jpg
391
- [rebelle-society]: http://www.rebellesociety.com/2012/10/11/the-writers-way-week-two-facing-procrastination/chronos_oeuvre_grand1/
392
-
393
- [wp-scd-2]: http://en.wikipedia.org/wiki/Slowly_changing_dimension#Type_2
394
- [wp-scd-4]: http://en.wikipedia.org/wiki/Slowly_changing_dimension#Type_4
395
-
396
- [pg-updatable-views]: http://www.postgresql.org/docs/9.4/static/sql-createview.html#SQL-CREATEVIEW-UPDATABLE-VIEWS
397
- [pg-table-inheritance]: http://www.postgresql.org/docs/9.4/static/ddl-inherit.html
398
- [pg-instead-of-triggers]: http://www.postgresql.org/docs/9.4/static/sql-createtrigger.html
399
- [pg-triggers]: http://www.postgresql.org/docs/9.4/static/trigger-definition.html
400
- [pg-schema]: http://www.postgresql.org/docs/9.4/static/ddl-schemas.html
401
- [pg-current-timestamp]: http://www.postgresql.org/docs/9.4/interactive/functions-datetime.html#FUNCTIONS-DATETIME-TABLE
402
- [pg-partitioning]: http://www.postgresql.org/docs/9.4/static/ddl-partitioning.html
403
- [pg-partitioning-excl-constraints]: http://www.postgresql.org/docs/9.4/static/ddl-partitioning.html#DDL-PARTITIONING-CONSTRAINT-EXCLUSION
404
- [pg-gist-indexes]: http://www.postgresql.org/docs/9.4/static/gist.html
405
- [pg-exclusion-constraints]: http://www.postgresql.org/docs/9.4/static/sql-createtable.html#SQL-CREATETABLE-EXCLUDE
406
- [pg-btree-gist]: http://www.postgresql.org/docs/9.4/static/btree-gist.html
407
- [pg-comment]: http://www.postgresql.org/docs/9.4/static/sql-comment.html
410
+
411
+ [wp-scd-2]: https://en.wikipedia.org/wiki/Slowly_changing_dimension#Type_2
412
+ [wp-scd-4]: https://en.wikipedia.org/wiki/Slowly_changing_dimension#Type_4
413
+
414
+ [pg-updatable-views]: https://www.postgresql.org/docs/9.4/sql-createview.html#SQL-CREATEVIEW-UPDATABLE-VIEWS
415
+ [pg-table-inheritance]: https://www.postgresql.org/docs/9.4/ddl-inherit.html
416
+ [pg-instead-of-triggers]: https://www.postgresql.org/docs/9.4/sql-createtrigger.html
417
+ [pg-triggers]: https://www.postgresql.org/docs/9.4/trigger-definition.html
418
+ [pg-schema]: https://www.postgresql.org/docs/9.4/ddl-schemas.html
419
+ [pg-current-timestamp]: https://www.postgresql.org/docs/9.4/functions-datetime.html#FUNCTIONS-DATETIME-TABLE
420
+ [pg-partitioning]: https://www.postgresql.org/docs/9.4/ddl-partitioning.html
421
+ [pg-partitioning-excl-constraints]: https://www.postgresql.org/docs/9.4/ddl-partitioning.html#DDL-PARTITIONING-CONSTRAINT-EXCLUSION
422
+ [pg-gist-indexes]: https://www.postgresql.org/docs/9.4/gist.html
423
+ [pg-exclusion-constraints]: https://www.postgresql.org/docs/9.4/sql-createtable.html#SQL-CREATETABLE-EXCLUDE
424
+ [pg-btree-gist]: https://www.postgresql.org/docs/9.4/btree-gist.html
425
+ [pg-comment]: https://www.postgresql.org/docs/9.4/sql-comment.html
408
426
  [pg-tsrange-and-ruby]: https://bugs.ruby-lang.org/issues/6864
409
- [pg-ctes]: http://www.postgresql.org/docs/9.4/static/queries-with.html
410
- [pg-cte-optimization-fence]: http://archives.postgresql.org/pgsql-hackers/2012-09/msg00700.php
411
- [pg-cte-opt-out-fence]: http://archives.postgresql.org/pgsql-hackers/2012-10/msg00024.php
412
- [pg-json-type]: http://www.postgresql.org/docs/9.4/static/datatype-json.html
413
- [pg-json-func]: http://www.postgresql.org/docs/9.4/static/functions-json.html
427
+ [pg-ctes]: https://www.postgresql.org/docs/9.4/queries-with.html
428
+ [pg-cte-optimization-fence]: https://www.postgresql.org/message-id/201209191305.44674.db@kavod.com
429
+ [pg-cte-opt-out-fence]: https://www.postgresql.org/message-id/CAHyXU0zpM5+Dsb_pKxDmm-ZoWUAt=SkHHaiK_DBqcmtxTas6Nw@mail.gmail.com
430
+ [pg-json-type]: https://www.postgresql.org/docs/9.4/datatype-json.html
431
+ [pg-json-func]: https://www.postgresql.org/docs/9.4/functions-json.html
414
432
  [pg-json-opclass]: https://github.com/ifad/chronomodel/blob/master/sql/json_ops.sql
415
433
 
416
434
  [r4-tsrange-broken]: https://github.com/rails/rails/pull/13793#issuecomment-34608093
@@ -421,3 +439,7 @@ This software is Made in Italy :it: :smile:.
421
439
  [cm-cte-impl]: https://github.com/ifad/chronomodel/commit/18f4c4b
422
440
 
423
441
  [gh-pzac]: https://github.com/pzac
442
+ [gh-issue-174]: https://github.com/ifad/chronomodel/issues/174
443
+ [gh-issue-186]: https://github.com/ifad/chronomodel/issues/186
444
+ [gh-issue-192]: https://github.com/ifad/chronomodel/issues/192
445
+ [gh-issue-206]: https://github.com/ifad/chronomodel/issues/206
@@ -1,13 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'chrono_model'
2
4
 
3
5
  module ActiveRecord
6
+ # TODO: Remove when dropping Rails < 7.2 compatibility
4
7
  module ConnectionHandling
8
+ def chronomodel_adapter_class
9
+ ChronoModel::Adapter
10
+ end
5
11
 
6
12
  # Install the new adapter in ActiveRecord. This approach is required because
7
13
  # the PG adapter defines +add_column+ itself, thus making impossible to use
8
14
  # super() in overridden Module methods.
9
15
  #
10
16
  def chronomodel_connection(config) # :nodoc:
17
+ return chronomodel_adapter_class.new(config) if ActiveRecord::VERSION::STRING >= '7.1'
18
+
11
19
  conn_params = config.symbolize_keys
12
20
 
13
21
  conn_params.delete_if { |_, v| v.nil? }
@@ -20,24 +28,22 @@ module ActiveRecord
20
28
  valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
21
29
  conn_params.slice!(*valid_conn_param_keys)
22
30
 
23
- # The postgres drivers don't allow the creation of an unconnected PG::Connection object,
24
- # so just pass a nil connection object for the time being.
25
- adapter = ChronoModel::Adapter.new(nil, logger, conn_params, config)
31
+ conn = PG.connect(conn_params) if ActiveRecord::VERSION::MAJOR >= 6
32
+
33
+ adapter = ChronoModel::Adapter.new(conn, logger, conn_params, config)
26
34
 
27
35
  unless adapter.chrono_supported?
28
- raise ChronoModel::Error, "Your database server is not supported by ChronoModel. "\
29
- "Currently, only PostgreSQL >= 9.3 is supported."
36
+ raise ChronoModel::Error, 'Your database server is not supported by ChronoModel. ' \
37
+ 'Currently, only PostgreSQL >= 9.3 is supported.'
30
38
  end
31
39
 
32
40
  adapter.chrono_setup!
33
41
 
34
- return adapter
35
- end
42
+ adapter
43
+ rescue ::PG::Error => e
44
+ raise ActiveRecord::NoDatabaseError if e.message.include?(conn_params[:dbname])
36
45
 
37
- module Connectionadapters
38
- ChronoModelAdapter = ::ChronoModel::Adapter
46
+ raise
39
47
  end
40
-
41
48
  end
42
49
  end
43
-
@@ -1,11 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Tasks
3
5
  class ChronomodelDatabaseTasks < PostgreSQLDatabaseTasks
6
+ CHRONOMODEL_SCHEMAS = [
7
+ ChronoModel::Adapter::TEMPORAL_SCHEMA,
8
+ ChronoModel::Adapter::HISTORY_SCHEMA
9
+ ].freeze
4
10
 
5
11
  def structure_dump(*arguments)
6
-
7
- with_chronomodel_schema_search_path do
8
- super(*arguments)
12
+ if schema_search_path.present?
13
+ with_chronomodel_schema_search_path { super }
14
+ else
15
+ super
9
16
  end
10
17
 
11
18
  # The structure.sql includes CREATE SCHEMA statements, but as these are executed
@@ -18,55 +25,82 @@ module ActiveRecord
18
25
  sql = File.read(filename).gsub(/CREATE SCHEMA (?!IF NOT EXISTS)/, '\&IF NOT EXISTS ')
19
26
  File.open(filename, 'w') { |file| file << sql }
20
27
 
21
- remove_sql_header_comments(filename)
28
+ remove_sql_header_comments(filename) if ActiveRecord::VERSION::STRING < '5.1'
22
29
  end
23
30
 
24
31
  def data_dump(target)
25
- set_psql_env
32
+ psql_env
26
33
 
27
- args = ['-c', '-f', target]
28
- args << configuration['database']
34
+ args = ['-c', '-f', target.to_s]
35
+ args << chronomodel_configuration[:database]
29
36
 
30
- run_cmd "pg_dump", args, 'dumping data'
37
+ run_cmd 'pg_dump', args, 'dumping data'
31
38
  end
32
39
 
33
40
  def data_load(source)
34
- set_psql_env
41
+ psql_env
35
42
 
36
43
  args = ['-f', source]
37
- args << configuration['database']
44
+ args << chronomodel_configuration[:database]
38
45
 
39
- run_cmd "psql", args, 'loading data'
46
+ run_cmd 'psql', args, 'loading data'
40
47
  end
41
48
 
42
49
  private
43
50
 
51
+ # In Rails 6.1.x the configuration instance variable is not available
52
+ # and it's been replaced by @configuration_hash (which is frozen).
53
+ def chronomodel_configuration
54
+ @chronomodel_configuration ||=
55
+ if defined?(@configuration_hash)
56
+ @configuration_hash
57
+ else
58
+ configuration.with_indifferent_access
59
+ end
60
+ end
61
+
44
62
  # If a schema search path is defined in the configuration file, it will
45
63
  # be used by the database tasks class to dump only the specified search
46
64
  # path. Here we add also ChronoModel's temporal and history schemas to
47
65
  # the search path and yield.
48
66
  #
49
67
  def with_chronomodel_schema_search_path
50
- original_schema_search_path = configuration['schema_search_path']
51
-
52
- if original_schema_search_path.present?
53
- configuration['schema_search_path'] = original_schema_search_path.split(',').concat([
54
- ChronoModel::Adapter::TEMPORAL_SCHEMA,
55
- ChronoModel::Adapter::HISTORY_SCHEMA
56
- ]).join(',')
57
- end
68
+ patch_configuration!
58
69
 
59
70
  yield
60
-
61
71
  ensure
62
- configuration['schema_search_path'] = original_schema_search_path
72
+ reset_configuration!
63
73
  end
64
74
 
65
- unless method_defined? :remove_sql_header_comments
75
+ def patch_configuration!
76
+ @original_schema_search_path = schema_search_path
77
+
78
+ chronomodel_schema_search_path = "#{schema_search_path},#{CHRONOMODEL_SCHEMAS.join(',')}"
79
+
80
+ if defined?(@configuration_hash)
81
+ @configuration_hash = @configuration_hash.dup
82
+ @configuration_hash[:schema_search_path] = chronomodel_schema_search_path
83
+ @configuration_hash.freeze
84
+ else
85
+ configuration['schema_search_path'] = chronomodel_schema_search_path
86
+ end
87
+ end
88
+
89
+ def reset_configuration!
90
+ if defined?(@configuration_hash)
91
+ @configuration_hash = @configuration_hash.dup
92
+ @configuration_hash[:schema_search_path] = @original_schema_search_path
93
+ @configuration_hash.freeze
94
+ else
95
+ configuration['schema_search_path'] = @original_schema_search_path
96
+ end
97
+ end
98
+
99
+ unless private_instance_methods.include?(:remove_sql_header_comments)
66
100
  def remove_sql_header_comments(filename)
67
101
  sql_comment_begin = '--'
68
102
  removing_comments = true
69
- tempfile = Tempfile.open("uncommented_structure.sql")
103
+ tempfile = Tempfile.open('uncommented_structure.sql')
70
104
  begin
71
105
  File.foreach(filename) do |line|
72
106
  unless removing_comments && (line.start_with?(sql_comment_begin) || line.blank?)
@@ -81,6 +115,13 @@ module ActiveRecord
81
115
  end
82
116
  end
83
117
 
118
+ unless private_instance_methods.include?(:psql_env)
119
+ alias psql_env set_psql_env
120
+ end
121
+
122
+ def schema_search_path
123
+ @schema_search_path ||= chronomodel_configuration[:schema_search_path]
124
+ end
84
125
  end
85
126
  end
86
127
  end