temporal_tables 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca70c4c007415e5835f5730f6e75f50c35c4df2d25ae815b6b40dd180609f3bc
4
- data.tar.gz: 2d65f6d907abef85e2746af4090b0e03a4da70ccf6bc2bbff988440996aab48c
3
+ metadata.gz: 7482588a765da3aeea2a1a5d7f32fdc000ee7f4c46b1affc2d9084822dd92313
4
+ data.tar.gz: 18eab05d32391261c5bf39bc4ddac2b91a177550d30100da2e270530f7bee8f4
5
5
  SHA512:
6
- metadata.gz: 2f67e6396728644773ef0a77e852329feb5bec150e04eb1c1172f3a366bde947b71e7d15d0056dc7fff829080002242ef04055aab8e447720e0efe622bbe5085
7
- data.tar.gz: 17271125d8e63c6a8baed4ed0e7b5c9cf58bd1cfd4afeb421286226004138b335f0f50e479f4c3886e4b3143a411d715d40e273712be40996cbb57247c843939
6
+ metadata.gz: 25a32d75519abc56c1dcd1debb1313ffefe964d1f514b82a8ad3919af84d5072418c87d0e580668f48617e41e2ed4bb33b28edd8ae2537315a0428b85a694cf2
7
+ data.tar.gz: 88b6b7f2db88810911f52c37faf86412ef9f315a6d664c2785a89c486cd4a38564a8d3b0849137ea796f5fc823788b2dc5b4c5b20629593b06d380452df5ab46
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- temporal_tables (1.0.1)
4
+ temporal_tables (1.0.2)
5
5
  rails (>= 6.0, < 7.1)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- temporal_tables (1.0.1)
4
+ temporal_tables (1.0.2)
5
5
  rails (>= 6.0, < 7.1)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- temporal_tables (1.0.1)
4
+ temporal_tables (1.0.2)
5
5
  rails (>= 6.0, < 7.1)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- temporal_tables (1.0.1)
4
+ temporal_tables (1.0.2)
5
5
  rails (>= 6.0, < 7.1)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- temporal_tables (1.0.1)
4
+ temporal_tables (1.0.2)
5
5
  rails (>= 6.0, < 7.1)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- temporal_tables (1.0.1)
4
+ temporal_tables (1.0.2)
5
5
  rails (>= 6.0, < 7.1)
6
6
 
7
7
  GEM
@@ -9,9 +9,10 @@ module TemporalTables
9
9
  execute "drop trigger #{table_name}_ad"
10
10
  end
11
11
 
12
- def create_temporal_triggers(table_name) # rubocop:disable Metrics/MethodLength
12
+ def create_temporal_triggers(table_name) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
13
13
  column_names = columns(table_name).map(&:name)
14
14
 
15
+ execute "drop trigger if exists #{table_name}_ai"
15
16
  execute %{
16
17
  create trigger #{table_name}_ai after insert on #{table_name}
17
18
  for each row
@@ -24,6 +25,7 @@ module TemporalTables
24
25
  end
25
26
  }
26
27
 
28
+ execute "drop trigger if exists #{table_name}_au"
27
29
  execute %{
28
30
  create trigger #{table_name}_au after update on #{table_name}
29
31
  for each row
@@ -40,6 +42,7 @@ module TemporalTables
40
42
  end
41
43
  }
42
44
 
