fx 0.1.0 → 0.11.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/.github/scripts/check-eol +95 -0
- data/.github/workflows/ci.yml +61 -0
- data/.github/workflows/eol-check.yml +30 -0
- data/.rspec +1 -1
- data/.standard.yml +3 -0
- data/CHANGELOG.md +186 -0
- data/CONTRIBUTING.md +13 -4
- data/Gemfile +21 -2
- data/LICENSE +18 -0
- data/README.md +99 -14
- data/Rakefile +11 -1
- data/bin/rake +2 -3
- data/bin/rspec +13 -3
- data/bin/setup +1 -4
- data/bin/standardrb +27 -0
- data/bin/yard +13 -3
- data/fx.gemspec +20 -27
- data/lib/fx/adapters/postgres/connection.rb +6 -0
- data/lib/fx/adapters/postgres/functions.rb +16 -28
- data/lib/fx/adapters/postgres/query_executor.rb +34 -0
- data/lib/fx/adapters/postgres/triggers.rb +14 -28
- data/lib/fx/adapters/postgres.rb +30 -17
- data/lib/fx/command_recorder.rb +104 -13
- data/lib/fx/configuration.rb +10 -25
- data/lib/fx/definition.rb +32 -10
- data/lib/fx/function.rb +23 -9
- data/lib/fx/railtie.rb +15 -0
- data/lib/fx/schema_dumper.rb +33 -10
- data/lib/fx/statements.rb +213 -11
- data/lib/fx/trigger.rb +5 -3
- data/lib/fx/version.rb +1 -1
- data/lib/fx.rb +40 -0
- data/lib/generators/fx/function/USAGE +2 -0
- data/lib/generators/fx/function/function_generator.rb +54 -39
- 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 +45 -0
- data/lib/generators/fx/name_helper.rb +33 -0
- data/lib/generators/fx/trigger/USAGE +2 -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 +46 -51
- data/lib/generators/fx/version_helper.rb +55 -0
- data/spec/acceptance/user_manages_functions_spec.rb +26 -6
- data/spec/acceptance/user_manages_triggers_spec.rb +11 -11
- data/spec/acceptance_helper.rb +17 -11
- data/spec/dummy/Rakefile +8 -1
- 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 +2 -0
- data/spec/dummy/config/database.yml +2 -0
- data/spec/dummy/config.ru +1 -1
- data/spec/features/functions/migrations_spec.rb +9 -9
- data/spec/features/functions/revert_spec.rb +13 -13
- data/spec/features/triggers/migrations_spec.rb +11 -11
- data/spec/features/triggers/revert_spec.rb +21 -21
- data/spec/fx/adapters/postgres/functions_spec.rb +40 -0
- data/spec/fx/adapters/postgres/query_executor_spec.rb +75 -0
- data/spec/fx/adapters/postgres/triggers_spec.rb +48 -0
- data/spec/fx/adapters/postgres_spec.rb +115 -111
- data/spec/fx/command_recorder_spec.rb +39 -53
- data/spec/fx/configuration_spec.rb +20 -9
- data/spec/fx/definition_spec.rb +53 -38
- data/spec/fx/function_spec.rb +143 -0
- data/spec/fx/schema_dumper_spec.rb +241 -0
- data/spec/fx/statements_spec.rb +219 -0
- data/spec/fx/trigger_spec.rb +52 -0
- data/spec/fx_spec.rb +28 -0
- data/spec/generators/fx/function/function_generator_spec.rb +22 -10
- data/spec/generators/fx/migration_helper_spec.rb +108 -0
- data/spec/generators/fx/name_helper_spec.rb +114 -0
- data/spec/generators/fx/trigger/trigger_generator_spec.rb +55 -20
- data/spec/generators/fx/version_helper_spec.rb +157 -0
- data/spec/spec_helper.rb +16 -4
- data/spec/support/database_reset.rb +24 -0
- data/spec/support/definition_helpers.rb +5 -9
- data/spec/support/generator_setup.rb +46 -5
- data/spec/support/migration_helpers.rb +9 -1
- data/spec/support/warning_helper.rb +5 -0
- metadata +43 -215
- data/.ruby-version +0 -1
- data/.travis.yml +0 -27
- data/Appraisals +0 -21
- data/bin/appraisal +0 -17
- 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 +0 -8
- data/gemfiles/rails42.gemfile.lock +0 -130
- data/gemfiles/rails50.gemfile +0 -8
- data/gemfiles/rails50.gemfile.lock +0 -126
- 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 -29
- data/lib/fx/schema_dumper/trigger.rb +0 -29
- data/lib/fx/statements/function.rb +0 -105
- data/lib/fx/statements/trigger.rb +0 -133
- data/spec/fx/command_recorder/arguments_spec.rb +0 -41
- data/spec/fx/schema_dumper/function_spec.rb +0 -22
- 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 "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,23 +17,23 @@ 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
|
-
EXECUTE
|
|
26
|
-
|
|
25
|
+
EXECUTE FUNCTION uppercase_users_name();
|
|
26
|
+
SQL
|
|
27
27
|
with_trigger_definition(
|
|
28
28
|
name: :uppercase_users_name,
|
|
29
|
-
sql_definition: sql_definition
|
|
29
|
+
sql_definition: sql_definition
|
|
30
30
|
) do
|
|
31
31
|
example.run
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
it "can run reversible migrations for creating triggers" do
|
|
36
|
-
migration = Class.new(
|
|
36
|
+
migration = Class.new(migration_class) do
|
|
37
37
|
def change
|
|
38
38
|
create_trigger :uppercase_users_name, on: :users
|
|
39
39
|
end
|
|
@@ -45,46 +45,46 @@ describe "Reverting migrations", :db do
|
|
|
45
45
|
it "can run reversible migrations for dropping triggers" do
|
|
46
46
|
connection.create_trigger(:uppercase_users_name, on: :users)
|
|
47
47
|
|
|
48
|
-
good_migration = Class.new(
|
|
48
|
+
good_migration = Class.new(migration_class) do
|
|
49
49
|
def change
|
|
50
50
|
drop_trigger :uppercase_users_name, on: :users, revert_to_version: 1
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
|
-
bad_migration = Class.new(
|
|
53
|
+
bad_migration = Class.new(migration_class) do
|
|
54
54
|
def change
|
|
55
55
|
drop_trigger :uppercase_users_name, on: :users
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
expect { run_migration(good_migration, [:up, :down]) }.not_to raise_error
|
|
60
|
-
expect { run_migration(bad_migration, [:up, :down]) }
|
|
61
|
-
to raise_error(
|
|
60
|
+
expect { run_migration(bad_migration, [:up, :down]) }
|
|
61
|
+
.to raise_error(
|
|
62
62
|
ActiveRecord::IrreversibleMigration,
|
|
63
|
-
/`create_trigger` is reversible only if given a `revert_to_version
|
|
63
|
+
/`create_trigger` is reversible only if given a `revert_to_version`/
|
|
64
64
|
)
|
|
65
65
|
end
|
|
66
66
|
|
|
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
|
-
EXECUTE
|
|
75
|
-
|
|
74
|
+
EXECUTE FUNCTION uppercase_users_name();
|
|
75
|
+
SQL
|
|
76
76
|
with_trigger_definition(
|
|
77
77
|
name: :uppercase_users_name,
|
|
78
78
|
sql_definition: sql_definition,
|
|
79
|
-
version: 2
|
|
79
|
+
version: 2
|
|
80
80
|
) do
|
|
81
|
-
migration = Class.new(
|
|
81
|
+
migration = Class.new(migration_class) do
|
|
82
82
|
def change
|
|
83
83
|
update_trigger(
|
|
84
84
|
:uppercase_users_name,
|
|
85
85
|
on: :users,
|
|
86
86
|
version: 2,
|
|
87
|
-
revert_to_version: 1
|
|
87
|
+
revert_to_version: 1
|
|
88
88
|
)
|
|
89
89
|
end
|
|
90
90
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
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
|
|
15
|
+
|
|
16
|
+
functions = Fx::Adapters::Postgres::Functions.all(connection)
|
|
17
|
+
|
|
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
|
|
38
|
+
end
|
|
39
|
+
end
|
|
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
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
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
|
|
29
|
+
|
|
30
|
+
triggers = Fx::Adapters::Postgres::Triggers.all(connection)
|
|
31
|
+
|
|
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
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -1,149 +1,153 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
describe
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
RETURNS text AS $$
|
|
12
|
-
BEGIN
|
|
13
|
-
RETURN 'test';
|
|
14
|
-
END;
|
|
15
|
-
$$ LANGUAGE plpgsql;
|
|
16
|
-
EOS
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
expect(adapter.functions.map(&:name)).to include("test")
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
describe "#create_trigger" do
|
|
24
|
-
it "successfully creates a trigger" do
|
|
25
|
-
connection.execute <<~EOS
|
|
26
|
-
CREATE TABLE users (
|
|
27
|
-
id int PRIMARY KEY,
|
|
28
|
-
name varchar(256),
|
|
29
|
-
upper_name varchar(256)
|
|
30
|
-
);
|
|
31
|
-
EOS
|
|
32
|
-
adapter = Postgres.new
|
|
33
|
-
adapter.create_function <<~EOS
|
|
34
|
-
CREATE OR REPLACE FUNCTION uppercase_users_name()
|
|
35
|
-
RETURNS trigger AS $$
|
|
3
|
+
RSpec.describe Fx::Adapters::Postgres, :db do
|
|
4
|
+
describe "#create_function" do
|
|
5
|
+
it "successfully creates a function" do
|
|
6
|
+
adapter = Fx::Adapters::Postgres.new
|
|
7
|
+
adapter.create_function(
|
|
8
|
+
<<~SQL
|
|
9
|
+
CREATE OR REPLACE FUNCTION test()
|
|
10
|
+
RETURNS text AS $$
|
|
36
11
|
BEGIN
|
|
37
|
-
|
|
38
|
-
RETURN NEW;
|
|
12
|
+
RETURN 'test';
|
|
39
13
|
END;
|
|
40
14
|
$$ LANGUAGE plpgsql;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<<~EOS
|
|
44
|
-
CREATE TRIGGER uppercase_users_name
|
|
45
|
-
BEFORE INSERT ON users
|
|
46
|
-
FOR EACH ROW
|
|
47
|
-
EXECUTE PROCEDURE uppercase_users_name();
|
|
48
|
-
EOS
|
|
49
|
-
)
|
|
15
|
+
SQL
|
|
16
|
+
)
|
|
50
17
|
|
|
51
|
-
|
|
52
|
-
end
|
|
18
|
+
expect(adapter.functions.map(&:name)).to include("test")
|
|
53
19
|
end
|
|
20
|
+
end
|
|
54
21
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
22
|
+
describe "#create_trigger" do
|
|
23
|
+
it "successfully creates a trigger" do
|
|
24
|
+
connection.execute <<~SQL
|
|
25
|
+
CREATE TABLE users (
|
|
26
|
+
id int PRIMARY KEY,
|
|
27
|
+
name varchar(256),
|
|
28
|
+
upper_name varchar(256)
|
|
29
|
+
);
|
|
30
|
+
SQL
|
|
31
|
+
adapter = Fx::Adapters::Postgres.new
|
|
32
|
+
adapter.create_function <<~SQL
|
|
33
|
+
CREATE OR REPLACE FUNCTION uppercase_users_name()
|
|
34
|
+
RETURNS trigger AS $$
|
|
35
|
+
BEGIN
|
|
36
|
+
NEW.upper_name = UPPER(NEW.name);
|
|
37
|
+
RETURN NEW;
|
|
38
|
+
END;
|
|
39
|
+
$$ LANGUAGE plpgsql;
|
|
40
|
+
SQL
|
|
41
|
+
adapter.create_trigger(
|
|
42
|
+
<<~SQL
|
|
43
|
+
CREATE TRIGGER uppercase_users_name
|
|
44
|
+
BEFORE INSERT ON users
|
|
45
|
+
FOR EACH ROW
|
|
46
|
+
EXECUTE FUNCTION uppercase_users_name();
|
|
47
|
+
SQL
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
expect(adapter.triggers.map(&:name)).to include("uppercase_users_name")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe "#drop_function" do
|
|
55
|
+
context "when the function has arguments" do
|
|
56
|
+
it "successfully drops a function with the entire function signature" do
|
|
57
|
+
adapter = Fx::Adapters::Postgres.new
|
|
58
58
|
adapter.create_function(
|
|
59
|
-
<<~
|
|
60
|
-
CREATE
|
|
61
|
-
RETURNS
|
|
59
|
+
<<~SQL
|
|
60
|
+
CREATE FUNCTION adder(x int, y int)
|
|
61
|
+
RETURNS int AS $$
|
|
62
62
|
BEGIN
|
|
63
|
-
RETURN
|
|
63
|
+
RETURN $1 + $2;
|
|
64
64
|
END;
|
|
65
65
|
$$ LANGUAGE plpgsql;
|
|
66
|
-
|
|
66
|
+
SQL
|
|
67
67
|
)
|
|
68
68
|
|
|
69
|
-
adapter.drop_function(:
|
|
69
|
+
adapter.drop_function(:adder)
|
|
70
70
|
|
|
71
|
-
expect(adapter.functions.map(&:name)).not_to include("
|
|
71
|
+
expect(adapter.functions.map(&:name)).not_to include("adder")
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
it "
|
|
77
|
-
adapter = Postgres.new
|
|
75
|
+
context "when the function does not have arguments" do
|
|
76
|
+
it "successfully drops a function" do
|
|
77
|
+
adapter = Fx::Adapters::Postgres.new
|
|
78
78
|
adapter.create_function(
|
|
79
|
-
<<~
|
|
79
|
+
<<~SQL
|
|
80
80
|
CREATE OR REPLACE FUNCTION test()
|
|
81
81
|
RETURNS text AS $$
|
|
82
82
|
BEGIN
|
|
83
83
|
RETURN 'test';
|
|
84
84
|
END;
|
|
85
85
|
$$ LANGUAGE plpgsql;
|
|
86
|
-
|
|
86
|
+
SQL
|
|
87
87
|
)
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
"definition" => <<~EOS
|
|
93
|
-
CREATE OR REPLACE FUNCTION public.test()
|
|
94
|
-
RETURNS text
|
|
95
|
-
LANGUAGE plpgsql
|
|
96
|
-
AS $function$
|
|
97
|
-
BEGIN
|
|
98
|
-
RETURN 'test';
|
|
99
|
-
END;
|
|
100
|
-
$function$
|
|
101
|
-
EOS
|
|
102
|
-
),
|
|
103
|
-
])
|
|
89
|
+
adapter.drop_function(:test)
|
|
90
|
+
|
|
91
|
+
expect(adapter.functions.map(&:name)).not_to include("test")
|
|
104
92
|
end
|
|
105
93
|
end
|
|
94
|
+
end
|
|
106
95
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
);
|
|
115
|
-
EOS
|
|
116
|
-
adapter = Postgres.new
|
|
117
|
-
adapter.create_function <<~EOS
|
|
118
|
-
CREATE OR REPLACE FUNCTION uppercase_users_name()
|
|
119
|
-
RETURNS trigger AS $$
|
|
96
|
+
describe "#functions" do
|
|
97
|
+
it "finds functions and builds Fx::Function objects" do
|
|
98
|
+
adapter = Fx::Adapters::Postgres.new
|
|
99
|
+
adapter.create_function(
|
|
100
|
+
<<~SQL
|
|
101
|
+
CREATE OR REPLACE FUNCTION test()
|
|
102
|
+
RETURNS text AS $$
|
|
120
103
|
BEGIN
|
|
121
|
-
|
|
122
|
-
RETURN NEW;
|
|
104
|
+
RETURN 'test';
|
|
123
105
|
END;
|
|
124
106
|
$$ LANGUAGE plpgsql;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
FOR EACH ROW
|
|
130
|
-
EXECUTE PROCEDURE uppercase_users_name()
|
|
131
|
-
EOS
|
|
132
|
-
adapter.create_trigger(sql_definition)
|
|
133
|
-
|
|
134
|
-
expect(adapter.triggers).to eq(
|
|
135
|
-
[
|
|
136
|
-
Fx::Trigger.new(
|
|
137
|
-
"name" => "uppercase_users_name",
|
|
138
|
-
"definition" => format_trigger(sql_definition),
|
|
139
|
-
),
|
|
140
|
-
],
|
|
141
|
-
)
|
|
142
|
-
end
|
|
107
|
+
SQL
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
expect(adapter.functions.map(&:name)).to eq ["test"]
|
|
143
111
|
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe "#triggers" do
|
|
115
|
+
it "finds triggers and builds Fx::Trigger objects" do
|
|
116
|
+
connection.execute <<~SQL
|
|
117
|
+
CREATE TABLE users (
|
|
118
|
+
id int PRIMARY KEY,
|
|
119
|
+
name varchar(256),
|
|
120
|
+
upper_name varchar(256)
|
|
121
|
+
);
|
|
122
|
+
SQL
|
|
123
|
+
adapter = Fx::Adapters::Postgres.new
|
|
124
|
+
adapter.create_function <<~SQL
|
|
125
|
+
CREATE OR REPLACE FUNCTION uppercase_users_name()
|
|
126
|
+
RETURNS trigger AS $$
|
|
127
|
+
BEGIN
|
|
128
|
+
NEW.upper_name = UPPER(NEW.name);
|
|
129
|
+
RETURN NEW;
|
|
130
|
+
END;
|
|
131
|
+
$$ LANGUAGE plpgsql;
|
|
132
|
+
SQL
|
|
133
|
+
sql_definition = <<~SQL
|
|
134
|
+
CREATE TRIGGER uppercase_users_name
|
|
135
|
+
BEFORE INSERT ON users
|
|
136
|
+
FOR EACH ROW
|
|
137
|
+
EXECUTE FUNCTION uppercase_users_name()
|
|
138
|
+
SQL
|
|
139
|
+
adapter.create_trigger(sql_definition)
|
|
140
|
+
|
|
141
|
+
expect(adapter.triggers.map(&:name)).to eq ["uppercase_users_name"]
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
describe "#support_drop_function_without_args" do
|
|
146
|
+
it "returns true for all supported PostgreSQL versions" do
|
|
147
|
+
adapter = Fx::Adapters::Postgres.new
|
|
148
|
+
connection = adapter.send(:connection)
|
|
144
149
|
|
|
145
|
-
|
|
146
|
-
trigger.gsub("\n", "").gsub(" ", " ")
|
|
150
|
+
expect(connection.support_drop_function_without_args).to be(true)
|
|
147
151
|
end
|
|
148
152
|
end
|
|
149
153
|
end
|