izolenta 0.0.3 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '09bc2895fc70a6c50727f81242f0f06e90c4492d3c1193ba4e1a1bffb83599ec'
4
- data.tar.gz: 14d8e61fbd7bb788b05054274418d14b55e18117fc5793d5f0b4a67af1e85a41
3
+ metadata.gz: fd520ce5cefeee28f6985c56bc36b29f102dfdb5972ee736d6cabd11928139b9
4
+ data.tar.gz: 8e3e5acc0b8d853e9f78a9a8b1bc25e3e08836c506e0787fdb465420700f81fd
5
5
  SHA512:
6
- metadata.gz: 1d3fdb8446cd4698487c397bb7c8de99cdf1a44b911d84ce218c76d46f4aa98adc922813abfbbb231ad612bb0430137a538555d4620f77e813e2ac19e39c2d56
7
- data.tar.gz: c9dc6ef925404436a15358c07a1c7a640f593a02f12fae1448b8b6429063c07629768e0f8f45dc78e44367ab482ade23bd53a5e5be926cf1f23d53910f13d62d
6
+ metadata.gz: d63396b28549ecde16b8e810c3c667c2a0245ee6fdce41cc9f1239abd5ebbad50e9b22a71780bf3b73ee7911bedd865e2d4f9315af6541ca226d5891b57f5dde
7
+ data.tar.gz: 8713a4d8039f843fe4d5eb9487a1dcf54146e83bc09564383a1673407034de28b3e1d6469b349dcf44ec23ca2f9b4a77b6d5d0dff23cc3828d87bd30fe25c9c6
data/.rubocop.yml ADDED
@@ -0,0 +1,92 @@
1
+ inherit_gem:
2
+ rubocop-shopify: rubocop.yml
3
+ #
4
+ #Style/SingleLineMethods:
5
+ # Description: 'Avoid single-line methods.'
6
+ # StyleGuide: '#no-single-line-methods'
7
+ # Enabled: false
8
+ # VersionAdded: '0.9'
9
+ # VersionChanged: '1.8'
10
+ # AllowIfMethodIsEmpty: true
11
+ #
12
+ #Style/AsciiComments:
13
+ # Description: 'Use only ascii symbols in comments.'
14
+ # StyleGuide: '#english-comments'
15
+ # Enabled: false
16
+ # VersionAdded: '0.9'
17
+ # VersionChanged: '1.21'
18
+ # AllowedChars:
19
+ # - ©
20
+ #
21
+ #Layout/LineLength:
22
+ # Description: 'Checks that line length does not exceed the configured limit.'
23
+ # StyleGuide: '#max-line-length'
24
+ # Enabled: true
25
+ # VersionAdded: '0.25'
26
+ # VersionChanged: '1.4'
27
+ # Max: 120
28
+ # # To make it possible to copy or click on URIs in the code, we allow lines
29
+ # # containing a URI to be longer than Max.
30
+ # AllowHeredoc: true
31
+ # AllowURI: true
32
+ # URISchemes:
33
+ # - http
34
+ # - https
35
+ # # The IgnoreCopDirectives option causes the LineLength rule to ignore cop
36
+ # # directives like '# rubocop: enable ...' when calculating a line's length.
37
+ # IgnoreCopDirectives: true
38
+ # # The AllowedPatterns option is a list of !ruby/regexp and/or string
39
+ # # elements. Strings will be converted to Regexp objects. A line that matches
40
+ # # any regular expression listed in this option will be ignored by LineLength.
41
+ # AllowedPatterns: []
42
+ # IgnoredPatterns: [] # deprecated
43
+ # Exclude:
44
+ # - "./test/**/**/*"
45
+ #
46
+ #Metrics/ClassLength:
47
+ # Description: 'Avoid classes longer than 100 lines of code.'
48
+ # Enabled: false
49
+ # VersionAdded: '0.25'
50
+ # VersionChanged: '0.87'
51
+ # CountComments: false # count full line comments?
52
+ # Max: 100
53
+ # CountAsOne: []
54
+ #
55
+ #Lint/MissingCopEnableDirective:
56
+ # Description: 'Checks for a `# rubocop:enable` after `# rubocop:disable`.'
57
+ # Enabled: true
58
+ # VersionAdded: '0.52'
59
+ # # Maximum number of consecutive lines the cop can be disabled for.
60
+ # # 0 allows only single-line disables
61
+ # # 1 would mean the maximum allowed is the following:
62
+ # # # rubocop:disable SomeCop
63
+ # # a = 1
64
+ # # # rubocop:enable SomeCop
65
+ # # .inf for any size
66
+ # MaximumRangeSize: .inf
67
+ #
68
+ #Style/MethodCallWithArgsParentheses:
69
+ # Enabled: true
70
+ # IgnoredMethods:
71
+ # - require
72
+ # - require_relative
73
+ # - require_dependency
74
+ # - yield
75
+ # - raise
76
+ # - puts
77
+ # Exclude:
78
+ # - "/**/Gemfile"
79
+ # - "./db/**/*"
80
+ #
81
+ #Layout/EmptyLinesAroundBlockBody:
82
+ # # its more documentation than code, so it should be readable and
83
+ # # there are huge amount of multiline description, looks nasty without spaces
84
+ # Exclude:
85
+ # - "./app_doc/**/*"
86
+ #
87
+ #Style/ClassAndModuleChildren:
88
+ # Enabled: false
89
+ #
90
+ #Lint/UnderscorePrefixedVariableName:
91
+ # Exclude:
92
+ # - "./test/**/**/*"
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
+ #0.0.6
2
+ - new ruby 3 image for ruby 3 testing
3
+ - fix get_new_column_type incompatibility with ruby
4
+
5
+ #0.0.5
6
+ - rubocop-shopify added to dev dependencies
7
+ - fixed ruby 3.0 incompatibility in delegate_uniqueness, now gem could be used with ruby 3+
8
+
9
+ #0.0.4
10
+ - removed 'OR REPLACE' in trigger definition, lowering Postgres version constraint
11
+ - trigger_condition added ( could replace partial uniq index )
12
+
1
13
  #0.0.3
