chrono_model 0.13.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +8 -8
- data/README.md +2 -2
- data/chrono_model.gemspec +1 -1
- data/gemfiles/rails_5.0.gemfile +0 -1
- data/gemfiles/rails_5.1.gemfile +0 -1
- data/gemfiles/rails_5.2.gemfile +6 -0
- data/lib/active_record/connection_adapters/chronomodel_adapter.rb +1 -5
- data/lib/chrono_model/adapter.rb +4 -4
- data/lib/chrono_model/patches.rb +30 -29
- data/lib/chrono_model/time_machine.rb +26 -34
- data/lib/chrono_model/version.rb +1 -1
- data/spec/aruba/migrations_spec.rb +4 -18
- data/spec/aruba/rake_task_spec.rb +4 -4
- data/spec/json_ops_spec.rb +5 -5
- data/spec/spec_helper.rb +0 -3
- data/spec/support/aruba.rb +0 -5
- data/spec/support/matchers/function.rb +1 -1
- data/spec/support/matchers/table.rb +3 -3
- data/spec/time_machine_spec.rb +1 -1
- metadata +5 -11
- data/gemfiles/rails_4.2.gemfile +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2697fea79973f57287cdb45ffa3bc3e5ecac4b3ad0c9b98b30ac77412a39727e
|
4
|
+
data.tar.gz: 2d683ca63fccf590d3f90e0196e8c3392e1033d726181a772ea80fba9acb8515
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbe2f67c78f27a89c007007dcf2b29e40ddafee336191be41fa05e40cea2f0cc5bbf0c509c46facc756ff03f212b203b4f7824ce8ec7e7d376610f1b03797204
|
7
|
+
data.tar.gz: 89f588e6b34b4b841e2a6f1b5bda6d7c9ee55a497134d738be53e9c08db6f3bef87a061421860524ada85f370e1c1e492ef0b54488cfda5bacdfe7eb84277de6
|
data/.travis.yml
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
rvm:
|
2
|
-
- 2.2.7
|
3
2
|
- 2.3
|
4
3
|
- 2.4
|
4
|
+
- 2.5
|
5
5
|
|
6
6
|
gemfile:
|
7
|
-
- gemfiles/rails_4.2.gemfile
|
8
7
|
- gemfiles/rails_5.0.gemfile
|
9
8
|
- gemfiles/rails_5.1.gemfile
|
9
|
+
- gemfiles/rails_5.2.gemfile
|
10
10
|
|
11
|
-
matrix:
|
12
|
-
exclude:
|
13
|
-
- rvm: 2.4
|
14
|
-
gemfile: gemfiles/rails_4.2.gemfile
|
11
|
+
#matrix:
|
12
|
+
# exclude:
|
13
|
+
# - rvm: 2.4
|
14
|
+
# gemfile: gemfiles/rails_4.2.gemfile
|
15
15
|
|
16
16
|
sudo: false
|
17
17
|
|
@@ -19,9 +19,9 @@ language: ruby
|
|
19
19
|
cache: bundler
|
20
20
|
|
21
21
|
addons:
|
22
|
-
postgresql: "9.
|
22
|
+
postgresql: "9.6"
|
23
23
|
apt:
|
24
|
-
packages: postgresql-plpython-9.
|
24
|
+
packages: postgresql-plpython-9.6
|
25
25
|
code_climate:
|
26
26
|
repo_token: dedfb7472ee410eec459bff3681d9a8fd8dd237e9bd7e8675a7c8eb7e253bba9
|
27
27
|
|
data/README.md
CHANGED
@@ -65,8 +65,8 @@ All timestamps are _forcibly_ stored in as UTC, bypassing the
|
|
65
65
|
|
66
66
|
## Requirements
|
67
67
|
|
68
|
-
* Ruby >= 2.
|
69
|
-
* Active Record
|
68
|
+
* Ruby >= 2.3
|
69
|
+
* Active Record >= 5.0. See the [detailed supported versions matrix on travis](https://travis-ci.org/ifad/chronomodel)
|
70
70
|
* PostgreSQL >= 9.3
|
71
71
|
* The `btree_gist` PostgreSQL extension
|
72
72
|
* The `plpython` PostgreSQL extension if you have *JSON* (*not* JSONB) columns
|
data/chrono_model.gemspec
CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = ChronoModel::VERSION
|
17
17
|
|
18
|
-
gem.add_dependency 'activerecord', '>=
|
18
|
+
gem.add_dependency 'activerecord', '>= 5.0.0'
|
19
19
|
gem.add_dependency "pg"
|
20
20
|
gem.add_dependency "multi_json"
|
21
21
|
|
data/gemfiles/rails_5.0.gemfile
CHANGED
data/gemfiles/rails_5.1.gemfile
CHANGED
@@ -17,11 +17,7 @@ module ActiveRecord
|
|
17
17
|
conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
|
18
18
|
|
19
19
|
# Forward only valid config params to PG::Connection.connect.
|
20
|
-
valid_conn_param_keys =
|
21
|
-
VALID_CONN_PARAMS
|
22
|
-
else
|
23
|
-
PG::Connection.conndefaults_hash.keys + [:requiressl]
|
24
|
-
end
|
20
|
+
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
|
25
21
|
conn_params.slice!(*valid_conn_param_keys)
|
26
22
|
|
27
23
|
# The postgres drivers don't allow the creation of an unconnected PG::Connection object,
|
data/lib/chrono_model/adapter.rb
CHANGED
@@ -35,8 +35,8 @@ module ChronoModel
|
|
35
35
|
return super unless options[:temporal]
|
36
36
|
|
37
37
|
if options[:id] == false
|
38
|
-
logger.warn "
|
39
|
-
logger.warn "
|
38
|
+
logger.warn "ChronoModel: Temporal Temporal tables require a primary key."
|
39
|
+
logger.warn "ChronoModel: Adding a `__chrono_id' primary key to #{table_name} definition."
|
40
40
|
|
41
41
|
options[:id] = '__chrono_id'
|
42
42
|
end
|
@@ -511,7 +511,7 @@ module ChronoModel
|
|
511
511
|
end
|
512
512
|
end
|
513
513
|
|
514
|
-
def initialize_type_map(type_map)
|
514
|
+
def initialize_type_map(m = type_map)
|
515
515
|
super.tap do
|
516
516
|
ar_type = type_map.fetch(TSRange::OID)
|
517
517
|
cm_type = TSRange.new(ar_type.subtype, ar_type.type)
|
@@ -601,7 +601,7 @@ module ChronoModel
|
|
601
601
|
upgrade_from_legacy(table_name)
|
602
602
|
logger.info "ChronoModel: legacy #{table_name} upgrade complete"
|
603
603
|
else
|
604
|
-
logger.info "ChronoModel: upgrading #{table_name} from #{
|
604
|
+
logger.info "ChronoModel: upgrading #{table_name} from #{version} to #{VERSION}"
|
605
605
|
chrono_create_view_for(table_name)
|
606
606
|
logger.info "ChronoModel: #{table_name} upgrade complete"
|
607
607
|
end
|
data/lib/chrono_model/patches.rb
CHANGED
@@ -6,8 +6,6 @@ module ChronoModel
|
|
6
6
|
module AsOfTimeHolder
|
7
7
|
# Sets the virtual 'as_of_time' attribute to the given time, converting to UTC.
|
8
8
|
#
|
9
|
-
# See ChronoModel::Patches::AsOfTimeHolder
|
10
|
-
#
|
11
9
|
def as_of_time!(time)
|
12
10
|
@_as_of_time = time.utc
|
13
11
|
|
@@ -16,14 +14,12 @@ module ChronoModel
|
|
16
14
|
|
17
15
|
# Reads the virtual 'as_of_time' attribute
|
18
16
|
#
|
19
|
-
# See ChronoModel::Patches::AsOfTimeHolder
|
20
|
-
#
|
21
17
|
def as_of_time
|
22
18
|
@_as_of_time
|
23
19
|
end
|
24
20
|
end
|
25
21
|
|
26
|
-
# This class supports the AR
|
22
|
+
# This class supports the AR 5.0 code that expects to receive an
|
27
23
|
# Arel::Table as the left join node. We need to replace the node
|
28
24
|
# with a virtual table that fetches from the history at a given
|
29
25
|
# point in time, we replace the join node with a SqlLiteral node
|
@@ -65,7 +61,7 @@ module ChronoModel
|
|
65
61
|
super.as_of_time!(@_as_of_time)
|
66
62
|
end
|
67
63
|
|
68
|
-
def build_arel
|
64
|
+
def build_arel(*)
|
69
65
|
return super unless @_as_of_time
|
70
66
|
|
71
67
|
super.tap do |arel|
|
@@ -85,11 +81,27 @@ module ChronoModel
|
|
85
81
|
end
|
86
82
|
end
|
87
83
|
|
88
|
-
# Build a preloader at the +as_of_time+ of this relation
|
84
|
+
# Build a preloader at the +as_of_time+ of this relation.
|
85
|
+
# Pass the current model to define Relation
|
89
86
|
#
|
90
87
|
def build_preloader
|
91
|
-
|
92
|
-
|
88
|
+
ActiveRecord::Associations::Preloader.new(
|
89
|
+
model: self.model, as_of_time: as_of_time
|
90
|
+
)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# This class is a dummy relation whose scope is only to pass around the
|
95
|
+
# as_of_time parameters across ActiveRecord call chains.
|
96
|
+
#
|
97
|
+
# With AR 5.2 a simple relation can be used, as the only required argument
|
98
|
+
# is the model. 5.0 and 5.1 require more arguments, that are passed here.
|
99
|
+
#
|
100
|
+
class AsOfTimeRelation < ActiveRecord::Relation
|
101
|
+
if ActiveRecord::VERSION::STRING.to_f < 5.2
|
102
|
+
def initialize(klass, table: klass.arel_table, predicate_builder: klass.predicate_builder, values: {})
|
103
|
+
super(klass, table, predicate_builder, values)
|
104
|
+
end
|
93
105
|
end
|
94
106
|
end
|
95
107
|
|
@@ -107,13 +119,6 @@ module ChronoModel
|
|
107
119
|
@options = options.freeze
|
108
120
|
end
|
109
121
|
|
110
|
-
# See +ActiveRecord::Associations::Preloader::NULL_RELATION+
|
111
|
-
NULL_RELATION = ActiveRecord::Associations::Preloader::NULL_RELATION
|
112
|
-
|
113
|
-
# Extend +NULL_RELATION+ by adding the +as_of_time!+ method.
|
114
|
-
# See +preload+ and +AsOfTimeHolder+.
|
115
|
-
NULL_RELATION.class.instance_eval { include AsOfTimeHolder }
|
116
|
-
|
117
122
|
# Patches the AR Preloader (lib/active_record/associations/preloader.rb)
|
118
123
|
# in order to carry around the +as_of_time+ of the original invocation.
|
119
124
|
#
|
@@ -128,22 +133,18 @@ module ChronoModel
|
|
128
133
|
# around the +as_of_time+ of the original query invocation, so that
|
129
134
|
# preloaded records are preloaded honoring the +as_of_time+.
|
130
135
|
#
|
131
|
-
# The +preload_scope+ is
|
136
|
+
# The +preload_scope+ is present only in through associations, but the
|
132
137
|
# preloader interfaces expect it to be always defined, for consistency.
|
133
138
|
#
|
134
|
-
# So, AR defines a +NULL_RELATION+ constant to pass around for the
|
135
|
-
# association types that do not have a preload_scope. It quacks like a
|
136
|
-
# Relation, and it contains only the methods that are used by the other
|
137
|
-
# preloader methods. We use this +NULL_RELATION+ to which we have added
|
138
|
-
# the `as_of_time!` holder method.
|
139
|
-
#
|
140
139
|
# For `:through` associations, the +given_preload_scope+ is already a
|
141
140
|
# +Relation+, that already has the +as_of_time+ getters and setters,
|
142
141
|
# so we use it directly.
|
143
142
|
#
|
144
143
|
def preload(records, associations, given_preload_scope = nil)
|
145
|
-
if options
|
146
|
-
preload_scope = given_preload_scope ||
|
144
|
+
if options[:as_of_time]
|
145
|
+
preload_scope = given_preload_scope ||
|
146
|
+
AsOfTimeRelation.new(options[:model])
|
147
|
+
|
147
148
|
preload_scope.as_of_time!(options[:as_of_time])
|
148
149
|
end
|
149
150
|
|
@@ -152,13 +153,13 @@ module ChronoModel
|
|
152
153
|
|
153
154
|
module Association
|
154
155
|
# Builds the preloader scope taking into account a potential
|
155
|
-
# +as_of_time+
|
156
|
-
# user
|
156
|
+
# +as_of_time+ passed down the call chain starting at the
|
157
|
+
# end user invocation.
|
157
158
|
#
|
158
159
|
def build_scope
|
159
160
|
scope = super
|
160
161
|
|
161
|
-
if preload_scope.
|
162
|
+
if preload_scope.try(:as_of_time)
|
162
163
|
scope = scope.as_of(preload_scope.as_of_time)
|
163
164
|
end
|
164
165
|
|
@@ -176,7 +177,7 @@ module ChronoModel
|
|
176
177
|
# on the join model's (:through association) one.
|
177
178
|
#
|
178
179
|
module Association
|
179
|
-
def skip_statement_cache?
|
180
|
+
def skip_statement_cache?(*)
|
180
181
|
super || _chrono_target?
|
181
182
|
end
|
182
183
|
|
@@ -9,8 +9,8 @@ module ChronoModel
|
|
9
9
|
|
10
10
|
included do
|
11
11
|
if table_exists? && !chrono?
|
12
|
-
puts
|
13
|
-
"Please use change_table :#{table_name}, :
|
12
|
+
puts "ChronoModel: #{table_name} is not a temporal table. " \
|
13
|
+
"Please use `change_table :#{table_name}, temporal: true` in a migration."
|
14
14
|
end
|
15
15
|
|
16
16
|
history = TimeMachine.define_history_model_for(self)
|
@@ -54,7 +54,7 @@ module ChronoModel
|
|
54
54
|
|
55
55
|
extend TimeMachine::HistoryMethods
|
56
56
|
|
57
|
-
scope :chronological, -> { order('lower(validity)') }
|
57
|
+
scope :chronological, -> { order(Arel.sql('lower(validity) ASC')) }
|
58
58
|
|
59
59
|
# The history id is `hid`, but this cannot set as primary key
|
60
60
|
# or temporal assocations will break. Solutions are welcome.
|
@@ -85,30 +85,16 @@ module ChronoModel
|
|
85
85
|
with_hid_pkey { super }
|
86
86
|
end
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
def save_with_pkey(*)
|
92
|
-
self.class.with_hid_pkey { save_without_pkey }
|
93
|
-
end
|
94
|
-
|
95
|
-
def save_with_pkey!(*)
|
96
|
-
self.class.with_hid_pkey { save_without_pkey! }
|
97
|
-
end
|
98
|
-
|
99
|
-
alias_method_chain :save, :pkey
|
100
|
-
else
|
101
|
-
def save(*)
|
102
|
-
self.class.with_hid_pkey { super }
|
103
|
-
end
|
88
|
+
def save(*)
|
89
|
+
self.class.with_hid_pkey { super }
|
90
|
+
end
|
104
91
|
|
105
|
-
|
106
|
-
|
107
|
-
|
92
|
+
def save!(*)
|
93
|
+
self.class.with_hid_pkey { super }
|
94
|
+
end
|
108
95
|
|
109
|
-
|
110
|
-
|
111
|
-
end
|
96
|
+
def update_columns(*)
|
97
|
+
self.class.with_hid_pkey { super }
|
112
98
|
end
|
113
99
|
|
114
100
|
# Returns the previous history entry, or nil if this
|
@@ -271,10 +257,13 @@ module ChronoModel
|
|
271
257
|
#
|
272
258
|
def pred(options = {})
|
273
259
|
if self.class.timeline_associations.empty?
|
274
|
-
history.order('upper(validity) DESC').offset(1).first
|
260
|
+
history.order(Arel.sql('upper(validity) DESC')).offset(1).first
|
275
261
|
else
|
276
262
|
return nil unless (ts = pred_timestamp(options))
|
277
|
-
|
263
|
+
|
264
|
+
order_clause = Arel.sql %[ LOWER(#{options[:table] || self.class.quoted_table_name}."validity") DESC ]
|
265
|
+
|
266
|
+
self.class.as_of(ts).order(order_clause).find(options[:id] || id)
|
278
267
|
end
|
279
268
|
end
|
280
269
|
|
@@ -284,9 +273,9 @@ module ChronoModel
|
|
284
273
|
def pred_timestamp(options = {})
|
285
274
|
if historical?
|
286
275
|
options[:before] ||= as_of_time
|
287
|
-
timeline(options.merge(:
|
276
|
+
timeline(options.merge(limit: 1, reverse: true)).first
|
288
277
|
else
|
289
|
-
timeline(options.merge(:
|
278
|
+
timeline(options.merge(limit: 2, reverse: true)).second
|
290
279
|
end
|
291
280
|
end
|
292
281
|
|
@@ -295,7 +284,10 @@ module ChronoModel
|
|
295
284
|
def succ(options = {})
|
296
285
|
unless self.class.timeline_associations.empty?
|
297
286
|
return nil unless (ts = succ_timestamp(options))
|
298
|
-
|
287
|
+
|
288
|
+
order_clause = Arel.sql %[ LOWER(#{options[:table] || self.class.quoted_table_name}."validity"_ DESC ]
|
289
|
+
|
290
|
+
self.class.as_of(ts).order(order_clause).find(options[:id] || id)
|
299
291
|
end
|
300
292
|
end
|
301
293
|
|
@@ -306,7 +298,7 @@ module ChronoModel
|
|
306
298
|
return nil unless historical?
|
307
299
|
|
308
300
|
options[:after] ||= as_of_time
|
309
|
-
timeline(options.merge(:
|
301
|
+
timeline(options.merge(limit: 1, reverse: false)).first
|
310
302
|
end
|
311
303
|
|
312
304
|
# Returns the current history version
|
@@ -444,9 +436,9 @@ module ChronoModel
|
|
444
436
|
|
445
437
|
def build_time_query(time, range, op = '&&')
|
446
438
|
if time.kind_of?(Array)
|
447
|
-
%[ #{range.type}(#{time.first}, #{time.last}) #{op} #{table_name}.#{range.name} ]
|
439
|
+
Arel.sql %[ #{range.type}(#{time.first}, #{time.last}) #{op} #{table_name}.#{range.name} ]
|
448
440
|
else
|
449
|
-
%[ #{time} <@ #{table_name}.#{range.name} ]
|
441
|
+
Arel.sql %[ #{time} <@ #{table_name}.#{range.name} ]
|
450
442
|
end
|
451
443
|
end
|
452
444
|
end
|
@@ -513,7 +505,7 @@ module ChronoModel
|
|
513
505
|
# Returns the history sorted by recorded_at
|
514
506
|
#
|
515
507
|
def sorted
|
516
|
-
all.order(%[ #{quoted_table_name}."recorded_at", #{quoted_table_name}."hid" ])
|
508
|
+
all.order(Arel.sql(%[ #{quoted_table_name}."recorded_at" ASC, #{quoted_table_name}."hid" ASC ]))
|
517
509
|
end
|
518
510
|
|
519
511
|
# Fetches the given +object+ history, sorted by history record time
|
data/lib/chrono_model/version.rb
CHANGED
@@ -5,10 +5,10 @@ describe 'database migrations', type: :aruba do
|
|
5
5
|
before { write_file('config/database.yml',
|
6
6
|
File.read(File.expand_path('fixtures/database_without_username_and_password.yml', __dir__))) }
|
7
7
|
|
8
|
-
before {
|
8
|
+
before { run_command_and_stop('bundle exec rails g migration CreateModels name:string') }
|
9
9
|
|
10
10
|
describe 'bundle exec rake db:migrate' do
|
11
|
-
let(:action) {
|
11
|
+
let(:action) { run_command('bundle exec rake db:migrate') }
|
12
12
|
let(:last_command) { action && last_command_started }
|
13
13
|
|
14
14
|
specify { expect(last_command).to be_successfully_executed }
|
@@ -30,21 +30,7 @@ describe 'database migrations', type: :aruba do
|
|
30
30
|
)
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
# Alter migrations and remove the version specifier for Rails < 5.0
|
35
|
-
#
|
36
|
-
if gem_version('rails') < Gem::Version.new('5.0')
|
37
|
-
Dir['spec/aruba/fixtures/migrations/56/*rb'].each do |migration|
|
38
|
-
migration = File.basename(migration)
|
39
|
-
|
40
|
-
file_mangle! "db/migrate/#{migration}" do |contents|
|
41
|
-
contents.sub(/::Migration\[\d\.\d\]/, '::Migration')
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
let(:action) { run(command) }
|
33
|
+
let(:action) { run_command(command) }
|
48
34
|
let(:regex) { /-- change_table\(:impressions, {:temporal=>true, :copy_data=>true}\)/ }
|
49
35
|
|
50
36
|
describe 'once' do
|
@@ -54,7 +40,7 @@ describe 'database migrations', type: :aruba do
|
|
54
40
|
end
|
55
41
|
|
56
42
|
describe 'twice' do
|
57
|
-
let(:last_command) {
|
43
|
+
let(:last_command) { run_command_and_stop(command) && action && last_command_started }
|
58
44
|
specify { expect(last_command).to be_successfully_executed }
|
59
45
|
specify { expect(last_command).to have_output(regex) }
|
60
46
|
end
|
@@ -5,14 +5,14 @@ require 'spec_helper'
|
|
5
5
|
#
|
6
6
|
describe 'rake tasks', type: :aruba do
|
7
7
|
describe 'bundle exec rake -T' do
|
8
|
-
before {
|
8
|
+
before { run_command_and_stop('bundle exec rake -T') }
|
9
9
|
subject { last_command_started }
|
10
10
|
|
11
11
|
it { is_expected.to have_output(/db:structure:load/) }
|
12
12
|
end
|
13
13
|
|
14
14
|
describe 'db:structure:load' do
|
15
|
-
let(:action) {
|
15
|
+
let(:action) { run_command('bundle exec rake db:structure:load') }
|
16
16
|
let(:last_command) { action && last_command_started }
|
17
17
|
|
18
18
|
context 'given a file db/structure.sql' do
|
@@ -51,7 +51,7 @@ describe 'rake tasks', type: :aruba do
|
|
51
51
|
let(:database_yml) { 'fixtures/database_without_username_and_password.yml' }
|
52
52
|
before { write_file('config/database.yml', File.read(File.expand_path(database_yml, __dir__))) }
|
53
53
|
|
54
|
-
before {
|
54
|
+
before { run_command_and_stop('bundle exec rake db:data:dump DUMP=db/test.sql') }
|
55
55
|
|
56
56
|
it { expect(last_command_started).to be_successfully_executed }
|
57
57
|
it { expect('db/test.sql').to be_an_existing_file }
|
@@ -64,7 +64,7 @@ describe 'rake tasks', type: :aruba do
|
|
64
64
|
let(:structure_sql) { 'fixtures/empty_structure.sql' }
|
65
65
|
before { write_file('db/test.sql', File.read(File.expand_path(structure_sql, __dir__))) }
|
66
66
|
|
67
|
-
before {
|
67
|
+
before { run_command_and_stop('bundle exec rake db:data:load DUMP=db/test.sql') }
|
68
68
|
|
69
69
|
it { expect(last_command_started).to be_successfully_executed }
|
70
70
|
end
|
data/spec/json_ops_spec.rb
CHANGED
@@ -14,11 +14,11 @@ describe 'JSON equality operator' do
|
|
14
14
|
ChronoModel::Json.drop
|
15
15
|
end
|
16
16
|
|
17
|
-
it { expect(adapter.select_value(%[ SELECT '{"a":1}'::json = '{"a":1}'::json ])).to eq
|
18
|
-
it { expect(adapter.select_value(%[ SELECT '{"a":1}'::json = '{"a" : 1}'::json ])).to eq
|
19
|
-
it { expect(adapter.select_value(%[ SELECT '{"a":1}'::json = '{"a":2}'::json ])).to eq
|
20
|
-
it { expect(adapter.select_value(%[ SELECT '{"a":1,"b":2}'::json = '{"b":2,"a":1}'::json ])).to eq
|
21
|
-
it { expect(adapter.select_value(%[ SELECT '{"a":1,"b":2,"x":{"c":4,"d":5}}'::json = '{"b":2, "x": { "d": 5, "c": 4}, "a":1}'::json ])).to eq
|
17
|
+
it { expect(adapter.select_value(%[ SELECT '{"a":1}'::json = '{"a":1}'::json ])).to eq true }
|
18
|
+
it { expect(adapter.select_value(%[ SELECT '{"a":1}'::json = '{"a" : 1}'::json ])).to eq true }
|
19
|
+
it { expect(adapter.select_value(%[ SELECT '{"a":1}'::json = '{"a":2}'::json ])).to eq false }
|
20
|
+
it { expect(adapter.select_value(%[ SELECT '{"a":1,"b":2}'::json = '{"b":2,"a":1}'::json ])).to eq true }
|
21
|
+
it { expect(adapter.select_value(%[ SELECT '{"a":1,"b":2,"x":{"c":4,"d":5}}'::json = '{"b":2, "x": { "d": 5, "c": 4}, "a":1}'::json ])).to eq true }
|
22
22
|
|
23
23
|
context 'on a temporal table' do
|
24
24
|
before :all do
|
data/spec/spec_helper.rb
CHANGED
@@ -17,9 +17,6 @@ require 'support/aruba'
|
|
17
17
|
|
18
18
|
puts "Testing against Active Record #{ActiveRecord::VERSION::STRING} with Arel #{Arel::VERSION}"
|
19
19
|
|
20
|
-
# Rails 5 returns a True/FalseClass
|
21
|
-
AR_TRUE, AR_FALSE = ActiveRecord::VERSION::MAJOR == 4 ? ['t', 'f'] : [true, false]
|
22
|
-
|
23
20
|
RSpec.configure do |config|
|
24
21
|
config.include(ChronoTest::Matchers::Schema)
|
25
22
|
config.include(ChronoTest::Matchers::Table)
|
data/spec/support/aruba.rb
CHANGED
@@ -31,7 +31,7 @@ module ChronoTest::Matchers
|
|
31
31
|
|
32
32
|
protected
|
33
33
|
def has_function?(name)
|
34
|
-
select_value(<<-SQL, [name], 'Check function') ==
|
34
|
+
select_value(<<-SQL, [name], 'Check function') == true
|
35
35
|
SELECT EXISTS(
|
36
36
|
SELECT 1
|
37
37
|
FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n
|
@@ -12,7 +12,7 @@ module ChronoTest::Matchers
|
|
12
12
|
schema = options[:in]
|
13
13
|
kind = options[:kind] == :view ? 'v' : 'r'
|
14
14
|
|
15
|
-
select_value(<<-SQL, [ table, schema ], 'Check table exists') ==
|
15
|
+
select_value(<<-SQL, [ table, schema ], 'Check table exists') == true
|
16
16
|
SELECT EXISTS (
|
17
17
|
SELECT 1
|
18
18
|
FROM pg_class c
|
@@ -129,7 +129,7 @@ module ChronoTest::Matchers
|
|
129
129
|
def inherits_from_temporal?
|
130
130
|
binds = ["#{history_schema}.#{table}", "#{temporal_schema}.#{table}"]
|
131
131
|
|
132
|
-
@inheritance = select_value(<<-SQL, binds, 'Check inheritance') ==
|
132
|
+
@inheritance = select_value(<<-SQL, binds, 'Check inheritance') == true
|
133
133
|
SELECT EXISTS (
|
134
134
|
SELECT 1 FROM pg_catalog.pg_inherits
|
135
135
|
WHERE inhrelid = ?::regclass::oid
|
@@ -172,7 +172,7 @@ module ChronoTest::Matchers
|
|
172
172
|
attname: connection.primary_key(table)
|
173
173
|
}
|
174
174
|
|
175
|
-
@constraint = select_value(<<-SQL, binds, 'Check Consistency Constraint') ==
|
175
|
+
@constraint = select_value(<<-SQL, binds, 'Check Consistency Constraint') == true
|
176
176
|
SELECT EXISTS (
|
177
177
|
SELECT 1 FROM pg_catalog.pg_constraint
|
178
178
|
WHERE conname = :conname
|
data/spec/time_machine_spec.rb
CHANGED
@@ -304,7 +304,7 @@ describe ChronoModel::TimeMachine do
|
|
304
304
|
|
305
305
|
context '.sorted' do
|
306
306
|
describe 'orders by recorded_at, hid' do
|
307
|
-
it { expect(foo.history.sorted.to_sql).to match(/order by .+"recorded_at", .+"hid"/i) }
|
307
|
+
it { expect(foo.history.sorted.to_sql).to match(/order by .+"recorded_at" ASC, .+"hid" ASC/i) }
|
308
308
|
end
|
309
309
|
end
|
310
310
|
end
|
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: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcello Barnaba
|
@@ -17,20 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version:
|
21
|
-
- - "<"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 5.2.0
|
20
|
+
version: 5.0.0
|
24
21
|
type: :runtime
|
25
22
|
prerelease: false
|
26
23
|
version_requirements: !ruby/object:Gem::Requirement
|
27
24
|
requirements:
|
28
25
|
- - ">="
|
29
26
|
- !ruby/object:Gem::Version
|
30
|
-
version:
|
31
|
-
- - "<"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 5.2.0
|
27
|
+
version: 5.0.0
|
34
28
|
- !ruby/object:Gem::Dependency
|
35
29
|
name: pg
|
36
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -217,9 +211,9 @@ files:
|
|
217
211
|
- README.sql
|
218
212
|
- Rakefile
|
219
213
|
- chrono_model.gemspec
|
220
|
-
- gemfiles/rails_4.2.gemfile
|
221
214
|
- gemfiles/rails_5.0.gemfile
|
222
215
|
- gemfiles/rails_5.1.gemfile
|
216
|
+
- gemfiles/rails_5.2.gemfile
|
223
217
|
- lib/active_record/connection_adapters/chronomodel_adapter.rb
|
224
218
|
- lib/active_record/tasks/chronomodel_database_tasks.rb
|
225
219
|
- lib/chrono_model.rb
|
@@ -278,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
278
272
|
version: '0'
|
279
273
|
requirements: []
|
280
274
|
rubyforge_project:
|
281
|
-
rubygems_version: 2.
|
275
|
+
rubygems_version: 2.7.6.2
|
282
276
|
signing_key:
|
283
277
|
specification_version: 4
|
284
278
|
summary: Temporal extensions (SCD Type II) for Active Record
|