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.
Files changed (106) hide show
  1. checksums.yaml +5 -5
  2. data/.github/scripts/check-eol +95 -0
  3. data/.github/workflows/ci.yml +61 -0
  4. data/.github/workflows/eol-check.yml +30 -0
  5. data/.rspec +1 -1
  6. data/.standard.yml +3 -0
  7. data/CHANGELOG.md +186 -0
  8. data/CONTRIBUTING.md +13 -4
  9. data/Gemfile +21 -2
  10. data/LICENSE +18 -0
  11. data/README.md +99 -14
  12. data/Rakefile +11 -1
  13. data/bin/rake +2 -3
  14. data/bin/rspec +13 -3
  15. data/bin/setup +1 -4
  16. data/bin/standardrb +27 -0
  17. data/bin/yard +13 -3
  18. data/fx.gemspec +20 -27
  19. data/lib/fx/adapters/postgres/connection.rb +6 -0
  20. data/lib/fx/adapters/postgres/functions.rb +16 -28
  21. data/lib/fx/adapters/postgres/query_executor.rb +34 -0
  22. data/lib/fx/adapters/postgres/triggers.rb +14 -28
  23. data/lib/fx/adapters/postgres.rb +30 -17
  24. data/lib/fx/command_recorder.rb +104 -13
  25. data/lib/fx/configuration.rb +10 -25
  26. data/lib/fx/definition.rb +32 -10
  27. data/lib/fx/function.rb +23 -9
  28. data/lib/fx/railtie.rb +15 -0
  29. data/lib/fx/schema_dumper.rb +33 -10
  30. data/lib/fx/statements.rb +213 -11
  31. data/lib/fx/trigger.rb +5 -3
  32. data/lib/fx/version.rb +1 -1
  33. data/lib/fx.rb +40 -0
  34. data/lib/generators/fx/function/USAGE +2 -0
  35. data/lib/generators/fx/function/function_generator.rb +54 -39
  36. data/lib/generators/fx/function/templates/db/migrate/create_function.erb +1 -1
  37. data/lib/generators/fx/function/templates/db/migrate/update_function.erb +1 -1
  38. data/lib/generators/fx/migration_helper.rb +45 -0
  39. data/lib/generators/fx/name_helper.rb +33 -0
  40. data/lib/generators/fx/trigger/USAGE +2 -0
  41. data/lib/generators/fx/trigger/templates/db/migrate/create_trigger.erb +1 -1
  42. data/lib/generators/fx/trigger/templates/db/migrate/update_trigger.erb +1 -1
  43. data/lib/generators/fx/trigger/trigger_generator.rb +46 -51
  44. data/lib/generators/fx/version_helper.rb +55 -0
  45. data/spec/acceptance/user_manages_functions_spec.rb +26 -6
  46. data/spec/acceptance/user_manages_triggers_spec.rb +11 -11
  47. data/spec/acceptance_helper.rb +17 -11
  48. data/spec/dummy/Rakefile +8 -1
  49. data/spec/dummy/bin/bundle +2 -2
  50. data/spec/dummy/bin/rails +3 -3
  51. data/spec/dummy/bin/rake +2 -2
  52. data/spec/dummy/config/application.rb +2 -0
  53. data/spec/dummy/config/database.yml +2 -0
  54. data/spec/dummy/config.ru +1 -1
  55. data/spec/features/functions/migrations_spec.rb +9 -9
  56. data/spec/features/functions/revert_spec.rb +13 -13
  57. data/spec/features/triggers/migrations_spec.rb +11 -11
  58. data/spec/features/triggers/revert_spec.rb +21 -21
  59. data/spec/fx/adapters/postgres/functions_spec.rb +40 -0
  60. data/spec/fx/adapters/postgres/query_executor_spec.rb +75 -0
  61. data/spec/fx/adapters/postgres/triggers_spec.rb +48 -0
  62. data/spec/fx/adapters/postgres_spec.rb +115 -111
  63. data/spec/fx/command_recorder_spec.rb +39 -53
  64. data/spec/fx/configuration_spec.rb +20 -9
  65. data/spec/fx/definition_spec.rb +53 -38
  66. data/spec/fx/function_spec.rb +143 -0
  67. data/spec/fx/schema_dumper_spec.rb +241 -0
  68. data/spec/fx/statements_spec.rb +219 -0
  69. data/spec/fx/trigger_spec.rb +52 -0
  70. data/spec/fx_spec.rb +28 -0
  71. data/spec/generators/fx/function/function_generator_spec.rb +22 -10
  72. data/spec/generators/fx/migration_helper_spec.rb +108 -0
  73. data/spec/generators/fx/name_helper_spec.rb +114 -0
  74. data/spec/generators/fx/trigger/trigger_generator_spec.rb +55 -20
  75. data/spec/generators/fx/version_helper_spec.rb +157 -0
  76. data/spec/spec_helper.rb +16 -4
  77. data/spec/support/database_reset.rb +24 -0
  78. data/spec/support/definition_helpers.rb +5 -9
  79. data/spec/support/generator_setup.rb +46 -5
  80. data/spec/support/migration_helpers.rb +9 -1
  81. data/spec/support/warning_helper.rb +5 -0
  82. metadata +43 -215
  83. data/.ruby-version +0 -1
  84. data/.travis.yml +0 -27
  85. data/Appraisals +0 -21
  86. data/bin/appraisal +0 -17
  87. data/gemfiles/rails40.gemfile +0 -8
  88. data/gemfiles/rails40.gemfile.lock +0 -111
  89. data/gemfiles/rails41.gemfile +0 -8
  90. data/gemfiles/rails41.gemfile.lock +0 -113
  91. data/gemfiles/rails42.gemfile +0 -8
  92. data/gemfiles/rails42.gemfile.lock +0 -130
  93. data/gemfiles/rails50.gemfile +0 -8
  94. data/gemfiles/rails50.gemfile.lock +0 -126
  95. data/lib/fx/command_recorder/arguments.rb +0 -43
  96. data/lib/fx/command_recorder/function.rb +0 -30
  97. data/lib/fx/command_recorder/trigger.rb +0 -30
  98. data/lib/fx/schema_dumper/function.rb +0 -29
  99. data/lib/fx/schema_dumper/trigger.rb +0 -29
  100. data/lib/fx/statements/function.rb +0 -105
  101. data/lib/fx/statements/trigger.rb +0 -133
  102. data/spec/fx/command_recorder/arguments_spec.rb +0 -41
  103. data/spec/fx/schema_dumper/function_spec.rb +0 -22
  104. data/spec/fx/schema_dumper/trigger_spec.rb +0 -40
  105. data/spec/fx/statements/function_spec.rb +0 -103
  106. data/spec/fx/statements/trigger_spec.rb +0 -132
