fx 0.9.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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -2
  3. data/CHANGELOG.md +27 -1
  4. data/Gemfile +0 -1
  5. data/bin/rake +2 -3
  6. data/bin/rspec +13 -3
  7. data/bin/yard +13 -3
  8. data/fx.gemspec +3 -3
  9. data/lib/fx/adapters/postgres/connection.rb +12 -4
  10. data/lib/fx/adapters/postgres/functions.rb +11 -28
  11. data/lib/fx/adapters/postgres/query_executor.rb +34 -0
  12. data/lib/fx/adapters/postgres/triggers.rb +14 -29
  13. data/lib/fx/adapters/postgres.rb +10 -10
  14. data/lib/fx/configuration.rb +2 -2
  15. data/lib/fx/schema_dumper.rb +6 -14
  16. data/lib/fx/statements.rb +61 -58
  17. data/lib/fx/version.rb +1 -1
  18. data/lib/generators/fx/function/function_generator.rb +50 -53
  19. data/lib/generators/fx/function/templates/db/migrate/create_function.erb +1 -1
  20. data/lib/generators/fx/function/templates/db/migrate/update_function.erb +1 -1
  21. data/lib/generators/fx/migration_helper.rb +53 -0
  22. data/lib/generators/fx/name_helper.rb +33 -0
  23. data/lib/generators/fx/trigger/templates/db/migrate/create_trigger.erb +1 -1
  24. data/lib/generators/fx/trigger/templates/db/migrate/update_trigger.erb +1 -1
  25. data/lib/generators/fx/trigger/trigger_generator.rb +45 -64
  26. data/lib/generators/fx/version_helper.rb +55 -0
  27. data/spec/acceptance/user_manages_functions_spec.rb +6 -6
  28. data/spec/acceptance/user_manages_triggers_spec.rb +10 -10
  29. data/spec/acceptance_helper.rb +2 -2
  30. data/spec/features/functions/migrations_spec.rb +4 -4
  31. data/spec/features/functions/revert_spec.rb +4 -4
  32. data/spec/features/triggers/migrations_spec.rb +6 -6
  33. data/spec/features/triggers/revert_spec.rb +8 -8
  34. data/spec/fx/adapters/postgres/functions_spec.rb +12 -5
  35. data/spec/fx/adapters/postgres/query_executor_spec.rb +75 -0
  36. data/spec/fx/adapters/postgres/triggers_spec.rb +14 -7
  37. data/spec/fx/adapters/postgres_spec.rb +62 -20
  38. data/spec/fx/definition_spec.rb +6 -6
  39. data/spec/fx/schema_dumper_spec.rb +60 -14
  40. data/spec/fx_spec.rb +1 -1
  41. data/spec/generators/fx/function/function_generator_spec.rb +10 -10
  42. data/spec/generators/fx/migration_helper_spec.rb +133 -0
  43. data/spec/generators/fx/name_helper_spec.rb +114 -0
  44. data/spec/generators/fx/trigger/trigger_generator_spec.rb +42 -19
  45. data/spec/generators/fx/version_helper_spec.rb +157 -0
  46. data/spec/spec_helper.rb +2 -0
  47. data/spec/support/generator_setup.rb +46 -5
  48. metadata +28 -11
@@ -6,12 +6,15 @@ RSpec.describe Fx::Generators::TriggerGenerator, :generator do
6
6
  migration = file("db/migrate/create_trigger_test.rb")
7
7
  trigger_definition = file("db/triggers/test_v01.sql")
8
8
 
9
- run_generator ["test", "table_name" => "some_table"]
9
+ run_generator(
10
+ described_class,
11
+ ["test", {"table_name" => "some_table"}]
12
+ )
10
13
 
11
14
  expect(trigger_definition).to exist
12
- expect(migration).to be_a_migration
13
- expect(migration_file(migration)).to contain("CreateTriggerTest")
14
- expect(migration_file(migration)).to contain("on: :some_table")
15
+ expect_to_be_a_migration(migration)
16
+ expect(migration_content(migration)).to include("CreateTriggerTest")
17
+ expect(migration_content(migration)).to include("on: :some_table")
15
18
  end
