sql_enum 0.2.2 → 0.3.0

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: dd16ecd7dbef436bf1613fa7b841e3575db7528778cee563fcb7128ae48ed24b
4
- data.tar.gz: 474745a0a9090a1e9203493c6f4864a69fb07f622ece22e3db432142ef2de953
3
+ metadata.gz: 7ba5a5a0695bc9c11496ca90509646d98e2e005e7c89664aba78acb1de45d270
4
+ data.tar.gz: 1cb90fe77fcc9b7e2d84c0fe9b9b41ddee264de6e488d5de8dbc9462371a8ecd
5
5
  SHA512:
6
- metadata.gz: 62b096819785f82af237b66cfe9cab150037e229796dda1e760f52e91140a8bcae092126e5bac5b0f51ea72cd25abad51ee9ad8f68b5ceb70b39682e18e367ce
7
- data.tar.gz: 2c702f4de99f2c50513ae2b1cbcf17a349601d63b7e59a09750488358bca93632219924f444270a33befee9a28153970e0d129e1d20f62d30dc94ac028359d46
6
+ metadata.gz: 795a28c30fc3fddb87865fc82325243c67a009694c409ffe880dace43c0d601cdcc32b4d9806a9d9c3220616dcc82be9b0e57ca8ccb3bb14c2d6562457c588a5
7
+ data.tar.gz: 67835417b809b63b7d97deb3531d059f3df63d1450406b0216cb81540a7276c691635126da7afdbf1dcf87fb128f7fe63cc8e196073fac55254e321ca1b66b58
data/.env ADDED
@@ -0,0 +1,3 @@
1
+ MYSQL_DATABASE=sql_enum_test
2
+ MYSQL_USER=sql_enum
3
+ MYSQL_PASSWORD=sql_enum
@@ -0,0 +1,16 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+
8
+ jobs:
9
+ rspec:
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - uses: actions/checkout@v2
14
+
15
+ - name: Test
16
+ run: docker-compose run --rm rspec
data/Dockerfile ADDED
@@ -0,0 +1,12 @@
1
+ FROM ruby:3.0
2
+
3
+ # throw errors if Gemfile has been modified since Gemfile.lock
4
+ RUN bundle config --global frozen 1
5
+
6
+ WORKDIR /usr/src/app
7
+
8
+ # Bundler caching
9
+ RUN mkdir -p lib/sql_enum
10
+ COPY lib/sql_enum/version.rb ./lib/sql_enum/
11
+ COPY sql_enum.gemspec Gemfile Gemfile.lock ./
12
+ RUN bundle install
data/Gemfile.lock CHANGED
@@ -1,28 +1,31 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sql_enum (0.2.2)
4
+ sql_enum (0.3.0)
5
5
  activerecord (>= 5.0)
6
+ activesupport (>= 5.0)
7
+ mysql2
6
8
 
7
9
  GEM
8
10
  remote: https://gem-proxy.chime.com/
9
11
  specs:
10
- activemodel (6.1.3.2)
11
- activesupport (= 6.1.3.2)
12
- activerecord (6.1.3.2)
13
- activemodel (= 6.1.3.2)
14
- activesupport (= 6.1.3.2)
15
- activesupport (6.1.3.2)
12
+ activemodel (6.1.4.1)
13
+ activesupport (= 6.1.4.1)
14
+ activerecord (6.1.4.1)
15
+ activemodel (= 6.1.4.1)
16
+ activesupport (= 6.1.4.1)
17
+ activesupport (6.1.4.1)
16
18
  concurrent-ruby (~> 1.0, >= 1.0.2)
17
19
  i18n (>= 1.6, < 2)
18
20
  minitest (>= 5.1)
19
21
  tzinfo (~> 2.0)
20
22
  zeitwerk (~> 2.3)
21
- concurrent-ruby (1.1.8)
23
+ concurrent-ruby (1.1.9)
22
24
  diff-lcs (1.3)
23
25
  i18n (1.8.10)
24
26
  concurrent-ruby (~> 1.0)