2
14
  - wrapper_function options added, you can define function to convert to uniquely sortable types, for instance array to string
15
+ - moved all helper functions to internal module, just to keep things clear on the migrations
3
16
 
4
17
  #0.0.2
5
18
  - delegate_uniqueness helper is available as a migration method
data/Gemfile CHANGED
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  # Specify your gem's dependencies in izolenta.gemspec
4
6
  gemspec
5
7
 
6
- gem "rake", "~> 12.0"
7
8
  gem "minitest", "~> 5.0"
9
+ gem "rake", "~> 12.0"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- izolenta (0.0.2)
4
+ izolenta (0.0.5)
5
5
  pg
6
6
 
7
7
  GEM
@@ -18,18 +18,41 @@ GEM
18
18
  minitest (>= 5.1)
19
19
  tzinfo (~> 2.0)
20
20
  zeitwerk (~> 2.3)
21
+ ast (2.4.2)
21
22
  byebug (11.1.3)
22
23
  coderay (1.1.3)
23
24
  concurrent-ruby (1.1.9)
24
25
  i18n (1.8.11)
25
26
  concurrent-ruby (~> 1.0)
27
+ json (2.6.2)
26
28
  method_source (1.0.0)
27
29
  minitest (5.14.4)
28
- pg (1.2.3)
30
+ parallel (1.22.1)
31
+ parser (3.1.2.0)
32
+ ast (~> 2.4.1)
33
+ pg (1.4.1)
29
34
  pry (0.13.1)
30
35
  coderay (~> 1.1)
31
36
  method_source (~> 1.0)
37
+ rainbow (3.1.1)
32
38
  rake (12.3.3)
39
+ regexp_parser (2.5.0)
40
+ rexml (3.2.5)
41
+ rubocop (1.31.2)
42
+ json (~> 2.3)
43
+ parallel (~> 1.10)
44
+ parser (>= 3.1.0.0)
45
+ rainbow (>= 2.2.2, < 4.0)
46
+ regexp_parser (>= 1.8, < 3.0)
47
+ rexml (>= 3.2.5, < 4.0)
48
+ rubocop-ast (>= 1.18.0, < 2.0)
49
+ ruby-progressbar (~> 1.7)
50
+ unicode-display_width (>= 1.4.0, < 3.0)
51
+ rubocop-ast (1.18.0)
52
+ parser (>= 3.1.1.0)
53
+ rubocop-shopify (2.8.0)
54
+ rubocop (~> 1.31)
55
+ ruby-progressbar (1.11.0)
33
56
  ruby_jard (0.3.1)
34
57
  byebug (>= 9.1, < 12.0)