@@ -1,21 +1,13 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Fx::CommandRecorder, :db do
3
+ RSpec.describe Fx::CommandRecorder, :db do
4
4
  describe "#create_function" do
5
5
  it "records the created function" do
6
6
  recorder = ActiveRecord::Migration::CommandRecorder.new
7
7
 
8
8
  recorder.create_function :test
9
9
 
10
- expect(recorder.commands).to eq [[:create_function, [:test], nil]]
11
- end
12
-
13
- it "reverts to drop_function" do
14
- recorder = ActiveRecord::Migration::CommandRecorder.new
15
-
16
- recorder.create_function :test
17
-
18
- expect(recorder.commands).to eq [[:create_function, [:test], nil]]
10
+ expect(recorder.commands).to eq([[:create_function, [:test], nil]])
19
11
  end
20
12
 
21
13
  it "reverts to drop_function" do
@@ -23,7 +15,7 @@ describe Fx::CommandRecorder, :db do
23
15
 
24
16
  recorder.revert { recorder.create_function :test }
25
17
 
26
- expect(recorder.commands).to eq [[:drop_function, [:test]]]
18
+ expect(recorder.commands).to eq([[:drop_function, [:test]]])
27
19
  end
28
20
  end
29
21
 
@@ -33,54 +25,56 @@ describe Fx::CommandRecorder, :db do
33
25
 
34
26
  recorder.drop_function :test
35
27
 