16
19
 
17
20
  context "when passed --no-migration" do
@@ -19,10 +22,14 @@ RSpec.describe Fx::Generators::TriggerGenerator, :generator do
19
22
  migration = file("db/migrate/create_trigger_test.rb")
20
23
  trigger_definition = file("db/triggers/test_v01.sql")
21
24
 
22
- run_generator ["test", {"table_name" => "some_table"}, "--no-migration"]
25
+ run_generator(
26
+ described_class,
27
+ ["test", {"table_name" => "some_table"}],
28
+ {migration: false}
29
+ )
23
30
 
24
31
  expect(trigger_definition).to exist
25
- expect(Pathname.new(migration_file(migration))).not_to exist
32
+ expect(migration).not_to exist
26
33
  end
27
34
  end
28
35
 
@@ -30,30 +37,46 @@ RSpec.describe Fx::Generators::TriggerGenerator, :generator do
30
37
  migration = file("db/migrate/create_trigger_test.rb")
31
38
  trigger_definition = file("db/triggers/test_v01.sql")
32
39
 
33
- run_generator ["test", "on" => "some_table"]
40
+ run_generator(
41
+ described_class,
42
+ ["test", {"on" => "some_table"}]
43
+ )
34
44
 
35
45
  expect(trigger_definition).to exist
36
- expect(migration).to be_a_migration
37
- expect(migration_file(migration)).to contain("CreateTriggerTest")
38
- expect(migration_file(migration)).to contain("on: :some_table")
46
+ expect_to_be_a_migration(migration)
47
+ expect(migration_content(migration)).to include("CreateTriggerTest")
48
+ expect(migration_content(migration)).to include("on: :some_table")
39
49
  end
40
50
 
41
51
  it "requires `table_name` or `on` to be specified" do
42
52
  expect do
43
- run_generator ["test", "foo" => "some_table"]
53
+ run_generator(
54
+ described_class,
55
+ ["test", {"foo" => "some_table"}]
56
+ )
44
57
  end.to raise_error(ArgumentError)
45
58
  end
46
59
 
47
60
  it "updates an existing trigger" do
48
- allow(Dir).to receive(:entries).and_return(["test_v01.sql"])
49
- migration = file("db/migrate/update_trigger_test_to_version_2.rb")
50
- trigger_definition = file("db/triggers/test_v02.sql")
61
+ with_trigger_definition(
62
+ name: "test",
63
+ version: 1,
64
+ sql_definition: "hello"
65
+ ) do
66
+ migration = file("db/migrate/update_trigger_test_to_version_2.rb")
67
+ trigger_definition = file("db/triggers/test_v02.sql")
51
68
 
52
- run_generator ["test", "table_name" => "some_table"]
69
+ run_generator(
70
+ described_class,
71
+ ["test", {"table_name" => "some_table"}]
72
+ )
53
73
 
54
- expect(trigger_definition).to exist
55
- expect(migration).to be_a_migration
56
- expect(migration_file(migration)).to contain("UpdateTriggerTestToVersion2")
57
- expect(migration_file(migration)).to contain("on: :some_table")
74
+ expect(trigger_definition).to exist
75
+ expect_to_be_a_migration(migration)
76
+ expect(migration_content(migration)).to include(
77
+ "UpdateTriggerTestToVersion2"
78
+ )
79
+ expect(migration_content(migration)).to include("on: :some_table")
80
+ end
58
81
  end
59
82
  end
