chrono_model 1.2.2 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +19 -20
  3. data/README.md +73 -62
  4. data/lib/active_record/connection_adapters/chronomodel_adapter.rb +14 -14
  5. data/lib/active_record/tasks/chronomodel_database_tasks.rb +40 -39
  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/stable.rb +41 -0
  10. data/lib/chrono_model/adapter/tsrange.rb +20 -5
  11. data/lib/chrono_model/adapter/upgrade.rb +89 -91
  12. data/lib/chrono_model/adapter.rb +59 -31
  13. data/lib/chrono_model/chrono.rb +17 -0
  14. data/lib/chrono_model/conversions.rb +14 -8
  15. data/lib/chrono_model/db_console.rb +5 -0
  16. data/lib/chrono_model/patches/as_of_time_holder.rb +2 -2
  17. data/lib/chrono_model/patches/as_of_time_relation.rb +3 -13
  18. data/lib/chrono_model/patches/association.rb +15 -12
  19. data/lib/chrono_model/patches/batches.rb +13 -0
  20. data/lib/chrono_model/patches/db_console.rb +20 -4
  21. data/lib/chrono_model/patches/join_node.rb +4 -4
  22. data/lib/chrono_model/patches/preloader.rb +41 -11
  23. data/lib/chrono_model/patches/relation.rb +51 -8
  24. data/lib/chrono_model/patches.rb +3 -1
  25. data/lib/chrono_model/railtie.rb +13 -27
  26. data/lib/chrono_model/time_gate.rb +3 -3
  27. data/lib/chrono_model/time_machine/history_model.rb +65 -31
  28. data/lib/chrono_model/time_machine/time_query.rb +65 -49
  29. data/lib/chrono_model/time_machine/timeline.rb +52 -28
  30. data/lib/chrono_model/time_machine.rb +57 -25
  31. data/lib/chrono_model/utilities.rb +3 -3
  32. data/lib/chrono_model/version.rb +3 -1
  33. data/lib/chrono_model.rb +31 -36
  34. metadata +24 -263
  35. data/.gitignore +0 -21
  36. data/.rspec +0 -2
  37. data/.travis.yml +0 -41
  38. data/Gemfile +0 -4
  39. data/README.sql +0 -161
  40. data/Rakefile +0 -25
  41. data/chrono_model.gemspec +0 -33
  42. data/gemfiles/rails_5.0.gemfile +0 -6
  43. data/gemfiles/rails_5.1.gemfile +0 -6
  44. data/gemfiles/rails_5.2.gemfile +0 -6
  45. data/lib/chrono_model/json.rb +0 -28
  46. data/spec/aruba/dbconsole_spec.rb +0 -25
  47. data/spec/aruba/fixtures/database_with_default_username_and_password.yml +0 -14
  48. data/spec/aruba/fixtures/database_without_username_and_password.yml +0 -11
  49. data/spec/aruba/fixtures/empty_structure.sql +0 -27
  50. data/spec/aruba/fixtures/migrations/56/20160812190335_create_impressions.rb +0 -10
  51. data/spec/aruba/fixtures/migrations/56/20171115195229_add_temporal_extension_to_impressions.rb +0 -10
  52. data/spec/aruba/fixtures/railsapp/config/application.rb +0 -17
  53. data/spec/aruba/fixtures/railsapp/config/boot.rb +0 -5
  54. data/spec/aruba/fixtures/railsapp/config/environments/development.rb +0 -38
  55. data/spec/aruba/migrations_spec.rb +0 -48
  56. data/spec/aruba/rake_task_spec.rb +0 -71
  57. data/spec/chrono_model/adapter/base_spec.rb +0 -157
  58. data/spec/chrono_model/adapter/ddl_spec.rb +0 -243
  59. data/spec/chrono_model/adapter/indexes_spec.rb +0 -72
  60. data/spec/chrono_model/adapter/migrations_spec.rb +0 -312
  61. data/spec/chrono_model/conversions_spec.rb +0 -43
  62. data/spec/chrono_model/history_models_spec.rb +0 -32
  63. data/spec/chrono_model/json_ops_spec.rb +0 -59
  64. data/spec/chrono_model/time_machine/as_of_spec.rb +0 -188
  65. data/spec/chrono_model/time_machine/changes_spec.rb +0 -50
  66. data/spec/chrono_model/time_machine/counter_cache_race_spec.rb +0 -46
  67. data/spec/chrono_model/time_machine/default_scope_spec.rb +0 -37
  68. data/spec/chrono_model/time_machine/history_spec.rb +0 -104
  69. data/spec/chrono_model/time_machine/keep_cool_spec.rb +0 -27
  70. data/spec/chrono_model/time_machine/manipulations_spec.rb +0 -84
  71. data/spec/chrono_model/time_machine/model_identification_spec.rb +0 -46
  72. data/spec/chrono_model/time_machine/sequence_spec.rb +0 -74
  73. data/spec/chrono_model/time_machine/sti_spec.rb +0 -100
  74. data/spec/chrono_model/time_machine/time_query_spec.rb +0 -261
  75. data/spec/chrono_model/time_machine/timeline_spec.rb +0 -63
  76. data/spec/chrono_model/time_machine/timestamps_spec.rb +0 -43
  77. data/spec/chrono_model/time_machine/transactions_spec.rb +0 -69
  78. data/spec/config.travis.yml +0 -5
  79. data/spec/config.yml.example +0 -9
  80. data/spec/spec_helper.rb +0 -33
  81. data/spec/support/adapter/helpers.rb +0 -53
  82. data/spec/support/adapter/structure.rb +0 -44
  83. data/spec/support/aruba.rb +0 -44
  84. data/spec/support/connection.rb +0 -70
  85. data/spec/support/matchers/base.rb +0 -56
  86. data/spec/support/matchers/column.rb +0 -99
  87. data/spec/support/matchers/function.rb +0 -79
  88. data/spec/support/matchers/index.rb +0 -69
  89. data/spec/support/matchers/schema.rb +0 -39
  90. data/spec/support/matchers/table.rb +0 -275
  91. data/spec/support/time_machine/helpers.rb +0 -47
  92. data/spec/support/time_machine/structure.rb +0 -111
  93. data/sql/json_ops.sql +0 -56
  94. 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: 222db0e6673e7171d44dac2163b5048ebf6b459c18fa2a2609a3051fce8c6591
