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