temporal_tables 1.1.0 → 3.0.0.pre.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +15 -11
  3. data/.rubocop.yml +30 -146
  4. data/.ruby-version +1 -1
  5. data/gemfiles/Gemfile.6.1.mysql +3 -0
  6. data/gemfiles/Gemfile.6.1.mysql.lock +147 -87
  7. data/gemfiles/Gemfile.6.1.pg +3 -0
  8. data/gemfiles/Gemfile.6.1.pg.lock +148 -88
  9. data/gemfiles/Gemfile.7.0.mysql +3 -0
  10. data/gemfiles/Gemfile.7.0.mysql.lock +150 -84
  11. data/gemfiles/Gemfile.7.0.pg +3 -0
  12. data/gemfiles/Gemfile.7.0.pg.lock +151 -85
  13. data/gemfiles/{Gemfile.6.0.mysql → Gemfile.7.1.mysql} +4 -1
  14. data/gemfiles/Gemfile.7.1.mysql.lock +266 -0
  15. data/gemfiles/{Gemfile.6.0.pg → Gemfile.7.1.pg} +4 -1
  16. data/gemfiles/Gemfile.7.1.pg.lock +266 -0
  17. data/lib/temporal_tables/arel_table.rb +1 -1
  18. data/lib/temporal_tables/association_extensions.rb +8 -0
  19. data/lib/temporal_tables/connection_adapters/mysql_adapter.rb +2 -2
  20. data/lib/temporal_tables/connection_adapters/postgresql_adapter.rb +2 -2
  21. data/lib/temporal_tables/constants.rb +5 -0
  22. data/lib/temporal_tables/temporal_adapter.rb +4 -3
  23. data/lib/temporal_tables/temporal_class.rb +4 -2
  24. data/lib/temporal_tables/version.rb +1 -1
  25. data/lib/temporal_tables.rb +2 -6
  26. data/spec/basic_history_spec.rb +39 -4
  27. data/spec/internal/app/models/bird/nest.rb +6 -0
  28. data/spec/internal/app/models/bird.rb +5 -0
  29. data/spec/internal/db/schema.rb +9 -0
  30. data/spec/spec_helper.rb +1 -1
  31. data/temporal_tables.gemspec +6 -4
  32. metadata +50 -19
  33. data/.travis.yml +0 -11
  34. data/gemfiles/Gemfile.6.0.mysql.lock +0 -171
  35. data/gemfiles/Gemfile.6.0.pg.lock +0 -176
  36. data/lib/temporal_tables/temporal_adapter_six_oh.rb +0 -207
