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.
- checksums.yaml +4 -4
- data/LICENSE +19 -20
- data/README.md +62 -40
- data/lib/active_record/connection_adapters/chronomodel_adapter.rb +17 -11
- data/lib/active_record/tasks/chronomodel_database_tasks.rb +64 -23
- data/lib/chrono_model/adapter/ddl.rb +168 -153
- data/lib/chrono_model/adapter/indexes.rb +99 -94
- data/lib/chrono_model/adapter/migrations.rb +81 -104
- data/lib/chrono_model/adapter/migrations_modules/legacy.rb +41 -0
- data/lib/chrono_model/adapter/migrations_modules/stable.rb +41 -0
- data/lib/chrono_model/adapter/tsrange.rb +20 -5
- data/lib/chrono_model/adapter/upgrade.rb +89 -91
- data/lib/chrono_model/adapter.rb +64 -31
- data/lib/chrono_model/chrono.rb +17 -0
- data/lib/chrono_model/conversions.rb +15 -9
- data/lib/chrono_model/db_console.rb +9 -0
- data/lib/chrono_model/json.rb +9 -6
- data/lib/chrono_model/patches/as_of_time_holder.rb +2 -2
- data/lib/chrono_model/patches/as_of_time_relation.rb +2 -2
- data/lib/chrono_model/patches/association.rb +15 -12
- data/lib/chrono_model/patches/batches.rb +17 -0
- data/lib/chrono_model/patches/db_console.rb +20 -4
- data/lib/chrono_model/patches/join_node.rb +4 -4
- data/lib/chrono_model/patches/preloader.rb +41 -11
- data/lib/chrono_model/patches/relation.rb +53 -8
- data/lib/chrono_model/patches.rb +3 -1
- data/lib/chrono_model/railtie.rb +29 -24
- data/lib/chrono_model/time_gate.rb +3 -3
- data/lib/chrono_model/time_machine/history_model.rb +65 -31
- data/lib/chrono_model/time_machine/time_query.rb +65 -49
- data/lib/chrono_model/time_machine/timeline.rb +52 -28
- data/lib/chrono_model/time_machine.rb +66 -25
- data/lib/chrono_model/utilities.rb +3 -3
- data/lib/chrono_model/version.rb +3 -1
- data/lib/chrono_model.rb +31 -36
- metadata +39 -136
- data/.gitignore +0 -21
- data/.rspec +0 -2
- data/.travis.yml +0 -41
- data/Gemfile +0 -4
- data/README.sql +0 -161
- data/Rakefile +0 -25
- data/chrono_model.gemspec +0 -33
- data/gemfiles/rails_5.0.gemfile +0 -6
- data/gemfiles/rails_5.1.gemfile +0 -6
- data/gemfiles/rails_5.2.gemfile +0 -6
- data/spec/aruba/dbconsole_spec.rb +0 -25
- data/spec/aruba/fixtures/database_with_default_username_and_password.yml +0 -14
- data/spec/aruba/fixtures/database_without_username_and_password.yml +0 -11
- data/spec/aruba/fixtures/empty_structure.sql +0 -27
- data/spec/aruba/fixtures/migrations/56/20160812190335_create_impressions.rb +0 -10
- data/spec/aruba/fixtures/migrations/56/20171115195229_add_temporal_extension_to_impressions.rb +0 -10
- data/spec/aruba/fixtures/railsapp/config/application.rb +0 -17
- data/spec/aruba/fixtures/railsapp/config/boot.rb +0 -5
- data/spec/aruba/fixtures/railsapp/config/environments/development.rb +0 -38
- data/spec/aruba/migrations_spec.rb +0 -48
- data/spec/aruba/rake_task_spec.rb +0 -71
- data/spec/chrono_model/adapter/base_spec.rb +0 -157
- data/spec/chrono_model/adapter/ddl_spec.rb +0 -243
- data/spec/chrono_model/adapter/indexes_spec.rb +0 -72
- data/spec/chrono_model/adapter/migrations_spec.rb +0 -312
- data/spec/chrono_model/conversions_spec.rb +0 -43
- data/spec/chrono_model/history_models_spec.rb +0 -32
- data/spec/chrono_model/json_ops_spec.rb +0 -59
- data/spec/chrono_model/time_machine/as_of_spec.rb +0 -188
- data/spec/chrono_model/time_machine/changes_spec.rb +0 -50
- data/spec/chrono_model/time_machine/counter_cache_race_spec.rb +0 -46
- data/spec/chrono_model/time_machine/default_scope_spec.rb +0 -37
- data/spec/chrono_model/time_machine/history_spec.rb +0 -104
- data/spec/chrono_model/time_machine/keep_cool_spec.rb +0 -27
- data/spec/chrono_model/time_machine/manipulations_spec.rb +0 -84
- data/spec/chrono_model/time_machine/model_identification_spec.rb +0 -46
- data/spec/chrono_model/time_machine/sequence_spec.rb +0 -74
- data/spec/chrono_model/time_machine/sti_spec.rb +0 -100
- data/spec/chrono_model/time_machine/time_query_spec.rb +0 -261
- data/spec/chrono_model/time_machine/timeline_spec.rb +0 -63
- data/spec/chrono_model/time_machine/timestamps_spec.rb +0 -43
- data/spec/chrono_model/time_machine/transactions_spec.rb +0 -69
- data/spec/config.travis.yml +0 -5
- data/spec/config.yml.example +0 -9
- data/spec/spec_helper.rb +0 -33
- data/spec/support/adapter/helpers.rb +0 -53
- data/spec/support/adapter/structure.rb +0 -44
- data/spec/support/aruba.rb +0 -44
- data/spec/support/connection.rb +0 -70
- data/spec/support/matchers/base.rb +0 -56
- data/spec/support/matchers/column.rb +0 -99
- data/spec/support/matchers/function.rb +0 -79
- data/spec/support/matchers/index.rb +0 -69
- data/spec/support/matchers/schema.rb +0 -39
- data/spec/support/matchers/table.rb +0 -275
- data/spec/support/time_machine/helpers.rb +0 -47
- data/spec/support/time_machine/structure.rb +0 -111
- data/sql/json_ops.sql +0 -56
- data/sql/uninstall-json_ops.sql +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9dc931f360178771e212906ec3a02d1ff49ffc2393b457a7f531b101bc1e8ce
|
4
|
+
data.tar.gz: 7606b75d5eaf453e0d0f90c760607af50bdf862744f7048cc2c8061f41018bc5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
the
|
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
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
OF
|
24
|
-
|
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
|
-
![
|
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.
|
66
|
-
* Active Record >= 5.0. See the [detailed supported versions matrix on
|
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, :
|
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
|
-
*
|
160
|
-
*
|
161
|
-
*
|
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
|
-
|
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
|
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
|
-
|
350
|
-
|
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://
|
380
|
-
[build-status-badge]: https://
|
381
|
-
[code-analysis]: https://codeclimate.com/github/ifad/chronomodel
|
382
|
-
[code-analysis-badge]: https://codeclimate.com/
|
383
|
-
[docs-analysis]:
|
384
|
-
[docs-analysis-badge]:
|
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
|
-
|
392
|
-
|
393
|
-
[wp-scd-
|
394
|
-
|
395
|
-
|
396
|
-
[pg-
|
397
|
-
[pg-
|
398
|
-
[pg-
|
399
|
-
[pg-
|
400
|
-
[pg-
|
401
|
-
[pg-
|
402
|
-
[pg-partitioning]:
|
403
|
-
[pg-
|
404
|
-
[pg-
|
405
|
-
[pg-
|
406
|
-
[pg-
|
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]:
|
410
|
-
[pg-cte-optimization-fence]:
|
411
|
-
[pg-cte-opt-out-fence]:
|
412
|
-
[pg-json-type]:
|
413
|
-
[pg-json-func]:
|
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
|
-
|
24
|
-
|
25
|
-
adapter = ChronoModel::Adapter.new(
|
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,
|
29
|
-
|
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
|
-
|
35
|
-
|
42
|
+
adapter
|
43
|
+
rescue ::PG::Error => e
|
44
|
+
raise ActiveRecord::NoDatabaseError if e.message.include?(conn_params[:dbname])
|
36
45
|
|
37
|
-
|
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
|
-
|
8
|
-
|
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
|
-
|
32
|
+
psql_env
|
26
33
|
|
27
|
-
args = ['-c', '-f', target]
|
28
|
-
args <<
|
34
|
+
args = ['-c', '-f', target.to_s]
|
35
|
+
args << chronomodel_configuration[:database]
|
29
36
|
|
30
|
-
run_cmd
|
37
|
+
run_cmd 'pg_dump', args, 'dumping data'
|
31
38
|
end
|
32
39
|
|
33
40
|
def data_load(source)
|
34
|
-
|
41
|
+
psql_env
|
35
42
|
|
36
43
|
args = ['-f', source]
|
37
|
-
args <<
|
44
|
+
args << chronomodel_configuration[:database]
|
38
45
|
|
39
|
-
run_cmd
|
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
|
-
|
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
|
-
|
72
|
+
reset_configuration!
|
63
73
|
end
|
64
74
|
|
65
|
-
|
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(
|
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
|