fx 0.10.0 → 0.10.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 817dff811b3dc0f946828957f9274117436ac97b273416cfdffdcf7bccf493fd
4
- data.tar.gz: 88d246804584933f266198d0edf384bfdd09eb0f6e7f57be5d4cbebcb8f7843e
3
+ metadata.gz: c58b9ff49b98b110220c15bb8e017038a237e2583b86a771a4fdad267fed316d
4
+ data.tar.gz: 4309eea32302e5828871134973269edeb532da5aa817639e4b8b9b466a7d8f1f
5
5
  SHA512:
6
- metadata.gz: f414bb7dc859d720dc4d9e4e5f48a37cb0745e63a03d109824c5d17230d1384f53eb013c122a675c17c78e8e9d8f4c71dbf944ec351b8ee8c3df0e406556e241
7
- data.tar.gz: d5caa370b2a0f132fd7aff53de631a2a836ba71ea8ac4c2eec79b73ea151d5df9615183855e3a2e0a4a608e45d8d43f2ea9c28ef66f53320ca6cc95ad2bdd215
6
+ metadata.gz: '09a4bc41360e92347b92bc9a3cadf3acd04cef9a87baaf549504c6667bf621053c0a156f00aea267b61505e1d14abee4993a1ce9b4acddea0a22c7bd926672fa'
7
+ data.tar.gz: 72883cf8649ac59df101613905842ac034ae8ecf5f7533474185ee15bda83e3e27c3373f790dbabd9209b06ec969ba7119aa2ea94590858a11cb9269d0c97b93
@@ -14,9 +14,8 @@ jobs:
14
14
  strategy:
15
15
  fail-fast: false
16
16
  matrix:
17
- ruby: ["3.2", "3.3", "3.4"]
18
- rails: ["7.2", "8.0", "8.1"]
19
- continue-on-error: [false]
17
+ ruby: ["3.2", "4.0"]
18
+ rails: ["7.2", "8.1"]
20
19
 
21
20
  services:
22
21
  postgres:
@@ -35,9 +34,10 @@ jobs:
35
34
 
36
35
  env:
37
36
  POSTGRES_USER: postgres
37
+ RAILS_VERSION: ${{ matrix.rails }}
38
38
 
39
39
  steps:
40
- - uses: actions/checkout@v3
40
+ - uses: actions/checkout@v6
41
41
 
42
42
  - name: Set up Ruby
43
43
  uses: ruby/setup-ruby@v1