36
- expect(recorder.commands).to eq [[:drop_function, [:test], nil]]
28
+ expect(recorder.commands).to eq([[:drop_function, [:test], nil]])
37
29
  end
38
30
 
39
31
  it "reverts to create_function with specified revert_to_version" do
40
32
  recorder = ActiveRecord::Migration::CommandRecorder.new
41
- args = [:test, { revert_to_version: 3 }]
42
- revert_args = [:test, { version: 3 }]
33
+ args = [:test, {revert_to_version: 3}]
34
+ revert_args = [:test, {version: 3}]
43
35
 
44
36
  recorder.revert { recorder.drop_function(*args) }
45
37
 
46
- expect(recorder.commands).to eq [[:create_function, revert_args]]
38
+ expect(recorder.commands).to eq([[:create_function, revert_args]])
47
39
  end
48
40
 
49
41
  it "raises when reverting without revert_to_version set" do
50
42
  recorder = ActiveRecord::Migration::CommandRecorder.new
51
- args = [:test, { another_argument: 1 }]
43
+ args = [:test, {another_argument: 1}]
52
44
 
53
- expect { recorder.revert { recorder.drop_function(*args) } }.
54
- to raise_error(ActiveRecord::IrreversibleMigration)
45
+ expect do
46
+ recorder.revert { recorder.drop_function(*args) }
47
+ end.to raise_error(ActiveRecord::IrreversibleMigration)
55
48
  end
56
49
  end
57
50
 
58
51
  describe "#update_function" do
59
52
  it "records the updated function" do
60
53
  recorder = ActiveRecord::Migration::CommandRecorder.new
61
- args = [:test, { version: 2 }]
54
+ args = [:test, {version: 2}]
62
55
 
63
56
  recorder.update_function(*args)
64
57
 
65
- expect(recorder.commands).to eq [[:update_function, args, nil]]
58
+ expect(recorder.commands).to eq([[:update_function, args, nil]])
66
59
  end
67
60
 
68
61
  it "reverts to update_function with the specified revert_to_version" do
69
62
  recorder = ActiveRecord::Migration::CommandRecorder.new
70
- args = [:test, { version: 2, revert_to_version: 1 }]
71
- revert_args = [:test, { version: 1 }]
63
+ args = [:test, {version: 2, revert_to_version: 1}]
64
+ revert_args = [:test, {version: 1}]
72
65
 
73
66
  recorder.revert { recorder.update_function(*args) }
74
67
 
75
- expect(recorder.commands).to eq [[:update_function, revert_args]]
68
+ expect(recorder.commands).to eq([[:update_function, revert_args]])
76
69
  end
77
70
 
78
71
  it "raises when reverting without revert_to_version set" do
79
72
  recorder = ActiveRecord::Migration::CommandRecorder.new
80
- args = [:test, { version: 42, another_argument: 1 }]
73
+ args = [:test, {version: 42, another_argument: 1}]
81
74
 
82
- expect { recorder.revert { recorder.update_function(*args) } }.
83
- to raise_error(ActiveRecord::IrreversibleMigration)
75
+ expect do
76
+ recorder.revert { recorder.update_function(*args) }
77
+ end.to raise_error(ActiveRecord::IrreversibleMigration)
84
78
  end
85
79
  end
86
80
 
@@ -90,17 +84,7 @@ describe Fx::CommandRecorder, :db do
90
84
 
91
85
  recorder.create_trigger :greetings
92
86
 
93
- expect(recorder.commands).to eq [[:create_trigger, [:greetings], nil]]
94
- end
95
-
96
- it "reverts to drop_trigger" do
97
- recorder = ActiveRecord::Migration::CommandRecorder.new
98
-
99
- recorder.create_trigger :greetings
100
-
101
- expect(recorder.commands).to eq [
102
- [:create_trigger, [:greetings], nil],
103
- ]
87
+ expect(recorder.commands).to eq([[:create_trigger, [:greetings], nil]])
104
88
  end
105
89
 
106
90
  it "reverts to drop_trigger" do
@@ -108,7 +92,7 @@ describe Fx::CommandRecorder, :db do
108
92
 
109
93
  recorder.revert { recorder.create_trigger :greetings }
110
94
 