4
+ data.tar.gz: 871fdf28717c85267e6b783f1f2d6ba3a24b1261e974e53a25de28d745bc8579
5
5
  SHA512:
6
- metadata.gz: 380cbab091ab178aea031fee4e8343797a5e461e98b233a8c732b7cc0f9bd584497fa3b1bcc8703f6d8b74b972aeed2a257f6aba9ca7a2d932b4e72e7c211506
7
- data.tar.gz: c601c91ce05f426aef3c75b37ba9920170666523abff9b219ab09816e6c17f42146131d5ffcc89d233d5d7ec94d6ac5592e6a8160dd8207b9a48c3ff51feb629
6
+ metadata.gz: 0bf942259052f134ea38de898307a65f20a6b448d8e8ff99a09ae06cd751f9834e1eb22abd4498c880005b8fc91f44ecebea4702be8c174570c50027dce13a75
7
+ data.tar.gz: 2b894f82a0cb9687d59dca9c3427a854cf6dc02191a08df71a215dfc577a8d1dd58632d44eb179395f097aa7d2391a7c738968d0f4c68f16cc14fffd2d18e034
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-2024 Marcello Barnaba <m.barnaba@ifad.org>
4
+ Copyright (c) 2012-2024 Peter J. Brindisi <p.brindisi@ifad.org>
5
+ Copyright (c) 2012-2024 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
@@ -6,7 +6,7 @@
6
6
  [![Gem Version][gem-version-badge]][gem-version]