45
+ execute "drop trigger if exists #{table_name}_ad"
43
46
  execute %{
44
47
  create trigger #{table_name}_ad after delete on #{table_name}
45
48
  for each row
@@ -2,7 +2,7 @@
2
2
 
3
3
  module TemporalTables
4
4
  module TemporalAdapter # rubocop:disable Metrics/ModuleLength
5
- def create_table(table_name, options = {}, &block) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
5
+ def create_table(table_name, **options, &block) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
6
6
  if options[:temporal_bypass]
7
7
  super(table_name, **options, &block)
8
8
  else
@@ -22,15 +22,15 @@ module TemporalTables
22
22
  end
23
23
 
24
24
  if options[:temporal] || (TemporalTables.create_by_default && !skip_table)
25
- add_temporal_table table_name, options
25
+ add_temporal_table table_name, **options
26
26
  end
27
27
  end
28
28
  end
29
29
 
30
- def add_temporal_table(table_name, options = {}) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
30
+ def add_temporal_table(table_name, **options) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
31
31
  create_table(
32
32
  temporal_name(table_name),
33
- options.merge(id: false, primary_key: 'history_id', temporal_bypass: true)
33
+ **options.merge(id: false, primary_key: 'history_id', temporal_bypass: true)
34
34
  ) do |t|
35
35
  t.column :id, options.fetch(:id, :integer) if options[:id] != false
36
36
  t.datetime :eff_from, null: false, limit: 6
@@ -61,7 +61,7 @@ module TemporalTables
61
61
  drop_table_without_temporal temporal_name(table_name)
62
62
  end
63
63
 
64
- def drop_table(table_name, options = {})
64
+ def drop_table(table_name, **options)
65
65
  super(table_name, **options)
66
66
 
67
67
  super(temporal_name(table_name), **options) if table_exists?(temporal_name(table_name))
@@ -78,30 +78,39 @@ module TemporalTables
78
78
  create_temporal_triggers new_name
79
79
  end
80
80
 
81
- def add_column(table_name, column_name, type, options = {})
81
+ def add_column(table_name, column_name, type, **options)
82
82
  super(table_name, column_name, type, **options)
83
83
 
84
84
  return unless table_exists?(temporal_name(table_name))
85
85
 
86
- super temporal_name(table_name), column_name, type, options
86
+ super temporal_name(table_name), column_name, type, **options
87
87
  create_temporal_triggers table_name
88
88
  end
89
89
 
90
- def remove_column(table_name, *column_names)
91
- super(table_name, *column_names)
90
+ def remove_columns(table_name, *column_names, **options)
91
+ super(table_name, *column_names, **options)
92
92
 
93
93
  return unless table_exists?(temporal_name(table_name))
94
94
 
95
- super temporal_name(table_name), *column_names
95
+ super temporal_name(table_name), *column_names, **options
96
96
  create_temporal_triggers table_name
97
97
  end
98
98
 
99
- def change_column(table_name, column_name, type, options = {})
100
- super(table_name, column_name, type, options)
99
+ def remove_column(table_name, column_name, type = nil, **options)
100
+ super(table_name, column_name, type, **options)
101
101
 
102
102
  return unless table_exists?(temporal_name(table_name))
103
103
 
104
- super temporal_name(table_name), column_name, type, options
104
+ super temporal_name(table_name), column_name, type, **options
105
+ create_temporal_triggers table_name
106
+ end
107
+
108
+ def change_column(table_name, column_name, type, **options)
109
+ super(table_name, column_name, type, **options)
110
+
111
+ return unless table_exists?(temporal_name(table_name))
112
+
113
+ super temporal_name(table_name), column_name, type, **options
105
114
  # Don't need to update triggers here...
106
115
  end
107
116
 
@@ -114,23 +123,22 @@ module TemporalTables
114
123
  create_temporal_triggers table_name
115
124
  end
116
125
 
117
- def add_index(table_name, column_name, options = {})
126
+ def add_index(table_name, column_name, **options)
118
127
  super(table_name, column_name, **options)
119
128
 
120
129
  return unless table_exists?(temporal_name(table_name))
121
130
 
122
- column_names = Array.wrap(column_name)
123
- idx_name = temporal_index_name(options[:name] || index_name(table_name, column: column_names))
124
- super temporal_name(table_name), column_name, options.except(:unique).merge(name: idx_name)
131
+ idx_name = temporal_index_name(options[:name] || index_name(table_name, column: column_name))
132
+ super temporal_name(table_name), column_name, **options.except(:unique).merge(name: idx_name)
125
133
  end
126
134
 
127
- def remove_index(table_name, options = {})
128
- super(table_name, options)
135
+ def remove_index(table_name, column_name = nil, **options)
136
+ super(table_name, column_name, **options)
129
137
 
130
138
  return unless table_exists?(temporal_name(table_name))
131
139
 
132
- idx_name = temporal_index_name(index_name(table_name, options))
133
- super temporal_name(table_name), name: idx_name
140
+ idx_name = temporal_index_name(options[:name] || index_name_for_remove(table_name, column_name, options))
141
+ super temporal_name(table_name), column_name, name: idx_name
134
142
  end
135
143
 
136
144
  def create_temporal_indexes(table_name) # rubocop:disable Metrics/MethodLength
@@ -143,12 +151,11 @@ module TemporalTables
143
151
 
144
152
  add_index(
145
153
  temporal_name(table_name),
146
- index.columns, {
147
- # exclude unique constraints for temporal tables
148
- name: index_name,
149
- length: index.lengths,
150
- order: index.orders
151
- }
154
+ index.columns,
155
+ # exclude unique constraints for temporal tables
156
+ name: index_name,
157
+ length: index.lengths,
158
+ order: index.orders
152
159
  )
153
160
  end
154
161
  end
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TemporalTables
4
+ # The main difference here is the add_index method, which still uses
5
+ # the old options={} syntax
6
+ module TemporalAdapterSixOh # rubocop:disable Metrics/ModuleLength
7
+ def create_table(table_name, **options, &block) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
8
+ if options[:temporal_bypass]
9
+ super(table_name, **options, &block)
10
+ else
11
+ skip_table = TemporalTables.skipped_temporal_tables.include?(table_name.to_sym) || table_name.to_s =~ /_h$/
12
+
13
+ super(table_name, **options) do |t|
14
+ block.call t
15
+
16
+ if TemporalTables.add_updated_by_field && !skip_table
17
+ updated_by_already_exists = t.columns.any? { |c| c.name == 'updated_by' }
18
+ if updated_by_already_exists
19
+ puts "consider adding #{table_name} to TemporalTables skip_table" # rubocop:disable Rails/Output
20
+ else
21
+ t.column(:updated_by, TemporalTables.updated_by_type)
22
+ end
23
+ end
24
+ end
25
+
26
+ if options[:temporal] || (TemporalTables.create_by_default && !skip_table)
27
+ add_temporal_table table_name, **options
28
+ end
29
+ end
30
+ end
31
+
32
+ def add_temporal_table(table_name, **options) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
33
+ create_table(
34
+ temporal_name(table_name),
35
+ **options.merge(id: false, primary_key: 'history_id', temporal_bypass: true)
36
+ ) do |t|
37
+ t.column :id, options.fetch(:id, :integer) if options[:id] != false
38
+ t.datetime :eff_from, null: false, limit: 6
39
+ t.datetime :eff_to, null: false, limit: 6, default: '9999-12-31'
40
+
41
+ columns(table_name).each do |c|
42
+ next if c.name == 'id'
43
+
44
+ t.send c.type, c.name, limit: c.limit
45
+ end
46
+ end
47
+
48
+ if TemporalTables.add_updated_by_field && !column_exists?(table_name, :updated_by)
49
+ change_table table_name do |t|
50
+ t.column :updated_by, TemporalTables.updated_by_type
51
+ end
52
+ end
53
+
54
+ add_index temporal_name(table_name), [:id, :eff_to]
55
+ create_temporal_triggers table_name
56
+ create_temporal_indexes table_name
57
+ end
58
+
59
+ def remove_temporal_table(table_name)
60
+ return unless table_exists?(temporal_name(table_name))
61
+
62
+ drop_temporal_triggers table_name
63
+ drop_table_without_temporal temporal_name(table_name)
64
+ end
65
+
66
+ def drop_table(table_name, **options)
67
+ super(table_name, **options)
68
+
69
+ super(temporal_name(table_name), **options) if table_exists?(temporal_name(table_name))
70
+ end
71
+
72
+ def rename_table(name, new_name)
73
+ drop_temporal_triggers name if table_exists?(temporal_name(name))
74
+
75
+ super name, new_name
76
+
77
+ return unless table_exists?(temporal_name(name))
78
+
79
+ super(temporal_name(name), temporal_name(new_name))
80
+ create_temporal_triggers new_name
81
+ end
82
+
83
+ def add_column(table_name, column_name, type, **options)
84
+ super(table_name, column_name, type, **options)
85
+
86
+ return unless table_exists?(temporal_name(table_name))
87
+
88
+ super temporal_name(table_name), column_name, type, **options
89
+ create_temporal_triggers table_name
90
+ end
91
+
92
+ def remove_columns(table_name, *column_names, **options)
93
+ super(table_name, *column_names, **options)
94
+
95
+ return unless table_exists?(temporal_name(table_name))
96
+
97
+ super temporal_name(table_name), *column_names, **options
98
+ create_temporal_triggers table_name
99
+ end
100
+
101
+ def remove_column(table_name, column_name, type = nil, **options)
102
+ super(table_name, column_name, type, **options)
103
+
104
+ return unless table_exists?(temporal_name(table_name))
105
+
106
+ super temporal_name(table_name), column_name, type, **options
107
+ create_temporal_triggers table_name
108
+ end
109
+
110
+ def change_column(table_name, column_name, type, **options)
111
+ super(table_name, column_name, type, **options)
112
+
113
+ return unless table_exists?(temporal_name(table_name))
114
+
115
+ super temporal_name(table_name), column_name, type, **options
116
+ # Don't need to update triggers here...
117
+ end
118
+
119
+ def rename_column(table_name, column_name, new_column_name)
120
+ super(table_name, column_name, new_column_name)
121
+
122
+ return unless table_exists?(temporal_name(table_name))
123
+
124
+ super temporal_name(table_name), column_name, new_column_name
125
+ create_temporal_triggers table_name
126
+ end
127
+
128
+ def add_index(table_name, column_name, options = {})
129
+ super(table_name, column_name, options)
130
+
131
+ return unless table_exists?(temporal_name(table_name))
132
+
133
+ column_names = Array.wrap(column_name)
134
+ idx_name = temporal_index_name(options[:name] || index_name(table_name, column: column_names))
135
+ super temporal_name(table_name), column_name, options.except(:unique).merge(name: idx_name)
136
+ end
137
+
138
+ def remove_index(table_name, options = {})
139
+ super(table_name, options)
140
+
141
+ return unless table_exists?(temporal_name(table_name))
142
+
143
+ idx_name = temporal_index_name(index_name_for_remove(table_name, options))
144
+ super temporal_name(table_name), name: idx_name
145
+ end
146
+
147
+ def create_temporal_indexes(table_name) # rubocop:disable Metrics/MethodLength
148
+ indexes = ActiveRecord::Base.connection.indexes(table_name)
149
+
150
+ indexes.each do |index|
151
+ index_name = temporal_index_name(index.name)
152
+
153
+ next if temporal_index_exists?(table_name, index_name)
154
+
155
+ add_index(
156
+ temporal_name(table_name),
157
+ index.columns,
158
+ # exclude unique constraints for temporal tables
159
+ name: index_name,
160
+ length: index.lengths,
161
+ order: index.orders
162
+ )
163
+ end
164
+ end
165
+
166
+ def temporal_name(table_name)
167
+ "#{table_name}_h"
168
+ end
169
+
170
+ def create_temporal_triggers(_table_name)
171
+ raise NotImplementedError, 'create_temporal_triggers is not implemented'
172
+ end
173
+
174
+ def drop_temporal_triggers(_table_name)
175
+ raise NotImplementedError, 'drop_temporal_triggers is not implemented'
176
+ end
177
+
178
+ # It's important not to increase the length of the returned string.
179
+ def temporal_index_name(index_name)
180
+ index_name.to_s.sub(/^index/, 'ind_h').sub(/_ix(\d+)$/, '_hi\1')
181
+ end
182
+
183
+ def temporal_index_exists?(table_name, index_name)
184
+ index_name_exists?(temporal_name(table_name), index_name)
185
+ end
186
+ end
187
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TemporalTables
4
- VERSION = '1.0.1'
4
+ VERSION = '1.0.2'
5
5
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'temporal_tables/temporal_adapter'
4
+ require 'temporal_tables/temporal_adapter_six_oh'
4
5
  require 'temporal_tables/connection_adapters/mysql_adapter'
5
6
  require 'temporal_tables/connection_adapters/postgresql_adapter'
6
7
  require 'temporal_tables/whodunnit'
@@ -21,7 +22,11 @@ module TemporalTables
21
22
  # It's necessary to do this on the implementations in order for the
22
23
  # alias method chain hooks to work.
23
24
  ActiveRecord::ConnectionAdapters::AbstractAdapter.subclasses.each do |subclass|
24
- subclass.send :prepend, TemporalTables::TemporalAdapter
25
+ if ActiveRecord.version < ::Gem::Version.new('6.1')
26
+ subclass.send :prepend, TemporalTables::TemporalAdapterSixOh
27
+ else
28
+ subclass.send :prepend, TemporalTables::TemporalAdapter
29
+ end
25
30
 
26
31
  module_name = subclass.name.split('::').last
27
32
  next unless TemporalTables::ConnectionAdapters.const_defined?(module_name)
@@ -9,20 +9,21 @@ end
9
9
  ActiveRecord::Schema.define do
10
10
  enable_extension 'pgcrypto' if postgres
11
11
 
12
- create_table :people, temporal: true, force: true do |t|
13
- t.belongs_to :coven
12
+ create_table :covens, force: true do |t|
14
13
  t.string :name
15
14
  end
15
+ add_temporal_table :covens
16
16
 
17
- create_table :covens, force: true do |t|
17
+ create_table :people, temporal: true, force: true do |t|
18
+ t.belongs_to :coven
18
19
  t.string :name
19
20
  end
20
- add_temporal_table :covens
21
+ add_index :people, :name, unique: true
21
22
 
22
23
  create_table :warts, temporal: true, force: true do |t|
23
24
  t.belongs_to :person
24
- t.integer :hairiness
25
25
  end
26
+ add_column :warts, :hairiness, :integer
26
27
 
27
28
  create_table :flying_machines, temporal: true, force: true do |t|
28
29
  t.belongs_to :person
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: temporal_tables
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brent Kroeker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-18 00:00:00.000000000 Z
11
+ date: 2022-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -184,6 +184,7 @@ files:
184
184
  - lib/temporal_tables/reflection_extensions.rb
185
185
  - lib/temporal_tables/relation_extensions.rb
186
186
  - lib/temporal_tables/temporal_adapter.rb
187
+ - lib/temporal_tables/temporal_adapter_six_oh.rb
187
188
  - lib/temporal_tables/temporal_class.rb
188
189
  - lib/temporal_tables/version.rb
189
190
  - lib/temporal_tables/whodunnit.rb