111
- expect(recorder.commands).to eq [[:drop_trigger, [:greetings]]]
95
+ expect(recorder.commands).to eq([[:drop_trigger, [:greetings]]])
112
96
  end
113
97
  end
114
98
 
@@ -118,54 +102,56 @@ describe Fx::CommandRecorder, :db do
118
102
 
119
103
  recorder.drop_trigger :users
120
104
 
121
- expect(recorder.commands).to eq [[:drop_trigger, [:users], nil]]
105
+ expect(recorder.commands).to eq([[:drop_trigger, [:users], nil]])
122
106
  end
123
107
 
124
108
  it "reverts to create_trigger with specified revert_to_version" do
125
109
  recorder = ActiveRecord::Migration::CommandRecorder.new
126
- args = [:users, { revert_to_version: 3 }]
127
- revert_args = [:users, { version: 3 }]
110
+ args = [:users, {revert_to_version: 3}]
111
+ revert_args = [:users, {version: 3}]
128
112
 
129
113
  recorder.revert { recorder.drop_trigger(*args) }
130
114
 
131
- expect(recorder.commands).to eq [[:create_trigger, revert_args]]
115
+ expect(recorder.commands).to eq([[:create_trigger, revert_args]])
132
116
  end
133
117
 
134
118
  it "raises when reverting without revert_to_version set" do
135
119
  recorder = ActiveRecord::Migration::CommandRecorder.new
136
- args = [:users, { another_argument: 1 }]
120
+ args = [:users, {another_argument: 1}]
137
121
 
138
- expect { recorder.revert { recorder.drop_trigger(*args) } }.
139
- to raise_error(ActiveRecord::IrreversibleMigration)
122
+ expect do
123
+ recorder.revert { recorder.drop_trigger(*args) }
124
+ end.to raise_error(ActiveRecord::IrreversibleMigration)
140
125
  end
141
126
  end
142
127
 
143
128
  describe "#update_trigger" do
144
129
  it "records the updated trigger" do
145
130
  recorder = ActiveRecord::Migration::CommandRecorder.new
146
- args = [:users, { version: 2 }]
131
+ args = [:users, {version: 2}]
147
132
 
148
133
  recorder.update_trigger(*args)
149
134
 
150
- expect(recorder.commands).to eq [[:update_trigger, args, nil]]
135
+ expect(recorder.commands).to eq([[:update_trigger, args, nil]])
151
136
  end
152
137
 
153
138
  it "reverts to update_trigger with the specified revert_to_version" do
154
139
  recorder = ActiveRecord::Migration::CommandRecorder.new
155
- args = [:users, { version: 2, revert_to_version: 1 }]
156
- revert_args = [:users, { version: 1 }]
140
+ args = [:users, {version: 2, revert_to_version: 1}]
141
+ revert_args = [:users, {version: 1}]
157
142
 
158
143
  recorder.revert { recorder.update_trigger(*args) }
159
144
 
160
- expect(recorder.commands).to eq [[:update_trigger, revert_args]]
145
+ expect(recorder.commands).to eq([[:update_trigger, revert_args]])
161
146
  end
162
147
 
163
148
  it "raises when reverting without revert_to_version set" do
164
149
  recorder = ActiveRecord::Migration::CommandRecorder.new
165
- args = [:users, { version: 42, another_argument: 1 }]
150
+ args = [:users, {version: 42, another_argument: 1}]
166
151
 
167
- expect { recorder.revert { recorder.update_trigger(*args) } }.
168
- to raise_error(ActiveRecord::IrreversibleMigration)
152
+ expect do
153
+ recorder.revert { recorder.update_trigger(*args) }
154
+ end.to raise_error(ActiveRecord::IrreversibleMigration)
169
155
  end
170
156
  end
171
157
  end
@@ -1,21 +1,32 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Fx::Configuration do
3
+ RSpec.describe Fx::Configuration do
4
4
  it "defaults the database adapter to postgres" do