35
58
  pry (~> 0.13.0)
@@ -37,6 +60,7 @@ GEM
37
60
  tty-screen (0.8.1)
38
61
  tzinfo (2.0.4)
39
62
  concurrent-ruby (~> 1.0)
63
+ unicode-display_width (2.2.0)
40
64
  zeitwerk (2.5.1)
41
65
 
42
66
  PLATFORMS
@@ -47,6 +71,8 @@ DEPENDENCIES
47
71
  izolenta!
48
72
  minitest (~> 5.0)
49
73
  rake (~> 12.0)
74
+ rubocop
75
+ rubocop-shopify
50
76
  ruby_jard
51
77
 
52
78
  BUNDLED WITH
data/README.md CHANGED
@@ -46,6 +46,15 @@ class WithWrapperFunctionMigration < ActiveRecord::Migration[5.0]
46
46
  delegate_uniqueness( :your_table_name, :column_name, wrapper_function: 'type_conversion_function' )
47
47
  end
48
48
  end
49
+
50
+
51
+ class WithWrapperFunctionMigration < ActiveRecord::Migration[5.0]
52
+ # apply trigger condition for partial uniqueness
53
+ def change
54
+ delegate_uniqueness( :your_table_name, :column_name, trigger_condition: 'NEW.type IS NOT NULL' )
55
+ end
56
+ end
57
+
49
58
  ```
50
59
 
51
60
  ## Development
@@ -55,6 +64,9 @@ docker-compose build
55
64
 
56
65
  docker-compose run test /bin/bash
57
66
  > service postgresql start && rake test
67
+
68
+ docker-compose run test3 /bin/bash
69
+ > service postgresql start && rake test
58
70
  ```
59
71
 
60
72
  ## Future Features
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rake/testtask"
3
5
 
@@ -7,4 +9,4 @@ Rake::TestTask.new(:test) do |t|
7
9
  t.test_files = FileList["test/**/*_test.rb"]
8
10
  end
9
11
 
10
- task :default => :test
12
+ task default: :test
data/docker-compose.yml CHANGED
@@ -8,3 +8,11 @@ services:
8
8
  volumes:
9
9
  - '.:/app'
10
10
 
11
+ test3:
12
+ build:
13
+ context: .
14
+ dockerfile: ruby3.Dockerfile
15
+ image: izolenta3
16
+ command: service postgresql start && rake test
17
+ volumes:
18
+ - '.:/app'
data/izolenta.gemspec CHANGED
@@ -1,4 +1,6 @@
1
- require_relative 'lib/izolenta/version'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/izolenta/version"
2
4
 
3
5
  Gem::Specification.new do |spec|
4
6
  spec.name = "izolenta"
@@ -6,8 +8,8 @@ Gem::Specification.new do |spec|
6
8
  spec.authors = ["alekseyl"]
7
9
  spec.email = ["leshchuk@gmail.com"]
8
10
 
9
- spec.summary = %q{Migration helpers for delegated uniqueness in Postgres}
10
- spec.description = %q{Migration helpers for delegated uniqueness in Postgres}
11
+ spec.summary = "Migration helpers for delegated uniqueness in Postgres"
12
+ spec.description = "Migration helpers for delegated uniqueness in Postgres"
11
13
  spec.homepage = "https://github.com/alekseyl/izolenta"
12
14
  spec.license = "MIT"
13
15
  spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
@@ -20,14 +22,15 @@ Gem::Specification.new do |spec|
20
22
 
21
23
  # Specify which files should be added to the gem when it is released.
22
24
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ %x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
27
  end
26
28
  spec.bindir = "exe"
27
29
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
30
  spec.require_paths = ["lib"]
29
31
 
30
- spec.add_dependency "pg"
31
- spec.add_development_dependency "activerecord", ">= 5"
32
- spec.add_development_dependency "ruby_jard"
32
+ spec.add_dependency("pg")
33
+ spec.add_development_dependency("activerecord", ">= 5")
34
+ spec.add_development_dependency("rubocop-shopify")
35
+ spec.add_development_dependency("ruby_jard")
33
36
  end
@@ -1,71 +1,86 @@
1
- module Izolenta::ActiveRecordMigration
2
- # options:
3
- # wrapper_function: 'some_func' # some_func should be defined prior
4
- def delegate_uniqueness(origin_table, column, options = {})
5
- helper_table_name = "#{column}_#{origin_table}_uniqs"
1
+ # frozen_string_literal: true
6
2
 
