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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -7
  3. data/CHANGELOG.md +150 -0
  4. data/CONTRIBUTING.md +3 -3
  5. data/Gemfile +11 -1
  6. data/README.md +2 -0
  7. data/bin/rake +2 -3
  8. data/bin/rspec +13 -3
  9. data/bin/standardrb +27 -0
  10. data/bin/yard +13 -3
  11. data/fx.gemspec +10 -15
  12. data/lib/fx/adapters/postgres/connection.rb +20 -0
  13. data/lib/fx/adapters/postgres/functions.rb +11 -28
  14. data/lib/fx/adapters/postgres/query_executor.rb +34 -0
  15. data/lib/fx/adapters/postgres/triggers.rb +14 -29
  16. data/lib/fx/adapters/postgres.rb +16 -24
  17. data/lib/fx/command_recorder.rb +87 -6
  18. data/lib/fx/configuration.rb +2 -27
  19. data/lib/fx/definition.rb +16 -6
  20. data/lib/fx/function.rb +3 -3
  21. data/lib/fx/schema_dumper.rb +37 -5
  22. data/lib/fx/statements.rb +231 -6
  23. data/lib/fx/trigger.rb +3 -3
  24. data/lib/fx/version.rb +1 -1
  25. data/lib/fx.rb +30 -12
  26. data/lib/generators/fx/function/function_generator.rb +50 -53
  27. data/lib/generators/fx/function/templates/db/migrate/create_function.erb +1 -1
  28. data/lib/generators/fx/function/templates/db/migrate/update_function.erb +1 -1
  29. data/lib/generators/fx/migration_helper.rb +53 -0
  30. data/lib/generators/fx/name_helper.rb +33 -0
  31. data/lib/generators/fx/trigger/templates/db/migrate/create_trigger.erb +1 -1
  32. data/lib/generators/fx/trigger/templates/db/migrate/update_trigger.erb +1 -1
  33. data/lib/generators/fx/trigger/trigger_generator.rb +44 -67
  34. data/lib/generators/fx/version_helper.rb +55 -0
  35. data/spec/acceptance/user_manages_functions_spec.rb +7 -7
  36. data/spec/acceptance/user_manages_triggers_spec.rb +11 -11
  37. data/spec/acceptance_helper.rb +4 -4
  38. data/spec/dummy/config/application.rb +5 -1
  39. data/spec/features/functions/migrations_spec.rb +5 -5
  40. data/spec/features/functions/revert_spec.rb +5 -5
  41. data/spec/features/triggers/migrations_spec.rb +7 -7
  42. data/spec/features/triggers/revert_spec.rb +9 -9
  43. data/spec/fx/adapters/postgres/functions_spec.rb +33 -30
  44. data/spec/fx/adapters/postgres/query_executor_spec.rb +75 -0
  45. data/spec/fx/adapters/postgres/triggers_spec.rb +41 -38
  46. data/spec/fx/adapters/postgres_spec.rb +155 -115
  47. data/spec/fx/command_recorder_spec.rb +27 -25
  48. data/spec/fx/configuration_spec.rb +20 -9
  49. data/spec/fx/definition_spec.rb +31 -39
  50. data/spec/fx/function_spec.rb +45 -48
  51. data/spec/fx/schema_dumper_spec.rb +169 -0
  52. data/spec/fx/statements_spec.rb +217 -0
  53. data/spec/fx/trigger_spec.rb +37 -40
  54. data/spec/fx_spec.rb +28 -0
  55. data/spec/generators/fx/function/function_generator_spec.rb +11 -11
  56. data/spec/generators/fx/migration_helper_spec.rb +133 -0
  57. data/spec/generators/fx/name_helper_spec.rb +114 -0
  58. data/spec/generators/fx/trigger/trigger_generator_spec.rb +45 -22
  59. data/spec/generators/fx/version_helper_spec.rb +157 -0
  60. data/spec/spec_helper.rb +7 -0
  61. data/spec/support/definition_helpers.rb +2 -6
  62. data/spec/support/generator_setup.rb +46 -5
  63. data/spec/support/warning_helper.rb +5 -0
  64. metadata +40 -165
  65. data/lib/fx/command_recorder/arguments.rb +0 -43
  66. data/lib/fx/command_recorder/function.rb +0 -30
  67. data/lib/fx/command_recorder/trigger.rb +0 -30
  68. data/lib/fx/schema_dumper/function.rb +0 -38
  69. data/lib/fx/schema_dumper/trigger.rb +0 -29
  70. data/lib/fx/statements/function.rb +0 -113
  71. data/lib/fx/statements/trigger.rb +0 -144
  72. data/spec/fx/command_recorder/arguments_spec.rb +0 -41
  73. data/spec/fx/schema_dumper/function_spec.rb +0 -78
  74. data/spec/fx/schema_dumper/trigger_spec.rb +0 -40
  75. data/spec/fx/statements/function_spec.rb +0 -103
  76. 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 = <<-EOS
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
- EOS
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 = <<-EOS
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
- EOS
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 = <<-EOS
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
- EOS
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 = <<-EOS
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
- EOS
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 <<-EOS
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
- EOS
12
- Fx.database.create_function <<-EOS
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
- EOS
21
- sql_definition = <<-EOS
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
- EOS
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 <<-EOS
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
- EOS
12
- Fx.database.create_function <<-EOS
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
- EOS
21
- sql_definition = <<-EOS
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
- EOS
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 = <<-EOS
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
- EOS
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
- 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
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
- functions = Postgres::Functions.new(connection).all
16
+ functions = Fx::Adapters::Postgres::Functions.all(connection)
19
17
 
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
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
- module Fx
4
- module Adapters
5
- describe Postgres::Triggers, :db do
6
- describe ".all" do
7
- it "returns `Trigger` objects" do
8
- connection = ActiveRecord::Base.connection
9
- connection.execute <<-EOS.strip_heredoc
10
- CREATE TABLE users (
11
- id int PRIMARY KEY,
12
- name varchar(256),
13
- upper_name varchar(256)
14
- );
15
- EOS
16
- connection.execute <<-EOS.strip_heredoc
17
- CREATE OR REPLACE FUNCTION uppercase_users_name()
18
- RETURNS trigger AS $$
19
- BEGIN
20
- NEW.upper_name = UPPER(NEW.name);
21
- RETURN NEW;
22
- END;
23
- $$ LANGUAGE plpgsql;
24
- EOS
25
- connection.execute <<-EOS.strip_heredoc
26
- CREATE TRIGGER uppercase_users_name
27
- BEFORE INSERT ON users
28
- FOR EACH ROW
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
- triggers = Postgres::Triggers.new(connection).all
30
+ triggers = Fx::Adapters::Postgres::Triggers.all(connection)
33
31
 
34
- first = triggers.first
35
- expect(triggers.size).to eq 1
36
- expect(first.name).to eq "uppercase_users_name"
37
- expect(first.definition).to include("BEFORE INSERT")
38
- expect(first.definition).to match(/ON [public.ser|]/)
39
- expect(first.definition).to include("FOR EACH ROW")
40
- expect(first.definition).to include("EXECUTE FUNCTION uppercase_users_name()")
41
- end
42
- end
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