25
27
  minitest (5.14.4)
28
+ mysql2 (0.5.3)
26
29
  rake (13.0.3)
27
30
  rspec (3.7.0)
28
31
  rspec-core (~> 3.7.0)
@@ -39,16 +42,16 @@ GEM
39
42
  rspec-support (3.7.1)
40
43
  tzinfo (2.0.4)
41
44
  concurrent-ruby (~> 1.0)
42
- zeitwerk (2.4.2)
45
+ zeitwerk (2.5.1)
43
46
 
44
47
  PLATFORMS
45
48
  ruby
46
49
 
47
50
  DEPENDENCIES
48
- bundler (~> 1.16)
51
+ bundler
49
52
  rake (~> 13.0)
50
53
  rspec (~> 3.0)
51
54
  sql_enum!
52
55
 
53
56
  BUNDLED WITH
54
- 1.17.3
57
+ 2.2.30
data/README.md CHANGED
@@ -48,9 +48,11 @@ class User < ActiveRecord::Base
48
48
  end
49
49
  ```
50
50
 
51
- ## TODO
51
+ ## Development
52
52
 
53
- * Enable passing `null` argument
53
+ ### Testing
54
+
55
+ Run `docker-compose run --rm rspec` to run the specs in a docker container alongside Mysql.
54
56
 
55
57
  ## Contributing
56
58
 
@@ -0,0 +1,23 @@
1
+ services:
2
+ rspec:
3
+ build: .
4
+ environment:
5
+ DATABASE_URL: "mysql2://${MYSQL_USER}:${MYSQL_PASSWORD}@mysql/${MYSQL_DATABASE}"
6
+ volumes:
7
+ - ./:/usr/src/app/
8
+ depends_on:
9
+ mysql:
10
+ condition: service_healthy
11
+ command: bundle exec rspec
12
+
13
+ mysql:
14
+ image: mysql:5.7
15
+ environment:
16
+ - MYSQL_ALLOW_EMPTY_PASSWORD=yes
17
+ - MYSQL_DATABASE
18
+ - MYSQL_USER
19
+ - MYSQL_PASSWORD
20
+ healthcheck:
21
+ test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
22
+ timeout: 20s
23
+ retries: 10
@@ -0,0 +1,3 @@
1
+ ActiveSupport.on_load(:active_record) do
2
+ extend SqlEnum::ClassMethods
3
+ end
@@ -0,0 +1,21 @@
1
+ module SqlEnum
2
+ module ClassMethods
3
+ def sql_enum(column_name, options = {})
4
+ # Query values
5
+ enum_column = EnumColumn.new(table_name, column_name)
6
+ values = enum_column.values.to_h { |value| [value.to_sym, value.to_s] }
7
+
8
+ # Check option defaults
9
+ prefix = options.fetch(:_prefix, !!SqlEnum.configuration&.default_prefix)
10
+ suffix = options.fetch(:_suffix, !!SqlEnum.configuration&.default_suffix)
11
+
12
+ # Define enum using Rails enum
13
+ enum(column_name => values, _prefix: prefix, _suffix: suffix)
14
+
15
+ # Override reader to return symbols
16
+ concerning "SqlEnum#{column_name.to_s.camelize}" do
17
+ define_method(column_name) { super()&.to_sym }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module SqlEnum
2
+ class Configuration
3
+ attr_accessor :default_prefix, :default_suffix
4
+
5
+ def initialize
6
+ @default_prefix = false
7
+ @default_suffix = false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SqlEnum
4
+ EnumColumn = Struct.new(:table_name, :column_name) do
5
+ def values
6
+ schema_values.to_s.scan(/\w+/).reject { |v| v == 'enum' }
7
+ end
8
+
9
+ private
10
+
11
+ def schema_values
12
+ ActiveRecord::Base.connection.exec_query(schema_values_query).rows.dig(0, 0)
13
+ end
14
+
15
+ def database_name
16
+ if ActiveRecord::Base.respond_to?(:connection_db_config)
17
+ ActiveRecord::Base.connection_db_config.configuration_hash[:database]
18
+ else
19
+ ActiveRecord::Base.connection_config.values_at(:database, :database_name).find(&:present?)
20
+ end
21
+ end
22
+
23
+ def schema_values_query
24
+ <<~EOSQL
25
+ SELECT column_type
26
+ FROM information_schema.COLUMNS
27
+ WHERE TABLE_SCHEMA = '#{database_name}'
28
+ AND TABLE_NAME = '#{table_name}'
29
+ AND COLUMN_NAME = '#{column_name}'
30
+ EOSQL
31
+ end
32
+ end
33
+ end
@@ -1,3 +1,3 @@
1
1
  module SqlEnum
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/sql_enum.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'active_record'
2
-
3
1
  module SqlEnum
4
2
  class << self
5
3
  attr_accessor :configuration
@@ -9,22 +7,18 @@ module SqlEnum
9
7
  self.configuration ||= Configuration.new
10
8
  yield(configuration)
11
9
  end
12
-
13
- class Configuration
14
- attr_accessor :default_prefix, :default_suffix
15
-
16
- def initialize
17
- @default_prefix = false
18
- @default_suffix = false
19
- end
20
- end
21
10
  end
22
11
 
23
- require_relative 'active_record/enum/enum_type'
12
+ require 'active_record'
13
+ require 'active_support/core_ext/module/concerning'
14
+
24
15
  require_relative 'active_record/type/enum'
25
- require_relative 'active_record/enum_override'
26
- require_relative 'active_record/fixtures_override'
27
16
  require_relative 'active_record/connection_adapters/mysql2'
28
17
  require_relative 'active_record/connection_adapters/abstract_mysql'
29
18
  require_relative 'active_record/connection_adapters/mysql/column_methods'
30
- require_relative "sql_enum/version"
19
+
20
+ require_relative 'sql_enum/version'
21
+ require_relative 'sql_enum/configuration'
22
+ require_relative 'sql_enum/enum_column'
23
+ require_relative 'sql_enum/class_methods'
24
+ require_relative 'sql_enum/active_record'
data/sql_enum.gemspec CHANGED
@@ -1,6 +1,6 @@
1
-
2
1
  lib = File.expand_path("../lib", __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
4
  require "sql_enum/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
@@ -20,8 +20,11 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ["lib"]
22
22
 
23
+ spec.add_dependency "activesupport", ">= 5.0"
23
24
  spec.add_dependency "activerecord", ">= 5.0"
24
- spec.add_development_dependency "bundler", "~> 1.16"
25
+ spec.add_dependency "mysql2"
26
+
27
+ spec.add_development_dependency "bundler"
25
28
  spec.add_development_dependency "rake", "~> 13.0"
26
29
  spec.add_development_dependency "rspec", "~> 3.0"
27
30
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sql_enum
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fletcher Fowler
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-13 00:00:00.000000000 Z
11
+ date: 2021-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: activerecord
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -24,20 +38,34 @@ dependencies:
24
38
  - - ">="
25
39
  - !ruby/object:Gem::Version
26
40
  version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mysql2
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: bundler
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
- - - "~>"
59
+ - - ">="
32
60
  - !ruby/object:Gem::Version
33
- version: '1.16'
61
+ version: '0'
34
62
  type: :development
35
63
  prerelease: false
36
64
  version_requirements: !ruby/object:Gem::Requirement
37
65
  requirements:
38
- - - "~>"
66
+ - - ">="
39
67
  - !ruby/object:Gem::Version
40
- version: '1.16'
68
+ version: '0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: rake
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -73,10 +101,13 @@ executables: []
73
101
  extensions: []
74
102
  extra_rdoc_files: []
75
103
  files:
104
+ - ".env"
105
+ - ".github/workflows/tests.yml"
76
106
  - ".gitignore"
77
107
  - ".rspec"
78
108
  - ".travis.yml"
79
109
  - CODE_OF_CONDUCT.md
110
+ - Dockerfile
80
111
  - Gemfile
81
112
  - Gemfile.lock
82
113
  - LICENSE.txt
@@ -84,14 +115,16 @@ files:
84
115
  - Rakefile
85
116
  - bin/console
86
117
  - bin/setup
118
+ - docker-compose.yml
87
119
  - lib/active_record/connection_adapters/abstract_mysql.rb
88
120
  - lib/active_record/connection_adapters/mysql/column_methods.rb
89
121
  - lib/active_record/connection_adapters/mysql2.rb
90
- - lib/active_record/enum/enum_type.rb
91
- - lib/active_record/enum_override.rb
92
- - lib/active_record/fixtures_override.rb
93
122
  - lib/active_record/type/enum.rb
94
123
  - lib/sql_enum.rb
124
+ - lib/sql_enum/active_record.rb
125
+ - lib/sql_enum/class_methods.rb
126
+ - lib/sql_enum/configuration.rb
127
+ - lib/sql_enum/enum_column.rb
95
128
  - lib/sql_enum/version.rb
96
129
  - sql_enum.gemspec
97
130
  homepage: https://github.com/1debit/sql_enum
@@ -113,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
146
  - !ruby/object:Gem::Version
114
147
  version: '0'
115
148
  requirements: []
116
- rubygems_version: 3.1.6
149
+ rubygems_version: 3.2.22
117
150
  signing_key:
118
151
  specification_version: 4
119
152
  summary: Enable using native sql enums
@@ -1,41 +0,0 @@
1
- module ActiveRecord
2
- module Enum
3
- class EnumType < Type::Value # :nodoc:
4
- delegate :type, to: :subtype
5
-
6
- def initialize(name, mapping, subtype)
7
- @name = name
8
- @mapping = mapping
9
- @subtype = subtype
10
- end
11
-
12
- def cast(value)
13
- return if value.blank?
14
-
15
- if valid?(value)
16
- value.to_sym
17
- else
18
- assert_valid_value(value)
19
- end
20
- end
21
-
22
- def deserialize(value)
23
- value&.to_sym
24
- end
25
-
26
- def serialize(value)
27
- value ? value.to_s : nil
28
- end
29
-
30
- def valid?(value)
31
- mapping.include?(value.to_s)
32
- end
33
-
34
- def assert_valid_value(value)
35
- unless value.blank? || valid?(value)
36
- raise ArgumentError, "'#{value}' is not a valid #{name}"
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,86 +0,0 @@
1
- require 'active_record/enum'
2
-
3
- module ActiveRecord
4
- module Enum
5
- def sql_enum(name, options={})
6
- enum_prefix = options.delete(:_prefix)
7
- enum_suffix = options.delete(:_suffix)
8
-
9
- enum_prefix ||= name if SqlEnum.configuration&.default_prefix
10
- enum_suffix ||= name if SqlEnum.configuration&.default_suffix
11
-
12
- klass = self
13
- enum_values = Array.new
14
- name = name.to_sym
15
-
16
- detect_enum_conflict!(name, name.to_s.pluralize, true)
17
- klass.singleton_class.send(:define_method, name.to_s.pluralize) { enum_values.map(&:to_sym) }
18
-
19
- detect_enum_conflict!(name, name)
20
- detect_enum_conflict!(name, "#{name}=")
21
-
22
- attr = attribute_alias?(name) ? attribute_alias(name) : name
23
-
24
- if Rails.version >= '6.1'
25
- decorate_attribute_type(name) do |subtype|
26
- EnumType.new(attr, enum_values, subtype)
27
- end
28
- else
29
- decorate_attribute_type(attr, :enum) do |subtype|
30
- EnumType.new(attr, enum_values, subtype)
31
- end
32
- end
33
-
34
- enum_values = values(name)
35
- enum_values.each do |value|
36
- if enum_prefix == true
37
- prefix = "#{name}_"
38
- elsif enum_prefix
39
- prefix = "#{enum_prefix}_"
40
- end
41
- if enum_suffix == true
42
- suffix = "_#{name}"
43
- elsif enum_suffix
44
- suffix = "_#{enum_suffix}"
45
- end
46
-
47
- value_method_name = "#{prefix}#{value}#{suffix}"
48
-
49
- # def active?() status == 0 end
50
- klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
51
- define_method("#{value_method_name}?") { self[attr] == value.to_sym }
52
-
53
- # def active!() update! status: :active end
54
- klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
55
- define_method("#{value_method_name}!") { update!(attr => value) }
56
-
57
- # scope :active, -> { where status: 0 }
58
- klass.send(:detect_enum_conflict!, name, value_method_name, true)
59
- klass.scope value_method_name, -> { where(attr => value) }
60
- end
61
- defined_enums[name.to_s] = enum_values
62
- end
63
-
64
- def values(name)
65
- schema_values(name).to_s.scan(/\w+/).reject{|v| v == 'enum'}
66
- end
67
-
68
- def schema_values(name)
69
- ActiveRecord::Base.connection.exec_query(schema_values_query(name)).rows.dig(0,0)
70
- end
71
-
72
- def database_name
73
- ActiveRecord::Base.connection_config[:database]
74
- end
75
-
76
- def schema_values_query(name)
77
- %{
78
- SELECT column_type
79
- FROM information_schema.COLUMNS
80
- WHERE TABLE_SCHEMA = '#{database_name}'
81
- AND TABLE_NAME = '#{table_name}'
82
- AND COLUMN_NAME = '#{name}'
83
- }
84
- end
85
- end
86
- end
@@ -1,79 +0,0 @@
1
- require 'active_record/fixtures'
2
-
3
- module ActiveRecord
4
- class FixtureSet
5
- def table_rows
6
- now = config.default_timezone == :utc ? Time.now.utc : Time.now
7
-
8
- # allow a standard key to be used for doing defaults in YAML
9
- fixtures.delete('DEFAULTS')
10
-
11
- # track any join tables we need to insert later
12
- rows = Hash.new { |h,table| h[table] = [] }
13
-
14
- rows[table_name] = fixtures.map do |label, fixture|
15
- row = fixture.to_hash
16
-
17
- if model_class
18
- # fill in timestamp columns if they aren't specified and the model is set to record_timestamps
19
- if model_class.record_timestamps
20
- timestamp_column_names.each do |c_name|
21
- row[c_name] = now unless row.key?(c_name)
22
- end
23
- end
24
-
25
- # interpolate the fixture label
26
- row.each do |key, value|
27
- row[key] = value.gsub("$LABEL", label.to_s) if value.is_a?(String)
28
- end
29
-
30
- # generate a primary key if necessary
31
- if has_primary_key_column? && !row.include?(primary_key_name)
32
- row[primary_key_name] = ActiveRecord::FixtureSet.identify(label, primary_key_type)
33
- end
34
-
35
- # Resolve enums
36
- # model_class.defined_enums.each do |name, values|
37
- # if row.include?(name)
38
- # row[name] = values.fetch(row[name], row[name])
39
- # end
40
- # end
41
-
42
- # If STI is used, find the correct subclass for association reflection
43
- reflection_class =
44
- if row.include?(inheritance_column_name)
45
- row[inheritance_column_name].constantize rescue model_class
46
- else
47
- model_class
48
- end
49
-
50
- reflection_class._reflections.each_value do |association|
51
- case association.macro
52
- when :belongs_to
53
- # Do not replace association name with association foreign key if they are named the same
54
- fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
55
-
56
- if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
57
- if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
58
- # support polymorphic belongs_to as "label (Type)"
59
- row[association.foreign_type] = $1
60
- end
61
-
62
- fk_type = reflection_class.type_for_attribute(fk_name).type
63
- row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
64
- end
65
- when :has_many
66
- if association.options[:through]
67
- add_join_records(rows, row, HasManyThroughProxy.new(association))
68
- end
69
- end
70
- end
71
- end
72
-
73
- row
74
- end
75
- rows
76
- end
77
- end
78
- end
79
-