fx 0.8.0 → 0.10.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 +2 -7
- data/CHANGELOG.md +150 -0
- data/CONTRIBUTING.md +3 -3
- data/Gemfile +11 -1
- data/README.md +2 -0
- data/bin/rake +2 -3
- data/bin/rspec +13 -3
- data/bin/standardrb +27 -0
- data/bin/yard +13 -3
- data/fx.gemspec +10 -15
- data/lib/fx/adapters/postgres/connection.rb +20 -0
- data/lib/fx/adapters/postgres/functions.rb +11 -28
- data/lib/fx/adapters/postgres/query_executor.rb +34 -0
- data/lib/fx/adapters/postgres/triggers.rb +14 -29
- data/lib/fx/adapters/postgres.rb +16 -24
- data/lib/fx/command_recorder.rb +87 -6
- data/lib/fx/configuration.rb +2 -27
- data/lib/fx/definition.rb +16 -6
- data/lib/fx/function.rb +3 -3
- data/lib/fx/schema_dumper.rb +37 -5
- data/lib/fx/statements.rb +231 -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 +50 -53
- data/lib/generators/fx/function/templates/db/migrate/create_function.erb +1 -1
- data/lib/generators/fx/function/templates/db/migrate/update_function.erb +1 -1
- data/lib/generators/fx/migration_helper.rb +53 -0
- data/lib/generators/fx/name_helper.rb +33 -0
- data/lib/generators/fx/trigger/templates/db/migrate/create_trigger.erb +1 -1
- data/lib/generators/fx/trigger/templates/db/migrate/update_trigger.erb +1 -1
- data/lib/generators/fx/trigger/trigger_generator.rb +44 -67
- data/lib/generators/fx/version_helper.rb +55 -0
- data/spec/acceptance/user_manages_functions_spec.rb +7 -7
- data/spec/acceptance/user_manages_triggers_spec.rb +11 -11
- data/spec/acceptance_helper.rb +4 -4
- data/spec/dummy/config/application.rb +5 -1
- data/spec/features/functions/migrations_spec.rb +5 -5
- data/spec/features/functions/revert_spec.rb +5 -5
- data/spec/features/triggers/migrations_spec.rb +7 -7
- data/spec/features/triggers/revert_spec.rb +9 -9
- data/spec/fx/adapters/postgres/functions_spec.rb +33 -30
- data/spec/fx/adapters/postgres/query_executor_spec.rb +75 -0
- data/spec/fx/adapters/postgres/triggers_spec.rb +41 -38
- data/spec/fx/adapters/postgres_spec.rb +155 -115
- data/spec/fx/command_recorder_spec.rb +27 -25
- data/spec/fx/configuration_spec.rb +20 -9
- data/spec/fx/definition_spec.rb +31 -39
- data/spec/fx/function_spec.rb +45 -48
- data/spec/fx/schema_dumper_spec.rb +169 -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 +11 -11
- data/spec/generators/fx/migration_helper_spec.rb +133 -0
- data/spec/generators/fx/name_helper_spec.rb +114 -0
- data/spec/generators/fx/trigger/trigger_generator_spec.rb +45 -22
- data/spec/generators/fx/version_helper_spec.rb +157 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/support/definition_helpers.rb +2 -6
- data/spec/support/generator_setup.rb +46 -5
- data/spec/support/warning_helper.rb +5 -0
- metadata +40 -165
- 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 -113
- data/lib/fx/statements/trigger.rb +0 -144
- data/spec/fx/command_recorder/arguments_spec.rb +0 -41
- data/spec/fx/schema_dumper/function_spec.rb +0 -78
- 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,15 +1,15 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
describe "Function migrations", :db do
|
|
3
|
+
RSpec.describe "Function migrations", :db do
|
|
4
4
|
around do |example|
|
|
5
|
-
sql_definition =
|
|
5
|
+
sql_definition = <<~SQL
|
|
6
6
|
CREATE OR REPLACE FUNCTION test()
|
|
7
7
|
RETURNS text AS $$
|
|
8
8
|
BEGIN
|
|
9
9
|
RETURN 'test';
|
|
10
10
|
END;
|
|
11
11
|
$$ LANGUAGE plpgsql;
|
|
12
|
-
|
|
12
|
+
SQL
|
|
13
13
|
with_function_definition(name: :test, sql_definition: sql_definition) do
|
|
14
14
|
example.run
|
|
15
15
|
end
|
|
@@ -40,14 +40,14 @@ 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 = <<~SQL
|
|
44
44
|
CREATE OR REPLACE FUNCTION test()
|
|
45
45
|
RETURNS text AS $$
|
|
46
46
|
BEGIN
|
|
47
47
|
RETURN 'testest';
|
|
48
48
|
END;
|
|
49
49
|
$$ LANGUAGE plpgsql;
|
|
50
|
-
|
|
50
|
+
SQL
|
|
51
51
|
with_function_definition(
|
|
52
52
|
name: :test,
|
|
53
53
|
version: 2,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
describe "Reverting migrations", :db do
|
|
3
|
+
RSpec.describe "Reverting migrations", :db do
|
|
4
4
|
around do |example|
|
|
5
|
-
sql_definition =
|
|
5
|
+
sql_definition = <<~SQL
|
|
6
6
|
CREATE OR REPLACE FUNCTION test()
|
|
7
7
|
RETURNS text AS $$
|
|
8
8
|
BEGIN
|
|
9
9
|
RETURN 'test';
|
|
10
10
|
END;
|
|
11
11
|
$$ LANGUAGE plpgsql;
|
|
12
|
-
|
|
12
|
+
SQL
|
|
13
13
|
with_function_definition(name: :test, sql_definition: sql_definition) do
|
|
14
14
|
example.run
|
|
15
15
|
end
|
|
@@ -50,14 +50,14 @@ 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 = <<~SQL
|
|
54
54
|
CREATE OR REPLACE FUNCTION test()
|
|
55
55
|
RETURNS text AS $$
|
|
56
56
|
BEGIN
|
|
57
57
|
RETURN 'bar';
|
|
58
58
|
END;
|
|
59
59
|
$$ LANGUAGE plpgsql;
|
|
60
|
-
|
|
60
|
+
SQL
|
|
61
61
|
with_function_definition(
|
|
62
62
|
name: :test,
|
|
63
63
|
version: 2,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
describe "Trigger migrations", :db do
|
|
3
|
+
RSpec.describe "Trigger migrations", :db do
|
|
4
4
|
around do |example|
|
|
5
|
-
connection.execute
|
|
5
|
+
connection.execute <<~SQL
|
|
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
|
-
|
|
12
|
-
Fx.database.create_function
|
|
11
|
+
SQL
|
|
12
|
+
Fx.database.create_function <<~SQL
|
|
13
13
|
CREATE OR REPLACE FUNCTION uppercase_users_name()
|
|
14
14
|
RETURNS trigger AS $$
|
|
15
15
|
BEGIN
|
|
@@ -17,13 +17,13 @@ describe "Trigger migrations", :db do
|
|
|
17
17
|
RETURN NEW;
|
|
18
18
|
END;
|
|
19
19
|
$$ LANGUAGE plpgsql;
|
|
20
|
-
|
|
21
|
-
sql_definition =
|
|
20
|
+
SQL
|
|
21
|
+
sql_definition = <<~SQL
|
|
22
22
|
CREATE TRIGGER uppercase_users_name
|
|
23
23
|
BEFORE INSERT ON users
|
|
24
24
|
FOR EACH ROW
|
|
25
25
|
EXECUTE FUNCTION uppercase_users_name();
|
|
26
|
-
|
|
26
|
+
SQL
|
|
27
27
|
with_trigger_definition(
|
|
28
28
|
name: :uppercase_users_name,
|
|
29
29
|
sql_definition: sql_definition
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
describe "Reverting migrations", :db do
|
|
3
|
+
RSpec.describe "Reverting migrations", :db do
|
|
4
4
|
around do |example|
|
|
5
|
-
connection.execute
|
|
5
|
+
connection.execute <<~SQL
|
|
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
|
-
|
|
12
|
-
Fx.database.create_function
|
|
11
|
+
SQL
|
|
12
|
+
Fx.database.create_function <<~SQL
|
|
13
13
|
CREATE OR REPLACE FUNCTION uppercase_users_name()
|
|
14
14
|
RETURNS trigger AS $$
|
|
15
15
|
BEGIN
|
|
@@ -17,13 +17,13 @@ describe "Reverting migrations", :db do
|
|
|
17
17
|
RETURN NEW;
|
|
18
18
|
END;
|
|
19
19
|
$$ LANGUAGE plpgsql;
|
|
20
|
-
|
|
21
|
-
sql_definition =
|
|
20
|
+
SQL
|
|
21
|
+
sql_definition = <<~SQL
|
|
22
22
|
CREATE TRIGGER uppercase_users_name
|
|
23
23
|
BEFORE INSERT ON users
|
|
24
24
|
FOR EACH ROW
|
|
25
25
|
EXECUTE FUNCTION uppercase_users_name();
|
|
26
|
-
|
|
26
|
+
SQL
|
|
27
27
|
with_trigger_definition(
|
|
28
28
|
name: :uppercase_users_name,
|
|
29
29
|
sql_definition: sql_definition
|
|
@@ -67,12 +67,12 @@ 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 = <<~SQL
|
|
71
71
|
CREATE TRIGGER uppercase_users_name
|
|
72
72
|
BEFORE UPDATE ON users
|
|
73
73
|
FOR EACH ROW
|
|
74
74
|
EXECUTE FUNCTION uppercase_users_name();
|
|
75
|
-
|
|
75
|
+
SQL
|
|
76
76
|
with_trigger_definition(
|
|
77
77
|
name: :uppercase_users_name,
|
|
78
78
|
sql_definition: sql_definition,
|
|
@@ -1,37 +1,40 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
$$ LANGUAGE plpgsql;
|
|
16
|
-
EOS
|
|
3
|
+
RSpec.describe Fx::Adapters::Postgres::Functions, :db do
|
|
4
|
+
describe ".all" do
|
|
5
|
+
it "returns `Function` objects" do
|
|
6
|
+
connection = ActiveRecord::Base.connection
|
|
7
|
+
connection.execute <<~SQL
|
|
8
|
+
CREATE OR REPLACE FUNCTION test()
|
|
9
|
+
RETURNS text AS $$
|
|
10
|
+
BEGIN
|
|
11
|
+
RETURN 'test';
|
|
12
|
+
END;
|
|
13
|
+
$$ LANGUAGE plpgsql;
|
|
14
|
+
SQL
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
functions = Fx::Adapters::Postgres::Functions.all(connection)
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
18
|
+
first = functions.first
|
|
19
|
+
expect(functions.size).to eq(1)
|
|
20
|
+
expect(first.name).to eq("test")
|
|
21
|
+
expect(first.definition).to eq(<<~SQL)
|
|
22
|
+
CREATE OR REPLACE FUNCTION public.test()
|
|
23
|
+
RETURNS text
|
|
24
|
+
LANGUAGE plpgsql
|
|
25
|
+
AS $function$
|
|
26
|
+
BEGIN
|
|
27
|
+
RETURN 'test';
|
|
28
|
+
END;
|
|
29
|
+
$function$
|
|
30
|
+
SQL
|
|
31
|
+
|
|
32
|
+
connection.execute "CREATE SCHEMA IF NOT EXISTS other;"
|
|
33
|
+
connection.execute "SET search_path = 'other';"
|
|
34
|
+
|
|
35
|
+
functions = Fx::Adapters::Postgres::Functions.all(connection)
|
|
36
|
+
|
|
37
|
+
expect(functions).to be_empty
|
|
35
38
|
end
|
|
36
39
|
end
|
|
37
40
|
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe Fx::Adapters::Postgres::QueryExecutor, :db do
|
|
4
|
+
it "executes the query and maps results to objects" do
|
|
5
|
+
connection = ActiveRecord::Base.connection
|
|
6
|
+
query = "SELECT 'Hello World' as message, 'english' as language"
|
|
7
|
+
greeter = Class.new do
|
|
8
|
+
attr_reader :message, :language
|
|
9
|
+
|
|
10
|
+
def initialize(row)
|
|
11
|
+
@message = row.fetch("message")
|
|
12
|
+
@language = row.fetch("language")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
results = described_class.call(
|
|
17
|
+
connection: connection,
|
|
18
|
+
query: query,
|
|
19
|
+
model_class: greeter
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
expect(results.size).to eq(1)
|
|
23
|
+
expect(results.first).to be_a(greeter)
|
|
24
|
+
expect(results.first.message).to eq("Hello World")
|
|
25
|
+
expect(results.first.language).to eq("english")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "executes query with multiple results" do
|
|
29
|
+
connection = ActiveRecord::Base.connection
|
|
30
|
+
query = <<~SQL
|
|
31
|
+
SELECT 'first' as name
|
|
32
|
+
UNION ALL
|
|
33
|
+
SELECT 'second' as name
|
|
34
|
+
ORDER BY name
|
|
35
|
+
SQL
|
|
36
|
+
simple_name = Class.new do
|
|
37
|
+
attr_reader :name
|
|
38
|
+
|
|
39
|
+
def initialize(row)
|
|
40
|
+
@name = row.fetch("name")
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
results = described_class.call(
|
|
45
|
+
connection: connection,
|
|
46
|
+
query: query,
|
|
47
|
+
model_class: simple_name
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
expect(results.size).to eq(2)
|
|
51
|
+
expect(results).to all(be_a(simple_name))
|
|
52
|
+
expect(results.first.name).to eq("first")
|
|
53
|
+
expect(results.last.name).to eq("second")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "returns an empty array when query returns no results" do
|
|
57
|
+
connection = ActiveRecord::Base.connection
|
|
58
|
+
query = "SELECT 'test' as name WHERE 1 = 0"
|
|
59
|
+
simple_name = Class.new do
|
|
60
|
+
attr_reader :name
|
|
61
|
+
|
|
62
|
+
def initialize(row)
|
|
63
|
+
@name = row.fetch("name")
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
results = described_class.call(
|
|
68
|
+
connection: connection,
|
|
69
|
+
query: query,
|
|
70
|
+
model_class: simple_name
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
expect(results).to eq([])
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -1,45 +1,48 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
EXECUTE FUNCTION uppercase_users_name();
|
|
30
|
-
EOS
|
|
3
|
+
RSpec.describe Fx::Adapters::Postgres::Triggers, :db do
|
|
4
|
+
describe ".all" do
|
|
5
|
+
it "returns `Trigger` objects" do
|
|
6
|
+
connection = ActiveRecord::Base.connection
|
|
7
|
+
connection.execute <<~SQL
|
|
8
|
+
CREATE TABLE users (
|
|
9
|
+
id int PRIMARY KEY,
|
|
10
|
+
name varchar(256),
|
|
11
|
+
upper_name varchar(256)
|
|
12
|
+
);
|
|
13
|
+
SQL
|
|
14
|
+
connection.execute <<~SQL
|
|
15
|
+
CREATE OR REPLACE FUNCTION uppercase_users_name()
|
|
16
|
+
RETURNS trigger AS $$
|
|
17
|
+
BEGIN
|
|
18
|
+
NEW.upper_name = UPPER(NEW.name);
|
|
19
|
+
RETURN NEW;
|
|
20
|
+
END;
|
|
21
|
+
$$ LANGUAGE plpgsql;
|
|
22
|
+
SQL
|
|
23
|
+
connection.execute <<~SQL
|
|
24
|
+
CREATE TRIGGER uppercase_users_name
|
|
25
|
+
BEFORE INSERT ON users
|
|
26
|
+
FOR EACH ROW
|
|
27
|
+
EXECUTE FUNCTION uppercase_users_name();
|
|
28
|
+
SQL
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
triggers = Fx::Adapters::Postgres::Triggers.all(connection)
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
32
|
+
first = triggers.first
|
|
33
|
+
expect(triggers.size).to eq(1)
|
|
34
|
+
expect(first.name).to eq("uppercase_users_name")
|
|
35
|
+
expect(first.definition).to include("BEFORE INSERT")
|
|
36
|
+
expect(first.definition).to match(/ON [public.ser|]/)
|
|
37
|
+
expect(first.definition).to include("FOR EACH ROW")
|
|
38
|
+
expect(first.definition).to include("EXECUTE FUNCTION uppercase_users_name()")
|
|
39
|
+
|
|
40
|
+
connection.execute "CREATE SCHEMA IF NOT EXISTS other;"
|
|
41
|
+
connection.execute "SET search_path = 'other';"
|
|
42
|
+
|
|
43
|
+
triggers = Fx::Adapters::Postgres::Triggers.all(connection)
|
|
44
|
+
|
|
45
|
+
expect(triggers).to be_empty
|
|
43
46
|
end
|
|
44
47
|
end
|
|
45
48
|
end
|