@@ -0,0 +1,157 @@
1
+ require "spec_helper"
2
+ require "generators/fx/version_helper"
3
+
4
+ RSpec.describe Fx::Generators::VersionHelper do
5
+ describe "#previous_version" do
6
+ it "returns 0 when no existing versions found" do
7
+ with_temp_directory do |temp_dir|
8
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
9
+
10
+ expect(helper.previous_version).to eq(0)
11
+ end
12
+ end
13
+
14
+ it "returns highest version number from existing files" do
15
+ with_temp_directory do |temp_dir|
16
+ create_version_file(temp_dir, "test_function", 1)
17
+ create_version_file(temp_dir, "test_function", 3)
18
+ create_version_file(temp_dir, "test_function", 2)
19
+
20
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
21
+
22
+ expect(helper.previous_version).to eq(3)
23
+ end
24
+ end
25
+
26
+ it "ignores files that don't match the pattern" do
27
+ with_temp_directory do |temp_dir|
28
+ create_version_file(temp_dir, "test_function", 2)
29
+ FileUtils.touch(temp_dir.join("other_function_v3.sql"))
30
+ FileUtils.touch(temp_dir.join("test_function.sql"))
31
+
32
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
33
+
34
+ expect(helper.previous_version).to eq(2)
35
+ end
36
+ end
37
+ end
38
+
39
+ describe "#current_version" do
40
+ it "returns previous version + 1" do
41
+ with_temp_directory do |temp_dir|
42
+ create_version_file(temp_dir, "test_function", 5)
43
+
44
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
45
+
46
+ expect(helper.current_version).to eq(6)
47
+ end
48
+ end
49
+
50
+ it "returns 1 when no previous versions exist" do
51
+ with_temp_directory do |temp_dir|
52
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
53
+
54
+ expect(helper.current_version).to eq(1)
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "#updating_existing?" do
60
+ it "returns false when no previous versions exist" do
61
+ with_temp_directory do |temp_dir|
62
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
63
+
64
+ expect(helper.updating_existing?).to be false
65
+ end
66
+ end
67
+
68
+ it "returns true when previous versions exist" do
69
+ with_temp_directory do |temp_dir|
70
+ create_version_file(temp_dir, "test_function", 1)
71
+
72
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
73
+
74
+ expect(helper.updating_existing?).to be true
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "#creating_new?" do
80
+ it "returns true when no previous versions exist" do
81
+ with_temp_directory do |temp_dir|
82
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
83
+
84
+ expect(helper.creating_new?).to be true
85
+ end
86
+ end
87
+
88
+ it "returns false when previous versions exist" do
89
+ with_temp_directory do |temp_dir|
90
+ create_version_file(temp_dir, "test_function", 1)
91
+
92
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
93
+
94
+ expect(helper.creating_new?).to be false
95
+ end
96
+ end
97
+ end
98
+
99
+ describe "#definition_for_version" do
100
+ it "returns function definition for function type" do
101
+ with_temp_directory do |temp_dir|
102
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
103
+ allow(Fx::Definition).to receive(:function)
104
+ .and_return("function_definition")
105
+
106
+ result = helper.definition_for_version(version: 2, type: :function)
107
+
108
+ expect(result).to eq("function_definition")
109
+ expect(Fx::Definition).to have_received(:function).with(
110
+ name: "test_function",
111
+ version: 2
112
+ )
113
+ end
114
+ end
115
+
116
+ it "returns trigger definition for trigger type" do
117
+ with_temp_directory do |temp_dir|
118
+ helper = described_class.new(file_name: "test_trigger", definition_path: temp_dir)
119
+ allow(Fx::Definition).to receive(:trigger)
120
+ .and_return("trigger_definition")
121
+
122
+ result = helper.definition_for_version(version: 3, type: :trigger)
123
+
124
+ expect(result).to eq("trigger_definition")
125
+ expect(Fx::Definition).to have_received(:trigger).with(
126
+ name: "test_trigger",
127
+ version: 3
128
+ )
129
+ end
130
+ end
131
+
132
+ it "raises error for unknown type" do
133
+ with_temp_directory do |temp_dir|
134
+ helper = described_class.new(file_name: "test_function", definition_path: temp_dir)
135
+
136
+ expect {
137
+ helper.definition_for_version(version: 1, type: :unknown)
138
+ }.to raise_error(
139
+ ArgumentError,
140
+ "Unknown type: unknown. Must be :function or :trigger"
141
+ )
142
+ end
143
+ end
144
+ end
145
+
146
+ private
147
+
148
+ def with_temp_directory
149
+ Dir.mktmpdir do |path|
150
+ yield Pathname.new(path)
151
+ end
152
+ end
153
+
154
+ def create_version_file(dir, name, version)
155
+ FileUtils.touch(dir.join("#{name}_v#{version}.sql"))
156
+ end
157
+ end
data/spec/spec_helper.rb CHANGED
@@ -14,6 +14,8 @@ RSpec.configure do |config|
14
14
  DatabaseCleaner.strategy = :transaction