5
- expect(Fx.configuration.database).to be_a Fx::Adapters::Postgres
6
- expect(Fx.database).to be_a Fx::Adapters::Postgres
5
+ configuration = Fx::Configuration.new
6
+
7
+ expect(configuration.database).to be_a(Fx::Adapters::Postgres)
8
+ end
9
+
10
+ it "defaults `dump_functions_at_beginning_of_schema` to false" do
11
+ configuration = Fx::Configuration.new
12
+
13
+ expect(configuration.dump_functions_at_beginning_of_schema).to eq(false)
7
14
  end
8
15
 
9
16
  it "allows the database adapter to be set" do
17
+ configuration = Fx::Configuration.new
10
18
  adapter = double("Fx Adapter")
11
19
 
12
- Fx.configure do |config|
13
- config.database = adapter
14
- end
20
+ configuration.database = adapter
21
+
22
+ expect(configuration.database).to eq(adapter)
23
+ end
24
+
25
+ it "allows `dump_functions_at_beginning_of_schema` to be set" do
26
+ configuration = Fx::Configuration.new
15
27
 
16
- expect(Fx.configuration.database).to eq adapter
17
- expect(Fx.database).to eq adapter
28
+ configuration.dump_functions_at_beginning_of_schema = true
18
29
 
19
- Fx.configuration = Fx::Configuration.new
30
+ expect(configuration.dump_functions_at_beginning_of_schema).to eq(true)
20
31
  end
21
32
  end
@@ -1,65 +1,84 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Fx::Definition do
3
+ RSpec.describe Fx::Definition do
4
4
  describe "#to_sql" do
5
5
  context "representing a function definition" do
6
6
  it "returns the content of a function definition" do
7
- sql_definition = <<~EOS
7
+ sql_definition = <<~SQL
8
8
  CREATE OR REPLACE FUNCTION test()
9
9
  RETURNS text AS $$
10
10
  BEGIN
11
11
  RETURN 'test';
12
12
  END;
13
13
  $$ LANGUAGE plpgsql;
14
- EOS
14
+ SQL
15
15
  allow(File).to receive(:read).and_return(sql_definition)
16
16
 
17
- definition = Fx::Definition.new(name: "test", version: 1)
17
+ definition = Fx::Definition.function(name: "test", version: 1)
18
18
 
19
- expect(definition.to_sql).to eq sql_definition
19
+ expect(definition.to_sql).to eq(sql_definition)
20
20
  end
21
21
 
22
22
  it "raises an error if the file is empty" do
23
23
  allow(File).to receive(:read).and_return("")
24
- definition = Fx::Definition.new(name: "test", version: 1)
24
+ definition = Fx::Definition.function(name: "test", version: 1)
25
25
 