@@ -1,207 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'digest'
4
-
5
- module TemporalTables
6
- # The main difference here is the add_index method, which still uses
7
- # the old options={} syntax
8
- module TemporalAdapterSixOh # rubocop:disable Metrics/ModuleLength
9
- def create_table(table_name, **options, &block) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
10
- if options[:temporal_bypass]
11
- super(table_name, **options, &block)
12
- else
13
- skip_table = TemporalTables.skipped_temporal_tables.include?(table_name.to_sym) || table_name.to_s =~ /_h$/
14
-
15
- super(table_name, **options) do |t|
16
- block.call t
17
-
18
- if TemporalTables.add_updated_by_field && !skip_table
19
- updated_by_already_exists = t.columns.any? { |c| c.name == 'updated_by' }
20
- if updated_by_already_exists
21
- puts "consider adding #{table_name} to TemporalTables skip_table" # rubocop:disable Rails/Output
22
- else
23
- t.column(:updated_by, TemporalTables.updated_by_type)
24
- end
25
- end
26
- end
27
-
28
- if options[:temporal] || (TemporalTables.create_by_default && !skip_table)
29
- add_temporal_table table_name, **options
30
- end
31
- end
32
- end
33
-
34
- def add_temporal_table(table_name, **options) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
35
- create_table(
36
- temporal_name(table_name),
37
- **options.merge(id: false, primary_key: 'history_id', temporal_bypass: true)
38
- ) do |t|
39
- t.datetime :eff_from, null: false, limit: 6
40
- t.datetime :eff_to, null: false, limit: 6, default: '9999-12-31'
41
-
42
- columns(table_name).each do |c|
43
- column_type = c.type == :enum ? c.sql_type_metadata.sql_type : c.type
44
- t.column c.name, column_type, 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
- original_primary_key = original_primary_key(table_name)
55
- temporal_table_index_name = index_name(temporal_name(table_name), [original_primary_key, :eff_to])
56
- if temporal_table_index_name.length > index_name_length
57
- temporal_table_index_name = truncated_index_name(temporal_table_index_name)
58
- end
59
- add_index temporal_name(table_name), [original_primary_key, :eff_to], { name: temporal_table_index_name }
60
- create_temporal_triggers table_name, original_primary_key
61
- create_temporal_indexes table_name
62
- end
63
-
64
- def remove_temporal_table(table_name)
65
- return unless table_exists?(temporal_name(table_name))
66
-
67
- drop_temporal_triggers table_name
68
- drop_table_without_temporal temporal_name(table_name)
69
- end
70
-
71
- def drop_table(table_name, **options)
72
- super(table_name, **options)
73
-
74
- super(temporal_name(table_name), **options) if table_exists?(temporal_name(table_name))
75
- end
76
-
77
- def rename_table(name, new_name)
78
- drop_temporal_triggers name if table_exists?(temporal_name(name))
79
-
80
- super name, new_name
81
-
82
- return unless table_exists?(temporal_name(name))
83
-
84
- super(temporal_name(name), temporal_name(new_name))
85
- create_temporal_triggers new_name, original_primary_key(table_name)
86
- end
87
-
88
- def add_column(table_name, column_name, type, **options)
89
- super(table_name, column_name, type, **options)
90
-
91
- return unless table_exists?(temporal_name(table_name))
92
-
93
- super temporal_name(table_name), column_name, type, **options
94
- create_temporal_triggers table_name, original_primary_key(table_name)
95
- end
96
-
97
- def remove_columns(table_name, *column_names, **options)
98
- super(table_name, *column_names, **options)
99
-
100
- return unless table_exists?(temporal_name(table_name))
101
-
102
- super temporal_name(table_name), *column_names, **options
103
- create_temporal_triggers table_name, original_primary_key(table_name)
104
- end
105
-
106
- def remove_column(table_name, column_name, type = nil, **options)
107
- super(table_name, column_name, type, **options)
108
-
109
- return unless table_exists?(temporal_name(table_name))
110
-
111
- super temporal_name(table_name), column_name, type, **options
112
- create_temporal_triggers table_name, original_primary_key(table_name)
113
- end
114
-
115
- def change_column(table_name, column_name, type, **options)
116
- super(table_name, column_name, type, **options)
117
-
118
- return unless table_exists?(temporal_name(table_name))
119
-
120
- super temporal_name(table_name), column_name, type, **options
121
- # Don't need to update triggers here...
122
- end
123
-
124
- def rename_column(table_name, column_name, new_column_name)
125
- super(table_name, column_name, new_column_name)
126
-
127
- return unless table_exists?(temporal_name(table_name))
128
-
129
- super temporal_name(table_name), column_name, new_column_name
130
- create_temporal_triggers table_name, original_primary_key(table_name)
131
- end
132
-
133
- def add_index(table_name, column_name, options = {})
134
- super(table_name, column_name, options)
135
-
136
- return unless table_exists?(temporal_name(table_name))
137
-
138
- column_names = Array.wrap(column_name)
139
- idx_name = temporal_index_name(options[:name] || index_name(table_name, column: column_names))
140
- super temporal_name(table_name), column_name, options.except(:unique).merge(name: idx_name)
141
- end
142
-
143
- def remove_index(table_name, options = {})
144
- original_index_name = index_name_for_remove(table_name, options)
145
- super(table_name, options)
146
-
147
- return unless table_exists?(temporal_name(table_name))
148
-
149
- idx_name = temporal_index_name(original_index_name)
150
- super temporal_name(table_name), name: idx_name
151
- end
152
-
153
- def create_temporal_indexes(table_name) # rubocop:disable Metrics/MethodLength
154
- indexes = ActiveRecord::Base.connection.indexes(table_name)
155
-
156
- indexes.each do |index|
157
- index_name = temporal_index_name(index.name)
158
-
159
- next if temporal_index_exists?(table_name, index_name)
160
-
161
- add_index(
162
- temporal_name(table_name),
163
- index.columns,
164
- # exclude unique constraints for temporal tables
165
- name: index_name,
166
- length: index.lengths,
167
- order: index.orders
168
- )
169
- end
170
- end
171
-
172
- def temporal_name(table_name)
173
- "#{table_name}_h"
174
- end
175
-
176
- def create_temporal_triggers(_table_name)
177
- raise NotImplementedError, 'create_temporal_triggers is not implemented'
178
- end
179
-
180
- def drop_temporal_triggers(_table_name)
181
- raise NotImplementedError, 'drop_temporal_triggers is not implemented'
182
- end
183
-
184
- # Index names max out at 63 characters. If appending _h to the index name would surpass that limit,
185
- # we can trim the index name and append a deterministically generated 5 character hash as well as _h.
186
- def temporal_index_name(index_name)
187
- "#{index_name.length < 62 ? index_name : truncated_index_name(index_name, 2)}_h"
188
- end
189
-
190
- def truncated_index_name(index_name, required_padding = 0)
191
- max_length = index_name_length - required_padding
192
- index_name_hash = Digest::SHA1.base64digest(index_name.to_s)[0, 5]
193
- "#{index_name[0, max_length - 6]}_#{index_name_hash}"
194
- end
195
-
196
- def temporal_index_exists?(table_name, index_name)
197
- index_name_exists?(temporal_name(table_name), index_name)
198
- end
199
-
200
- def original_primary_key(table_name)
201
- original_primary_key = primary_key(table_name)
202
- raise 'temporal_adapter requires that the table has a single primary key' unless original_primary_key.is_a? String
203
-
204
- original_primary_key
205
- end
206
- end
207
- end