15
15
 
16
16
  config.around(:each, db: true) do |example|
17
+ ActiveRecord::Base.connection.execute("SET search_path TO DEFAULT;")
18
+
17
19
  DatabaseCleaner.start
18
20
  example.run
19
21
  DatabaseCleaner.clean
@@ -1,11 +1,52 @@
1
- require "ammeter/init"
1
+ module GeneratorSetup
2
+ RAILS_ROOT = Pathname.new(File.expand_path("../../../tmp/dummy", __dir__)).freeze
3
+ MIGRATION_TIMESTAMP_PATTERN = /\A\d{14}_/
4
+
5
+ def run_generator(generator_class, args = [], options = {})
6
+ allow(Rails).to receive(:root).and_return(RAILS_ROOT)
7
+ generator = generator_class.new(args, options, destination_root: RAILS_ROOT)
8
+
9
+ silence_stream($stdout) do
10
+ generator.invoke_all
11
+ end
12
+ end
13
+
14
+ def file(relative_path)
15
+ RAILS_ROOT.join(relative_path)
16
+ end
17
+
18
+ def migration_content(file_path)
19
+ migration_path = find_migration_files(file_path).first
20
+ return if migration_path.nil?
21
+
22
+ Pathname.new(migration_path).read
23
+ end
24
+
25
+ def find_migration_files(file_path)
26
+ directory = File.dirname(file_path)
27
+ basename = File.basename(file_path, ".rb")
28
+ Dir.glob(File.join(directory, "*#{basename}.rb"))
29
+ end
30
+
31
+ def expect_to_be_a_migration(pathname)
32
+ migration_files = find_migration_files(pathname)
33
+
34
+ expect(migration_files).to be_present,
35
+ "expected #{pathname} to be a migration file"
36
+ first_migration = migration_files.first
37
+ migration_basename = File.basename(first_migration)
38
+ expect(migration_basename).to match(MIGRATION_TIMESTAMP_PATTERN),
39
+ "expected #{migration_basename} to have timestamp prefix (format: YYYYMMDDHHMMSS_)"
40
+ end
41
+ end
2
42
 
3
43
  RSpec.configure do |config|
44
+ config.include GeneratorSetup, :generator
45
+
4
46
  config.before(:each, :generator) do
5
- fake_rails_root = File.expand_path("../../../tmp/dummy", __FILE__)
6
- allow(Rails).to receive(:root).and_return(Pathname.new(fake_rails_root))
47
+ FileUtils.rm_rf(GeneratorSetup::RAILS_ROOT) if File.exist?(GeneratorSetup::RAILS_ROOT)
48
+ FileUtils.mkdir_p(GeneratorSetup::RAILS_ROOT)
7
49
 
8
- destination fake_rails_root
9
- prepare_destination
50
+ allow(Rails).to receive(:root).and_return(Pathname.new(GeneratorSetup::RAILS_ROOT))
10
51
  end
11
52
  end
metadata CHANGED
@@ -1,11 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Teo Ljungberg
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
10
  date: 1980-01-01 00:00:00.000000000 Z
@@ -16,28 +15,40 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: '7.0'
18
+ version: '7.2'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '8.2'
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
23
25
  requirements:
24
26
  - - ">="
25
27
  - !ruby/object:Gem::Version
26
- version: '7.0'
28
+ version: '7.2'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '8.2'
27
32
  - !ruby/object:Gem::Dependency
28
33
  name: railties
29
34
  requirement: !ruby/object:Gem::Requirement
30
35
  requirements:
31
36
  - - ">="
32
37
  - !ruby/object:Gem::Version
33
- version: '7.0'
38
+ version: '7.2'
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '8.2'
34
42
  type: :runtime
35
43
  prerelease: false
36
44
  version_requirements: !ruby/object:Gem::Requirement
37
45
  requirements:
38
46
  - - ">="
39
47
  - !ruby/object:Gem::Version
