chrono_model 1.2.2 → 2.0.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.
- 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
|