torque-postgresql 4.0.0.rc1 → 4.0.1
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/lib/generators/torque/function_generator.rb +13 -0
- data/lib/generators/torque/templates/function.sql.erb +4 -0
- data/lib/generators/torque/templates/type.sql.erb +2 -0
- data/lib/generators/torque/templates/view.sql.erb +3 -0
- data/lib/generators/torque/type_generator.rb +13 -0
- data/lib/generators/torque/view_generator.rb +16 -0
- data/lib/torque/postgresql/adapter/database_statements.rb +48 -10
- data/lib/torque/postgresql/adapter/schema_definitions.rb +22 -0
- data/lib/torque/postgresql/adapter/schema_dumper.rb +49 -3
- data/lib/torque/postgresql/adapter/schema_statements.rb +45 -0
- data/lib/torque/postgresql/arel/nodes.rb +14 -0
- data/lib/torque/postgresql/arel/visitors.rb +4 -0
- data/lib/torque/postgresql/attributes/builder/full_text_search.rb +16 -28
- data/lib/torque/postgresql/base.rb +2 -1
- data/lib/torque/postgresql/config.rb +35 -1
- data/lib/torque/postgresql/function.rb +33 -0
- data/lib/torque/postgresql/railtie.rb +26 -1
- data/lib/torque/postgresql/relation/auxiliary_statement.rb +7 -2
- data/lib/torque/postgresql/relation/buckets.rb +124 -0
- data/lib/torque/postgresql/relation/distinct_on.rb +7 -2
- data/lib/torque/postgresql/relation/inheritance.rb +18 -8
- data/lib/torque/postgresql/relation/join_series.rb +114 -0
- data/lib/torque/postgresql/relation/merger.rb +17 -3
- data/lib/torque/postgresql/relation.rb +18 -28
- data/lib/torque/postgresql/version.rb +1 -1
- data/lib/torque/postgresql/versioned_commands/command_migration.rb +146 -0
- data/lib/torque/postgresql/versioned_commands/generator.rb +57 -0
- data/lib/torque/postgresql/versioned_commands/migration_context.rb +83 -0
- data/lib/torque/postgresql/versioned_commands/migrator.rb +39 -0
- data/lib/torque/postgresql/versioned_commands/schema_table.rb +101 -0
- data/lib/torque/postgresql/versioned_commands.rb +161 -0
- data/spec/fixtures/migrations/20250101000001_create_users.rb +0 -0
- data/spec/fixtures/migrations/20250101000002_create_function_count_users_v1.sql +0 -0
- data/spec/fixtures/migrations/20250101000003_create_internal_users.rb +0 -0
- data/spec/fixtures/migrations/20250101000004_update_function_count_users_v2.sql +0 -0
- data/spec/fixtures/migrations/20250101000005_create_view_all_users_v1.sql +0 -0
- data/spec/fixtures/migrations/20250101000006_create_type_user_id_v1.sql +0 -0
- data/spec/fixtures/migrations/20250101000007_remove_function_count_users_v2.sql +0 -0
- data/spec/initialize.rb +9 -0
- data/spec/schema.rb +3 -4
- data/spec/spec_helper.rb +6 -1
- data/spec/tests/full_text_seach_test.rb +30 -2
- data/spec/tests/relation_spec.rb +229 -0
- data/spec/tests/schema_spec.rb +4 -1
- data/spec/tests/versioned_commands_spec.rb +513 -0
- metadata +34 -7
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe 'VersionedCommands' do
|
|
4
|
+
let(:connection) { ActiveRecord::Base.connection }
|
|
5
|
+
|
|
6
|
+
context 'on migration' do
|
|
7
|
+
it 'does not have any of the schema methods' do
|
|
8
|
+
expect(connection).not_to respond_to(:create_function)
|
|
9
|
+
expect(connection).not_to respond_to(:create_type)
|
|
10
|
+
expect(connection).not_to respond_to(:create_view)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'does not have the methods available in a migration' do
|
|
14
|
+
instance = Class.new(ActiveRecord::Migration::Current).allocate
|
|
15
|
+
expect(instance).not_to respond_to(:create_function)
|
|
16
|
+
expect(instance).not_to respond_to(:create_type)
|
|
17
|
+
expect(instance).not_to respond_to(:create_view)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'does have the methods in schema definition' do
|
|
21
|
+
instance = ActiveRecord::Schema[ActiveRecord::Migration.current_version].allocate
|
|
22
|
+
expect(instance).to respond_to(:create_function)
|
|
23
|
+
expect(instance).to respond_to(:create_type)
|
|
24
|
+
expect(instance).to respond_to(:create_view)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context 'on context' do
|
|
28
|
+
let(:context) { connection.pool.migration_context }
|
|
29
|
+
let(:path) { Pathname.new(__FILE__).join('../../fixtures/migrations').expand_path.to_s }
|
|
30
|
+
|
|
31
|
+
before { context.instance_variable_set(:@migrations_paths, [path]) }
|
|
32
|
+
|
|
33
|
+
it 'list all migrations accordingly' do
|
|
34
|
+
result = context.migrations.map { |m| File.basename(m.filename) }
|
|
35
|
+
expect(result[0]).to eq('20250101000001_create_users.rb')
|
|
36
|
+
expect(result[1]).to eq('20250101000002_create_function_count_users_v1.sql')
|
|
37
|
+
expect(result[2]).to eq('20250101000003_create_internal_users.rb')
|
|
38
|
+
expect(result[3]).to eq('20250101000004_update_function_count_users_v2.sql')
|
|
39
|
+
expect(result[4]).to eq('20250101000005_create_view_all_users_v1.sql')
|
|
40
|
+
expect(result[5]).to eq('20250101000006_create_type_user_id_v1.sql')
|
|
41
|
+
expect(result[6]).to eq('20250101000007_remove_function_count_users_v2.sql')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'correctly report the status of all migrations' do
|
|
45
|
+
result = context.migrations_status.reject { |s| s[1].start_with?('0') }
|
|
46
|
+
expect(result[0]).to eq(['down', '20250101000001', 'Create users'])
|
|
47
|
+
expect(result[1]).to eq(['down', '20250101000002', 'Create Function count_users (v1)'])
|
|
48
|
+
expect(result[2]).to eq(['down', '20250101000003', 'Create internal users'])
|
|
49
|
+
expect(result[3]).to eq(['down', '20250101000004', 'Update Function count_users (v2)'])
|
|
50
|
+
expect(result[4]).to eq(['down', '20250101000005', 'Create View all_users (v1)'])
|
|
51
|
+
expect(result[5]).to eq(['down', '20250101000006', 'Create Type user_id (v1)'])
|
|
52
|
+
expect(result[6]).to eq(['down', '20250101000007', 'Remove Function count_users (v2)'])
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'reports for invalid names' do
|
|
56
|
+
allow(context).to receive(:command_files).and_return(['something.sql'])
|
|
57
|
+
error = ::Torque::PostgreSQL::IllegalCommandTypeError
|
|
58
|
+
expect { context.migrations }.to raise_error(error)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context 'on validation' do
|
|
63
|
+
let(:base) { Torque::PostgreSQL::VersionedCommands }
|
|
64
|
+
|
|
65
|
+
context 'on function' do
|
|
66
|
+
it 'prevents multiple functions definition' do
|
|
67
|
+
content = <<~SQL
|
|
68
|
+
CREATE FUNCTION test(a integer);
|
|
69
|
+
CREATE FUNCTION other_test(a varchar);
|
|
70
|
+
SQL
|
|
71
|
+
|
|
72
|
+
expect do
|
|
73
|
+
base.validate!(:function, content, 'test')
|
|
74
|
+
end.to raise_error(ArgumentError)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'prevents same name but different schema' do
|
|
78
|
+
content = <<~SQL
|
|
79
|
+
CREATE FUNCTION internal.test(a integer);
|
|
80
|
+
CREATE FUNCTION external.test(a varchar);
|
|
81
|
+
SQL
|
|
82
|
+
|
|
83
|
+
expect do
|
|
84
|
+
base.validate!(:function, content, 'test')
|
|
85
|
+
end.to raise_error(ArgumentError)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'requires OR REPLACE clause' do
|
|
89
|
+
content = <<~SQL
|
|
90
|
+
CREATE OR REPLACE FUNCTION test(a integer);
|
|
91
|
+
CREATE FUNCTION test(a varchar);
|
|
92
|
+
SQL
|
|
93
|
+
|
|
94
|
+
expect do
|
|
95
|
+
base.validate!(:function, content, 'test')
|
|
96
|
+
end.to raise_error(ArgumentError)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'requires matching name' do
|
|
100
|
+
content = <<~SQL
|
|
101
|
+
CREATE OR REPLACE FUNCTION other_test(a integer);
|
|
102
|
+
CREATE OR REPLACE FUNCTION other_test(a varchar);
|
|
103
|
+
SQL
|
|
104
|
+
|
|
105
|
+
expect do
|
|
106
|
+
base.validate!(:function, content, 'test')
|
|
107
|
+
end.to raise_error(ArgumentError)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it 'works when setup correctly' do
|
|
111
|
+
content = <<~SQL
|
|
112
|
+
CREATE OR REPLACE FUNCTION test(a integer);
|
|
113
|
+
CREATE OR REPLACE FUNCTION test(a varchar);
|
|
114
|
+
CREATE OR REPLACE FUNCTION TEST(a date);
|
|
115
|
+
SQL
|
|
116
|
+
|
|
117
|
+
expect { base.validate!(:function, content, 'test') }.not_to raise_error
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it 'supports name with schema' do
|
|
121
|
+
content = <<~SQL
|
|
122
|
+
CREATE OR REPLACE FUNCTION internal.test(a integer);
|
|
123
|
+
CREATE OR REPLACE FUNCTION internal.test(a varchar);
|
|
124
|
+
CREATE OR REPLACE FUNCTION internal.TEST(a date);
|
|
125
|
+
SQL
|
|
126
|
+
|
|
127
|
+
expect { base.validate!(:function, content, 'internal_test') }.not_to raise_error
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
context 'on type' do
|
|
132
|
+
it 'prevents multiple type definitions' do
|
|
133
|
+
content = <<~SQL
|
|
134
|
+
CREATE TYPE test AS;
|
|
135
|
+
CREATE TYPE other_test AS;
|
|
136
|
+
SQL
|
|
137
|
+
|
|
138
|
+
expect do
|
|
139
|
+
base.validate!(:type, content, 'test')
|
|
140
|
+
end.to raise_error(ArgumentError)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it 'prevents same name but different schema' do
|
|
144
|
+
content = <<~SQL
|
|
145
|
+
DROP TYPE IF EXISTS internal.test;
|
|
146
|
+
CREATE TYPE external.test AS;
|
|
147
|
+
SQL
|
|
148
|
+
|
|
149
|
+
expect do
|
|
150
|
+
base.validate!(:type, content, 'test')
|
|
151
|
+
end.to raise_error(ArgumentError)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it 'prevents multiple type drops' do
|
|
155
|
+
content = <<~SQL
|
|
156
|
+
DROP TYPE IF EXISTS test;
|
|
157
|
+
DROP TYPE IF EXISTS other_test;
|
|
158
|
+
CREATE TYPE test AS;
|
|
159
|
+
SQL
|
|
160
|
+
|
|
161
|
+
expect do
|
|
162
|
+
base.validate!(:type, content, 'test')
|
|
163
|
+
end.to raise_error(ArgumentError)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it 'requires DROP TYPE clause' do
|
|
167
|
+
content = <<~SQL
|
|
168
|
+
CREATE TYPE test AS;
|
|
169
|
+
SQL
|
|
170
|
+
|
|
171
|
+
expect do
|
|
172
|
+
base.validate!(:type, content, 'test')
|
|
173
|
+
end.to raise_error(ArgumentError)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it 'prevents dropping other types' do
|
|
177
|
+
content = <<~SQL
|
|
178
|
+
DROP TYPE IF EXISTS other_test;
|
|
179
|
+
CREATE TYPE test AS;
|
|
180
|
+
SQL
|
|
181
|
+
|
|
182
|
+
expect do
|
|
183
|
+
base.validate!(:type, content, 'test')
|
|
184
|
+
end.to raise_error(ArgumentError)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it 'requires matching name' do
|
|
188
|
+
content = <<~SQL
|
|
189
|
+
DROP TYPE IF EXISTS other_test;
|
|
190
|
+
CREATE TYPE other_test AS;
|
|
191
|
+
SQL
|
|
192
|
+
|
|
193
|
+
expect do
|
|
194
|
+
base.validate!(:type, content, 'test')
|
|
195
|
+
end.to raise_error(ArgumentError)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it 'works when setup correctly' do
|
|
199
|
+
content = <<~SQL
|
|
200
|
+
DROP TYPE IF EXISTS test;
|
|
201
|
+
CREATE TYPE TEST AS;
|
|
202
|
+
SQL
|
|
203
|
+
|
|
204
|
+
expect { base.validate!(:type, content, 'test') }.not_to raise_error
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it 'supports name with schema' do
|
|
208
|
+
content = <<~SQL
|
|
209
|
+
DROP TYPE IF EXISTS internal.test;
|
|
210
|
+
CREATE TYPE INTERNAL.TEST AS;
|
|
211
|
+
SQL
|
|
212
|
+
|
|
213
|
+
expect { base.validate!(:type, content, 'internal_test') }.not_to raise_error
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
context 'on view' do
|
|
218
|
+
it 'requires a proper definition' do
|
|
219
|
+
content = <<~SQL
|
|
220
|
+
CREATE TEMP MATERIALIZED VIEW test AS;
|
|
221
|
+
SQL
|
|
222
|
+
|
|
223
|
+
expect do
|
|
224
|
+
base.validate!(:view, content, 'test')
|
|
225
|
+
end.to raise_error(ArgumentError)
|
|
226
|
+
end
|
|
227
|
+
it 'prevents multiple view definitions' do
|
|
228
|
+
content = <<~SQL
|
|
229
|
+
CREATE VIEW test AS;
|
|
230
|
+
CREATE VIEW other_test AS;
|
|
231
|
+
SQL
|
|
232
|
+
|
|
233
|
+
expect do
|
|
234
|
+
base.validate!(:view, content, 'test')
|
|
235
|
+
end.to raise_error(ArgumentError)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it 'requires OR REPLACE clause' do
|
|
239
|
+
content = <<~SQL
|
|
240
|
+
CREATE VIEW test AS;
|
|
241
|
+
SQL
|
|
242
|
+
|
|
243
|
+
expect do
|
|
244
|
+
base.validate!(:view, content, 'test')
|
|
245
|
+
end.to raise_error(ArgumentError)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it 'requires matching name' do
|
|
249
|
+
content = <<~SQL
|
|
250
|
+
CREATE OR REPLACE VIEW other_test AS;
|
|
251
|
+
SQL
|
|
252
|
+
|
|
253
|
+
expect do
|
|
254
|
+
base.validate!(:view, content, 'test')
|
|
255
|
+
end.to raise_error(ArgumentError)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
it 'works when setup correctly' do
|
|
259
|
+
content = <<~SQL
|
|
260
|
+
CREATE OR REPLACE VIEW TEST AS;
|
|
261
|
+
SQL
|
|
262
|
+
|
|
263
|
+
expect { base.validate!(:view, content, 'test') }.not_to raise_error
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
it 'supports materialized views' do
|
|
267
|
+
content = <<~SQL
|
|
268
|
+
DROP MATERIALIZED VIEW IF EXISTS test;
|
|
269
|
+
CREATE MATERIALIZED VIEW test AS;
|
|
270
|
+
SQL
|
|
271
|
+
|
|
272
|
+
expect { base.validate!(:view, content, 'test') }.not_to raise_error
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it 'supports name with schema' do
|
|
276
|
+
content = <<~SQL
|
|
277
|
+
CREATE OR REPLACE VIEW internal.test AS;
|
|
278
|
+
SQL
|
|
279
|
+
|
|
280
|
+
expect { base.validate!(:view, content, 'internal_test') }.not_to raise_error
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
context 'on running' do
|
|
286
|
+
let(:base) { Torque::PostgreSQL::VersionedCommands }
|
|
287
|
+
let(:sql) { 'CREATE TYPE test;' }
|
|
288
|
+
let(:command) do
|
|
289
|
+
base::CommandMigration.new('test.sql', 1, 'create', 'type', 'test', 1)
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
before do
|
|
293
|
+
allow_any_instance_of(ActiveRecord::Migration).to receive(:puts) # Disable messages
|
|
294
|
+
|
|
295
|
+
allow(File).to receive(:expand_path, &:itself)
|
|
296
|
+
allow(File).to receive(:read).with('test.sql').and_return(sql)
|
|
297
|
+
|
|
298
|
+
# Validations are better tested above
|
|
299
|
+
allow(base).to receive(:validate!).and_return(true)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
it 'has the right name' do
|
|
303
|
+
expect(command.name).to eq('create_type_test_v1')
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
it 'creates the type properly' do
|
|
307
|
+
expect(connection).to receive(:execute).with(sql)
|
|
308
|
+
command.migrate(:up)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
it 'reverts to the previous file' do
|
|
312
|
+
sql2 = 'CREATE TYPE test_v1;'
|
|
313
|
+
command.op_version = 2
|
|
314
|
+
expect(base).to receive(:fetch_command).with(Array, 'type', 'test', 1).and_return(sql2)
|
|
315
|
+
expect(connection).to receive(:execute).with(sql2)
|
|
316
|
+
command.migrate(:down)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
it 'reverts to the same version when reverting a remove' do
|
|
320
|
+
command.op = 'remove'
|
|
321
|
+
command.op_version = 2
|
|
322
|
+
expect(base).to receive(:fetch_command).with(Array, 'type', 'test', 2).and_return(sql)
|
|
323
|
+
expect(connection).to receive(:execute).with(sql)
|
|
324
|
+
command.migrate(:down)
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
it 'properly drops functions' do
|
|
328
|
+
command.type = 'function'
|
|
329
|
+
|
|
330
|
+
sql.replace('CREATE FUNCTION test;')
|
|
331
|
+
expect(connection).to receive(:execute).with('DROP FUNCTION test;')
|
|
332
|
+
command.migrate(:down)
|
|
333
|
+
|
|
334
|
+
sql.replace('CREATE FUNCTION test();')
|
|
335
|
+
expect(connection).to receive(:execute).with('DROP FUNCTION test();')
|
|
336
|
+
command.migrate(:down)
|
|
337
|
+
|
|
338
|
+
sql.replace('CREATE FUNCTION test(int); CREATE FUNCTION test(float);')
|
|
339
|
+
expect(connection).to receive(:execute).with('DROP FUNCTION test(int), test(float);')
|
|
340
|
+
command.migrate(:down)
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
it 'properly drops types' do
|
|
344
|
+
command.type = 'type'
|
|
345
|
+
|
|
346
|
+
sql.replace('CREATE TYPE test;')
|
|
347
|
+
expect(connection).to receive(:execute).with('DROP TYPE test;')
|
|
348
|
+
command.migrate(:down)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
it 'properly drops views' do
|
|
352
|
+
command.type = 'view'
|
|
353
|
+
|
|
354
|
+
sql.replace('CREATE VIEW test AS SELECT 1;')
|
|
355
|
+
expect(connection).to receive(:execute).with('DROP VIEW test;')
|
|
356
|
+
command.migrate(:down)
|
|
357
|
+
|
|
358
|
+
sql.replace('CREATE MATERIALIZED VIEW test AS SELECT 1;')
|
|
359
|
+
expect(connection).to receive(:execute).with('DROP MATERIALIZED VIEW test;')
|
|
360
|
+
command.migrate(:down)
|
|
361
|
+
|
|
362
|
+
sql.replace('CREATE RECURSIVE VIEW test AS SELECT 1;')
|
|
363
|
+
expect(connection).to receive(:execute).with('DROP VIEW test;')
|
|
364
|
+
command.migrate(:down)
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
context 'on migrator' do
|
|
369
|
+
let(:base) { Torque::PostgreSQL::VersionedCommands }
|
|
370
|
+
let(:table) { base::SchemaTable.new(connection.pool) }
|
|
371
|
+
let(:context) { connection.pool.migration_context }
|
|
372
|
+
let(:versions) { migrations.map(&:version).map(&:to_i) }
|
|
373
|
+
let(:migrations) { [ActiveRecord::Migration.new('base', 1)] }
|
|
374
|
+
|
|
375
|
+
before do
|
|
376
|
+
allow_any_instance_of(ActiveRecord::Migration).to receive(:puts) # Disable messages
|
|
377
|
+
allow(File).to receive(:expand_path, &:itself)
|
|
378
|
+
|
|
379
|
+
# Validations are better tested above
|
|
380
|
+
allow(base).to receive(:validate!).and_return(true)
|
|
381
|
+
allow(context).to receive(:migrations).and_return(migrations)
|
|
382
|
+
allow(context.schema_migration).to receive(:integer_versions).and_return(versions)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
it 'expect the table to not exist by default' do
|
|
386
|
+
expect(table.table_exists?).to be_falsey
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
it 'creates the table on first migration' do
|
|
390
|
+
migration('CREATE TYPE test;')
|
|
391
|
+
|
|
392
|
+
expect(table.table_exists?).to be_falsey
|
|
393
|
+
context.up(2)
|
|
394
|
+
expect(table.table_exists?).to be_truthy
|
|
395
|
+
expect(table.count).to eq(1)
|
|
396
|
+
expect(table.versions_of('type')).to eq([['test_2', 1]])
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
it 'drops the table if all versions are removed' do
|
|
400
|
+
migrations << ActiveRecord::Migration.new('other', 2)
|
|
401
|
+
versions << 2
|
|
402
|
+
|
|
403
|
+
migration('CREATE TYPE test;')
|
|
404
|
+
|
|
405
|
+
expect(table.table_exists?).to be_falsey
|
|
406
|
+
context.up(3)
|
|
407
|
+
expect(table.table_exists?).to be_truthy
|
|
408
|
+
expect(table.count).to eq(1)
|
|
409
|
+
|
|
410
|
+
versions << 3
|
|
411
|
+
context.down(2)
|
|
412
|
+
expect(table.table_exists?).to be_falsey
|
|
413
|
+
expect(table.count).to eq(0)
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
it 'does no drop the table if there are still records' do
|
|
417
|
+
migration('CREATE TYPE test;')
|
|
418
|
+
migration('CREATE TYPE other;')
|
|
419
|
+
|
|
420
|
+
expect(table.table_exists?).to be_falsey
|
|
421
|
+
context.up(3)
|
|
422
|
+
expect(table.table_exists?).to be_truthy
|
|
423
|
+
expect(table.count).to eq(2)
|
|
424
|
+
|
|
425
|
+
versions << 2
|
|
426
|
+
versions << 3
|
|
427
|
+
context.down(2)
|
|
428
|
+
expect(table.table_exists?).to be_truthy
|
|
429
|
+
expect(table.count).to eq(1)
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
def migration(command)
|
|
433
|
+
version = migrations.size + 1
|
|
434
|
+
file = "test_#{version}.sql"
|
|
435
|
+
name = file.split('.').first
|
|
436
|
+
allow(File).to receive(:read).with(file).and_return(command)
|
|
437
|
+
migrations << base::CommandMigration.new(file, version, 'create', 'type', name, 1)
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
context 'on schema dumper' do
|
|
443
|
+
let(:source) { ActiveRecord::Base.connection_pool }
|
|
444
|
+
let(:schema_table) { double(commands_table.name) }
|
|
445
|
+
let(:commands_table) { Torque::PostgreSQL::VersionedCommands::SchemaTable }
|
|
446
|
+
let(:dump_result) do
|
|
447
|
+
ActiveRecord::SchemaDumper.dump(source, (dump_result = StringIO.new))
|
|
448
|
+
dump_result.string
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
before do
|
|
452
|
+
allow(commands_table).to receive(:new).and_return(schema_table)
|
|
453
|
+
allow(schema_table).to receive(:versions_of).and_return([])
|
|
454
|
+
allow(schema_table).to receive(:table_name).and_return('versioned_commands_tbl')
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
it 'does not include versioned commands info by default' do
|
|
458
|
+
expect(dump_result).not_to include('"versioned_commands_tbl"')
|
|
459
|
+
expect(dump_result).not_to include('# These are types managed by versioned commands')
|
|
460
|
+
expect(dump_result).not_to include('# These are functions managed by versioned commands')
|
|
461
|
+
expect(dump_result).not_to include('# These are views managed by versioned commands')
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
it 'includes all types' do
|
|
465
|
+
connection.execute('CREATE TYPE test;')
|
|
466
|
+
connection.execute('CREATE TYPE internal.other;')
|
|
467
|
+
|
|
468
|
+
allow(schema_table).to receive(:versions_of).with('type').and_return([
|
|
469
|
+
['test', 1],
|
|
470
|
+
['internal_other', 2],
|
|
471
|
+
['remove', 1],
|
|
472
|
+
])
|
|
473
|
+
|
|
474
|
+
expect(dump_result).to include('# These are types managed by versioned commands')
|
|
475
|
+
expect(dump_result).to include('create_type "test", version: 1')
|
|
476
|
+
expect(dump_result).to include('create_type "internal_other", version: 2')
|
|
477
|
+
expect(dump_result).not_to include('create_type "removed", version: 1')
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
it 'includes all functions' do
|
|
481
|
+
body = 'RETURNS void AS $$ BEGIN NULL; END; $$ LANGUAGE plpgsql'
|
|
482
|
+
connection.execute("CREATE FUNCTION test() #{body};")
|
|
483
|
+
connection.execute("CREATE FUNCTION internal.other() #{body};")
|
|
484
|
+
|
|
485
|
+
allow(schema_table).to receive(:versions_of).with('function').and_return([
|
|
486
|
+
['test', 1],
|
|
487
|
+
['internal_other', 2],
|
|
488
|
+
['remove', 1],
|
|
489
|
+
])
|
|
490
|
+
|
|
491
|
+
expect(dump_result).to include('# These are functions managed by versioned commands')
|
|
492
|
+
expect(dump_result).to include('create_function "test", version: 1')
|
|
493
|
+
expect(dump_result).to include('create_function "internal_other", version: 2')
|
|
494
|
+
expect(dump_result).not_to include('create_function "removed", version: 1')
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
it 'includes all views' do
|
|
498
|
+
connection.execute('CREATE VIEW test AS SELECT 1;')
|
|
499
|
+
connection.execute('CREATE MATERIALIZED VIEW internal.other AS SELECT 2;')
|
|
500
|
+
|
|
501
|
+
allow(schema_table).to receive(:versions_of).with('view').and_return([
|
|
502
|
+
['test', 1],
|
|
503
|
+
['internal_other', 2],
|
|
504
|
+
['remove', 1],
|
|
505
|
+
])
|
|
506
|
+
|
|
507
|
+
expect(dump_result).to include('# These are views managed by versioned commands')
|
|
508
|
+
expect(dump_result).to include('create_view "test", version: 1')
|
|
509
|
+
expect(dump_result).to include('create_view "internal_other", version: 2')
|
|
510
|
+
expect(dump_result).not_to include('create_view "removed", version: 1')
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: torque-postgresql
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.0.
|
|
4
|
+
version: 4.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Carlos Silva
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
10
|
+
date: 2025-12-19 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rails
|
|
@@ -133,6 +132,12 @@ files:
|
|
|
133
132
|
- MIT-LICENSE
|
|
134
133
|
- README.rdoc
|
|
135
134
|
- Rakefile
|
|
135
|
+
- lib/generators/torque/function_generator.rb
|
|
136
|
+
- lib/generators/torque/templates/function.sql.erb
|
|
137
|
+
- lib/generators/torque/templates/type.sql.erb
|
|
138
|
+
- lib/generators/torque/templates/view.sql.erb
|
|
139
|
+
- lib/generators/torque/type_generator.rb
|
|
140
|
+
- lib/generators/torque/view_generator.rb
|
|
136
141
|
- lib/torque-postgresql.rb
|
|
137
142
|
- lib/torque/postgresql.rb
|
|
138
143
|
- lib/torque/postgresql/adapter.rb
|
|
@@ -209,8 +214,10 @@ files:
|
|
|
209
214
|
- lib/torque/postgresql/reflection/through_reflection.rb
|
|
210
215
|
- lib/torque/postgresql/relation.rb
|
|
211
216
|
- lib/torque/postgresql/relation/auxiliary_statement.rb
|
|
217
|
+
- lib/torque/postgresql/relation/buckets.rb
|
|
212
218
|
- lib/torque/postgresql/relation/distinct_on.rb
|
|
213
219
|
- lib/torque/postgresql/relation/inheritance.rb
|
|
220
|
+
- lib/torque/postgresql/relation/join_series.rb
|
|
214
221
|
- lib/torque/postgresql/relation/merger.rb
|
|
215
222
|
- lib/torque/postgresql/schema_cache.rb
|
|
216
223
|
- lib/torque/postgresql/schema_cache/bound_schema_reflection.rb
|
|
@@ -218,6 +225,12 @@ files:
|
|
|
218
225
|
- lib/torque/postgresql/schema_cache/schema_reflection.rb
|
|
219
226
|
- lib/torque/postgresql/table_name.rb
|
|
220
227
|
- lib/torque/postgresql/version.rb
|
|
228
|
+
- lib/torque/postgresql/versioned_commands.rb
|
|
229
|
+
- lib/torque/postgresql/versioned_commands/command_migration.rb
|
|
230
|
+
- lib/torque/postgresql/versioned_commands/generator.rb
|
|
231
|
+
- lib/torque/postgresql/versioned_commands/migration_context.rb
|
|
232
|
+
- lib/torque/postgresql/versioned_commands/migrator.rb
|
|
233
|
+
- lib/torque/postgresql/versioned_commands/schema_table.rb
|
|
221
234
|
- spec/en.yml
|
|
222
235
|
- spec/factories/authors.rb
|
|
223
236
|
- spec/factories/comments.rb
|
|
@@ -227,6 +240,13 @@ files:
|
|
|
227
240
|
- spec/factories/texts.rb
|
|
228
241
|
- spec/factories/users.rb
|
|
229
242
|
- spec/factories/videos.rb
|
|
243
|
+
- spec/fixtures/migrations/20250101000001_create_users.rb
|
|
244
|
+
- spec/fixtures/migrations/20250101000002_create_function_count_users_v1.sql
|
|
245
|
+
- spec/fixtures/migrations/20250101000003_create_internal_users.rb
|
|
246
|
+
- spec/fixtures/migrations/20250101000004_update_function_count_users_v2.sql
|
|
247
|
+
- spec/fixtures/migrations/20250101000005_create_view_all_users_v1.sql
|
|
248
|
+
- spec/fixtures/migrations/20250101000006_create_type_user_id_v1.sql
|
|
249
|
+
- spec/fixtures/migrations/20250101000007_remove_function_count_users_v2.sql
|
|
230
250
|
- spec/initialize.rb
|
|
231
251
|
- spec/mocks/cache_query.rb
|
|
232
252
|
- spec/mocks/create_table.rb
|
|
@@ -273,6 +293,7 @@ files:
|
|
|
273
293
|
- spec/tests/relation_spec.rb
|
|
274
294
|
- spec/tests/schema_spec.rb
|
|
275
295
|
- spec/tests/table_inheritance_spec.rb
|
|
296
|
+
- spec/tests/versioned_commands_spec.rb
|
|
276
297
|
homepage: https://github.com/crashtech/torque-postgresql
|
|
277
298
|
licenses:
|
|
278
299
|
- MIT
|
|
@@ -281,7 +302,6 @@ metadata:
|
|
|
281
302
|
source_code_uri: https://github.com/crashtech/torque-postgresql
|
|
282
303
|
bug_tracker_uri: https://github.com/crashtech/torque-postgresql/issues
|
|
283
304
|
changelog_uri: https://github.com/crashtech/torque-postgresql/releases
|
|
284
|
-
post_install_message:
|
|
285
305
|
rdoc_options:
|
|
286
306
|
- "--title"
|
|
287
307
|
- Torque PostgreSQL
|
|
@@ -298,8 +318,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
298
318
|
- !ruby/object:Gem::Version
|
|
299
319
|
version: 1.8.11
|
|
300
320
|
requirements: []
|
|
301
|
-
rubygems_version: 3.
|
|
302
|
-
signing_key:
|
|
321
|
+
rubygems_version: 3.6.9
|
|
303
322
|
specification_version: 4
|
|
304
323
|
summary: ActiveRecord extension to access PostgreSQL advanced resources
|
|
305
324
|
test_files:
|
|
@@ -312,13 +331,20 @@ test_files:
|
|
|
312
331
|
- spec/factories/texts.rb
|
|
313
332
|
- spec/factories/users.rb
|
|
314
333
|
- spec/factories/videos.rb
|
|
334
|
+
- spec/fixtures/migrations/20250101000001_create_users.rb
|
|
335
|
+
- spec/fixtures/migrations/20250101000002_create_function_count_users_v1.sql
|
|
336
|
+
- spec/fixtures/migrations/20250101000003_create_internal_users.rb
|
|
337
|
+
- spec/fixtures/migrations/20250101000004_update_function_count_users_v2.sql
|
|
338
|
+
- spec/fixtures/migrations/20250101000005_create_view_all_users_v1.sql
|
|
339
|
+
- spec/fixtures/migrations/20250101000006_create_type_user_id_v1.sql
|
|
340
|
+
- spec/fixtures/migrations/20250101000007_remove_function_count_users_v2.sql
|
|
315
341
|
- spec/initialize.rb
|
|
316
342
|
- spec/mocks/cache_query.rb
|
|
317
343
|
- spec/mocks/create_table.rb
|
|
318
344
|
- spec/models/activity.rb
|
|
319
345
|
- spec/models/activity_book.rb
|
|
320
|
-
- spec/models/activity_post/sample.rb
|
|
321
346
|
- spec/models/activity_post.rb
|
|
347
|
+
- spec/models/activity_post/sample.rb
|
|
322
348
|
- spec/models/author.rb
|
|
323
349
|
- spec/models/author_journalist.rb
|
|
324
350
|
- spec/models/category.rb
|
|
@@ -358,3 +384,4 @@ test_files:
|
|
|
358
384
|
- spec/tests/relation_spec.rb
|
|
359
385
|
- spec/tests/schema_spec.rb
|
|
360
386
|
- spec/tests/table_inheritance_spec.rb
|
|
387
|
+
- spec/tests/versioned_commands_spec.rb
|