7
- reversible do |dir|
8
- dir.up {
9
- Helpers.create_helper_table(helper_table_name, column, Helpers.get_new_column_type(origin_table, column, options))
10
- add_index( helper_table_name, column, unique: true )
3
+ if defined? ActiveRecord
4
+ module Izolenta
5
+ module ActiveRecordMigration
6
+ # options:
7
+ # wrapper_function: 'some_func' # some_func should be defined prior
8
+ def delegate_uniqueness(origin_table, column, **options)
9
+ helper_table_name = "#{column}_#{origin_table}_uniqs"
11
10
 
12
- Helpers.create_sync_trigger( origin_table, column, helper_table_name, options )
13
- }
11
+ reversible do |dir|
12
+ dir.up do
13
+ Helpers.create_helper_table(helper_table_name, column,
14
+ Helpers.get_new_column_type(origin_table, column, **options))
15
+ add_index(helper_table_name, column, unique: true)
14
16
 
15
- dir.down {
16
- drop_table( helper_table_name )
17
- Helpers.drop_sync_trigger( origin_table, column )
18
- }
19
- end
20
- end
17
+ Helpers.create_sync_trigger(origin_table, column, helper_table_name, options)
18
+ end
21
19
 
22
- module Helpers
23
- class << self
24
- def create_helper_table(helper_table, column_name, column_type )
25
- ActiveRecord::Base.connection.execute "CREATE TABLE #{helper_table} ( #{column_name} #{column_type} );"
20
+ dir.down do
21
+ drop_table(helper_table_name)
22
+ Helpers.drop_sync_trigger(origin_table, column)
23
+ end
24
+ end
26
25
  end
27
26
 
28
- def create_sync_trigger(table, column_name, helper_table_name, options )
29
- trg_name = "#{table}_#{column_name}_trg"
30
- insert_value = options[:wrapper_function] ? "#{options[:wrapper_function]}(NEW.#{column_name})"
31
- : "NEW.#{column_name}"
32
- ActiveRecord::Base.connection.execute <<~SYNC_TRIGGER
33
- CREATE OR REPLACE FUNCTION #{trg_name}() RETURNS trigger AS $$
34
- BEGIN
35
- INSERT INTO #{helper_table_name} VALUES ( #{insert_value} );
36
- RETURN NEW;
37
- END $$ LANGUAGE plpgSQL;
38
-
39
- CREATE OR REPLACE TRIGGER #{trg_name} BEFORE INSERT ON #{table} FOR EACH ROW
40
- EXECUTE FUNCTION #{trg_name}();
41
- SYNC_TRIGGER
42
- end
27
+ # helpers na
28
+ module Helpers
29
+ class << self
30
+ def create_helper_table(helper_table, column_name, column_type)
31
+ ActiveRecord::Base.connection.execute("CREATE TABLE #{helper_table} ( #{column_name} #{column_type} );")
32
+ end
43
33
 
44
- def drop_sync_trigger(table, column_name)
45
- trg_name = "#{table}_#{column_name}_trg"
34
+ def create_sync_trigger(table, column_name, helper_table_name, options)
35
+ trg_name = "#{table}_#{column_name}_trg"
36
+ insert_value = if options[:wrapper_function]
37
+ "#{options[:wrapper_function]}(NEW.#{column_name})"
38
+ else
39
+ "NEW.#{column_name}"
40
+ end
46
41
 
47
- ActiveRecord::Base.connection.execute <<~SYNC_TRIGGER
48
- DROP TRIGGER IF EXISTS #{trg_name} ON #{table};
49
- SYNC_TRIGGER
50
- end
42
+ trigger_condition = "WHEN( #{options[:trigger_condition]} )" if options[:trigger_condition]
51
43
 
52
- def get_new_column_type(origin_table, column, wrapper_function: nil)
53
- wrapper_function ? get_function_type(wrapper_function) : get_column_type(origin_table, column)
54
- end
44
+ ActiveRecord::Base.connection.execute(<<~SYNC_TRIGGER)
45
+ CREATE OR REPLACE FUNCTION #{trg_name}() RETURNS trigger AS $$
46
+ BEGIN#{" "}
47
+ INSERT INTO #{helper_table_name} VALUES ( #{insert_value} );
48
+ RETURN NEW;
49
+ END $$ LANGUAGE plpgSQL;
55
50
 
