fx 0.2.0 → 0.6.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 +5 -5
- data/.gitignore +1 -0
- data/.hound.yml +2 -0
- data/.rubocop.yml +648 -0
- data/.travis.yml +18 -6
- data/Appraisals +21 -10
- data/LICENSE +18 -0
- data/README.md +45 -13
- data/bin/setup +1 -0
- 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 +8 -0
- data/lib/fx.rb +22 -0
- data/lib/fx/adapters/postgres.rb +26 -1
- data/lib/fx/adapters/postgres/functions.rb +5 -2
- data/lib/fx/adapters/postgres/triggers.rb +2 -2
- 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/function.rb +2 -0
- 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/statements/function.rb +4 -2
- data/lib/fx/statements/trigger.rb +2 -0
- data/lib/fx/trigger.rb +2 -0
- data/lib/fx/version.rb +1 -1
- data/lib/generators/fx/function/USAGE +2 -0
- data/lib/generators/fx/function/function_generator.rb +14 -1
- data/lib/generators/fx/trigger/USAGE +2 -0
- data/lib/generators/fx/trigger/trigger_generator.rb +14 -1
- data/spec/acceptance/user_manages_functions_spec.rb +22 -2
- data/spec/acceptance/user_manages_triggers_spec.rb +6 -6
- data/spec/acceptance_helper.rb +2 -1
- data/spec/dummy/Rakefile +7 -0
- data/spec/features/functions/migrations_spec.rb +2 -2
- data/spec/features/functions/revert_spec.rb +2 -2
- data/spec/features/triggers/migrations_spec.rb +3 -3
- data/spec/features/triggers/revert_spec.rb +4 -4
- 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 +46 -49
- data/spec/fx/definition_spec.rb +25 -2
- data/spec/fx/function_spec.rb +55 -0
- data/spec/fx/schema_dumper/function_spec.rb +58 -2
- data/spec/fx/schema_dumper/trigger_spec.rb +3 -3
- data/spec/fx/trigger_spec.rb +55 -0
- data/spec/generators/fx/function/function_generator_spec.rb +12 -0
- data/spec/generators/fx/trigger/trigger_generator_spec.rb +12 -0
- metadata +19 -11
- 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/lib/fx/railtie.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "rails/railtie"
|
2
|
+
|
3
|
+
module Fx
|
4
|
+
# Automatically initializes Fx in the context of a Rails application when
|
5
|
+
# ActiveRecord is loaded.
|
6
|
+
#
|
7
|
+
# @see Fx.load
|
8
|
+
class Railtie < Rails::Railtie
|
9
|
+
initializer "fx.load" do
|
10
|
+
ActiveSupport.on_load :active_record do
|
11
|
+
Fx.load
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/fx/schema_dumper.rb
CHANGED
@@ -5,15 +5,24 @@ module Fx
|
|
5
5
|
# @api private
|
6
6
|
module Function
|
7
7
|
def tables(stream)
|
8
|
+
if Fx.configuration.dump_functions_at_beginning_of_schema
|
9
|
+
functions(stream)
|
10
|
+
empty_line(stream)
|
11
|
+
end
|
12
|
+
|
8
13
|
super
|
9
|
-
functions(stream)
|
10
|
-
end
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
stream
|
15
|
+
unless Fx.configuration.dump_functions_at_beginning_of_schema
|
16
|
+
functions(stream)
|
17
|
+
empty_line(stream)
|
15
18
|
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def empty_line(stream)
|
22
|
+
stream.puts if dumpable_functions_in_database.any?
|
23
|
+
end
|
16
24
|
|
25
|
+
def functions(stream)
|
17
26
|
dumpable_functions_in_database.each do |function|
|
18
27
|
stream.puts(function.to_schema)
|
19
28
|
end
|
data/lib/fx/statements.rb
CHANGED
@@ -36,6 +36,7 @@ module Fx
|
|
36
36
|
"version or sql_definition must be specified",
|
37
37
|
)
|
38
38
|
end
|
39
|
+
sql_definition = sql_definition.strip_heredoc if sql_definition
|
39
40
|
sql_definition ||= Fx::Definition.new(name: name, version: version).to_sql
|
40
41
|
|
41
42
|
Fx.database.create_function(sql_definition)
|
@@ -49,8 +50,8 @@ module Fx
|
|
49
50
|
# the `version` argument to {#create_function}.
|
50
51
|
# @return The database response from executing the drop statement.
|
51
52
|
#
|
52
|
-
# @example Drop a function, rolling back to version
|
53
|
-
# drop_function(:uppercase_users_name,
|
53
|
+
# @example Drop a function, rolling back to version 2 on rollback
|
54
|
+
# drop_function(:uppercase_users_name, revert_to_version: 2)
|
54
55
|
#
|
55
56
|
def drop_function(name, revert_to_version: nil)
|
56
57
|
Fx.database.drop_function(name)
|
@@ -93,6 +94,7 @@ module Fx
|
|
93
94
|
)
|
94
95
|
end
|
95
96
|
|
97
|
+
sql_definition = sql_definition.strip_heredoc if sql_definition
|
96
98
|
sql_definition ||= Fx::Definition.new(
|
97
99
|
name: name,
|
98
100
|
version: version,
|
@@ -39,6 +39,7 @@ module Fx
|
|
39
39
|
version = 1
|
40
40
|
end
|
41
41
|
|
42
|
+
sql_definition = sql_definition.strip_heredoc if sql_definition
|
42
43
|
sql_definition ||= Fx::Definition.new(
|
43
44
|
name: name,
|
44
45
|
version: version,
|
@@ -116,6 +117,7 @@ module Fx
|
|
116
117
|
raise ArgumentError, "on is required"
|
117
118
|
end
|
118
119
|
|
120
|
+
sql_definition = sql_definition.strip_heredoc if sql_definition
|
119
121
|
sql_definition ||= Fx::Definition.new(
|
120
122
|
name: name,
|
121
123
|
version: version,
|
data/lib/fx/trigger.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,16 @@ 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
|
+
def migration
|
115
|
+
options[:migration]
|
116
|
+
end
|
104
117
|
end
|
105
118
|
end
|
106
119
|
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,16 @@ 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
|
+
def migration
|
125
|
+
options[:migration]
|
126
|
+
end
|
114
127
|
end
|
115
128
|
end
|
116
129
|
end
|
@@ -3,7 +3,7 @@ require "acceptance_helper"
|
|
3
3
|
describe "User manages functions" do
|
4
4
|
it "handles simple functions" do
|
5
5
|
successfully "rails generate fx:function test"
|
6
|
-
write_function_definition "test_v01",
|
6
|
+
write_function_definition "test_v01", <<-EOS
|
7
7
|
CREATE OR REPLACE FUNCTION test()
|
8
8
|
RETURNS text AS $$
|
9
9
|
BEGIN
|
@@ -21,7 +21,7 @@ describe "User manages functions" do
|
|
21
21
|
"db/functions/test_v01.sql",
|
22
22
|
"db/functions/test_v02.sql",
|
23
23
|
)
|
24
|
-
write_function_definition "test_v02",
|
24
|
+
write_function_definition "test_v02", <<-EOS
|
25
25
|
CREATE OR REPLACE FUNCTION test()
|
26
26
|
RETURNS text AS $$
|
27
27
|
BEGIN
|
@@ -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
|
@@ -4,7 +4,7 @@ describe "User manages triggers" do
|
|
4
4
|
it "handles simple triggers" do
|
5
5
|
successfully "rails generate model user name:string upper_name:string"
|
6
6
|
successfully "rails generate fx:function uppercase_users_name"
|
7
|
-
write_function_definition "uppercase_users_name_v01",
|
7
|
+
write_function_definition "uppercase_users_name_v01", <<-EOS
|
8
8
|
CREATE OR REPLACE FUNCTION uppercase_users_name()
|
9
9
|
RETURNS trigger AS $$
|
10
10
|
BEGIN
|
@@ -14,7 +14,7 @@ describe "User manages triggers" do
|
|
14
14
|
$$ LANGUAGE plpgsql;
|
15
15
|
EOS
|
16
16
|
successfully "rails generate fx:trigger uppercase_users_name table_name:users"
|
17
|
-
write_trigger_definition "uppercase_users_name_v01",
|
17
|
+
write_trigger_definition "uppercase_users_name_v01", <<-EOS
|
18
18
|
CREATE TRIGGER uppercase_users_name
|
19
19
|
BEFORE INSERT ON users
|
20
20
|
FOR EACH ROW
|
@@ -22,24 +22,24 @@ describe "User manages triggers" do
|
|
22
22
|
EOS
|
23
23
|
successfully "rake db:migrate"
|
24
24
|
|
25
|
-
execute
|
25
|
+
execute <<-EOS
|
26
26
|
INSERT INTO users
|
27
27
|
(name, created_at, updated_at)
|
28
28
|
VALUES
|
29
29
|
('Bob', NOW(), NOW());
|
30
|
-
|
30
|
+
EOS
|
31
31
|
result = execute("SELECT upper_name FROM users WHERE name = 'Bob';")
|
32
32
|
expect(result).to eq("upper_name" => "BOB")
|
33
33
|
|
34
34
|
successfully "rails generate fx:trigger uppercase_users_name table_name:users"
|
35
|
-
write_trigger_definition "uppercase_users_name_v02",
|
35
|
+
write_trigger_definition "uppercase_users_name_v02", <<-EOS
|
36
36
|
CREATE TRIGGER uppercase_users_name
|
37
37
|
BEFORE UPDATE ON users
|
38
38
|
FOR EACH ROW
|
39
39
|
EXECUTE PROCEDURE uppercase_users_name();
|
40
40
|
EOS
|
41
41
|
successfully "rake db:migrate"
|
42
|
-
execute
|
42
|
+
execute <<-EOS
|
43
43
|
UPDATE users
|
44
44
|
SET name = 'Alice'
|
45
45
|
WHERE id = 1;
|
data/spec/acceptance_helper.rb
CHANGED
@@ -23,7 +23,8 @@ RSpec.configure do |config|
|
|
23
23
|
Dir.chdir("spec/dummy") do
|
24
24
|
ActiveRecord::Base.connection.disconnect!
|
25
25
|
system <<-CMD
|
26
|
-
|
26
|
+
echo &&
|
27
|
+
rake db:environment:set db:drop db:create &&
|
27
28
|
git add -A &&
|
28
29
|
git reset --hard HEAD 1>/dev/null &&
|
29
30
|
rm -rf .git/ 1>/dev/null
|
data/spec/dummy/Rakefile
CHANGED
@@ -4,3 +4,10 @@
|
|
4
4
|
require File.expand_path('../config/application', __FILE__)
|
5
5
|
|
6
6
|
Rails.application.load_tasks
|
7
|
+
|
8
|
+
unless Rake::Task.task_defined?('db:environment:set')
|
9
|
+
desc 'dummy task for rails versions where this task does not exist'
|
10
|
+
task 'db:environment:set' do
|
11
|
+
# no-op
|
12
|
+
end
|
13
|
+
end
|
@@ -2,7 +2,7 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe "Function migrations", :db do
|
4
4
|
around do |example|
|
5
|
-
sql_definition =
|
5
|
+
sql_definition = <<-EOS
|
6
6
|
CREATE OR REPLACE FUNCTION test()
|
7
7
|
RETURNS text AS $$
|
8
8
|
BEGIN
|
@@ -40,7 +40,7 @@ describe "Function migrations", :db do
|
|
40
40
|
it "can run migrations that updates functions" do
|
41
41
|
connection.create_function(:test)
|
42
42
|
|
43
|
-
sql_definition =
|
43
|
+
sql_definition = <<-EOS
|
44
44
|
CREATE OR REPLACE FUNCTION test()
|
45
45
|
RETURNS text AS $$
|
46
46
|
BEGIN
|
@@ -2,7 +2,7 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe "Reverting migrations", :db do
|
4
4
|
around do |example|
|
5
|
-
sql_definition =
|
5
|
+
sql_definition = <<-EOS
|
6
6
|
CREATE OR REPLACE FUNCTION test()
|
7
7
|
RETURNS text AS $$
|
8
8
|
BEGIN
|
@@ -50,7 +50,7 @@ describe "Reverting migrations", :db do
|
|
50
50
|
it "can run reversible migrations for updating functions" do
|
51
51
|
connection.create_function(:test)
|
52
52
|
|
53
|
-
sql_definition =
|
53
|
+
sql_definition = <<-EOS
|
54
54
|
CREATE OR REPLACE FUNCTION test()
|
55
55
|
RETURNS text AS $$
|
56
56
|
BEGIN
|
@@ -2,14 +2,14 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe "Trigger migrations", :db do
|
4
4
|
around do |example|
|
5
|
-
connection.execute
|
5
|
+
connection.execute <<-EOS
|
6
6
|
CREATE TABLE users (
|
7
7
|
id int PRIMARY KEY,
|
8
8
|
name varchar(256),
|
9
9
|
upper_name varchar(256)
|
10
10
|
);
|
11
11
|
EOS
|
12
|
-
Fx.database.create_function
|
12
|
+
Fx.database.create_function <<-EOS
|
13
13
|
CREATE OR REPLACE FUNCTION uppercase_users_name()
|
14
14
|
RETURNS trigger AS $$
|
15
15
|
BEGIN
|
@@ -18,7 +18,7 @@ describe "Trigger migrations", :db do
|
|
18
18
|
END;
|
19
19
|
$$ LANGUAGE plpgsql;
|
20
20
|
EOS
|
21
|
-
sql_definition =
|
21
|
+
sql_definition = <<-EOS
|
22
22
|
CREATE TRIGGER uppercase_users_name
|
23
23
|
BEFORE INSERT ON users
|
24
24
|
FOR EACH ROW
|
@@ -2,14 +2,14 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe "Reverting migrations", :db do
|
4
4
|
around do |example|
|
5
|
-
connection.execute
|
5
|
+
connection.execute <<-EOS
|
6
6
|
CREATE TABLE users (
|
7
7
|
id int PRIMARY KEY,
|
8
8
|
name varchar(256),
|
9
9
|
upper_name varchar(256)
|
10
10
|
);
|
11
11
|
EOS
|
12
|
-
Fx.database.create_function
|
12
|
+
Fx.database.create_function <<-EOS
|
13
13
|
CREATE OR REPLACE FUNCTION uppercase_users_name()
|
14
14
|
RETURNS trigger AS $$
|
15
15
|
BEGIN
|
@@ -18,7 +18,7 @@ describe "Reverting migrations", :db do
|
|
18
18
|
END;
|
19
19
|
$$ LANGUAGE plpgsql;
|
20
20
|
EOS
|
21
|
-
sql_definition =
|
21
|
+
sql_definition = <<-EOS
|
22
22
|
CREATE TRIGGER uppercase_users_name
|
23
23
|
BEFORE INSERT ON users
|
24
24
|
FOR EACH ROW
|
@@ -67,7 +67,7 @@ describe "Reverting migrations", :db do
|
|
67
67
|
it "can run reversible migrations for updating triggers" do
|
68
68
|
connection.create_trigger(:uppercase_users_name)
|
69
69
|
|
70
|
-
sql_definition =
|
70
|
+
sql_definition = <<-EOS
|
71
71
|
CREATE TRIGGER uppercase_users_name
|
72
72
|
BEFORE UPDATE ON users
|
73
73
|
FOR EACH ROW
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Fx
|
4
|
+
module Adapters
|
5
|
+
describe Postgres::Functions, :db do
|
6
|
+
describe ".all" do
|
7
|
+
it "returns `Function` objects" do
|
8
|
+
connection = ActiveRecord::Base.connection
|
9
|
+
connection.execute <<-EOS.strip_heredoc
|
10
|
+
CREATE OR REPLACE FUNCTION test()
|
11
|
+
RETURNS text AS $$
|
12
|
+
BEGIN
|
13
|
+
RETURN 'test';
|
14
|
+
END;
|
15
|
+
$$ LANGUAGE plpgsql;
|
16
|
+
EOS
|
17
|
+
|
18
|
+
functions = Postgres::Functions.new(connection).all
|
19
|
+
|
20
|
+
first = functions.first
|
21
|
+
expect(functions.size).to eq 1
|
22
|
+
expect(first.name).to eq "test"
|
23
|
+
expect(first.definition).to eq <<-EOS.strip_heredoc
|
24
|
+
CREATE OR REPLACE FUNCTION public.test()
|
25
|
+
RETURNS text
|
26
|
+
LANGUAGE plpgsql
|
27
|
+
AS $function$
|
28
|
+
BEGIN
|
29
|
+
RETURN 'test';
|
30
|
+
END;
|
31
|
+
$function$
|
32
|
+
EOS
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|