fx 0.3.1 → 0.6.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 +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +15 -8
- data/Appraisals +16 -10
- data/LICENSE +18 -0
- data/README.md +42 -13
- data/fx.gemspec +1 -1
- data/gemfiles/rails42.gemfile +2 -1
- data/gemfiles/rails50.gemfile +1 -1
- data/gemfiles/rails51.gemfile +8 -0
- data/gemfiles/rails52.gemfile +8 -0
- data/gemfiles/rails60.gemfile +8 -0
- data/gemfiles/rails_edge.gemfile +3 -3
- data/lib/fx.rb +22 -0
- data/lib/fx/adapters/postgres.rb +13 -1
- data/lib/fx/adapters/postgres/functions.rb +3 -0
- data/lib/fx/command_recorder.rb +0 -5
- data/lib/fx/configuration.rb +10 -0
- data/lib/fx/definition.rb +13 -3
- data/lib/fx/railtie.rb +15 -0
- data/lib/fx/schema_dumper.rb +0 -5
- data/lib/fx/schema_dumper/function.rb +14 -5
- data/lib/fx/statements.rb +0 -5
- data/lib/fx/version.rb +1 -1
- data/lib/generators/fx/function/USAGE +2 -0
- data/lib/generators/fx/function/function_generator.rb +15 -1
- data/lib/generators/fx/trigger/USAGE +2 -0
- data/lib/generators/fx/trigger/trigger_generator.rb +15 -1
- data/spec/acceptance/user_manages_functions_spec.rb +20 -0
- data/spec/fx/adapters/postgres/triggers_spec.rb +4 -3
- data/spec/fx/adapters/postgres_spec.rb +36 -14
- data/spec/fx/definition_spec.rb +23 -0
- data/spec/fx/schema_dumper/function_spec.rb +57 -1
- data/spec/generators/fx/function/function_generator_spec.rb +12 -0
- data/spec/generators/fx/trigger/trigger_generator_spec.rb +12 -0
- metadata +12 -16
- data/.ruby-version +0 -1
- data/gemfiles/rails40.gemfile +0 -8
- data/gemfiles/rails40.gemfile.lock +0 -111
- data/gemfiles/rails41.gemfile +0 -8
- data/gemfiles/rails41.gemfile.lock +0 -113
- data/gemfiles/rails42.gemfile.lock +0 -130
- data/gemfiles/rails50.gemfile.lock +0 -126
- data/gemfiles/rails_edge.gemfile.lock +0 -179
data/lib/fx/statements.rb
CHANGED
data/lib/fx/version.rb
CHANGED
@@ -8,6 +8,8 @@ module Fx
|
|
8
8
|
include Rails::Generators::Migration
|
9
9
|
source_root File.expand_path("../templates", __FILE__)
|
10
10
|
|
11
|
+
class_option :migration, type: :boolean
|
12
|
+
|
11
13
|
def create_functions_directory
|
12
14
|
unless function_definition_path.exist?
|
13
15
|
empty_directory(function_definition_path)
|
@@ -23,6 +25,7 @@ module Fx
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def create_migration_file
|
28
|
+
return if skip_migration_creation?
|
26
29
|
if updating_existing_function?
|
27
30
|
migration_template(
|
28
31
|
"db/migrate/update_function.erb",
|
@@ -61,7 +64,7 @@ module Fx
|
|
61
64
|
|
62
65
|
def activerecord_migration_class
|
63
66
|
if ActiveRecord::Migration.respond_to?(:current_version)
|
64
|
-
"ActiveRecord::Migration[
|
67
|
+
"ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]"
|
65
68
|
else
|
66
69
|
"ActiveRecord::Migration"
|
67
70
|
end
|
@@ -101,6 +104,17 @@ module Fx
|
|
101
104
|
def previous_definition
|
102
105
|
Fx::Definition.new(name: file_name, version: previous_version)
|
103
106
|
end
|
107
|
+
|
108
|
+
# Skip creating migration file if:
|
109
|
+
# - migrations option is nil or false
|
110
|
+
def skip_migration_creation?
|
111
|
+
!migration
|
112
|
+
end
|
113
|
+
|
114
|
+
# True unless explicitly false
|
115
|
+
def migration
|
116
|
+
options[:migration] != false
|
117
|
+
end
|
104
118
|
end
|
105
119
|
end
|
106
120
|
end
|
@@ -5,6 +5,8 @@ Description:
|
|
5
5
|
If a trigger of the given name already exists, create a new version of the
|
6
6
|
trigger and a migration to replace the old version with the new.
|
7
7
|
|
8
|
+
When --no-migration is passed, skips generating a migration.
|
9
|
+
|
8
10
|
Examples:
|
9
11
|
|
10
12
|
rails generate fx:trigger test
|
@@ -9,6 +9,8 @@ module Fx
|
|
9
9
|
source_root File.expand_path("../templates", __FILE__)
|
10
10
|
argument :table_name, type: :hash, required: true
|
11
11
|
|
12
|
+
class_option :migration, type: :boolean
|
13
|
+
|
12
14
|
def create_triggers_directory
|
13
15
|
unless trigger_definition_path.exist?
|
14
16
|
empty_directory(trigger_definition_path)
|
@@ -20,6 +22,7 @@ module Fx
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def create_migration_file
|
25
|
+
return if skip_migration_creation?
|
23
26
|
if updating_existing_trigger?
|
24
27
|
migration_template(
|
25
28
|
"db/migrate/update_trigger.erb",
|
@@ -58,7 +61,7 @@ module Fx
|
|
58
61
|
|
59
62
|
def activerecord_migration_class
|
60
63
|
if ActiveRecord::Migration.respond_to?(:current_version)
|
61
|
-
"ActiveRecord::Migration[
|
64
|
+
"ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]"
|
62
65
|
else
|
63
66
|
"ActiveRecord::Migration"
|
64
67
|
end
|
@@ -111,6 +114,17 @@ module Fx
|
|
111
114
|
def trigger_definition_path
|
112
115
|
@_trigger_definition_path ||= Rails.root.join(*["db", "triggers"])
|
113
116
|
end
|
117
|
+
|
118
|
+
# Skip creating migration file if:
|
119
|
+
# - migrations option is nil or false
|
120
|
+
def skip_migration_creation?
|
121
|
+
!migration
|
122
|
+
end
|
123
|
+
|
124
|
+
# True unless explicitly false
|
125
|
+
def migration
|
126
|
+
options[:migration] != false
|
127
|
+
end
|
114
128
|
end
|
115
129
|
end
|
116
130
|
end
|
@@ -34,4 +34,24 @@ describe "User manages functions" do
|
|
34
34
|
result = execute("SELECT * FROM test() AS result")
|
35
35
|
expect(result).to eq("result" => "testest")
|
36
36
|
end
|
37
|
+
|
38
|
+
it "handles functions with arguments" do
|
39
|
+
successfully "rails generate fx:function adder"
|
40
|
+
write_function_definition "adder_v01", <<-EOS
|
41
|
+
CREATE FUNCTION adder(x int, y int)
|
42
|
+
RETURNS int AS $$
|
43
|
+
BEGIN
|
44
|
+
RETURN $1 + $2;
|
45
|
+
END;
|
46
|
+
$$ LANGUAGE plpgsql;
|
47
|
+
EOS
|
48
|
+
successfully "rake db:migrate"
|
49
|
+
|
50
|
+
result = execute("SELECT * FROM adder(1, 2) AS result")
|
51
|
+
result["result"] = result["result"].to_i
|
52
|
+
expect(result).to eq("result" => 3)
|
53
|
+
|
54
|
+
successfully "rails destroy fx:function adder"
|
55
|
+
successfully "rake db:migrate"
|
56
|
+
end
|
37
57
|
end
|
@@ -34,9 +34,10 @@ module Fx
|
|
34
34
|
first = triggers.first
|
35
35
|
expect(triggers.size).to eq 1
|
36
36
|
expect(first.name).to eq "uppercase_users_name"
|
37
|
-
expect(first.definition).to
|
38
|
-
|
39
|
-
|
37
|
+
expect(first.definition).to include("BEFORE INSERT")
|
38
|
+
expect(first.definition).to match(/ON [public\.users|users]/)
|
39
|
+
expect(first.definition).to include("FOR EACH ROW")
|
40
|
+
expect(first.definition).to include("EXECUTE PROCEDURE uppercase_users_name()")
|
40
41
|
end
|
41
42
|
end
|
42
43
|
end
|
@@ -53,22 +53,44 @@ module Fx::Adapters
|
|
53
53
|
end
|
54
54
|
|
55
55
|
describe "#drop_function" do
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
56
|
+
context "when the function has arguments" do
|
57
|
+
it "successfully drops a function with the entire function signature" do
|
58
|
+
adapter = Postgres.new
|
59
|
+
adapter.create_function(
|
60
|
+
<<-EOS
|
61
|
+
CREATE FUNCTION adder(x int, y int)
|
62
|
+
RETURNS int AS $$
|
63
|
+
BEGIN
|
64
|
+
RETURN $1 + $2;
|
65
|
+
END;
|
66
|
+
$$ LANGUAGE plpgsql;
|
67
|
+
EOS
|
68
|
+
)
|
69
|
+
|
70
|
+
adapter.drop_function(:adder)
|
71
|
+
|
72
|
+
expect(adapter.functions.map(&:name)).not_to include("adder")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "when the function does not have arguments" do
|
77
|
+
it "successfully drops a function" do
|
78
|
+
adapter = Postgres.new
|
79
|
+
adapter.create_function(
|
80
|
+
<<-EOS
|
81
|
+
CREATE OR REPLACE FUNCTION test()
|
82
|
+
RETURNS text AS $$
|
83
|
+
BEGIN
|
84
|
+
RETURN 'test';
|
85
|
+
END;
|
86
|
+
$$ LANGUAGE plpgsql;
|
87
|
+
EOS
|
88
|
+
)
|
68
89
|
|
69
|
-
|
90
|
+
adapter.drop_function(:test)
|
70
91
|
|
71
|
-
|
92
|
+
expect(adapter.functions.map(&:name)).not_to include("test")
|
93
|
+
end
|
72
94
|
end
|
73
95
|
end
|
74
96
|
|
data/spec/fx/definition_spec.rb
CHANGED
@@ -28,6 +28,29 @@ describe Fx::Definition do
|
|
28
28
|
%r(Define function in db/functions/test_v01.sql before migrating),
|
29
29
|
)
|
30
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 = Rails.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
|
+
Rails.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
|
31
54
|
end
|
32
55
|
|
33
56
|
context "representing a trigger definition" do
|
@@ -3,14 +3,69 @@ require "spec_helper"
|
|
3
3
|
describe Fx::SchemaDumper::Function, :db do
|
4
4
|
it "dumps a create_function for a function in the database" do
|
5
5
|
sql_definition = <<-EOS
|
6
|
-
CREATE OR REPLACE FUNCTION
|
6
|
+
CREATE OR REPLACE FUNCTION my_function()
|
7
7
|
RETURNS text AS $$
|
8
8
|
BEGIN
|
9
9
|
RETURN 'test';
|
10
10
|
END;
|
11
11
|
$$ LANGUAGE plpgsql;
|
12
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
|
+
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
|
+
ActiveRecord::SchemaDumper.dump(connection, stream)
|
41
|
+
|
42
|
+
expect(output).to(
|
43
|
+
match(/function :my_function.*RETURN 'test';.*table "my_table"/m),
|
44
|
+
)
|
45
|
+
ensure
|
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
|
+
|
13
67
|
connection.create_function :test, sql_definition: sql_definition
|
68
|
+
connection.execute aggregate_sql_definition
|
14
69
|
stream = StringIO.new
|
15
70
|
|
16
71
|
ActiveRecord::SchemaDumper.dump(connection, stream)
|
@@ -18,5 +73,6 @@ describe Fx::SchemaDumper::Function, :db do
|
|
18
73
|
output = stream.string
|
19
74
|
expect(output).to include "create_function :test, sql_definition: <<-SQL"
|
20
75
|
expect(output).to include "RETURN 'test';"
|
76
|
+
expect(output).not_to include "aggregate_test"
|
21
77
|
end
|
22
78
|
end
|
@@ -13,6 +13,18 @@ describe Fx::Generators::FunctionGenerator, :generator do
|
|
13
13
|
expect(migration_file(migration)).to contain "CreateFunctionTest"
|
14
14
|
end
|
15
15
|
|
16
|
+
context "when passed --no-migration" do
|
17
|
+
it "creates a only function definition file" do
|
18
|
+
migration = file("db/migrate/create_function_test.rb")
|
19
|
+
function_definition = file("db/functions/test_v01.sql")
|
20
|
+
|
21
|
+
run_generator ["test", "--no-migration"]
|
22
|
+
|
23
|
+
expect(function_definition).to exist
|
24
|
+
expect(migration_file(migration)).not_to exist
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
16
28
|
it "updates an existing function" do
|
17
29
|
with_function_definition(
|
18
30
|
name: "test",
|
@@ -14,6 +14,18 @@ describe Fx::Generators::TriggerGenerator, :generator do
|
|
14
14
|
expect(migration_file(migration)).to contain "on: :some_table"
|
15
15
|
end
|
16
16
|
|
17
|
+
context "when passed --no-migration" do
|
18
|
+
it "creates a only trigger definition file" do
|
19
|
+
migration = file("db/migrate/create_trigger_test.rb")
|
20
|
+
trigger_definition = file("db/triggers/test_v01.sql")
|
21
|
+
|
22
|
+
run_generator ["test", {"table_name" => "some_table"}, "--no-migration"]
|
23
|
+
|
24
|
+
expect(trigger_definition).to exist
|
25
|
+
expect(migration_file(migration)).not_to exist
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
17
29
|
it "supports naming the table as `on` aswell as `table_name`" do
|
18
30
|
migration = file("db/migrate/create_trigger_test.rb")
|
19
31
|
trigger_definition = file("db/triggers/test_v01.sql")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Teo Ljungberg
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: appraisal
|
@@ -191,12 +191,12 @@ files:
|
|
191
191
|
- ".hound.yml"
|
192
192
|
- ".rspec"
|
193
193
|
- ".rubocop.yml"
|
194
|
-
- ".ruby-version"
|
195
194
|
- ".travis.yml"
|
196
195
|
- ".yardopts"
|
197
196
|
- Appraisals
|
198
197
|
- CONTRIBUTING.md
|
199
198
|
- Gemfile
|
199
|
+
- LICENSE
|
200
200
|
- README.md
|
201
201
|
- Rakefile
|
202
202
|
- bin/appraisal
|
@@ -206,16 +206,12 @@ files:
|
|
206
206
|
- bin/setup
|
207
207
|
- bin/yard
|
208
208
|
- fx.gemspec
|
209
|
-
- gemfiles/rails40.gemfile
|
210
|
-
- gemfiles/rails40.gemfile.lock
|
211
|
-
- gemfiles/rails41.gemfile
|
212
|
-
- gemfiles/rails41.gemfile.lock
|
213
209
|
- gemfiles/rails42.gemfile
|
214
|
-
- gemfiles/rails42.gemfile.lock
|
215
210
|
- gemfiles/rails50.gemfile
|
216
|
-
- gemfiles/
|
211
|
+
- gemfiles/rails51.gemfile
|
212
|
+
- gemfiles/rails52.gemfile
|
213
|
+
- gemfiles/rails60.gemfile
|
217
214
|
- gemfiles/rails_edge.gemfile
|
218
|
-
- gemfiles/rails_edge.gemfile.lock
|
219
215
|
- lib/fx.rb
|
220
216
|
- lib/fx/adapters/postgres.rb
|
221
217
|
- lib/fx/adapters/postgres/connection.rb
|
@@ -228,6 +224,7 @@ files:
|
|
228
224
|
- lib/fx/configuration.rb
|
229
225
|
- lib/fx/definition.rb
|
230
226
|
- lib/fx/function.rb
|
227
|
+
- lib/fx/railtie.rb
|
231
228
|
- lib/fx/schema_dumper.rb
|
232
229
|
- lib/fx/schema_dumper/function.rb
|
233
230
|
- lib/fx/schema_dumper/trigger.rb
|
@@ -286,13 +283,13 @@ homepage: https://github.com/teoljungberg/fx
|
|
286
283
|
licenses:
|
287
284
|
- MIT
|
288
285
|
metadata: {}
|
289
|
-
post_install_message:
|
286
|
+
post_install_message:
|
290
287
|
rdoc_options: []
|
291
288
|
require_paths:
|
292
289
|
- lib
|
293
290
|
required_ruby_version: !ruby/object:Gem::Requirement
|
294
291
|
requirements:
|
295
|
-
- - "
|
292
|
+
- - ">="
|
296
293
|
- !ruby/object:Gem::Version
|
297
294
|
version: '2.1'
|
298
295
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
@@ -301,9 +298,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
301
298
|
- !ruby/object:Gem::Version
|
302
299
|
version: '0'
|
303
300
|
requirements: []
|
304
|
-
|
305
|
-
|
306
|
-
signing_key:
|
301
|
+
rubygems_version: 3.2.2
|
302
|
+
signing_key:
|
307
303
|
specification_version: 4
|
308
304
|
summary: Support for database functions and triggers in Rails migrations
|
309
305
|
test_files:
|