56
- def get_column_type(origin_table, column)
57
- ActiveRecord::Base.connection.schema_cache.columns_hash(origin_table.to_s)[column.to_s]&.sql_type
58
- end
51
+ CREATE TRIGGER #{trg_name} BEFORE INSERT ON #{table}#{" "}
52
+ FOR EACH ROW
53
+ #{trigger_condition}
54
+ EXECUTE FUNCTION #{trg_name}();
55
+ SYNC_TRIGGER
56
+ end
59
57
 
60
- def get_function_type(wrapper_function)
61
- ActiveRecord::Base
62
- .connection
63
- .execute("SELECT typname FROM pg_type WHERE oid=(SELECT prorettype FROM pg_proc WHERE proname ='#{wrapper_function}')")
64
- .first['typname']
58
+ def drop_sync_trigger(table, column_name)
59
+ trg_name = "#{table}_#{column_name}_trg"
60
+
61
+ ActiveRecord::Base.connection.execute(<<~SYNC_TRIGGER)
62
+ DROP TRIGGER IF EXISTS #{trg_name} ON #{table};
63
+ SYNC_TRIGGER
64
+ end
65
+
66
+ def get_new_column_type(origin_table, column, wrapper_function: nil, **)
67
+ wrapper_function ? get_function_type(wrapper_function) : get_column_type(origin_table, column)
68
+ end
69
+
70
+ def get_column_type(origin_table, column)
71
+ ActiveRecord::Base.connection.schema_cache.columns_hash(origin_table.to_s)[column.to_s]&.sql_type
72
+ end
73
+
74
+ def get_function_type(wrapper_function)
75
+ ActiveRecord::Base
76
+ .connection
77
+ .execute("SELECT typname FROM pg_type WHERE oid=(SELECT prorettype FROM pg_proc WHERE proname ='#{wrapper_function}')") # rubocop:disable Layout/LineLength
78
+ .first["typname"]
79
+ end
80
+ end
65
81
  end
66
82
  end
67
83
  end
84
+ end
68
85
 
69
- end if defined? ActiveRecord
70
-
71
- ActiveRecord::Migration.include(Izolenta::ActiveRecordMigration) if defined? ActiveRecord
86
+ ActiveRecord::Migration.include(Izolenta::ActiveRecordMigration) if defined? ActiveRecord
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Izolenta
2
- VERSION = "0.0.3"
4
+ VERSION = "0.0.6"
3
5
  end
data/lib/izolenta.rb CHANGED
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "izolenta/version"
2
- require 'izolenta/active_record_migration'
4
+ require "izolenta/active_record_migration"
3
5
 
4
6
  module Izolenta
5
7
  class Error < StandardError; end
data/ruby3.Dockerfile ADDED
@@ -0,0 +1,20 @@
1
+ FROM ruby:3-bullseye
2
+
3
+ WORKDIR /app
4
+ RUN apt-get update && apt-get -y install lsb-release
5
+ #
6
+ RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
7
+ sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' && \
8
+ apt-get update && apt-get -y install postgresql postgresql-client-12
9
+
10
+ RUN sh -c 'echo "local all all trust" > /etc/postgresql/14/main/pg_hba.conf' && \
11
+ service postgresql start && \
12
+ psql -U postgres -c 'CREATE DATABASE "izolenta-test"'
13
+
14
+ RUN gem install bundler
15
+
16
+ COPY lib/izolenta/version.rb /app/lib/izolenta/version.rb
17
+ COPY izolenta.gemspec /app/
18
+ COPY Gemfil* /app/
19
+ #
20
+ RUN bundle install
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: izolenta
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - alekseyl
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-24 00:00:00.000000000 Z
11
+ date: 2022-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop-shopify
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: ruby_jard
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -60,6 +74,7 @@ extensions: []
60
74
  extra_rdoc_files: []
61
75
  files:
62
76
  - ".gitignore"
77
+ - ".rubocop.yml"
63
78
  - ".ruby-gemset"
64
79
  - ".ruby-version"
65
80
  - ".travis.yml"
@@ -77,6 +92,7 @@ files:
77
92
  - lib/izolenta.rb
78
93
  - lib/izolenta/active_record_migration.rb
79
94
  - lib/izolenta/version.rb
95
+ - ruby3.Dockerfile
80
96
  homepage: https://github.com/alekseyl/izolenta
81
97
  licenses:
82
98
  - MIT