fx 0.7.0 → 0.9.0
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/.github/workflows/ci.yml +53 -0
- data/.gitignore +0 -1
- data/.rspec +1 -1
- data/.standard.yml +3 -0
- data/CHANGELOG.md +124 -0
- data/CONTRIBUTING.md +13 -4
- data/Gemfile +13 -2
- data/README.md +4 -2
- data/Rakefile +2 -1
- data/bin/setup +0 -4
- data/bin/standardrb +27 -0
- data/fx.gemspec +20 -27
- data/lib/fx/adapters/postgres/connection.rb +12 -0
- data/lib/fx/adapters/postgres/functions.rb +3 -3
- data/lib/fx/adapters/postgres/triggers.rb +3 -3
- data/lib/fx/adapters/postgres.rb +6 -14
- data/lib/fx/command_recorder.rb +87 -6
- data/lib/fx/configuration.rb +0 -25
- data/lib/fx/definition.rb +16 -6
- data/lib/fx/function.rb +7 -7
- data/lib/fx/schema_dumper.rb +45 -5
- data/lib/fx/statements.rb +228 -6
- data/lib/fx/trigger.rb +3 -3
- data/lib/fx/version.rb +1 -1
- data/lib/fx.rb +30 -12
- data/lib/generators/fx/function/function_generator.rb +8 -8
- data/lib/generators/fx/trigger/trigger_generator.rb +6 -10
- data/spec/acceptance/user_manages_functions_spec.rb +5 -5
- data/spec/acceptance/user_manages_triggers_spec.rb +8 -8
- data/spec/acceptance_helper.rb +6 -4
- data/spec/dummy/Rakefile +4 -4
- data/spec/dummy/bin/bundle +2 -2
- data/spec/dummy/bin/rails +3 -3
- data/spec/dummy/bin/rake +2 -2
- data/spec/dummy/config/application.rb +6 -0
- data/spec/dummy/config/database.yml +2 -0
- data/spec/dummy/config.ru +1 -1
- data/spec/features/functions/migrations_spec.rb +4 -4
- data/spec/features/functions/revert_spec.rb +7 -7
- data/spec/features/triggers/migrations_spec.rb +6 -6
- data/spec/features/triggers/revert_spec.rb +13 -13
- data/spec/fx/adapters/postgres/functions_spec.rb +26 -30
- data/spec/fx/adapters/postgres/triggers_spec.rb +34 -38
- data/spec/fx/adapters/postgres_spec.rb +107 -109
- data/spec/fx/command_recorder_spec.rb +41 -39
- data/spec/fx/configuration_spec.rb +20 -9
- data/spec/fx/definition_spec.rb +30 -38
- data/spec/fx/function_spec.rb +45 -48
- data/spec/fx/schema_dumper_spec.rb +123 -0
- data/spec/fx/statements_spec.rb +217 -0
- data/spec/fx/trigger_spec.rb +37 -40
- data/spec/fx_spec.rb +28 -0
- data/spec/generators/fx/function/function_generator_spec.rb +6 -6
- data/spec/generators/fx/trigger/trigger_generator_spec.rb +10 -10
- data/spec/spec_helper.rb +5 -0
- data/spec/support/definition_helpers.rb +5 -9
- data/spec/support/generator_setup.rb +1 -1
- data/spec/support/migration_helpers.rb +1 -1
- data/spec/support/warning_helper.rb +5 -0
- metadata +24 -213
- data/.hound.yml +0 -2
- data/.rubocop.yml +0 -648
- data/.travis.yml +0 -60
- data/Appraisals +0 -45
- data/bin/appraisal +0 -17
- data/gemfiles/rails42.gemfile +0 -10
- data/gemfiles/rails50.gemfile +0 -8
- data/gemfiles/rails51.gemfile +0 -8
- data/gemfiles/rails52.gemfile +0 -8
- data/gemfiles/rails60.gemfile +0 -8
- data/gemfiles/rails61.gemfile +0 -8
- data/gemfiles/rails_edge.gemfile +0 -8
- data/lib/fx/command_recorder/arguments.rb +0 -43
- data/lib/fx/command_recorder/function.rb +0 -30
- data/lib/fx/command_recorder/trigger.rb +0 -30
- data/lib/fx/schema_dumper/function.rb +0 -38
- data/lib/fx/schema_dumper/trigger.rb +0 -29
- data/lib/fx/statements/function.rb +0 -115
- data/lib/fx/statements/trigger.rb +0 -146
- data/spec/fx/command_recorder/arguments_spec.rb +0 -41
- data/spec/fx/schema_dumper/function_spec.rb +0 -80
- data/spec/fx/schema_dumper/trigger_spec.rb +0 -40
- data/spec/fx/statements/function_spec.rb +0 -103
- data/spec/fx/statements/trigger_spec.rb +0 -132
@@ -1,13 +1,13 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe Fx::CommandRecorder, :db do
|
3
|
+
RSpec.describe Fx::CommandRecorder, :db do
|
4
4
|
describe "#create_function" do
|
5
5
|
it "records the created function" do
|
6
6
|
recorder = ActiveRecord::Migration::CommandRecorder.new
|
7
7
|
|
8
8
|
recorder.create_function :test
|
9
9
|
|
10
|
-
expect(recorder.commands).to eq
|
10
|
+
expect(recorder.commands).to eq([[:create_function, [:test], nil]])
|
11
11
|
end
|
12
12
|
|
13
13
|
it "reverts to drop_function" do
|
@@ -15,7 +15,7 @@ describe Fx::CommandRecorder, :db do
|
|
15
15
|
|
16
16
|
recorder.create_function :test
|
17
17
|
|
18
|
-
expect(recorder.commands).to eq
|
18
|
+
expect(recorder.commands).to eq([[:create_function, [:test], nil]])
|
19
19
|
end
|
20
20
|
|
21
21
|
it "reverts to drop_function" do
|
@@ -23,7 +23,7 @@ describe Fx::CommandRecorder, :db do
|
|
23
23
|
|
24
24
|
recorder.revert { recorder.create_function :test }
|
25
25
|
|
26
|
-
expect(recorder.commands).to eq
|
26
|
+
expect(recorder.commands).to eq([[:drop_function, [:test]]])
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -33,54 +33,56 @@ describe Fx::CommandRecorder, :db do
|
|
33
33
|
|
34
34
|
recorder.drop_function :test
|
35
35
|
|
36
|
-
expect(recorder.commands).to eq
|
36
|
+
expect(recorder.commands).to eq([[:drop_function, [:test], nil]])
|
37
37
|
end
|
38
38
|
|
39
39
|
it "reverts to create_function with specified revert_to_version" do
|
40
40
|
recorder = ActiveRecord::Migration::CommandRecorder.new
|
41
|
-
args = [:test, {
|
42
|
-
revert_args = [:test, {
|
41
|
+
args = [:test, {revert_to_version: 3}]
|
42
|
+
revert_args = [:test, {version: 3}]
|
43
43
|
|
44
44
|
recorder.revert { recorder.drop_function(*args) }
|
45
45
|
|
46
|
-
expect(recorder.commands).to eq
|
46
|
+
expect(recorder.commands).to eq([[:create_function, revert_args]])
|
47
47
|
end
|
48
48
|
|
49
49
|
it "raises when reverting without revert_to_version set" do
|
50
50
|
recorder = ActiveRecord::Migration::CommandRecorder.new
|
51
|
-
args = [:test, {
|
51
|
+
args = [:test, {another_argument: 1}]
|
52
52
|
|
53
|
-
expect
|
54
|
-
|
53
|
+
expect do
|
54
|
+
recorder.revert { recorder.drop_function(*args) }
|
55
|
+
end.to raise_error(ActiveRecord::IrreversibleMigration)
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
58
59
|
describe "#update_function" do
|
59
60
|
it "records the updated function" do
|
60
61
|
recorder = ActiveRecord::Migration::CommandRecorder.new
|
61
|
-
args = [:test, {
|
62
|
+
args = [:test, {version: 2}]
|
62
63
|
|
63
64
|
recorder.update_function(*args)
|
64
65
|
|
65
|
-
expect(recorder.commands).to eq
|
66
|
+
expect(recorder.commands).to eq([[:update_function, args, nil]])
|
66
67
|
end
|
67
68
|
|
68
69
|
it "reverts to update_function with the specified revert_to_version" do
|
69
70
|
recorder = ActiveRecord::Migration::CommandRecorder.new
|
70
|
-
args = [:test, {
|
71
|
-
revert_args = [:test, {
|
71
|
+
args = [:test, {version: 2, revert_to_version: 1}]
|
72
|
+
revert_args = [:test, {version: 1}]
|
72
73
|
|
73
74
|
recorder.revert { recorder.update_function(*args) }
|
74
75
|
|
75
|
-
expect(recorder.commands).to eq
|
76
|
+
expect(recorder.commands).to eq([[:update_function, revert_args]])
|
76
77
|
end
|
77
78
|
|
78
79
|
it "raises when reverting without revert_to_version set" do
|
79
80
|
recorder = ActiveRecord::Migration::CommandRecorder.new
|
80
|
-
args = [:test, {
|
81
|
+
args = [:test, {version: 42, another_argument: 1}]
|
81
82
|
|
82
|
-
expect
|
83
|
-
|
83
|
+
expect do
|
84
|
+
recorder.revert { recorder.update_function(*args) }
|
85
|
+
end.to raise_error(ActiveRecord::IrreversibleMigration)
|
84
86
|
end
|
85
87
|
end
|
86
88
|
|
@@ -90,7 +92,7 @@ describe Fx::CommandRecorder, :db do
|
|
90
92
|
|
91
93
|
recorder.create_trigger :greetings
|
92
94
|
|
93
|
-
expect(recorder.commands).to eq
|
95
|
+
expect(recorder.commands).to eq([[:create_trigger, [:greetings], nil]])
|
94
96
|
end
|
95
97
|
|
96
98
|
it "reverts to drop_trigger" do
|
@@ -98,9 +100,7 @@ describe Fx::CommandRecorder, :db do
|
|
98
100
|
|
99
101
|
recorder.create_trigger :greetings
|
100
102
|
|
101
|
-
expect(recorder.commands).to eq [
|
102
|
-
[:create_trigger, [:greetings], nil],
|
103
|
-
]
|
103
|
+
expect(recorder.commands).to eq([[:create_trigger, [:greetings], nil]])
|
104
104
|
end
|
105
105
|
|
106
106
|
it "reverts to drop_trigger" do
|
@@ -108,7 +108,7 @@ describe Fx::CommandRecorder, :db do
|
|
108
108
|
|
109
109
|
recorder.revert { recorder.create_trigger :greetings }
|
110
110
|
|
111
|
-
expect(recorder.commands).to eq
|
111
|
+
expect(recorder.commands).to eq([[:drop_trigger, [:greetings]]])
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
@@ -118,54 +118,56 @@ describe Fx::CommandRecorder, :db do
|
|
118
118
|
|
119
119
|
recorder.drop_trigger :users
|
120
120
|
|
121
|
-
expect(recorder.commands).to eq
|
121
|
+
expect(recorder.commands).to eq([[:drop_trigger, [:users], nil]])
|
122
122
|
end
|
123
123
|
|
124
124
|
it "reverts to create_trigger with specified revert_to_version" do
|
125
125
|
recorder = ActiveRecord::Migration::CommandRecorder.new
|
126
|
-
args = [:users, {
|
127
|
-
revert_args = [:users, {
|
126
|
+
args = [:users, {revert_to_version: 3}]
|
127
|
+
revert_args = [:users, {version: 3}]
|
128
128
|
|
129
129
|
recorder.revert { recorder.drop_trigger(*args) }
|
130
130
|
|
131
|
-
expect(recorder.commands).to eq
|
131
|
+
expect(recorder.commands).to eq([[:create_trigger, revert_args]])
|
132
132
|
end
|
133
133
|
|
134
134
|
it "raises when reverting without revert_to_version set" do
|
135
135
|
recorder = ActiveRecord::Migration::CommandRecorder.new
|
136
|
-
args = [:users, {
|
136
|
+
args = [:users, {another_argument: 1}]
|
137
137
|
|
138
|
-
expect
|
139
|
-
|
138
|
+
expect do
|
139
|
+
recorder.revert { recorder.drop_trigger(*args) }
|
140
|
+
end.to raise_error(ActiveRecord::IrreversibleMigration)
|
140
141
|
end
|
141
142
|
end
|
142
143
|
|
143
144
|
describe "#update_trigger" do
|
144
145
|
it "records the updated trigger" do
|
145
146
|
recorder = ActiveRecord::Migration::CommandRecorder.new
|
146
|
-
args = [:users, {
|
147
|
+
args = [:users, {version: 2}]
|
147
148
|
|
148
149
|
recorder.update_trigger(*args)
|
149
150
|
|
150
|
-
expect(recorder.commands).to eq
|
151
|
+
expect(recorder.commands).to eq([[:update_trigger, args, nil]])
|
151
152
|
end
|
152
153
|
|
153
154
|
it "reverts to update_trigger with the specified revert_to_version" do
|
154
155
|
recorder = ActiveRecord::Migration::CommandRecorder.new
|
155
|
-
args = [:users, {
|
156
|
-
revert_args = [:users, {
|
156
|
+
args = [:users, {version: 2, revert_to_version: 1}]
|
157
|
+
revert_args = [:users, {version: 1}]
|
157
158
|
|
158
159
|
recorder.revert { recorder.update_trigger(*args) }
|
159
160
|
|
160
|
-
expect(recorder.commands).to eq
|
161
|
+
expect(recorder.commands).to eq([[:update_trigger, revert_args]])
|
161
162
|
end
|
162
163
|
|
163
164
|
it "raises when reverting without revert_to_version set" do
|
164
165
|
recorder = ActiveRecord::Migration::CommandRecorder.new
|
165
|
-
args = [:users, {
|
166
|
+
args = [:users, {version: 42, another_argument: 1}]
|
166
167
|
|
167
|
-
expect
|
168
|
-
|
168
|
+
expect do
|
169
|
+
recorder.revert { recorder.update_trigger(*args) }
|
170
|
+
end.to raise_error(ActiveRecord::IrreversibleMigration)
|
169
171
|
end
|
170
172
|
end
|
171
173
|
end
|
@@ -1,21 +1,32 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe Fx::Configuration do
|
3
|
+
RSpec.describe Fx::Configuration do
|
4
4
|
it "defaults the database adapter to postgres" do
|
5
|
-
|
6
|
-
|
5
|
+
configuration = Fx::Configuration.new
|
6
|
+
|
7
|
+
expect(configuration.database).to be_a(Fx::Adapters::Postgres)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "defaults `dump_functions_at_beginning_of_schema` to false" do
|
11
|
+
configuration = Fx::Configuration.new
|
12
|
+
|
13
|
+
expect(configuration.dump_functions_at_beginning_of_schema).to eq(false)
|
7
14
|
end
|
8
15
|
|
9
16
|
it "allows the database adapter to be set" do
|
17
|
+
configuration = Fx::Configuration.new
|
10
18
|
adapter = double("Fx Adapter")
|
11
19
|
|
12
|
-
|
13
|
-
|
14
|
-
|
20
|
+
configuration.database = adapter
|
21
|
+
|
22
|
+
expect(configuration.database).to eq(adapter)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "allows `dump_functions_at_beginning_of_schema` to be set" do
|
26
|
+
configuration = Fx::Configuration.new
|
15
27
|
|
16
|
-
|
17
|
-
expect(Fx.database).to eq adapter
|
28
|
+
configuration.dump_functions_at_beginning_of_schema = true
|
18
29
|
|
19
|
-
|
30
|
+
expect(configuration.dump_functions_at_beginning_of_schema).to eq(true)
|
20
31
|
end
|
21
32
|
end
|
data/spec/fx/definition_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe Fx::Definition do
|
3
|
+
RSpec.describe Fx::Definition do
|
4
4
|
describe "#to_sql" do
|
5
5
|
context "representing a function definition" do
|
6
6
|
it "returns the content of a function definition" do
|
@@ -14,24 +14,26 @@ describe Fx::Definition do
|
|
14
14
|
EOS
|
15
15
|
allow(File).to receive(:read).and_return(sql_definition)
|
16
16
|
|
17
|
-
definition = Fx::Definition.
|
17
|
+
definition = Fx::Definition.function(name: "test", version: 1)
|
18
18
|
|
19
|
-
expect(definition.to_sql).to eq
|
19
|
+
expect(definition.to_sql).to eq(sql_definition)
|
20
20
|
end
|
21
21
|
|
22
22
|
it "raises an error if the file is empty" do
|
23
23
|
allow(File).to receive(:read).and_return("")
|
24
|
-
definition = Fx::Definition.
|
24
|
+
definition = Fx::Definition.function(name: "test", version: 1)
|
25
25
|
|
26
|
-
expect
|
26
|
+
expect do
|
27
|
+
definition.to_sql
|
28
|
+
end.to raise_error(
|
27
29
|
RuntimeError,
|
28
|
-
%r
|
30
|
+
%r{Define function in db/functions/test_v01.sql before migrating}
|
29
31
|
)
|
30
32
|
end
|
31
33
|
|
32
34
|
context "when definition is at Rails engine" do
|
33
35
|
it "returns the content of a function definition" do
|
34
|
-
sql_definition =
|
36
|
+
sql_definition = <<~EOS
|
35
37
|
CREATE OR REPLACE FUNCTION test()
|
36
38
|
RETURNS text AS $$
|
37
39
|
BEGIN
|
@@ -44,9 +46,9 @@ describe Fx::Definition do
|
|
44
46
|
File.write(engine_path.join("db", "functions", "custom_test_v01.sql"), sql_definition)
|
45
47
|
Rails.application.config.paths["db/migrate"].push(engine_path.join("db", "migrate"))
|
46
48
|
|
47
|
-
definition = Fx::Definition.
|
49
|
+
definition = Fx::Definition.function(name: "custom_test", version: 1)
|
48
50
|
|
49
|
-
expect(definition.to_sql).to eq
|
51
|
+
expect(definition.to_sql).to eq(sql_definition)
|
50
52
|
|
51
53
|
FileUtils.rm_rf(engine_path)
|
52
54
|
end
|
@@ -55,34 +57,28 @@ describe Fx::Definition do
|
|
55
57
|
|
56
58
|
context "representing a trigger definition" do
|
57
59
|
it "returns the content of a trigger definition" do
|
58
|
-
sql_definition =
|
60
|
+
sql_definition = <<~EOS
|
59
61
|
CREATE TRIGGER check_update
|
60
62
|
BEFORE UPDATE ON accounts
|
61
63
|
FOR EACH ROW
|
62
|
-
EXECUTE
|
64
|
+
EXECUTE FUNCTION check_account_update();
|
63
65
|
EOS
|
64
66
|
allow(File).to receive(:read).and_return(sql_definition)
|
65
67
|
|
66
|
-
definition = Fx::Definition.
|
67
|
-
name: "test",
|
68
|
-
version: 1,
|
69
|
-
type: "trigger",
|
70
|
-
)
|
68
|
+
definition = Fx::Definition.trigger(name: "test", version: 1)
|
71
69
|
|
72
|
-
expect(definition.to_sql).to eq
|
70
|
+
expect(definition.to_sql).to eq(sql_definition)
|
73
71
|
end
|
74
72
|
|
75
73
|
it "raises an error if the file is empty" do
|
76
74
|
allow(File).to receive(:read).and_return("")
|
77
|
-
definition = Fx::Definition.
|
78
|
-
name: "test",
|
79
|
-
version: 1,
|
80
|
-
type: "trigger",
|
81
|
-
)
|
75
|
+
definition = Fx::Definition.trigger(name: "test", version: 1)
|
82
76
|
|
83
|
-
expect
|
77
|
+
expect do
|
78
|
+
definition.to_sql
|
79
|
+
end.to raise_error(
|
84
80
|
RuntimeError,
|
85
|
-
%r
|
81
|
+
%r{Define trigger in db/triggers/test_v01.sql before migrating}
|
86
82
|
)
|
87
83
|
end
|
88
84
|
end
|
@@ -91,44 +87,40 @@ describe Fx::Definition do
|
|
91
87
|
describe "#path" do
|
92
88
|
context "representing a function definition" do
|
93
89
|
it "returns a sql file with padded version and function name" do
|
94
|
-
definition = Fx::Definition.
|
90
|
+
definition = Fx::Definition.function(name: "test", version: 1)
|
95
91
|
|
96
|
-
expect(definition.path).to eq
|
92
|
+
expect(definition.path).to eq("db/functions/test_v01.sql")
|
97
93
|
end
|
98
94
|
end
|
99
95
|
|
100
96
|
context "representing a trigger definition" do
|
101
97
|
it "returns a sql file with padded version and trigger name" do
|
102
|
-
definition = Fx::Definition.
|
103
|
-
name: "test",
|
104
|
-
version: 1,
|
105
|
-
type: "trigger",
|
106
|
-
)
|
98
|
+
definition = Fx::Definition.trigger(name: "test", version: 1)
|
107
99
|
|
108
|
-
expect(definition.path).to eq
|
100
|
+
expect(definition.path).to eq("db/triggers/test_v01.sql")
|
109
101
|
end
|
110
102
|
end
|
111
103
|
end
|
112
104
|
|
113
105
|
describe "#full_path" do
|
114
106
|
it "joins the path with Rails.root" do
|
115
|
-
definition = Fx::Definition.
|
107
|
+
definition = Fx::Definition.function(name: "test", version: 15)
|
116
108
|
|
117
|
-
expect(definition.full_path).to eq
|
109
|
+
expect(definition.full_path).to eq(Rails.root.join(definition.path))
|
118
110
|
end
|
119
111
|
end
|
120
112
|
|
121
113
|
describe "#version" do
|
122
114
|
it "pads the version number with 0" do
|
123
|
-
definition = Fx::Definition.
|
115
|
+
definition = Fx::Definition.function(name: :_, version: 1)
|
124
116
|
|
125
|
-
expect(definition.version).to eq
|
117
|
+
expect(definition.version).to eq("01")
|
126
118
|
end
|
127
119
|
|
128
120
|
it "does not pad more than 2 characters" do
|
129
|
-
definition = Fx::Definition.
|
121
|
+
definition = Fx::Definition.function(name: :_, version: 15)
|
130
122
|
|
131
|
-
expect(definition.version).to eq
|
123
|
+
expect(definition.version).to eq("15")
|
132
124
|
end
|
133
125
|
end
|
134
126
|
end
|
data/spec/fx/function_spec.rb
CHANGED
@@ -1,68 +1,65 @@
|
|
1
1
|
require "spec_helper"
|
2
|
-
require "fx/function"
|
3
2
|
|
4
|
-
|
5
|
-
describe
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
)
|
3
|
+
RSpec.describe Fx::Function do
|
4
|
+
describe "#<=>" do
|
5
|
+
it "delegates to `name`" do
|
6
|
+
function_a = Fx::Function.new(
|
7
|
+
"name" => "name_a",
|
8
|
+
"definition" => "some definition"
|
9
|
+
)
|
10
|
+
function_b = Fx::Function.new(
|
11
|
+
"name" => "name_b",
|
12
|
+
"definition" => "some definition"
|
13
|
+
)
|
14
|
+
function_c = Fx::Function.new(
|
15
|
+
"name" => "name_c",
|
16
|
+
"definition" => "some definition"
|
17
|
+
)
|
20
18
|
|
21
|
-
|
22
|
-
end
|
19
|
+
expect(function_b).to be_between(function_a, function_c)
|
23
20
|
end
|
21
|
+
end
|
24
22
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
23
|
+
describe "#==" do
|
24
|
+
it "compares `name` and `definition`" do
|
25
|
+
function_a = Fx::Function.new(
|
26
|
+
"name" => "name_a",
|
27
|
+
"definition" => "some definition"
|
28
|
+
)
|
29
|
+
function_b = Fx::Function.new(
|
30
|
+
"name" => "name_b",
|
31
|
+
"definition" => "some other definition"
|
32
|
+
)
|
35
33
|
|
36
|
-
|
37
|
-
end
|
34
|
+
expect(function_a).not_to eq(function_b)
|
38
35
|
end
|
36
|
+
end
|
39
37
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
38
|
+
describe "#to_schema" do
|
39
|
+
it "returns a schema compatible version of the function" do
|
40
|
+
function = Fx::Function.new(
|
41
|
+
"name" => "uppercase_users_name",
|
42
|
+
"definition" => "CREATE OR REPLACE TRIGGER uppercase_users_name ..."
|
43
|
+
)
|
46
44
|
|
47
|
-
|
45
|
+
expect(function.to_schema).to eq(<<-EOS)
|
48
46
|
create_function :uppercase_users_name, sql_definition: <<-'SQL'
|
49
47
|
CREATE OR REPLACE TRIGGER uppercase_users_name ...
|
50
48
|
SQL
|
51
|
-
|
52
|
-
|
49
|
+
EOS
|
50
|
+
end
|
53
51
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
52
|
+
it "maintains backslashes" do
|
53
|
+
function = Fx::Function.new(
|
54
|
+
"name" => "regex",
|
55
|
+
"definition" => "CREATE OR REPLACE FUNCTION regex \\1"
|
56
|
+
)
|
59
57
|
|
60
|
-
|
58
|
+
expect(function.to_schema).to eq(<<-'EOS')
|
61
59
|
create_function :regex, sql_definition: <<-'SQL'
|
62
60
|
CREATE OR REPLACE FUNCTION regex \1
|
63
61
|
SQL
|
64
|
-
|
65
|
-
end
|
62
|
+
EOS
|
66
63
|
end
|
67
64
|
end
|
68
65
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe Fx::SchemaDumper, :db do
|
4
|
+
it "dumps a create_function for a function in the database" do
|
5
|
+
sql_definition = <<~EOS
|
6
|
+
CREATE OR REPLACE FUNCTION my_function()
|
7
|
+
RETURNS text AS $$
|
8
|
+
BEGIN
|
9
|
+
RETURN 'test';
|
10
|
+
END;
|
11
|
+
$$ LANGUAGE plpgsql;
|
12
|
+
EOS
|
13
|
+
connection.create_function :my_function, sql_definition: sql_definition
|
14
|
+
connection.create_table :my_table
|
15
|
+
stream = StringIO.new
|
16
|
+
output = stream.string
|
17
|
+
|
18
|
+
dump(connection: connection, stream: stream)
|
19
|
+
|
20
|
+
expect(output).to match(
|
21
|
+
/table "my_table".*function :my_function.*RETURN 'test';/m
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "dumps a create_function for a function in the database" do
|
26
|
+
Fx.configuration.dump_functions_at_beginning_of_schema = true
|
27
|
+
sql_definition = <<~EOS
|
28
|
+
CREATE OR REPLACE FUNCTION my_function()
|
29
|
+
RETURNS text AS $$
|
30
|
+
BEGIN
|
31
|
+
RETURN 'test';
|
32
|
+
END;
|
33
|
+
$$ LANGUAGE plpgsql;
|
34
|
+
EOS
|
35
|
+
connection.create_function :my_function, sql_definition: sql_definition
|
36
|
+
connection.create_table :my_table
|
37
|
+
stream = StringIO.new
|
38
|
+
output = stream.string
|
39
|
+
|
40
|
+
dump(connection: connection, stream: stream)
|
41
|
+
|
42
|
+
expect(output).to(
|
43
|
+
match(/function :my_function.*RETURN 'test';.*table "my_table"/m)
|
44
|
+
)
|
45
|
+
|
46
|
+
Fx.configuration.dump_functions_at_beginning_of_schema = false
|
47
|
+
end
|
48
|
+
|
49
|
+
it "does not dump a create_function for aggregates in the database" do
|
50
|
+
sql_definition = <<~EOS
|
51
|
+
CREATE OR REPLACE FUNCTION test(text, text)
|
52
|
+
RETURNS text AS $$
|
53
|
+
BEGIN
|
54
|
+
RETURN 'test';
|
55
|
+
END;
|
56
|
+
$$ LANGUAGE plpgsql;
|
57
|
+
EOS
|
58
|
+
|
59
|
+
aggregate_sql_definition = <<~EOS
|
60
|
+
CREATE AGGREGATE aggregate_test(text)
|
61
|
+
(
|
62
|
+
sfunc = test,
|
63
|
+
stype = text
|
64
|
+
);
|
65
|
+
EOS
|
66
|
+
|
67
|
+
connection.create_function :test, sql_definition: sql_definition
|
68
|
+
connection.execute aggregate_sql_definition
|
69
|
+
stream = StringIO.new
|
70
|
+
|
71
|
+
dump(connection: connection, stream: stream)
|
72
|
+
|
73
|
+
output = stream.string
|
74
|
+
expect(output).to include("create_function :test, sql_definition: <<-'SQL'")
|
75
|
+
expect(output).to include("RETURN 'test';")
|
76
|
+
expect(output).not_to include("aggregate_test")
|
77
|
+
end
|
78
|
+
|
79
|
+
it "dumps a create_trigger for a trigger in the database" do
|
80
|
+
connection.execute <<~EOS
|
81
|
+
CREATE TABLE users (
|
82
|
+
id int PRIMARY KEY,
|
83
|
+
name varchar(256),
|
84
|
+
upper_name varchar(256)
|
85
|
+
);
|
86
|
+
EOS
|
87
|
+
Fx.database.create_function <<~EOS
|
88
|
+
CREATE OR REPLACE FUNCTION uppercase_users_name()
|
89
|
+
RETURNS trigger AS $$
|
90
|
+
BEGIN
|
91
|
+
NEW.upper_name = UPPER(NEW.name);
|
92
|
+
RETURN NEW;
|
93
|
+
END;
|
94
|
+
$$ LANGUAGE plpgsql;
|
95
|
+
EOS
|
96
|
+
sql_definition = <<~EOS
|
97
|
+
CREATE TRIGGER uppercase_users_name
|
98
|
+
BEFORE INSERT ON users
|
99
|
+
FOR EACH ROW
|
100
|
+
EXECUTE FUNCTION uppercase_users_name();
|
101
|
+
EOS
|
102
|
+
connection.create_trigger(
|
103
|
+
:uppercase_users_name,
|
104
|
+
sql_definition: sql_definition
|
105
|
+
)
|
106
|
+
stream = StringIO.new
|
107
|
+
|
108
|
+
dump(connection: connection, stream: stream)
|
109
|
+
|
110
|
+
output = stream.string
|
111
|
+
expect(output).to include("create_trigger :uppercase_users_name")
|
112
|
+
expect(output).to include("sql_definition: <<-SQL")
|
113
|
+
expect(output).to include("EXECUTE FUNCTION uppercase_users_name()")
|
114
|
+
end
|
115
|
+
|
116
|
+
def dump(connection:, stream:)
|
117
|
+
if Rails.version >= "7.2"
|
118
|
+
ActiveRecord::SchemaDumper.dump(connection.pool, stream)
|
119
|
+
else
|
120
|
+
ActiveRecord::SchemaDumper.dump(connection, stream)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|