26
- expect { definition.to_sql }.to raise_error(
26
+ expect do
27
+ definition.to_sql
28
+ end.to raise_error(
27
29
  RuntimeError,
28
- %r(Define function in db/functions/test_v01.sql before migrating),
30
+ %r{Define function in db/functions/test_v01.sql before migrating}
29
31
  )
30
32
  end
33
+
34
+ context "when definition is at Rails engine" do
35
+ it "returns the content of a function definition" do
36
+ sql_definition = <<~SQL
37
+ CREATE OR REPLACE FUNCTION test()
38
+ RETURNS text AS $$
39
+ BEGIN
40
+ RETURN 'test';
41
+ END;
42
+ $$ LANGUAGE plpgsql;
43
+ SQL
44
+ engine_path = Rails.root.join("tmp", "engine")
45
+ FileUtils.mkdir_p(engine_path.join("db", "functions"))
46
+ File.write(engine_path.join("db", "functions", "custom_test_v01.sql"), sql_definition)
47
+ Rails.application.config.paths["db/migrate"].push(engine_path.join("db", "migrate"))
48
+
49
+ definition = Fx::Definition.function(name: "custom_test", version: 1)
50
+
51
+ expect(definition.to_sql).to eq(sql_definition)
52
+
53
+ FileUtils.rm_rf(engine_path)
54
+ end
55
+ end
31
56
  end
32
57
 
33
58
  context "representing a trigger definition" do
34
59
  it "returns the content of a trigger definition" do
35
- sql_definition = <<~EOS
60
+ sql_definition = <<~SQL
36
61
  CREATE TRIGGER check_update
37
62
  BEFORE UPDATE ON accounts
38
63
  FOR EACH ROW
39
- EXECUTE PROCEDURE check_account_update();
40
- EOS
64
+ EXECUTE FUNCTION check_account_update();
65
+ SQL
41
66
  allow(File).to receive(:read).and_return(sql_definition)
42
67
 
43
- definition = Fx::Definition.new(
44
- name: "test",
45
- version: 1,
46
- type: "trigger",
47
- )
68
+ definition = Fx::Definition.trigger(name: "test", version: 1)
48
69
 
49
- expect(definition.to_sql).to eq sql_definition
70
+ expect(definition.to_sql).to eq(sql_definition)
50
71
  end
51
72
 
52
73
  it "raises an error if the file is empty" do
53
74
  allow(File).to receive(:read).and_return("")
54
- definition = Fx::Definition.new(
55
- name: "test",
56
- version: 1,
57
- type: "trigger",
58
- )
75
+ definition = Fx::Definition.trigger(name: "test", version: 1)
59
76
 
60
- expect { definition.to_sql }.to raise_error(
77
+ expect do
78
+ definition.to_sql
79
+ end.to raise_error(
61
80
  RuntimeError,
62
- %r(Define trigger in db/triggers/test_v01.sql before migrating),
81
+ %r{Define trigger in db/triggers/test_v01.sql before migrating}
63
82
  )
64
83
  end
65
84
  end
@@ -68,44 +87,40 @@ describe Fx::Definition do
68
87
  describe "#path" do
69
88
  context "representing a function definition" do
70
89
  it "returns a sql file with padded version and function name" do
71
- definition = Fx::Definition.new(name: "test", version: 1)
90
+ definition = Fx::Definition.function(name: "test", version: 1)
72
91
 
73
- expect(definition.path).to eq "db/functions/test_v01.sql"
92
+ expect(definition.path).to eq("db/functions/test_v01.sql")
74
93
  end
75
94
  end
76
95
 
77
96
  context "representing a trigger definition" do
78
97
  it "returns a sql file with padded version and trigger name" do
79
- definition = Fx::Definition.new(
80
- name: "test",
81
- version: 1,
82
- type: "trigger",
83
- )
98
+ definition = Fx::Definition.trigger(name: "test", version: 1)
84
99
 
85
- expect(definition.path).to eq "db/triggers/test_v01.sql"
100
+ expect(definition.path).to eq("db/triggers/test_v01.sql")
86
101
  end
87
102
  end
88
103
  end
89
104
 
90
105
  describe "#full_path" do
91
106
  it "joins the path with Rails.root" do
92
- definition = Fx::Definition.new(name: "test", version: 15)
107
+ definition = Fx::Definition.function(name: "test", version: 15)
93
108
 
94
- expect(definition.full_path).to eq Rails.root.join(definition.path)
109
+ expect(definition.full_path).to eq(Rails.root.join(definition.path))
95
110
  end
96
111
  end
97
112
 
98
113
  describe "#version" do
99
114
  it "pads the version number with 0" do
100
- definition = Fx::Definition.new(name: :_, version: 1)
115
+ definition = Fx::Definition.function(name: :_, version: 1)
101
116
 
102
- expect(definition.version).to eq "01"
117
+ expect(definition.version).to eq("01")
103
118
  end
104
119
 
105
120
  it "does not pad more than 2 characters" do
106
- definition = Fx::Definition.new(name: :_, version: 15)
121
+ definition = Fx::Definition.function(name: :_, version: 15)
107
122
 
108
- expect(definition.version).to eq "15"
123
+ expect(definition.version).to eq("15")
109
124
  end
110
125
  end
111
126
  end
@@ -0,0 +1,143 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Fx::Function do
4
+ describe "#<=>" do
5
+ it "delegates to `signature`" do
6
+ function_a = Fx::Function.new(
7
+ "name" => "name_a",
8
+ "definition" => "some definition",
9
+ "arguments" => ""
10
+ )
11
+ function_b = Fx::Function.new(
12
+ "name" => "name_b",
13
+ "definition" => "some definition",
14
+ "arguments" => ""
15
+ )
16
+ function_c = Fx::Function.new(
17
+ "name" => "name_c",
18
+ "definition" => "some definition",
19
+ "arguments" => ""
20
+ )
21
+
22
+ expect(function_b).to be_between(function_a, function_c)
23
+ end
24
+
25
+ it "orders overloads by signature" do
26
+ add_int = Fx::Function.new(
27
+ "name" => "add",
28
+ "definition" => "some definition",
29
+ "arguments" => "integer, integer"
30
+ )
31
+ add_text = Fx::Function.new(
32
+ "name" => "add",
33
+ "definition" => "some definition",
34
+ "arguments" => "text, text"
35
+ )
36
+
37
+ expect(add_int <=> add_text).to be < 0
38
+ end
39
+ end
40
+
41
+ describe "#==" do
42
+ it "compares `signature` and `definition`" do
43
+ function_a = Fx::Function.new(
44
+ "name" => "name_a",
45
+ "definition" => "some definition",
46
+ "arguments" => ""
47
+ )
48
+ function_b = Fx::Function.new(
49
+ "name" => "name_b",
50
+ "definition" => "some other definition",
51
+ "arguments" => ""
52
+ )
53
+
54
+ expect(function_a).not_to eq(function_b)
55
+ end
56
+
57
+ it "distinguishes overloads with the same name" do
58
+ add_int = Fx::Function.new(
59
+ "name" => "add",
60
+ "definition" => "CREATE FUNCTION add(integer)",
61
+ "arguments" => "integer"
62
+ )
63
+ add_text = Fx::Function.new(
64
+ "name" => "add",
65
+ "definition" => "CREATE FUNCTION add(text)",
66
+ "arguments" => "text"
67
+ )
68
+
69
+ expect(add_int).not_to eq(add_text)
70
+ end
71
+ end
72
+
73
+ describe "#signature" do
74
+ it "returns name with arguments when arguments are present" do
75
+ function = Fx::Function.new(
76
+ "name" => "inc",
77
+ "definition" => "some definition",
78
+ "arguments" => "integer"
79
+ )
80
+
81
+ expect(function.signature).to eq("inc(integer)")
82
+ end
83
+
84
+ it "returns name with multiple arguments" do
85
+ function = Fx::Function.new(
86
+ "name" => "add",
87
+ "definition" => "some definition",
88
+ "arguments" => "integer, integer"
89
+ )
90
+
91
+ expect(function.signature).to eq("add(integer, integer)")
92
+ end
93
+
94
+ it "returns name with empty parens for no-arg functions" do
95
+ function = Fx::Function.new(
96
+ "name" => "now_utc",
97
+ "definition" => "some definition",
98
+ "arguments" => ""
99
+ )
100
+
101
+ expect(function.signature).to eq("now_utc()")
102
+ end
103
+
104
+ it "returns just the name when arguments key is missing" do
105
+ function = Fx::Function.new(
106
+ "name" => "now_utc",
107
+ "definition" => "some definition"
108
+ )
109
+
110
+ expect(function.signature).to eq("now_utc")
111
+ end
112
+ end
113
+
114
+ describe "#to_schema" do
115
+ it "returns a schema compatible version of the function" do
116
+ function = Fx::Function.new(
117
+ "name" => "uppercase_users_name",
118
+ "definition" => "CREATE OR REPLACE TRIGGER uppercase_users_name ...",
119
+ "arguments" => ""
120
+ )
121
+
122
+ expect(function.to_schema).to eq(<<-EOS)
123
+ create_function :uppercase_users_name, sql_definition: <<-'SQL'
124
+ CREATE OR REPLACE TRIGGER uppercase_users_name ...
125
+ SQL
126
+ EOS
127
+ end
128
+
129
+ it "maintains backslashes" do
130
+ function = Fx::Function.new(
131
+ "name" => "regex",
132
+ "definition" => "CREATE OR REPLACE FUNCTION regex \\1",
133
+ "arguments" => ""
134
+ )
135
+
136
+ expect(function.to_schema).to eq(<<-'EOS')
137
+ create_function :regex, sql_definition: <<-'SQL'
138
+ CREATE OR REPLACE FUNCTION regex \1
139
+ SQL
140
+ EOS
141
+ end
142
+ end
143
+ end