7
7
  [![Inlinedocs][docs-analysis-badge]][docs-analysis]
8
8
 
9
- ![{A Delorean that we all love}][delorean-image]
9
+ ![A Delorean that we all love][delorean-image]
10
10
 
11
11
  ChronoModel implements what Oracle sells as "Flashback Queries", with standard
12
12
  SQL on free PostgreSQL. Academically speaking, ChronoModel implements a
@@ -62,9 +62,9 @@ All timestamps are _forcibly_ stored in as UTC, bypassing the
62
62
 
63
63
  ## Requirements
64
64
 
65
- * Ruby >= 2.3
66
- * Active Record >= 5.0. See the [detailed supported versions matrix on travis](https://travis-ci.org/ifad/chronomodel)
67
- * PostgreSQL >= 9.4 (legacy support for 9.3)
65
+ * Ruby >= 3.0
66
+ * Active Record >= 7.0. See the [detailed supported versions matrix on Ruby GitHub Actions workflows](https://github.com/ifad/chronomodel/blob/master/.github/workflows)
67
+ * PostgreSQL >= 9.4
68
68
  * The `btree_gist` PostgreSQL extension
69
69
 
70
70
  With Homebrew:
@@ -96,6 +96,13 @@ development:
96
96
  username: ...
97
97
  ```
98
98
 
99
+ Configure Active Record in your `config/application.rb` to use the `:sql` schema
100
+ format:
101
+
102
+ ```rb
103
+ config.active_record.schema_format = :sql
104
+ ```
105
+
99
106
  ## Schema creation
100
107
 
101
108
  ChronoModel hooks all `ActiveRecord::Migration` methods to make them temporal
@@ -141,7 +148,7 @@ validity from midnight, January 1st, 1 CE. You can set a specific validity with
141
148
  the `:validity` option:
142
149
 
143
150
  ```ruby
144
- change_table :your_table, :temporal => true, :copy_data => true, :validity => '1977-01-01'
151
+ change_table :your_table, temporal: true, copy_data: true, validity: '1977-01-01'
145
152
  ```
146
153
 
147
154
  Please note that `change_table` requires you to use *old_style* `up` and
@@ -156,9 +163,9 @@ history.
156
163
  You can also choose which fields are to be journaled, passing the following
157
164
  options to `create_table`:
158
165
 
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`.
166
+ * `journal: %w( fld1 fld2 .. .. )` - record changes in the history only when changing specified fields
167
+ * `no_journal: %w( fld1 fld2 .. )` - do not record changes to the specified fields
168
+ * `full_journal: true` - record changes to *all* fields, including `updated_at`.
162
169
 
163
170
  These options are stored as JSON in the [COMMENT][pg-comment] area of the
164
171
  public view, alongside with the ChronoModel version that created them.
@@ -195,7 +202,7 @@ to your `create_table`. Example:
195
202
  Include the `ChronoModel::TimeMachine` module in your model.
196
203
 
197
204
  ```ruby
198
- module Country < ActiveRecord::Base
205
+ class Country < ActiveRecord::Base
199
206
  include ChronoModel::TimeMachine
200
207
 
201
208
  has_many :compositions
@@ -310,31 +317,19 @@ only against ActiveRecord by using
310
317
 
311
318
  Ensure to run the full test suite before pushing.
312
319
 
313
- ## Usage with JSON (*not* JSONB) columns
314
-
315
- **DEPRECATED**: Please migrate to JSONB. It has an equality operator built-in,
316
- it's faster and stricter, and offers many more indexing abilities and better
317
- performance than JSON. It is going to be desupported soon because PostgreSQL 10
318
- does not support these anymore.
319
-
320
- The [JSON][pg-json-type] does not provide an [equality operator][pg-json-func].
321
- As both unnecessary update suppression and selective journaling require
322
- comparing the OLD and NEW rows fields, this fails by default.
323
-
324
- ChronoModel provides a naive and heavyweight JSON equality operator using
325
- [pl/python][pg-json-opclass] and associated Postgres objects.
326
-
327
- To set up you can use
328
-
329
- ```ruby
330
- require 'chrono_model/json'
331
- ChronoModel::Json.create
332
- ```
333
-
334
320
  ## Caveats
335
321
 
322
+ * Considering the nature of modern applications, it's crucial to understand
323
+ that the database time does not necessarily align with the application time
324
+ due to the delay introduced by communication between the application and
325
+ the database server. Consequently, there is no assurance that the application
326
+ time will always be less than the database time. Therefore, relying solely
327
+ on `created_at` and `updated_at` fields as timestamps to determine the state
328
+ of an object at a specific point in time within the application could
329
+ lead to inaccuracies.
330
+
336
331
  * Rails 4+ support requires disabling tsrange parsing support, as it
337
- [is broken][r4-tsrange-broken] and [incomplete][r4-tsrange-incomplete]
332
+ [is broken][r4-tsrange-broken] and [incomplete][r4-tsrange-incomplete]
338
333
  as of now, mainly due to a [design clash with ruby][pg-tsrange-and-ruby].
339
334
 
340
335
  * The triggers and temporal indexes cannot be saved in schema.rb. The AR
@@ -345,14 +340,27 @@ ChronoModel::Json.create
345
340
  `db:structure:load`.
346
341
  Two helper tasks are also added, `db:data:dump` and `db:data:load`.
347
342
 
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].
343
+ * The choice of using subqueries instead of [Common Table Expressions][pg-ctes]
344
+ was dictated by the fact that CTEs [currently act as an optimization
345
+ fence][pg-cte-optimization-fence].
351
346
  If it will be possible [to opt-out of the fence][pg-cte-opt-out-fence]
352
347
  in the future, they will be probably be used again as they were [in the
353
348
  past][cm-cte-impl], because the resulting queries were more readable,
354
349
  and do not inhibit using `.from()` on the `AR::Relation`.
355
350
 
351
+ * Foreign keys are not supported. [See issue #174][gh-issue-174]
352
+
353
+ * There may be unexpected results when combining eager loading and joins.
354
+ [See issue #186][gh-issue-186]
355
+
356
+ * Global ID ignores historical objects. [See issue #192][gh-issue-192]
357
+
358
+ * Different historical objects are considered the identical. [See issue
359
+ #206][gh-issue-206]
360
+
361
+ * Use with caution when implementing inline editing features, as Chronomodel
362
+ creates a new record for each modification. This will lead to increased
363
+ storage requirements and bloated history
356
364
 
357
365
  ## Contributing
358
366
 
@@ -376,41 +384,40 @@ while using it in many important projects.
376
384
  This software is Made in Italy :it: :smile:.
377
385
 
378
386
 
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
387
+ [build-status]: https://github.com/ifad/chronomodel/actions
388
+ [build-status-badge]: https://github.com/ifad/chronomodel/actions/workflows/ruby.yml/badge.svg
389
+ [code-analysis]: https://codeclimate.com/github/ifad/chronomodel/maintainability
390
+ [code-analysis-badge]: https://api.codeclimate.com/v1/badges/cdee7327938dc2eaff99/maintainability
391
+ [docs-analysis]: https://inch-ci.org/github/ifad/chronomodel
392
+ [docs-analysis-badge]: https://inch-ci.org/github/ifad/chronomodel.svg?branch=master
385
393
  [gem-version]: https://rubygems.org/gems/chrono_model
386
394
  [gem-version-badge]: https://badge.fury.io/rb/chrono_model.svg
387
395
  [test-coverage]: https://codeclimate.com/github/ifad/chronomodel
388
396
  [test-coverage-badge]: https://codeclimate.com/github/ifad/chronomodel/badges/coverage.svg
389
397
 
390
398
  [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
399
+
400
+ [wp-scd-2]: https://en.wikipedia.org/wiki/Slowly_changing_dimension#Type_2
401
+ [wp-scd-4]: https://en.wikipedia.org/wiki/Slowly_changing_dimension#Type_4
402
+
403
+ [pg-updatable-views]: https://www.postgresql.org/docs/9.4/sql-createview.html#SQL-CREATEVIEW-UPDATABLE-VIEWS
404
+ [pg-table-inheritance]: https://www.postgresql.org/docs/9.4/ddl-inherit.html
405
+ [pg-instead-of-triggers]: https://www.postgresql.org/docs/9.4/sql-createtrigger.html
406
+ [pg-triggers]: https://www.postgresql.org/docs/9.4/trigger-definition.html
407
+ [pg-schema]: https://www.postgresql.org/docs/9.4/ddl-schemas.html
408
+ [pg-current-timestamp]: https://www.postgresql.org/docs/9.4/functions-datetime.html#FUNCTIONS-DATETIME-TABLE
409
+ [pg-partitioning]: https://www.postgresql.org/docs/9.4/ddl-partitioning.html
410
+ [pg-partitioning-excl-constraints]: https://www.postgresql.org/docs/9.4/ddl-partitioning.html#DDL-PARTITIONING-CONSTRAINT-EXCLUSION
411
+ [pg-gist-indexes]: https://www.postgresql.org/docs/9.4/gist.html
412
+ [pg-exclusion-constraints]: https://www.postgresql.org/docs/9.4/sql-createtable.html#SQL-CREATETABLE-EXCLUDE
413
+ [pg-btree-gist]: https://www.postgresql.org/docs/9.4/btree-gist.html
414
+ [pg-comment]: https://www.postgresql.org/docs/9.4/sql-comment.html
408
415
  [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
416
+ [pg-ctes]: https://www.postgresql.org/docs/9.4/queries-with.html
417
+ [pg-cte-optimization-fence]: https://www.postgresql.org/message-id/201209191305.44674.db@kavod.com
418
+ [pg-cte-opt-out-fence]: https://www.postgresql.org/message-id/CAHyXU0zpM5+Dsb_pKxDmm-ZoWUAt=SkHHaiK_DBqcmtxTas6Nw@mail.gmail.com
419
+ [pg-json-type]: https://www.postgresql.org/docs/9.4/datatype-json.html
420
+ [pg-json-func]: https://www.postgresql.org/docs/9.4/functions-json.html
414
421
  [pg-json-opclass]: https://github.com/ifad/chronomodel/blob/master/sql/json_ops.sql
415
422
 
416
423
  [r4-tsrange-broken]: https://github.com/rails/rails/pull/13793#issuecomment-34608093
@@ -421,3 +428,7 @@ This software is Made in Italy :it: :smile:.
421
428
  [cm-cte-impl]: https://github.com/ifad/chronomodel/commit/18f4c4b
422
429
 
423
430
  [gh-pzac]: https://github.com/pzac
431
+ [gh-issue-174]: https://github.com/ifad/chronomodel/issues/174
432
+ [gh-issue-186]: https://github.com/ifad/chronomodel/issues/186
433
+ [gh-issue-192]: https://github.com/ifad/chronomodel/issues/192
434
+ [gh-issue-206]: https://github.com/ifad/chronomodel/issues/206
@@ -1,16 +1,22 @@
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:
11
- conn_params = config.symbolize_keys
17
+ return chronomodel_adapter_class.new(config) if ActiveRecord::VERSION::STRING >= '7.1'
12
18
 
13
- conn_params.delete_if { |_, v| v.nil? }
19
+ conn_params = config.symbolize_keys.compact
14
20
 
15
21
  # Map ActiveRecords param names to PGs.
16
22
  conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
@@ -20,24 +26,18 @@ module ActiveRecord
20
26
  valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
21
27
  conn_params.slice!(*valid_conn_param_keys)
22
28
 
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)
29
+ conn = PG.connect(conn_params)
30
+
31
+ adapter = ChronoModel::Adapter.new(conn, logger, conn_params, config)
26
32
 
27
33
  unless adapter.chrono_supported?
28
- raise ChronoModel::Error, "Your database server is not supported by ChronoModel. "\
29
- "Currently, only PostgreSQL >= 9.3 is supported."
34
+ raise ChronoModel::Error, 'Your database server is not supported by ChronoModel. ' \
35
+ 'Currently, only PostgreSQL >= 9.3 is supported.'
30
36
  end
31
37
 
32
38
  adapter.chrono_setup!
33
39
 
34
- return adapter
40
+ adapter
35
41
  end
36
-
37
- module Connectionadapters
38
- ChronoModelAdapter = ::ChronoModel::Adapter
39
- end
40
-
41
42
  end
42
43
  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
@@ -17,70 +24,64 @@ module ActiveRecord
17
24
  filename = arguments.first
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
-
21
- remove_sql_header_comments(filename)
22
27
  end
23
28
 
24
29
  def data_dump(target)
25
- set_psql_env
30
+ psql_env
26
31
 
27
- args = ['-c', '-f', target]
28
- args << configuration['database']
32
+ args = ['-c', '-f', target.to_s]
33
+ args << chronomodel_configuration[:database]
29
34
 
30
- run_cmd "pg_dump", args, 'dumping data'
35
+ run_cmd 'pg_dump', args, 'dumping data'
31
36
  end
32
37
 
33
38
  def data_load(source)
34
- set_psql_env
39
+ psql_env
35
40
 
36
41
  args = ['-f', source]
37
- args << configuration['database']
42
+ args << chronomodel_configuration[:database]
38
43
 
39
- run_cmd "psql", args, 'loading data'
44
+ run_cmd 'psql', args, 'loading data'
40
45
  end
41
46
 
42
47
  private
43
48
 
49
+ def chronomodel_configuration
50
+ @chronomodel_configuration ||= @configuration_hash
51
+ end
52
+
44
53
  # If a schema search path is defined in the configuration file, it will
45
54
  # be used by the database tasks class to dump only the specified search
46
55
  # path. Here we add also ChronoModel's temporal and history schemas to
47
56
  # the search path and yield.
48
57
  #
49
58
  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
59
+ patch_configuration!
58
60
 
59
61
  yield
60
-
61
62
  ensure
62
- configuration['schema_search_path'] = original_schema_search_path
63
+ reset_configuration!
63
64
  end
64
65
 
65
- unless method_defined? :remove_sql_header_comments
66
- def remove_sql_header_comments(filename)
67
- sql_comment_begin = '--'
68
- removing_comments = true
69
- tempfile = Tempfile.open("uncommented_structure.sql")
70
- begin
71
- File.foreach(filename) do |line|
72
- unless removing_comments && (line.start_with?(sql_comment_begin) || line.blank?)
73
- tempfile << line
74
- removing_comments = false
75
- end
76
- end
77
- ensure
78
- tempfile.close
79
- end
80
- FileUtils.mv(tempfile.path, filename)
81
- end
66
+ def patch_configuration!
67
+ @original_schema_search_path = schema_search_path
68
+
69
+ chronomodel_schema_search_path = "#{schema_search_path},#{CHRONOMODEL_SCHEMAS.join(',')}"
70
+
71
+ @configuration_hash = @configuration_hash.dup
72
+ @configuration_hash[:schema_search_path] = chronomodel_schema_search_path
73
+ @configuration_hash.freeze
82
74
  end
83
75
 
76
+ def reset_configuration!
77
+ @configuration_hash = @configuration_hash.dup
78
+ @configuration_hash[:schema_search_path] = @original_schema_search_path
79
+ @configuration_hash.freeze
80
+ end
81
+
82
+ def schema_search_path
83
+ @schema_search_path ||= chronomodel_configuration[:schema_search_path]
84
+ end
84
85
  end
85
86
  end
86
87
  end