data/CHANGELOG.md CHANGED
@@ -7,7 +7,23 @@ changelog, see the [commits] for each version via the version links.
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- [Unreleased]: https://github.com/teoljungberg/fx/compare/v0.10.0..HEAD
10
+ [Unreleased]: https://github.com/teoljungberg/fx/compare/v0.10.1..HEAD
11
+
12
+ ## [0.10.1]
13
+
14
+ [0.10.1]: https://github.com/teoljungberg/fx/compare/v0.10.0...v0.10.1
15
+
16
+ - Fix spacing between functions and triggers in schema.rb (#195)
17
+ - Remove `database_cleaner` dependency (#190)
18
+ - Internal refactorings / improvements
19
+ - Improve schema dumper test coverage
20
+ - Use methods over instance variables (#192)
21
+ - Write out fully qualified path in definitions (#189)
22
+ - Improve test isolation with schema reset (#190)
23
+ - Rewrite shell command chains (#188)
24
+ - Inline `active_record_migration_class` (#187)
25
+ - Add Ruby 4.0 to CI matrix (#193)
26
+ - Minimize CI matrix to boundary versions (#196)
11
27
 
12
28
  ## [0.10.0]
13
29
 
data/Gemfile CHANGED
@@ -1,9 +1,13 @@
1
1
  source "https://rubygems.org"
2
2
 
3
+ rails_version = ENV.fetch("RAILS_VERSION", "8.1")
4
+
3
5
  gemspec
4
6
 
7
+ gem "activerecord", "~> #{rails_version}.0"
8
+ gem "railties", "~> #{rails_version}.0"
9
+
5
10
  gem "bundler", ">= 1.5"
6
- gem "database_cleaner"
7
11
  gem "pg"
8
12
  gem "pry"
9
13
  gem "rake"
data/README.md CHANGED
@@ -114,6 +114,22 @@ column value instead of a plain string.
114
114
  - [Oracle](https://github.com/zygotecnologia/fx-oracle-adapter)
115
115
  - [SQLserver](https://github.com/tarellel/fx-sqlserver-adapter)
116
116
 
117
+ ## Version Support
118
+
119
+ F(x) follows the maintenance policies of Ruby and Rails, supporting versions
120
+ within their official maintenance windows.
121
+
122
+ **Ruby:** 3.2+ ([maintenance branches])
123
+
124
+ **Rails:** 7.2, 8.0, 8.1 ([maintenance policy])
125
+
126
+ When a Ruby or Rails version reaches end-of-life, support will be dropped in the
127
+ next minor release of F(x). Older versions may continue to work but are not
128
+ tested or guaranteed.
129
+
130
+ [maintenance branches]: https://www.ruby-lang.org/en/downloads/branches/
131
+ [maintenance policy]: https://rubyonrails.org/maintenance
132
+
117
133
  ## Contributing
118
134
 
119
135
  See [contributing](CONTRIBUTING.md) for more details.
@@ -30,7 +30,7 @@ module Fx
30
30
  #
31
31
  # @return [Array<Fx::Function>]
32
32
  def self.all(connection)
33
- QueryExecutor.call(
33
+ Fx::Adapters::Postgres::QueryExecutor.call(
34
34
  connection: connection,
35
35
  query: FUNCTIONS_WITH_DEFINITIONS_QUERY,
36
36
  model_class: Fx::Function
@@ -30,7 +30,7 @@ module Fx
30
30
  #
31
31
  # @return [Array<Fx::Trigger>]
32
32
  def self.all(connection)
33
- QueryExecutor.call(
33
+ Fx::Adapters::Postgres::QueryExecutor.call(
34
34
  connection: connection,
35
35
  query: TRIGGERS_WITH_DEFINITIONS_QUERY,
36
36
  model_class: Fx::Trigger
@@ -47,7 +47,7 @@ module Fx
47
47
  #
48
48
  # @return [Array<Fx::Function>]
49
49
  def functions
50
- Functions.all(connection)
50
+ Fx::Adapters::Postgres::Functions.all(connection)
51
51
  end
52
52
 
53
53
  # Returns an array of triggers in the database.
@@ -57,7 +57,7 @@ module Fx
57
57
  #
58
58
  # @return [Array<Fx::Trigger>]
59
59
  def triggers
60
- Triggers.all(connection)
60
+ Fx::Adapters::Postgres::Triggers.all(connection)
61
61
  end
62
62
 
63
63
  # Creates a function in the database.
@@ -152,7 +152,7 @@ module Fx
152
152
  delegate :execute, to: :connection
153
153
 
154
154
  def connection
155
- Connection.new(connectable.connection)
155
+ Fx::Adapters::Postgres::Connection.new(connectable.connection)
156
156
  end
157
157
  end
158
158
  end
@@ -68,7 +68,7 @@ module Fx
68
68
  end
69
69
 
70
70
  def function
71
- @args[0]
71
+ args[0]
72
72
  end
73
73
 
74
74
  def version
@@ -84,13 +84,15 @@ module Fx
84
84
  end
85
85
 
86
86
  def to_a
87
- @args.to_a
87
+ args.to_a
88
88
  end
89
89
 
90
90
  private
91
91
 
92
+ attr_reader :args
93
+
92
94
  def options
93
- @options ||= @args[1] || {}
95
+ @options ||= args[1] || {}
94
96
  end
95
97
 
96
98
  def options_for_revert
data/lib/fx/definition.rb CHANGED
@@ -14,13 +14,13 @@ module Fx
14
14
 
15
15
  def initialize(name:, version:, type:)
16
16
  @name = name
17
- @version = version.to_i
17
+ @version_number = version.to_i
18
18
  @type = type
19
19
  end
20
20
 
21
21
  def to_sql
22
22
  content = File.read(find_file || full_path)
23
- raise "Define #{@type} in #{path} before migrating." if content.empty?
23
+ raise "Define #{type} in #{path} before migrating." if content.empty?
24
24
 
25
25
  content
26
26
  end
@@ -30,17 +30,19 @@ module Fx
30
30
  end
31
31
 
32
32
  def path
33
- @_path ||= File.join("db", @type.pluralize, filename)
33
+ @_path ||= File.join("db", type.pluralize, filename)
34
34
  end
35
35
 
36
36
  def version
37
- @version.to_s.rjust(2, "0")
37
+ version_number.to_s.rjust(2, "0")
38
38
  end
39
39
 
40
40
  private
41
41
 
42
+ attr_reader :name, :version_number, :type
43
+
42
44
  def filename
43
- @_filename ||= "#{@name}_v#{version}.sql"
45
+ @_filename ||= "#{name}_v#{version}.sql"
44
46
  end
45
47
 
46
48
  def find_file
@@ -21,20 +21,16 @@ module Fx
21
21
  dumpable_functions_in_database = Fx.database.functions
22
22
 
23
23
  dumpable_functions_in_database.each do |function|
24
+ stream.puts
24
25
  stream.puts(function.to_schema)
25
26
  end
26
-
27
- stream.puts if dumpable_functions_in_database.any?
28
27
  end
29
28
 
30
29
  def triggers(stream)
31
30
  dumpable_triggers_in_database = Fx.database.triggers
32
31
 
33
- if dumpable_triggers_in_database.any?
34
- stream.puts
35
- end
36
-
37
32
  dumpable_triggers_in_database.each do |trigger|
33
+ stream.puts
38
34
  stream.puts(trigger.to_schema)
39
35
  end
40
36
  end
data/lib/fx/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Fx
2
2
  # @api private
3
- VERSION = "0.10.0"
3
+ VERSION = "0.10.1"
4
4
  end
data/lib/fx.rb CHANGED
@@ -28,7 +28,7 @@ module Fx
28
28
 
29
29
  # @return [Fx::Configuration] F(x)'s current configuration
30
30
  def self.configuration
31
- @_configuration ||= Configuration.new
31
+ @_configuration ||= Fx::Configuration.new
32
32
  end
33
33
 
34
34
  # Set F(x)'s configuration
@@ -71,12 +71,8 @@ module Fx
71
71
  end
72
72
  end
73
73
 
74
- def active_record_migration_class
75
- migration_helper.active_record_migration_class
76
- end
77
-
78
74
  def formatted_name
79
- NameHelper.format_for_migration(singular_name)
75
+ Fx::Generators::NameHelper.format_for_migration(singular_name)
80
76
  end
81
77
  end
82
78
 
@@ -1,4 +1,4 @@
1
- class <%= migration_class_name %> < <%= active_record_migration_class %>
1
+ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
2
  def change
3
3
  create_function <%= formatted_name %>
4
4
  end
@@ -1,4 +1,4 @@
1
- class <%= migration_class_name %> < <%= active_record_migration_class %>
1
+ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
2
  def change
3
3
  update_function <%= formatted_name %>, version: <%= version %>, revert_to_version: <%= previous_version %>
4
4
  end
@@ -10,14 +10,6 @@ module Fx
10
10
  !should_create_migration?
11
11
  end
12
12
 
13
- def active_record_migration_class
14
- if ActiveRecord::Migration.respond_to?(:current_version)
15
- "ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]"
16
- else
17
- "ActiveRecord::Migration"
18
- end
19
- end
20
-
21
13
  def update_migration_class_name(object_type:, class_name:, version:)
22
14
  "Update#{object_type.capitalize}#{class_name}ToVersion#{version}"
23
15
  end
@@ -1,4 +1,4 @@
1
- class <%= migration_class_name %> < <%= active_record_migration_class %>
1
+ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
2
  def change
3
3
  create_trigger <%= formatted_name %>, on: <%= formatted_table_name %>
4
4
  end
@@ -1,4 +1,4 @@
1
- class <%= migration_class_name %> < <%= active_record_migration_class %>
1
+ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
2
  def change
3
3
  update_trigger <%= formatted_name %>, on: <%= formatted_table_name %>, version: <%= version %>, revert_to_version: <%= previous_version %>
4
4
  end
@@ -65,16 +65,12 @@ module Fx
65
65
  end
66
66
  end
67
67
 
68
- def active_record_migration_class
69
- migration_helper.active_record_migration_class
70
- end
71
-
72
68
  def formatted_name
73
- NameHelper.format_for_migration(singular_name)
69
+ Fx::Generators::NameHelper.format_for_migration(singular_name)
74
70
  end
75
71
 
76
72
  def formatted_table_name
77
- NameHelper.format_table_name_from_hash(table_name)
73
+ Fx::Generators::NameHelper.format_table_name_from_hash(table_name)
78
74
  end
79
75
  end
80
76
 
@@ -5,32 +5,35 @@ ENV["RAILS_ENV"] = "test"
5
5
  RSpec.configure do |config|
6
6
  config.around(:each) do |example|
7
7
  Dir.chdir("spec/dummy") do
8
+ DatabaseReset.call
9
+
8
10
  example.run
11
+
12
+ DatabaseReset.call
9
13
  end
10
14
  end
11
15
 
12
16
  config.before(:suite) do
13
17
  Dir.chdir("spec/dummy") do
14
- system <<~CMD
15
- git init -b master 1>/dev/null &&
16
- git config user.email "fx@example.com" &&
17
- git config user.name "Fx" &&
18
- git add -A &&
19
- git commit --no-gpg-sign --message 'initial' 1>/dev/null
20
- CMD
18
+ system [
19
+ "git init -b master 1>/dev/null",
20
+ "git config user.email 'fx@example.com'",
21
+ "git config user.name 'Fx'",
22
+ "git add -A",
23
+ "git commit --no-gpg-sign --message 'initial' 1>/dev/null"
24
+ ].join(" && ")
21
25
  end
22
26
  end
23
27
 
24
28
  config.after(:suite) do
25
29
  Dir.chdir("spec/dummy") do
26
30
  ActiveRecord::Base.connection.disconnect!
27
- system <<~CMD
28
- echo &&
29
- rake db:environment:set db:drop db:create 1>/dev/null &&
30
- git add -A &&
31
- git reset --hard HEAD 1>/dev/null &&
32
- rm -rf .git/ 1>/dev/null
33
- CMD
31
+ DatabaseReset.call
32
+ system [
33
+ "git add -A",
34
+ "git reset --hard HEAD 1>/dev/null",
35
+ "rm -rf .git/ 1>/dev/null"
36
+ ].join(" && ")
34
37
  end
35
38
  end
36
39
 
@@ -12,10 +12,6 @@ module Dummy
12
12
  config.eager_load = false
13
13
  config.active_support.deprecation = :stderr
14
14
 
15
- config.load_defaults 7.0
16
-
17
- if Rails.version >= "8.0"
18
- config.active_support.to_time_preserves_timezone = :zone
19
- end
15
+ config.load_defaults 7.2
20
16
  end
21
17
  end
@@ -155,10 +155,82 @@ RSpec.describe Fx::SchemaDumper, :db do
155
155
  expect(output.scan("create_trigger :test_public_trigger").size).to eq(1)
156
156
  expect(output.scan("create_function :test_schema_func").size).to eq(1)
157
157
  expect(output.scan("create_trigger :test_schema_trigger").size).to eq(1)
158
-
158
+ ensure
159
159
  connection.schema_search_path = "public"
160
160
  end
161
161
 
162
+ it "puts a blank line before each function and trigger" do
163
+ connection.create_table :users do |t|
164
+ t.string :name
165
+ t.string :upper_name
166
+ t.string :down_name
167
+ end
168
+ Fx.database.create_function <<~SQL
169
+ CREATE OR REPLACE FUNCTION uppercase_users_name()
170
+ RETURNS trigger AS $$
171
+ BEGIN
172
+ NEW.upper_name = UPPER(NEW.name);
173
+ RETURN NEW;
174
+ END;
175
+ $$ LANGUAGE plpgsql;
176
+ SQL
177
+ sql_definition = <<~SQL
178
+ CREATE TRIGGER uppercase_users_name
179
+ BEFORE INSERT ON users
180
+ FOR EACH ROW
181
+ EXECUTE FUNCTION uppercase_users_name();
182
+ SQL
183
+ connection.create_trigger(
184
+ :uppercase_users_name,
185
+ sql_definition: sql_definition
186
+ )
187
+ Fx.database.create_function <<~SQL
188
+ CREATE OR REPLACE FUNCTION downcase_users_name()
189
+ RETURNS trigger AS $$
190
+ BEGIN
191
+ NEW.down_name = LOWER(NEW.name);
192
+ RETURN NEW;
193
+ END;
194
+ $$ LANGUAGE plpgsql;
195
+ SQL
196
+ sql_definition = <<~SQL
197
+ CREATE TRIGGER downcase_users_name
198
+ BEFORE INSERT ON users
199
+ FOR EACH ROW
200
+ EXECUTE FUNCTION downcase_users_name();
201
+ SQL
202
+ connection.create_trigger(
203
+ :downcase_users_name,
204
+ sql_definition: sql_definition
205
+ )
206
+ stream = StringIO.new
207
+ output = stream.string
208
+
209
+ dump(connection: connection, stream: stream)
210
+
211
+ pattern = /(end|SQL)\n\n (create_function|create_trigger)/
212
+ # a blank line between:
213
+ # - the table and the uppercase_users_name function,
214
+ # - the uppercase_users_name function and the downcase_users_name function,
215
+ # - the downcase_users_name function and the uppercase_users_name trigger,
216
+ # - the uppercase_users_name trigger and the downcase_users_name trigger,
217
+ expect(output.scan(pattern).size).to eq(4)
218
+ end
219
+
220
+ it "does not add blank lines when there are no functions or triggers" do
221
+ connection.create_table :users do |t|
222
+ t.string :name
223
+ end
224
+ stream = StringIO.new
225
+ output = stream.string
226
+
227
+ dump(connection: connection, stream: stream)
228
+
229
+ expect(output).not_to match(/create_function/)
230
+ expect(output).not_to match(/create_trigger/)
231
+ expect(output).not_to match(/end\n\n\nend/)
232
+ end
233
+
162
234
  def dump(connection:, stream:)
163
235
  if Rails.version >= "7.2"
164
236
  ActiveRecord::SchemaDumper.dump(connection.pool, stream)
@@ -16,31 +16,6 @@ RSpec.describe Fx::Generators::MigrationHelper do
16
16
  end
17
17
  end
18
18
 
19
- describe "#active_record_migration_class" do
20
- it "returns versioned migration class when current_version is available" do
21
- allow(ActiveRecord::Migration).to receive(:current_version)
22
- .and_return(7.0)
23
-
24
- helper = described_class.new({})
25
-
26
- expect(helper.active_record_migration_class).to eq(
27
- "ActiveRecord::Migration[7.0]"
28
- )
29
- end
30
-
31
- it "returns base migration class when current_version is not available" do
32
- allow(ActiveRecord::Migration).to receive(:respond_to?)
33
- .with(:current_version)
34
- .and_return(false)
35
-
36
- helper = described_class.new({})
37
-
38
- expect(helper.active_record_migration_class).to eq(
39
- "ActiveRecord::Migration"
40
- )
41
- end
42
- end
43
-
44
19
  describe "#update_migration_class_name" do
45
20
  it "generates correct class name for functions" do
46
21
  helper = described_class.new({})
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  ENV["RAILS_ENV"] = "test"
2
- require "database_cleaner"
3
2
 
4
3
  require File.expand_path("../dummy/config/environment", __FILE__)
5
4
  Dir["spec/support/**/*.rb"].sort.each { |file| load file }
@@ -11,14 +10,20 @@ RSpec.configure do |config|
11
10
  config.order = "random"
12
11
  config.disable_monkey_patching!
13
12
 
14
- DatabaseCleaner.strategy = :transaction
13
+ config.define_derived_metadata(file_path: %r{spec/(fx|features)/}) do |metadata|
14
+ metadata[:db] = true
15
+ end
16
+
17
+ config.before(:suite) do
18
+ DatabaseReset.call
19
+ end
15
20
 
16
21
  config.around(:each, db: true) do |example|
17
- ActiveRecord::Base.connection.execute("SET search_path TO DEFAULT;")
22
+ DatabaseReset.call
18
23
 
19
- DatabaseCleaner.start
20
24
  example.run
21
- DatabaseCleaner.clean
25
+
26
+ DatabaseReset.call
22
27
  end
23
28
 
24
29
  unless defined?(silence_stream)
@@ -0,0 +1,24 @@
1
+ module DatabaseReset
2
+ def self.call
3
+ connection = ActiveRecord::Base.connection
4
+ connection.execute("SET search_path TO DEFAULT;")
5
+
6
+ connection.execute <<~SQL
7
+ DO $$
8
+ DECLARE
9
+ schema_name TEXT;
10
+ BEGIN
11
+ FOR schema_name IN
12
+ SELECT nspname FROM pg_namespace
13
+ WHERE nspname NOT LIKE 'pg_%'
14
+ AND nspname != 'information_schema'
15
+ LOOP
16
+ EXECUTE format('DROP SCHEMA IF EXISTS %I CASCADE', schema_name);
17
+ END LOOP;
18
+ END $$;
19
+ SQL
20
+
21
+ connection.execute("CREATE SCHEMA public;")
22
+ connection.schema_search_path = "public"
23
+ end
24
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Teo Ljungberg
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 1980-01-01 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activerecord
@@ -139,6 +139,7 @@ files:
139
139
  - spec/generators/fx/trigger/trigger_generator_spec.rb
140
140
  - spec/generators/fx/version_helper_spec.rb
141
141
  - spec/spec_helper.rb
142
+ - spec/support/database_reset.rb
142
143
  - spec/support/definition_helpers.rb
143
144
  - spec/support/generator_setup.rb
144
145
  - spec/support/migration_helpers.rb
@@ -148,7 +149,7 @@ licenses:
148
149
  - MIT
149
150
  metadata:
150
151
  bug_tracker_uri: https://github.com/teoljungberg/fx/issues
151
- changelog_uri: https://github.com/teoljungberg/fx/blob/v0.10.0/CHANGELOG.md
152
+ changelog_uri: https://github.com/teoljungberg/fx/blob/v0.10.1/CHANGELOG.md
152
153
  homepage_uri: https://github.com/teoljungberg/fx
153
154
  source_code_uri: https://github.com/teoljungberg/fx
154
155
  rdoc_options: []
@@ -165,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
166
  - !ruby/object:Gem::Version
166
167
  version: '0'
167
168
  requirements: []
168
- rubygems_version: 3.6.9
169
+ rubygems_version: 4.0.6
169
170
  specification_version: 4
170
171
  summary: Support for database functions and triggers in Rails migrations
171
172
  test_files: []