temporal_tables 1.0.1 → 1.0.2

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 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