chrono_model 2.0.0 → 3.0.1
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 +3 -3
- data/README.md +15 -26
- data/lib/active_record/connection_adapters/chronomodel_adapter.rb +2 -8
- data/lib/active_record/tasks/chronomodel_database_tasks.rb +7 -47
- data/lib/chrono_model/adapter/ddl.rb +3 -3
- data/lib/chrono_model/adapter.rb +1 -6
- data/lib/chrono_model/conversions.rb +2 -2
- data/lib/chrono_model/db_console.rb +1 -5
- data/lib/chrono_model/patches/as_of_time_relation.rb +1 -11
- data/lib/chrono_model/patches/batches.rb +4 -8
- data/lib/chrono_model/patches/relation.rb +9 -11
- data/lib/chrono_model/railtie.rb +2 -21
- data/lib/chrono_model/time_machine/timeline.rb +1 -1
- data/lib/chrono_model/time_machine.rb +19 -28
- data/lib/chrono_model/version.rb +1 -1
- data/lib/chrono_model.rb +2 -2
- metadata +7 -149
- data/lib/chrono_model/adapter/migrations_modules/legacy.rb +0 -41
- data/lib/chrono_model/json.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 222db0e6673e7171d44dac2163b5048ebf6b459c18fa2a2609a3051fce8c6591
|
4
|
+
data.tar.gz: 871fdf28717c85267e6b783f1f2d6ba3a24b1261e974e53a25de28d745bc8579
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0bf942259052f134ea38de898307a65f20a6b448d8e8ff99a09ae06cd751f9834e1eb22abd4498c880005b8fc91f44ecebea4702be8c174570c50027dce13a75
|
7
|
+
data.tar.gz: 2b894f82a0cb9687d59dca9c3427a854cf6dc02191a08df71a215dfc577a8d1dd58632d44eb179395f097aa7d2391a7c738968d0f4c68f16cc14fffd2d18e034
|
data/LICENSE
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
MIT License
|
2
2
|
|
3
|
-
Copyright (c) 2012-
|
4
|
-
Copyright (c) 2012-
|
5
|
-
Copyright (c) 2012-
|
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
6
|
|
7
7
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
8
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -1,7 +1,6 @@
|
|
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]
|
5
4
|
[![Code Climate][code-analysis-badge]][code-analysis]
|
6
5
|
[![Test Coverage][test-coverage-badge]][test-coverage]
|
7
6
|
[![Gem Version][gem-version-badge]][gem-version]
|
@@ -63,9 +62,9 @@ All timestamps are _forcibly_ stored in as UTC, bypassing the
|
|
63
62
|
|
64
63
|
## Requirements
|
65
64
|
|
66
|
-
* Ruby >=
|
67
|
-
* Active Record >=
|
68
|
-
* PostgreSQL >= 9.4
|
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
|
69
68
|
* The `btree_gist` PostgreSQL extension
|
70
69
|
|
71
70
|
With Homebrew:
|
@@ -318,29 +317,17 @@ only against ActiveRecord by using
|
|
318
317
|
|
319
318
|
Ensure to run the full test suite before pushing.
|
320
319
|
|
321
|
-
## Usage with JSON (*not* JSONB) columns
|
322
|
-
|
323
|
-
**DEPRECATED**: Please migrate to JSONB. It has an equality operator built-in,
|
324
|
-
it's faster and stricter, and offers many more indexing abilities and better
|
325
|
-
performance than JSON. It is going to be desupported soon because PostgreSQL 10
|
326
|
-
does not support these anymore.
|
327
|
-
|
328
|
-
The [JSON][pg-json-type] does not provide an [equality operator][pg-json-func].
|
329
|
-
As both unnecessary update suppression and selective journaling require
|
330
|
-
comparing the OLD and NEW rows fields, this fails by default.
|
331
|
-
|
332
|
-
ChronoModel provides a naive and heavyweight JSON equality operator using
|
333
|
-
[pl/python][pg-json-opclass] and associated Postgres objects.
|
334
|
-
|
335
|
-
To set up you can use
|
336
|
-
|
337
|
-
```ruby
|
338
|
-
require 'chrono_model/json'
|
339
|
-
ChronoModel::Json.create
|
340
|
-
```
|
341
|
-
|
342
320
|
## Caveats
|
343
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
|
+
|
344
331
|
* Rails 4+ support requires disabling tsrange parsing support, as it
|
345
332
|
[is broken][r4-tsrange-broken] and [incomplete][r4-tsrange-incomplete]
|
346
333
|
as of now, mainly due to a [design clash with ruby][pg-tsrange-and-ruby].
|
@@ -371,6 +358,9 @@ ChronoModel::Json.create
|
|
371
358
|
* Different historical objects are considered the identical. [See issue
|
372
359
|
#206][gh-issue-206]
|
373
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
|
374
364
|
|
375
365
|
## Contributing
|
376
366
|
|
@@ -402,7 +392,6 @@ This software is Made in Italy :it: :smile:.
|
|
402
392
|
[docs-analysis-badge]: https://inch-ci.org/github/ifad/chronomodel.svg?branch=master
|
403
393
|
[gem-version]: https://rubygems.org/gems/chrono_model
|
404
394
|
[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
|
406
395
|
[test-coverage]: https://codeclimate.com/github/ifad/chronomodel
|
407
396
|
[test-coverage-badge]: https://codeclimate.com/github/ifad/chronomodel/badges/coverage.svg
|
408
397
|
|
@@ -16,9 +16,7 @@ module ActiveRecord
|
|
16
16
|
def chronomodel_connection(config) # :nodoc:
|
17
17
|
return chronomodel_adapter_class.new(config) if ActiveRecord::VERSION::STRING >= '7.1'
|
18
18
|
|
19
|
-
conn_params = config.symbolize_keys
|
20
|
-
|
21
|
-
conn_params.delete_if { |_, v| v.nil? }
|
19
|
+
conn_params = config.symbolize_keys.compact
|
22
20
|
|
23
21
|
# Map ActiveRecords param names to PGs.
|
24
22
|
conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
|
@@ -28,7 +26,7 @@ module ActiveRecord
|
|
28
26
|
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
|
29
27
|
conn_params.slice!(*valid_conn_param_keys)
|
30
28
|
|
31
|
-
conn = PG.connect(conn_params)
|
29
|
+
conn = PG.connect(conn_params)
|
32
30
|
|
33
31
|
adapter = ChronoModel::Adapter.new(conn, logger, conn_params, config)
|
34
32
|
|
@@ -40,10 +38,6 @@ module ActiveRecord
|
|
40
38
|
adapter.chrono_setup!
|
41
39
|
|
42
40
|
adapter
|
43
|
-
rescue ::PG::Error => e
|
44
|
-
raise ActiveRecord::NoDatabaseError if e.message.include?(conn_params[:dbname])
|
45
|
-
|
46
|
-
raise
|
47
41
|
end
|
48
42
|
end
|
49
43
|
end
|
@@ -24,8 +24,6 @@ module ActiveRecord
|
|
24
24
|
filename = arguments.first
|
25
25
|
sql = File.read(filename).gsub(/CREATE SCHEMA (?!IF NOT EXISTS)/, '\&IF NOT EXISTS ')
|
26
26
|
File.open(filename, 'w') { |file| file << sql }
|
27
|
-
|
28
|
-
remove_sql_header_comments(filename) if ActiveRecord::VERSION::STRING < '5.1'
|
29
27
|
end
|
30
28
|
|
31
29
|
def data_dump(target)
|
@@ -48,15 +46,8 @@ module ActiveRecord
|
|
48
46
|
|
49
47
|
private
|
50
48
|
|
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
49
|
def chronomodel_configuration
|
54
|
-
@chronomodel_configuration ||=
|
55
|
-
if defined?(@configuration_hash)
|
56
|
-
@configuration_hash
|
57
|
-
else
|
58
|
-
configuration.with_indifferent_access
|
59
|
-
end
|
50
|
+
@chronomodel_configuration ||= @configuration_hash
|
60
51
|
end
|
61
52
|
|
62
53
|
# If a schema search path is defined in the configuration file, it will
|
@@ -77,46 +68,15 @@ module ActiveRecord
|
|
77
68
|
|
78
69
|
chronomodel_schema_search_path = "#{schema_search_path},#{CHRONOMODEL_SCHEMAS.join(',')}"
|
79
70
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
@configuration_hash.freeze
|
84
|
-
else
|
85
|
-
configuration['schema_search_path'] = chronomodel_schema_search_path
|
86
|
-
end
|
71
|
+
@configuration_hash = @configuration_hash.dup
|
72
|
+
@configuration_hash[:schema_search_path] = chronomodel_schema_search_path
|
73
|
+
@configuration_hash.freeze
|
87
74
|
end
|
88
75
|
|
89
76
|
def reset_configuration!
|
90
|
-
|
91
|
-
|
92
|
-
|
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)
|
100
|
-
def remove_sql_header_comments(filename)
|
101
|
-
sql_comment_begin = '--'
|
102
|
-
removing_comments = true
|
103
|
-
tempfile = Tempfile.open('uncommented_structure.sql')
|
104
|
-
begin
|
105
|
-
File.foreach(filename) do |line|
|
106
|
-
unless removing_comments && (line.start_with?(sql_comment_begin) || line.blank?)
|
107
|
-
tempfile << line
|
108
|
-
removing_comments = false
|
109
|
-
end
|
110
|
-
end
|
111
|
-
ensure
|
112
|
-
tempfile.close
|
113
|
-
end
|
114
|
-
FileUtils.mv(tempfile.path, filename)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
unless private_instance_methods.include?(:psql_env)
|
119
|
-
alias psql_env set_psql_env
|
77
|
+
@configuration_hash = @configuration_hash.dup
|
78
|
+
@configuration_hash[:schema_search_path] = @original_schema_search_path
|
79
|
+
@configuration_hash.freeze
|
120
80
|
end
|
121
81
|
|
122
82
|
def schema_search_path
|
@@ -82,7 +82,7 @@ module ChronoModel
|
|
82
82
|
# allow setting the PK to a specific value (think migration scenario).
|
83
83
|
#
|
84
84
|
def chrono_create_INSERT_trigger(table, pk, current, history, fields, values)
|
85
|
-
execute <<-SQL.strip_heredoc # rubocop:disable Rails/SquishedSQLHeredocs
|
85
|
+
execute <<-SQL.strip_heredoc # rubocop:disable Rails/SquishedSQLHeredocs,Rails/StripHeredoc
|
86
86
|
CREATE OR REPLACE FUNCTION chronomodel_#{table}_insert() RETURNS TRIGGER AS $$
|
87
87
|
BEGIN
|
88
88
|
#{insert_sequence_sql(pk, current)} INTO #{current} ( #{pk}, #{fields} )
|
@@ -135,7 +135,7 @@ module ChronoModel
|
|
135
135
|
|
136
136
|
journal &= columns
|
137
137
|
|
138
|
-
execute <<-SQL.strip_heredoc # rubocop:disable Rails/SquishedSQLHeredocs
|
138
|
+
execute <<-SQL.strip_heredoc # rubocop:disable Rails/SquishedSQLHeredocs,Rails/StripHeredoc
|
139
139
|
CREATE OR REPLACE FUNCTION chronomodel_#{table}_update() RETURNS TRIGGER AS $$
|
140
140
|
DECLARE _now timestamp;
|
141
141
|
DECLARE _hid integer;
|
@@ -189,7 +189,7 @@ module ChronoModel
|
|
189
189
|
# DELETEd in the same transaction.
|
190
190
|
#
|
191
191
|
def chrono_create_DELETE_trigger(table, pk, current, history)
|
192
|
-
execute <<-SQL.strip_heredoc # rubocop:disable Rails/SquishedSQLHeredocs
|
192
|
+
execute <<-SQL.strip_heredoc # rubocop:disable Rails/SquishedSQLHeredocs,Rails/StripHeredoc
|
193
193
|
CREATE OR REPLACE FUNCTION chronomodel_#{table}_delete() RETURNS TRIGGER AS $$
|
194
194
|
DECLARE _now timestamp;
|
195
195
|
BEGIN
|
data/lib/chrono_model/adapter.rb
CHANGED
@@ -3,12 +3,7 @@
|
|
3
3
|
require 'active_record/connection_adapters/postgresql_adapter'
|
4
4
|
|
5
5
|
require 'chrono_model/adapter/migrations'
|
6
|
-
|
7
|
-
if ActiveRecord::VERSION::STRING >= '6.1'
|
8
|
-
require 'chrono_model/adapter/migrations_modules/stable'
|
9
|
-
else
|
10
|
-
require 'chrono_model/adapter/migrations_modules/legacy'
|
11
|
-
end
|
6
|
+
require 'chrono_model/adapter/migrations_modules/stable'
|
12
7
|
|
13
8
|
require 'chrono_model/adapter/ddl'
|
14
9
|
require 'chrono_model/adapter/indexes'
|
@@ -4,7 +4,7 @@ module ChronoModel
|
|
4
4
|
module Conversions
|
5
5
|
module_function
|
6
6
|
|
7
|
-
ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(?:\.(\d+))?\z
|
7
|
+
ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(?:\.(\d+))?\z/
|
8
8
|
|
9
9
|
# rubocop:disable Style/PerlBackrefs
|
10
10
|
def string_to_utc_time(string)
|
@@ -20,7 +20,7 @@ module ChronoModel
|
|
20
20
|
# rubocop:enable Style/PerlBackrefs
|
21
21
|
|
22
22
|
def time_to_utc_string(time)
|
23
|
-
time.
|
23
|
+
time.to_fs(:db) << '.' << format('%06d', time.usec)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -2,8 +2,4 @@
|
|
2
2
|
|
3
3
|
require 'chrono_model/patches/db_console'
|
4
4
|
|
5
|
-
|
6
|
-
Rails::DBConsole.prepend ChronoModel::Patches::DBConsole::Config
|
7
|
-
else
|
8
|
-
Rails::DBConsole.prepend ChronoModel::Patches::DBConsole::DbConfig
|
9
|
-
end
|
5
|
+
Rails::DBConsole.prepend ChronoModel::Patches::DBConsole::DbConfig
|
@@ -4,16 +4,6 @@ module ChronoModel
|
|
4
4
|
module Patches
|
5
5
|
# This class is a dummy relation whose scope is only to pass around the
|
6
6
|
# as_of_time parameters across ActiveRecord call chains.
|
7
|
-
|
8
|
-
# With AR 5.2 a simple relation can be used, as the only required argument
|
9
|
-
# is the model. 5.0 and 5.1 require more arguments, that are passed here.
|
10
|
-
#
|
11
|
-
class AsOfTimeRelation < ActiveRecord::Relation
|
12
|
-
if ActiveRecord::VERSION::STRING.to_f < 5.2
|
13
|
-
def initialize(klass, table: klass.arel_table, predicate_builder: klass.predicate_builder, values: {})
|
14
|
-
super(klass, table, predicate_builder, values)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
7
|
+
class AsOfTimeRelation < ActiveRecord::Relation; end
|
18
8
|
end
|
19
9
|
end
|
@@ -3,14 +3,10 @@
|
|
3
3
|
module ChronoModel
|
4
4
|
module Patches
|
5
5
|
module Batches
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
else
|
11
|
-
super
|
12
|
-
end
|
13
|
-
end
|
6
|
+
def in_batches(**)
|
7
|
+
return super unless try(:history?)
|
8
|
+
|
9
|
+
with_hid_pkey { super }
|
14
10
|
end
|
15
11
|
end
|
16
12
|
end
|
@@ -5,17 +5,15 @@ module ChronoModel
|
|
5
5
|
module Relation
|
6
6
|
include ChronoModel::Patches::AsOfTimeHolder
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
).call
|
18
|
-
end
|
8
|
+
def preload_associations(records) # :nodoc:
|
9
|
+
preload = preload_values
|
10
|
+
preload += includes_values unless eager_loading?
|
11
|
+
scope = StrictLoadingScope if strict_loading_value
|
12
|
+
|
13
|
+
preload.each do |associations|
|
14
|
+
ActiveRecord::Associations::Preloader.new(
|
15
|
+
records: records, associations: associations, scope: scope, model: model, as_of_time: as_of_time
|
16
|
+
).call
|
19
17
|
end
|
20
18
|
end
|
21
19
|
|
data/lib/chrono_model/railtie.rb
CHANGED
@@ -7,30 +7,11 @@ module ChronoModel
|
|
7
7
|
TASKS_CLASS = ActiveRecord::Tasks::ChronomodelDatabaseTasks
|
8
8
|
|
9
9
|
# Register our database tasks under our adapter name
|
10
|
-
|
11
|
-
ActiveRecord::Tasks::DatabaseTasks.register_task(/chronomodel/, TASKS_CLASS)
|
12
|
-
else
|
13
|
-
ActiveRecord::Tasks::DatabaseTasks.register_task(/chronomodel/, TASKS_CLASS.to_s)
|
14
|
-
end
|
10
|
+
ActiveRecord::Tasks::DatabaseTasks.register_task(/chronomodel/, TASKS_CLASS.to_s)
|
15
11
|
|
16
12
|
rake_tasks do
|
17
13
|
def task_config
|
18
|
-
|
19
|
-
ActiveRecord::Tasks::DatabaseTasks.current_config.with_indifferent_access
|
20
|
-
else
|
21
|
-
ActiveRecord::Base.connection_db_config
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
if Rails.version < '6.1'
|
26
|
-
# Make schema:dump and schema:load invoke structure:dump and structure:load
|
27
|
-
Rake::Task['db:schema:dump'].clear.enhance(['environment']) do
|
28
|
-
Rake::Task['db:structure:dump'].invoke
|
29
|
-
end
|
30
|
-
|
31
|
-
Rake::Task['db:schema:load'].clear.enhance(['environment']) do
|
32
|
-
Rake::Task['db:structure:load'].invoke
|
33
|
-
end
|
14
|
+
ActiveRecord::Base.connection_db_config
|
34
15
|
end
|
35
16
|
|
36
17
|
desc 'Dumps database into db/data.NOW.sql or file specified via DUMP='
|
@@ -59,7 +59,7 @@ module ChronoModel
|
|
59
59
|
relation = relation.from("public.#{quoted_table_name}") unless chrono?
|
60
60
|
relation = relation.where(id: rid) if rid
|
61
61
|
|
62
|
-
sql = "SELECT ts FROM ( #{relation.to_sql} ) AS foo WHERE ts IS NOT NULL"
|
62
|
+
sql = +"SELECT ts FROM ( #{relation.to_sql} ) AS foo WHERE ts IS NOT NULL"
|
63
63
|
|
64
64
|
if options.key?(:before)
|
65
65
|
sql << " AND ts < '#{Conversions.time_to_utc_string(options[:before])}'"
|
@@ -22,37 +22,28 @@ module ChronoModel
|
|
22
22
|
ChronoModel.history_models[table_name] = history
|
23
23
|
|
24
24
|
class << self
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
def subclasses_with_history
|
33
|
-
subclasses(with_history: true)
|
34
|
-
end
|
25
|
+
def subclasses(with_history: false)
|
26
|
+
subclasses = super()
|
27
|
+
subclasses.reject!(&:history?) unless with_history
|
28
|
+
subclasses
|
29
|
+
end
|
35
30
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
alias_method :direct_descendants_with_history, :subclasses_with_history
|
40
|
-
alias_method :direct_descendants, :subclasses
|
41
|
-
end
|
31
|
+
def subclasses_with_history
|
32
|
+
subclasses(with_history: true)
|
33
|
+
end
|
42
34
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
else
|
51
|
-
alias_method :descendants_with_history, :descendants
|
35
|
+
# `direct_descendants` is deprecated method in 7.0 and has been
|
36
|
+
# removed in 7.1
|
37
|
+
if method_defined?(:direct_descendants)
|
38
|
+
alias_method :direct_descendants_with_history, :subclasses_with_history
|
39
|
+
alias_method :direct_descendants, :subclasses
|
40
|
+
end
|
52
41
|
|
53
|
-
|
54
|
-
|
55
|
-
|
42
|
+
# Ruby 3.1 has a native subclasses method and descendants is
|
43
|
+
# implemented with recursion of subclasses
|
44
|
+
if Class.method_defined?(:subclasses)
|
45
|
+
def descendants_with_history
|
46
|
+
subclasses_with_history.concat(subclasses.flat_map(&:descendants_with_history))
|
56
47
|
end
|
57
48
|
end
|
58
49
|
|
data/lib/chrono_model/version.rb
CHANGED
data/lib/chrono_model.rb
CHANGED
@@ -33,7 +33,7 @@ module ChronoModel
|
|
33
33
|
# Computed upon inclusion of the +TimeMachine+ module.
|
34
34
|
#
|
35
35
|
def self.history_models
|
36
|
-
@
|
36
|
+
@history_models ||= {}
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -56,7 +56,7 @@ ActiveSupport.on_load :active_record do
|
|
56
56
|
|
57
57
|
ActiveRecord::Associations::Preloader::ThroughAssociation.prepend ChronoModel::Patches::Preloader::ThroughAssociation
|
58
58
|
|
59
|
-
ActiveRecord::Batches
|
59
|
+
ActiveRecord::Batches.prepend ChronoModel::Patches::Batches
|
60
60
|
end
|
61
61
|
|
62
62
|
ActiveSupport.on_load :after_initialize do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chrono_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcello Barnaba
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-02-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
20
|
+
version: '7.0'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
27
|
+
version: '7.0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: multi_json
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -41,152 +41,12 @@ dependencies:
|
|
41
41
|
version: '0'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: pg
|
44
|
-
requirement: !ruby/object:Gem::Requirement
|
45
|
-
requirements:
|
46
|
-
- - ">"
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: '1.1'
|
49
|
-
type: :runtime
|
50
|
-
prerelease: false
|
51
|
-
version_requirements: !ruby/object:Gem::Requirement
|
52
|
-
requirements:
|
53
|
-
- - ">"
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
version: '1.1'
|
56
|
-
- !ruby/object:Gem::Dependency
|
57
|
-
name: aruba
|
58
|
-
requirement: !ruby/object:Gem::Requirement
|
59
|
-
requirements:
|
60
|
-
- - ">="
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: '0'
|
63
|
-
type: :development
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - ">="
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '0'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: bundler
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - ">="
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: '0'
|
77
|
-
type: :development
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
80
|
-
requirements:
|
81
|
-
- - ">="
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
version: '0'
|
84
|
-
- !ruby/object:Gem::Dependency
|
85
|
-
name: byebug
|
86
|
-
requirement: !ruby/object:Gem::Requirement
|
87
|
-
requirements:
|
88
|
-
- - ">="
|
89
|
-
- !ruby/object:Gem::Version
|
90
|
-
version: '0'
|
91
|
-
type: :development
|
92
|
-
prerelease: false
|
93
|
-
version_requirements: !ruby/object:Gem::Requirement
|
94
|
-
requirements:
|
95
|
-
- - ">="
|
96
|
-
- !ruby/object:Gem::Version
|
97
|
-
version: '0'
|
98
|
-
- !ruby/object:Gem::Dependency
|
99
|
-
name: fuubar
|
100
|
-
requirement: !ruby/object:Gem::Requirement
|
101
|
-
requirements:
|
102
|
-
- - ">="
|
103
|
-
- !ruby/object:Gem::Version
|
104
|
-
version: '0'
|
105
|
-
type: :development
|
106
|
-
prerelease: false
|
107
|
-
version_requirements: !ruby/object:Gem::Requirement
|
108
|
-
requirements:
|
109
|
-
- - ">="
|
110
|
-
- !ruby/object:Gem::Version
|
111
|
-
version: '0'
|
112
|
-
- !ruby/object:Gem::Dependency
|
113
|
-
name: hirb
|
114
|
-
requirement: !ruby/object:Gem::Requirement
|
115
|
-
requirements:
|
116
|
-
- - ">="
|
117
|
-
- !ruby/object:Gem::Version
|
118
|
-
version: '0'
|
119
|
-
type: :development
|
120
|
-
prerelease: false
|
121
|
-
version_requirements: !ruby/object:Gem::Requirement
|
122
|
-
requirements:
|
123
|
-
- - ">="
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
version: '0'
|
126
|
-
- !ruby/object:Gem::Dependency
|
127
|
-
name: pry
|
128
|
-
requirement: !ruby/object:Gem::Requirement
|
129
|
-
requirements:
|
130
|
-
- - ">="
|
131
|
-
- !ruby/object:Gem::Version
|
132
|
-
version: '0'
|
133
|
-
type: :development
|
134
|
-
prerelease: false
|
135
|
-
version_requirements: !ruby/object:Gem::Requirement
|
136
|
-
requirements:
|
137
|
-
- - ">="
|
138
|
-
- !ruby/object:Gem::Version
|
139
|
-
version: '0'
|
140
|
-
- !ruby/object:Gem::Dependency
|
141
|
-
name: rails
|
142
44
|
requirement: !ruby/object:Gem::Requirement
|
143
45
|
requirements:
|
144
46
|
- - ">="
|
145
47
|
- !ruby/object:Gem::Version
|
146
48
|
version: '0'
|
147
|
-
type: :
|
148
|
-
prerelease: false
|
149
|
-
version_requirements: !ruby/object:Gem::Requirement
|
150
|
-
requirements:
|
151
|
-
- - ">="
|
152
|
-
- !ruby/object:Gem::Version
|
153
|
-
version: '0'
|
154
|
-
- !ruby/object:Gem::Dependency
|
155
|
-
name: rake
|
156
|
-
requirement: !ruby/object:Gem::Requirement
|
157
|
-
requirements:
|
158
|
-
- - ">="
|
159
|
-
- !ruby/object:Gem::Version
|
160
|
-
version: '0'
|
161
|
-
type: :development
|
162
|
-
prerelease: false
|
163
|
-
version_requirements: !ruby/object:Gem::Requirement
|
164
|
-
requirements:
|
165
|
-
- - ">="
|
166
|
-
- !ruby/object:Gem::Version
|
167
|
-
version: '0'
|
168
|
-
- !ruby/object:Gem::Dependency
|
169
|
-
name: rspec
|
170
|
-
requirement: !ruby/object:Gem::Requirement
|
171
|
-
requirements:
|
172
|
-
- - ">="
|
173
|
-
- !ruby/object:Gem::Version
|
174
|
-
version: '0'
|
175
|
-
type: :development
|
176
|
-
prerelease: false
|
177
|
-
version_requirements: !ruby/object:Gem::Requirement
|
178
|
-
requirements:
|
179
|
-
- - ">="
|
180
|
-
- !ruby/object:Gem::Version
|
181
|
-
version: '0'
|
182
|
-
- !ruby/object:Gem::Dependency
|
183
|
-
name: simplecov
|
184
|
-
requirement: !ruby/object:Gem::Requirement
|
185
|
-
requirements:
|
186
|
-
- - ">="
|
187
|
-
- !ruby/object:Gem::Version
|
188
|
-
version: '0'
|
189
|
-
type: :development
|
49
|
+
type: :runtime
|
190
50
|
prerelease: false
|
191
51
|
version_requirements: !ruby/object:Gem::Requirement
|
192
52
|
requirements:
|
@@ -211,14 +71,12 @@ files:
|
|
211
71
|
- lib/chrono_model/adapter/ddl.rb
|
212
72
|
- lib/chrono_model/adapter/indexes.rb
|
213
73
|
- lib/chrono_model/adapter/migrations.rb
|
214
|
-
- lib/chrono_model/adapter/migrations_modules/legacy.rb
|
215
74
|
- lib/chrono_model/adapter/migrations_modules/stable.rb
|
216
75
|
- lib/chrono_model/adapter/tsrange.rb
|
217
76
|
- lib/chrono_model/adapter/upgrade.rb
|
218
77
|
- lib/chrono_model/chrono.rb
|
219
78
|
- lib/chrono_model/conversions.rb
|
220
79
|
- lib/chrono_model/db_console.rb
|
221
|
-
- lib/chrono_model/json.rb
|
222
80
|
- lib/chrono_model/patches.rb
|
223
81
|
- lib/chrono_model/patches/as_of_time_holder.rb
|
224
82
|
- lib/chrono_model/patches/as_of_time_relation.rb
|
@@ -252,14 +110,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
252
110
|
requirements:
|
253
111
|
- - ">="
|
254
112
|
- !ruby/object:Gem::Version
|
255
|
-
version:
|
113
|
+
version: '3.0'
|
256
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
257
115
|
requirements:
|
258
116
|
- - ">="
|
259
117
|
- !ruby/object:Gem::Version
|
260
118
|
version: '0'
|
261
119
|
requirements: []
|
262
|
-
rubygems_version: 3.5.
|
120
|
+
rubygems_version: 3.5.5
|
263
121
|
signing_key:
|
264
122
|
specification_version: 4
|
265
123
|
summary: Temporal extensions (SCD Type II) for Active Record
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ChronoModel
|
4
|
-
class Adapter
|
5
|
-
module MigrationsModules
|
6
|
-
module Legacy
|
7
|
-
# If adding an index to a temporal table, add it to the one in the
|
8
|
-
# temporal schema and to the history one. If the `:unique` option is
|
9
|
-
# present, it is removed from the index created in the history table.
|
10
|
-
#
|
11
|
-
def add_index(table_name, column_name, options = {})
|
12
|
-
return super unless is_chrono?(table_name)
|
13
|
-
|
14
|
-
transaction do
|
15
|
-
on_temporal_schema { super }
|
16
|
-
|
17
|
-
# Uniqueness constraints do not make sense in the history table
|
18
|
-
options = options.dup.tap { |o| o.delete(:unique) } if options[:unique].present?
|
19
|
-
|
20
|
-
on_history_schema { super(table_name, column_name, options) }
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# If removing an index from a temporal table, remove it both from the
|
25
|
-
# temporal and the history schemas.
|
26
|
-
#
|
27
|
-
def remove_index(table_name, options = {})
|
28
|
-
return super unless is_chrono?(table_name)
|
29
|
-
|
30
|
-
transaction do
|
31
|
-
on_temporal_schema { super }
|
32
|
-
|
33
|
-
on_history_schema { super }
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
ChronoModel::Adapter::Migrations.include ChronoModel::Adapter::MigrationsModules::Legacy
|
data/lib/chrono_model/json.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ChronoModel
|
4
|
-
module Json
|
5
|
-
extend self
|
6
|
-
|
7
|
-
def create
|
8
|
-
ActiveSupport::Deprecation.warn <<-MSG.squish
|
9
|
-
ChronoModel: JSON ops are deprecated. Please migrate to JSONB.
|
10
|
-
MSG
|
11
|
-
|
12
|
-
adapter.execute 'CREATE OR REPLACE LANGUAGE plpythonu'
|
13
|
-
adapter.execute File.read(sql('json_ops.sql'))
|
14
|
-
end
|
15
|
-
|
16
|
-
def drop
|
17
|
-
adapter.execute File.read(sql('uninstall-json_ops.sql'))
|
18
|
-
adapter.execute 'DROP LANGUAGE IF EXISTS plpythonu'
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def sql(file)
|
24
|
-
"#{File.dirname(__FILE__)}/../../sql/#{file}"
|
25
|
-
end
|
26
|
-
|
27
|
-
def adapter
|
28
|
-
ActiveRecord::Base.connection
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|