activerecord-temporal 0.1.0 → 0.2.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/CHANGELOG.md +8 -0
- data/README.md +775 -7
- data/lib/activerecord/temporal/application_versioning/application_versioned.rb +122 -0
- data/lib/activerecord/temporal/application_versioning/command_recorder.rb +14 -0
- data/lib/activerecord/temporal/application_versioning/migration.rb +25 -0
- data/lib/activerecord/temporal/application_versioning/schema_statements.rb +33 -0
- data/lib/activerecord/temporal/application_versioning.rb +3 -69
- data/lib/activerecord/temporal/patches/association_reflection.rb +10 -3
- data/lib/activerecord/temporal/patches/command_recorder.rb +23 -0
- data/lib/activerecord/temporal/patches/join_dependency.rb +3 -0
- data/lib/activerecord/temporal/patches/merger.rb +1 -1
- data/lib/activerecord/temporal/patches/relation.rb +10 -6
- data/lib/activerecord/temporal/patches/through_association.rb +4 -1
- data/lib/activerecord/temporal/{as_of_query → querying}/association_macros.rb +1 -1
- data/lib/activerecord/temporal/querying/association_scope.rb +55 -0
- data/lib/activerecord/temporal/{as_of_query → querying}/association_walker.rb +1 -1
- data/lib/activerecord/temporal/querying/predicate_builder/contains_handler.rb +24 -0
- data/lib/activerecord/temporal/querying/predicate_builder/handlers.rb +31 -0
- data/lib/activerecord/temporal/querying/query_methods.rb +37 -0
- data/lib/activerecord/temporal/querying/scope_registry.rb +95 -0
- data/lib/activerecord/temporal/querying/scoping.rb +70 -0
- data/lib/activerecord/temporal/{as_of_query → querying}/time_dimensions.rb +13 -3
- data/lib/activerecord/temporal/querying/where_clause_refinement.rb +17 -0
- data/lib/activerecord/temporal/querying.rb +95 -0
- data/lib/activerecord/temporal/scoping.rb +7 -0
- data/lib/activerecord/temporal/system_versioning/command_recorder.rb +27 -1
- data/lib/activerecord/temporal/system_versioning/history_model.rb +47 -0
- data/lib/activerecord/temporal/system_versioning/history_model_namespace.rb +45 -0
- data/lib/activerecord/temporal/system_versioning/history_models.rb +29 -0
- data/lib/activerecord/temporal/system_versioning/migration.rb +35 -0
- data/lib/activerecord/temporal/system_versioning/schema_creation.rb +2 -2
- data/lib/activerecord/temporal/system_versioning/schema_statements.rb +80 -8
- data/lib/activerecord/temporal/system_versioning/system_versioned.rb +13 -0
- data/lib/activerecord/temporal/system_versioning.rb +6 -18
- data/lib/activerecord/temporal/version.rb +1 -1
- data/lib/activerecord/temporal.rb +75 -30
- metadata +27 -14
- data/lib/activerecord/temporal/as_of_query/association_scope.rb +0 -54
- data/lib/activerecord/temporal/as_of_query/query_methods.rb +0 -24
- data/lib/activerecord/temporal/as_of_query/scope_registry.rb +0 -38
- data/lib/activerecord/temporal/as_of_query.rb +0 -109
- data/lib/activerecord/temporal/system_versioning/model.rb +0 -37
- data/lib/activerecord/temporal/system_versioning/namespace.rb +0 -34
|
@@ -1,63 +1,108 @@
|
|
|
1
1
|
require "active_support"
|
|
2
2
|
|
|
3
|
-
require_relative "temporal/application_versioning"
|
|
4
|
-
require_relative "temporal/
|
|
5
|
-
require_relative "temporal/
|
|
6
|
-
require_relative "temporal/
|
|
7
|
-
require_relative "temporal/
|
|
8
|
-
require_relative "temporal/
|
|
9
|
-
require_relative "temporal/
|
|
10
|
-
require_relative "temporal/
|
|
3
|
+
require_relative "temporal/application_versioning/application_versioned"
|
|
4
|
+
require_relative "temporal/application_versioning/command_recorder"
|
|
5
|
+
require_relative "temporal/application_versioning/migration"
|
|
6
|
+
require_relative "temporal/application_versioning/schema_statements"
|
|
7
|
+
require_relative "temporal/querying/association_macros"
|
|
8
|
+
require_relative "temporal/querying/association_scope"
|
|
9
|
+
require_relative "temporal/querying/association_walker"
|
|
10
|
+
require_relative "temporal/querying/predicate_builder/handlers"
|
|
11
|
+
require_relative "temporal/querying/query_methods"
|
|
12
|
+
require_relative "temporal/querying/scope_registry"
|
|
13
|
+
require_relative "temporal/querying/scoping"
|
|
14
|
+
require_relative "temporal/querying/time_dimensions"
|
|
11
15
|
require_relative "temporal/patches/association_reflection"
|
|
16
|
+
require_relative "temporal/patches/command_recorder"
|
|
12
17
|
require_relative "temporal/patches/join_dependency"
|
|
13
18
|
require_relative "temporal/patches/merger"
|
|
14
19
|
require_relative "temporal/patches/relation"
|
|
15
20
|
require_relative "temporal/patches/through_association"
|
|
16
|
-
require_relative "temporal/system_versioning"
|
|
17
21
|
require_relative "temporal/system_versioning/command_recorder"
|
|
18
|
-
require_relative "temporal/system_versioning/
|
|
19
|
-
require_relative "temporal/system_versioning/
|
|
22
|
+
require_relative "temporal/system_versioning/history_model_namespace"
|
|
23
|
+
require_relative "temporal/system_versioning/history_model"
|
|
24
|
+
require_relative "temporal/system_versioning/history_models"
|
|
25
|
+
require_relative "temporal/system_versioning/migration"
|
|
20
26
|
require_relative "temporal/system_versioning/schema_creation"
|
|
21
27
|
require_relative "temporal/system_versioning/schema_definitions"
|
|
22
28
|
require_relative "temporal/system_versioning/schema_statements"
|
|
29
|
+
require_relative "temporal/system_versioning/system_versioned"
|
|
30
|
+
require_relative "temporal/application_versioning"
|
|
31
|
+
require_relative "temporal/querying"
|
|
32
|
+
require_relative "temporal/scoping"
|
|
33
|
+
require_relative "temporal/system_versioning"
|
|
34
|
+
|
|
35
|
+
module ActiveRecord::Temporal
|
|
36
|
+
def system_versioning
|
|
37
|
+
include SystemVersioning
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def application_versioning(**options)
|
|
41
|
+
include Querying
|
|
42
|
+
include ApplicationVersioning
|
|
43
|
+
|
|
44
|
+
self.time_dimensions = options[:dimensions] if options[:dimensions]
|
|
45
|
+
end
|
|
46
|
+
end
|
|
23
47
|
|
|
24
48
|
ActiveSupport.on_load(:active_record) do
|
|
25
49
|
require "active_record/connection_adapters/postgresql_adapter" # TODO: add test
|
|
26
50
|
|
|
27
|
-
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
|
52
|
+
.include ActiveRecord::Temporal::ApplicationVersioning::SchemaStatements
|
|
53
|
+
|
|
54
|
+
ActiveRecord::Migration::CommandRecorder
|
|
55
|
+
.include ActiveRecord::Temporal::ApplicationVersioning::CommandRecorder
|
|
56
|
+
|
|
57
|
+
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
|
58
|
+
.include ActiveRecord::Temporal::SystemVersioning::SchemaStatements
|
|
59
|
+
|
|
60
|
+
ActiveRecord::Migration::CommandRecorder
|
|
61
|
+
.include ActiveRecord::Temporal::SystemVersioning::CommandRecorder
|
|
62
|
+
|
|
63
|
+
ActiveRecord::Relation
|
|
64
|
+
.include ActiveRecord::Temporal::Querying::QueryMethods
|
|
30
65
|
|
|
31
66
|
# Patches
|
|
32
67
|
|
|
33
|
-
# Patches
|
|
68
|
+
# Patches `#invert_drop` to remove the `system_versioning` option. The original
|
|
69
|
+
# method determines reversibility by looking for the presence of arguments
|
|
70
|
+
ActiveRecord::Migration::CommandRecorder
|
|
71
|
+
.prepend ActiveRecord::Temporal::Patches::CommandRecorder
|
|
72
|
+
|
|
73
|
+
# Patches `#build_arel` to wrap itself in the as-of query scope registry.
|
|
34
74
|
# This is what allows temporal association scopes to be aware of the time-scope
|
|
35
75
|
# value of the relation that included them.
|
|
36
76
|
#
|
|
37
|
-
# Patches
|
|
77
|
+
# Patches `#instantiate_records` method to call `initialize_time_tags_from_relation`
|
|
38
78
|
# on each loaded record.
|
|
39
|
-
ActiveRecord::Relation
|
|
79
|
+
ActiveRecord::Relation
|
|
80
|
+
.prepend ActiveRecord::Temporal::Patches::Relation
|
|
40
81
|
|
|
41
|
-
# Patches
|
|
42
|
-
#
|
|
43
|
-
ActiveRecord::Relation::Merger
|
|
82
|
+
# Patches `#merge` (called by `Relation#merge`) to handle the new query method
|
|
83
|
+
# `time_tags` that this gem adds.
|
|
84
|
+
ActiveRecord::Relation::Merger
|
|
85
|
+
.prepend ActiveRecord::Temporal::Patches::Merger
|
|
44
86
|
|
|
45
|
-
# Patches
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
ActiveRecord::Associations::Preloader::ThroughAssociation
|
|
87
|
+
# Patches `#through_scope` to pass along the relation's time tag values when it
|
|
88
|
+
# handles has-many-through associations. The handler for has-many association
|
|
89
|
+
# uses `Relation#merge`, but this one doesn't.
|
|
90
|
+
ActiveRecord::Associations::Preloader::ThroughAssociation
|
|
91
|
+
.prepend ActiveRecord::Temporal::Patches::ThroughAssociation
|
|
49
92
|
|
|
50
93
|
# This permits association scopes generated by this gem to be eager-load if they
|
|
51
|
-
# are "optionally instance-dependent." That is to say, they accept
|
|
52
|
-
#
|
|
94
|
+
# are "optionally instance-dependent." That is to say, they accept but don't
|
|
95
|
+
# require arguments.
|
|
53
96
|
#
|
|
54
|
-
# I think permitting eager-loading
|
|
55
|
-
#
|
|
97
|
+
# I think permitting eager-loading of such scopes would make sense as a
|
|
98
|
+
# standalone feature for Active Record. See this PR for my justification:
|
|
56
99
|
# https://github.com/rails/rails/pull/56004
|
|
57
|
-
ActiveRecord::Reflection::AssociationReflection
|
|
100
|
+
ActiveRecord::Reflection::AssociationReflection
|
|
101
|
+
.prepend ActiveRecord::Temporal::Patches::AssociationReflection
|
|
58
102
|
|
|
59
103
|
# This is a copy of a fix from https://github.com/rails/rails/pull/56088 that
|
|
60
104
|
# impacts this gem. I has been backported to supported stable versions of
|
|
61
105
|
# Active Record, but until those patches are released it's included here.
|
|
62
|
-
ActiveRecord::Associations::JoinDependency
|
|
106
|
+
ActiveRecord::Associations::JoinDependency
|
|
107
|
+
.prepend ActiveRecord::Temporal::Patches::JoinDependency
|
|
63
108
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-temporal
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Martin-Alexander
|
|
@@ -15,7 +15,7 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '
|
|
18
|
+
version: '8'
|
|
19
19
|
- - "<"
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
21
|
version: '9.0'
|
|
@@ -25,7 +25,7 @@ dependencies:
|
|
|
25
25
|
requirements:
|
|
26
26
|
- - ">="
|
|
27
27
|
- !ruby/object:Gem::Version
|
|
28
|
-
version: '
|
|
28
|
+
version: '8'
|
|
29
29
|
- - "<"
|
|
30
30
|
- !ruby/object:Gem::Version
|
|
31
31
|
version: '9.0'
|
|
@@ -35,7 +35,7 @@ dependencies:
|
|
|
35
35
|
requirements:
|
|
36
36
|
- - ">="
|
|
37
37
|
- !ruby/object:Gem::Version
|
|
38
|
-
version: '
|
|
38
|
+
version: '8'
|
|
39
39
|
- - "<"
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
41
|
version: '9.0'
|
|
@@ -45,7 +45,7 @@ dependencies:
|
|
|
45
45
|
requirements:
|
|
46
46
|
- - ">="
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
|
-
version: '
|
|
48
|
+
version: '8'
|
|
49
49
|
- - "<"
|
|
50
50
|
- !ruby/object:Gem::Version
|
|
51
51
|
version: '9.0'
|
|
@@ -77,25 +77,38 @@ files:
|
|
|
77
77
|
- README.md
|
|
78
78
|
- lib/activerecord/temporal.rb
|
|
79
79
|
- lib/activerecord/temporal/application_versioning.rb
|
|
80
|
-
- lib/activerecord/temporal/
|
|
81
|
-
- lib/activerecord/temporal/
|
|
82
|
-
- lib/activerecord/temporal/
|
|
83
|
-
- lib/activerecord/temporal/
|
|
84
|
-
- lib/activerecord/temporal/as_of_query/query_methods.rb
|
|
85
|
-
- lib/activerecord/temporal/as_of_query/scope_registry.rb
|
|
86
|
-
- lib/activerecord/temporal/as_of_query/time_dimensions.rb
|
|
80
|
+
- lib/activerecord/temporal/application_versioning/application_versioned.rb
|
|
81
|
+
- lib/activerecord/temporal/application_versioning/command_recorder.rb
|
|
82
|
+
- lib/activerecord/temporal/application_versioning/migration.rb
|
|
83
|
+
- lib/activerecord/temporal/application_versioning/schema_statements.rb
|
|
87
84
|
- lib/activerecord/temporal/patches/association_reflection.rb
|
|
85
|
+
- lib/activerecord/temporal/patches/command_recorder.rb
|
|
88
86
|
- lib/activerecord/temporal/patches/join_dependency.rb
|
|
89
87
|
- lib/activerecord/temporal/patches/merger.rb
|
|
90
88
|
- lib/activerecord/temporal/patches/relation.rb
|
|
91
89
|
- lib/activerecord/temporal/patches/through_association.rb
|
|
90
|
+
- lib/activerecord/temporal/querying.rb
|
|
91
|
+
- lib/activerecord/temporal/querying/association_macros.rb
|
|
92
|
+
- lib/activerecord/temporal/querying/association_scope.rb
|
|
93
|
+
- lib/activerecord/temporal/querying/association_walker.rb
|
|
94
|
+
- lib/activerecord/temporal/querying/predicate_builder/contains_handler.rb
|
|
95
|
+
- lib/activerecord/temporal/querying/predicate_builder/handlers.rb
|
|
96
|
+
- lib/activerecord/temporal/querying/query_methods.rb
|
|
97
|
+
- lib/activerecord/temporal/querying/scope_registry.rb
|
|
98
|
+
- lib/activerecord/temporal/querying/scoping.rb
|
|
99
|
+
- lib/activerecord/temporal/querying/time_dimensions.rb
|
|
100
|
+
- lib/activerecord/temporal/querying/where_clause_refinement.rb
|
|
101
|
+
- lib/activerecord/temporal/scoping.rb
|
|
92
102
|
- lib/activerecord/temporal/system_versioning.rb
|
|
93
103
|
- lib/activerecord/temporal/system_versioning/command_recorder.rb
|
|
94
|
-
- lib/activerecord/temporal/system_versioning/
|
|
95
|
-
- lib/activerecord/temporal/system_versioning/
|
|
104
|
+
- lib/activerecord/temporal/system_versioning/history_model.rb
|
|
105
|
+
- lib/activerecord/temporal/system_versioning/history_model_namespace.rb
|
|
106
|
+
- lib/activerecord/temporal/system_versioning/history_models.rb
|
|
107
|
+
- lib/activerecord/temporal/system_versioning/migration.rb
|
|
96
108
|
- lib/activerecord/temporal/system_versioning/schema_creation.rb
|
|
97
109
|
- lib/activerecord/temporal/system_versioning/schema_definitions.rb
|
|
98
110
|
- lib/activerecord/temporal/system_versioning/schema_statements.rb
|
|
111
|
+
- lib/activerecord/temporal/system_versioning/system_versioned.rb
|
|
99
112
|
- lib/activerecord/temporal/version.rb
|
|
100
113
|
homepage: https://github.com/Martin-Alexander/activerecord-temporal
|
|
101
114
|
licenses:
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
module ActiveRecord::Temporal
|
|
2
|
-
module AsOfQuery
|
|
3
|
-
class AssociationScope
|
|
4
|
-
class << self
|
|
5
|
-
def build(block)
|
|
6
|
-
scope = build_scope(block || default_base_scope)
|
|
7
|
-
|
|
8
|
-
def scope.as_of_scope? = true
|
|
9
|
-
|
|
10
|
-
scope
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
private
|
|
14
|
-
|
|
15
|
-
def build_scope(block)
|
|
16
|
-
temporal_scope = build_temporal_scope
|
|
17
|
-
|
|
18
|
-
if block.arity != 0
|
|
19
|
-
return ->(owner) do
|
|
20
|
-
base = instance_exec(owner, &block)
|
|
21
|
-
instance_exec(owner, base, &temporal_scope)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
->(owner = nil) do
|
|
26
|
-
base = instance_exec(owner, &block)
|
|
27
|
-
instance_exec(owner, base, &temporal_scope)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def build_temporal_scope
|
|
32
|
-
->(owner, base) do
|
|
33
|
-
time_scopes = ScopeRegistry.query_scope_for(time_dimensions)
|
|
34
|
-
owner_time_scopes = owner&.time_scopes_for(time_dimensions)
|
|
35
|
-
|
|
36
|
-
time_scopes.merge!(owner_time_scopes) if owner_time_scopes
|
|
37
|
-
|
|
38
|
-
default_time_scopes = time_dimensions.map do |dimension|
|
|
39
|
-
[dimension, Time.current]
|
|
40
|
-
end.to_h
|
|
41
|
-
|
|
42
|
-
time_scope_constraints = default_time_scopes.merge(time_scopes)
|
|
43
|
-
|
|
44
|
-
base.existed_at(time_scope_constraints).time_scope(time_scopes)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def default_base_scope
|
|
49
|
-
proc { all }
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
module ActiveRecord::Temporal
|
|
2
|
-
module AsOfQuery
|
|
3
|
-
module QueryMethods
|
|
4
|
-
def time_scope(scope)
|
|
5
|
-
spawn.time_scope!(scope)
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def time_scope!(scope)
|
|
9
|
-
self.time_scope_values = time_scope_values.merge(scope)
|
|
10
|
-
self
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def time_scope_values
|
|
14
|
-
@values.fetch(:time_scope, ActiveRecord::QueryMethods::FROZEN_EMPTY_HASH)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def time_scope_values=(scope)
|
|
18
|
-
assert_modifiable! # TODO: write test
|
|
19
|
-
|
|
20
|
-
@values[:time_scope] = scope
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
module ActiveRecord::Temporal
|
|
2
|
-
module AsOfQuery
|
|
3
|
-
class ScopeRegistry
|
|
4
|
-
class << self
|
|
5
|
-
delegate :default_scopes, :query_scopes, :set_default_scopes, :query_scope_for, :with_query_scope, to: :instance
|
|
6
|
-
|
|
7
|
-
def instance
|
|
8
|
-
ActiveSupport::IsolatedExecutionState[:temporal_as_of_query_registry] ||= new
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
attr_reader :default_scopes, :query_scopes
|
|
13
|
-
|
|
14
|
-
def initialize
|
|
15
|
-
@default_scopes = {}
|
|
16
|
-
@query_scopes = {}
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def set_default_scopes(default_scopes)
|
|
20
|
-
@default_scopes = default_scopes
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def query_scope_for(dimensions)
|
|
24
|
-
query_scopes.slice(*dimensions)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def with_query_scope(scope, &block)
|
|
28
|
-
original = @query_scopes.dup
|
|
29
|
-
|
|
30
|
-
@query_scopes = @query_scopes.merge(scope)
|
|
31
|
-
|
|
32
|
-
block.call
|
|
33
|
-
ensure
|
|
34
|
-
@query_scopes = original
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
module ActiveRecord::Temporal
|
|
2
|
-
module AsOfQuery
|
|
3
|
-
class RangeError < StandardError; end
|
|
4
|
-
|
|
5
|
-
extend ActiveSupport::Concern
|
|
6
|
-
|
|
7
|
-
class_methods do
|
|
8
|
-
def existed_at_constraint(arel_table, time, time_dimension)
|
|
9
|
-
time_as_tstz = Arel::Nodes::As.new(
|
|
10
|
-
Arel::Nodes::Quoted.new(time),
|
|
11
|
-
Arel::Nodes::SqlLiteral.new("timestamptz")
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
cast_value = Arel::Nodes::NamedFunction.new("CAST", [time_as_tstz])
|
|
15
|
-
|
|
16
|
-
arel_table[time_dimension].contains(cast_value)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def temporal_association_scope(&block)
|
|
20
|
-
AssociationScope.build(block)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def resolve_time_scopes(time_or_time_scopes)
|
|
24
|
-
return time_or_time_scopes if time_or_time_scopes.is_a?(Hash)
|
|
25
|
-
|
|
26
|
-
{default_time_dimension.to_sym => time_or_time_scopes}
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
included do
|
|
31
|
-
include AssociationMacros
|
|
32
|
-
include TimeDimensions
|
|
33
|
-
|
|
34
|
-
delegate :resolve_time_scopes, to: :class
|
|
35
|
-
|
|
36
|
-
scope :as_of, ->(time) do
|
|
37
|
-
time_scopes = resolve_time_scopes(time)
|
|
38
|
-
|
|
39
|
-
existed_at(time_scopes).time_scope(time_scopes)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
scope :existed_at, ->(time) do
|
|
43
|
-
time_scopes = resolve_time_scopes(time)
|
|
44
|
-
|
|
45
|
-
rel = all
|
|
46
|
-
|
|
47
|
-
time_scopes.each do |time_dimension, time|
|
|
48
|
-
next unless time_dimension_column?(time_dimension)
|
|
49
|
-
|
|
50
|
-
rel = rel.where(existed_at_constraint(table, time, time_dimension))
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
rel
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def time_scopes
|
|
58
|
-
@time_scopes || {}
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def time_scopes=(value)
|
|
62
|
-
@time_scopes = value&.slice(*time_dimensions)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def time_scope
|
|
66
|
-
time_scopes[default_time_dimension]
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def time_scopes_for(time_dimensions)
|
|
70
|
-
time_scopes.slice(*time_dimensions)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def as_of!(time)
|
|
74
|
-
time_scopes = resolve_time_scopes(time)
|
|
75
|
-
|
|
76
|
-
ensure_time_scopes_in_bounds!(time_scopes)
|
|
77
|
-
|
|
78
|
-
reload
|
|
79
|
-
|
|
80
|
-
self.time_scopes = time_scopes
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def as_of(time)
|
|
84
|
-
time_scopes = resolve_time_scopes(time)
|
|
85
|
-
|
|
86
|
-
self.class.as_of(time_scopes).find_by(self.class.primary_key => [id])
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def initialize_time_scope_from_relation(relation)
|
|
90
|
-
associations = relation.includes_values | relation.eager_load_values
|
|
91
|
-
|
|
92
|
-
self.time_scopes = relation.time_scope_values
|
|
93
|
-
|
|
94
|
-
AssociationWalker.each_target(self, associations) do |target|
|
|
95
|
-
target.time_scopes = relation.time_scope_values
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
private
|
|
100
|
-
|
|
101
|
-
def ensure_time_scopes_in_bounds!(time_scopes)
|
|
102
|
-
time_scopes.each do |dimension, time|
|
|
103
|
-
if time_dimension_column?(dimension) && !time_dimension(dimension).cover?(time)
|
|
104
|
-
raise RangeError, "#{time} is outside of '#{dimension}' range"
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
end
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
module ActiveRecord::Temporal
|
|
2
|
-
module SystemVersioning
|
|
3
|
-
module Model
|
|
4
|
-
extend ActiveSupport::Concern
|
|
5
|
-
|
|
6
|
-
included do
|
|
7
|
-
include AsOfQuery
|
|
8
|
-
|
|
9
|
-
set_time_dimensions :system_period
|
|
10
|
-
|
|
11
|
-
reflect_on_all_associations.each do |reflection|
|
|
12
|
-
scope = temporal_association_scope(&reflection.scope)
|
|
13
|
-
|
|
14
|
-
send(reflection.macro, reflection.name, scope, **reflection.options)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
class_methods do
|
|
19
|
-
def polymorphic_class_for(name)
|
|
20
|
-
super.version_model
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def sti_name
|
|
24
|
-
superclass.sti_name
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def find_sti_class(type_name)
|
|
28
|
-
superclass.send(:find_sti_class, type_name).version_model
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def finder_needs_type_condition?
|
|
32
|
-
superclass.finder_needs_type_condition?
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
module ActiveRecord::Temporal
|
|
2
|
-
module SystemVersioning
|
|
3
|
-
module Namespace
|
|
4
|
-
extend ActiveSupport::Concern
|
|
5
|
-
|
|
6
|
-
class_methods do
|
|
7
|
-
def const_missing(name)
|
|
8
|
-
model = name.to_s.constantize
|
|
9
|
-
rescue NameError
|
|
10
|
-
super
|
|
11
|
-
else
|
|
12
|
-
unless model.is_a?(Class) && model < ActiveRecord::Base
|
|
13
|
-
raise NameError, "#{model} is not a descendent of ActiveRecord::Base"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
version_model = if (history_table = model.history_table)
|
|
17
|
-
Class.new(model) do
|
|
18
|
-
self.table_name = history_table
|
|
19
|
-
self.primary_key = model.primary_key_from_db + [:system_period]
|
|
20
|
-
|
|
21
|
-
include Model
|
|
22
|
-
end
|
|
23
|
-
else
|
|
24
|
-
Class.new(model) do
|
|
25
|
-
include Model
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
const_set(name, version_model)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|