40
- version: '7.0'
48
+ version: '7.2'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '8.2'
41
52
  description: |
42
53
  Adds methods to ActiveRecord::Migration to create and manage database functions
43
54
  and triggers in Rails
@@ -69,6 +80,7 @@ files:
69
80
  - lib/fx/adapters/postgres.rb
70
81
  - lib/fx/adapters/postgres/connection.rb
71
82
  - lib/fx/adapters/postgres/functions.rb
83
+ - lib/fx/adapters/postgres/query_executor.rb
72
84
  - lib/fx/adapters/postgres/triggers.rb
73
85
  - lib/fx/command_recorder.rb
74
86
  - lib/fx/configuration.rb
@@ -84,10 +96,13 @@ files:
84
96
  - lib/generators/fx/function/function_generator.rb
85
97
  - lib/generators/fx/function/templates/db/migrate/create_function.erb
86
98
  - lib/generators/fx/function/templates/db/migrate/update_function.erb
99
+ - lib/generators/fx/migration_helper.rb
100
+ - lib/generators/fx/name_helper.rb
87
101
  - lib/generators/fx/trigger/USAGE
88
102
  - lib/generators/fx/trigger/templates/db/migrate/create_trigger.erb
89
103
  - lib/generators/fx/trigger/templates/db/migrate/update_trigger.erb
90
104
  - lib/generators/fx/trigger/trigger_generator.rb
105
+ - lib/generators/fx/version_helper.rb
91
106
  - spec/acceptance/user_manages_functions_spec.rb
92
107
  - spec/acceptance/user_manages_triggers_spec.rb
93
108
  - spec/acceptance_helper.rb
@@ -107,6 +122,7 @@ files:
107
122
  - spec/features/triggers/migrations_spec.rb
108
123
  - spec/features/triggers/revert_spec.rb
109
124
  - spec/fx/adapters/postgres/functions_spec.rb
125
+ - spec/fx/adapters/postgres/query_executor_spec.rb
110
126
  - spec/fx/adapters/postgres/triggers_spec.rb
111
127
  - spec/fx/adapters/postgres_spec.rb
112
128
  - spec/fx/command_recorder_spec.rb
@@ -118,7 +134,10 @@ files:
118
134
  - spec/fx/trigger_spec.rb
119
135
  - spec/fx_spec.rb
120
136
  - spec/generators/fx/function/function_generator_spec.rb
137
+ - spec/generators/fx/migration_helper_spec.rb
138
+ - spec/generators/fx/name_helper_spec.rb
121
139
  - spec/generators/fx/trigger/trigger_generator_spec.rb
140
+ - spec/generators/fx/version_helper_spec.rb
122
141
  - spec/spec_helper.rb
123
142
  - spec/support/definition_helpers.rb
124
143
  - spec/support/generator_setup.rb
@@ -129,10 +148,9 @@ licenses:
129
148
  - MIT
130
149
  metadata:
131
150
  bug_tracker_uri: https://github.com/teoljungberg/fx/issues
132
- changelog_uri: https://github.com/teoljungberg/fx/blob/v0.9.0/CHANGELOG.md
151
+ changelog_uri: https://github.com/teoljungberg/fx/blob/v0.10.0/CHANGELOG.md
133
152
  homepage_uri: https://github.com/teoljungberg/fx
134
153
  source_code_uri: https://github.com/teoljungberg/fx
135
- post_install_message:
136
154
  rdoc_options: []
137
155
  require_paths:
138
156
  - lib
@@ -140,15 +158,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
140
158
  requirements:
141
159
  - - ">="
142
160
  - !ruby/object:Gem::Version
143
- version: '3.0'
161
+ version: '3.2'
144
162
  required_rubygems_version: !ruby/object:Gem::Requirement
145
163
  requirements:
146
164
  - - ">="
147
165
  - !ruby/object:Gem::Version
148
166
  version: '0'
149
167
  requirements: []
150
- rubygems_version: 3.5.9
151
- signing_key:
168
+ rubygems_version: 3.6.9
152
169
  specification_version: 4
153
170
  summary: Support for database functions and triggers in Rails migrations
154
171
  test_files: []