stairwell 0.2.0 → 0.5.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: 9c4e331d0e1037b7e3a1e52cc0390bf84797e4898fa4d978e73a99454b81f37f
4
- data.tar.gz: b58a61a030aa209e8b04511011a6dc1319d984d7347c5fdd23b581669a6220f2
3
+ metadata.gz: a9eb7f5f503d74ee340bc8e9011dcf587604c20d6fd959a5b006def17769b71a
4
+ data.tar.gz: 6bcbbc5866685ef8d767428a33b5862b58952a849e37237f869622ba720806d0
5
5
  SHA512:
6
- metadata.gz: cc90cda2b768f201a94b04241b3f09bb555433e18ddfc8781ceb33f5a88ec641a1ad602f69f17c4da55b425757bfcb12115f95ec09c512ec999691f80ca688a0
7
- data.tar.gz: 80c07a75ad1970ca578374a48757990edd1e1d19f37b97fb1bae8ceba3c236e629a7c4ba8ae5b03d44d4837835a49c2ce875851576d09d22f005c07f5a329e97
6
+ metadata.gz: fc068d002df5eddc9026ae6ce34c786697712c2b475255fdcf5e0a0e8eaedbe9b3dc138f505ca6328342cc2e7a99648fd78087ae26b6946a481ddaefec35d943
7
+ data.tar.gz: 8d9b86448fe37776e4aef1c4a7620946af302f016516c06fe931975e6d00b9128ee1ce2d087567850bc384ff0fa147fbbf82a93cb6a2e94de9daf09918e009c4
data/.bin/bundle ADDED
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "rubygems"
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($0) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV["BUNDLER_VERSION"]
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
+ bundler_version = nil
28
+ update_index = nil
29
+ ARGV.each_with_index do |a, i|
30
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31
+ bundler_version = a
32
+ end
33
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34
+ bundler_version = $1
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path("../Gemfile", __dir__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+ lockfile_contents = File.read(lockfile)
59
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60
+ Regexp.last_match(1)
61
+ end
62
+
63
+ def bundler_requirement
64
+ @bundler_requirement ||=
65
+ env_var_version ||
66
+ cli_arg_version ||
67
+ bundler_requirement_for(lockfile_version)
68
+ end
69
+
70
+ def bundler_requirement_for(version)
71
+ return "#{Gem::Requirement.default}.a" unless version
72
+
73
+ bundler_gem_version = Gem::Version.new(version)
74
+
75
+ bundler_gem_version.approximate_recommendation
76
+ end
77
+
78
+ def load_bundler!
79
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
80
+
81
+ activate_bundler
82
+ end
83
+
84
+ def activate_bundler
85
+ gem_error = activation_error_handling do
86
+ gem "bundler", bundler_requirement
87
+ end
88
+ return if gem_error.nil?
89
+ require_error = activation_error_handling do
90
+ require "bundler/version"
91
+ end
92
+ return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
93
+ warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
94
+ exit 42
95
+ end
96
+
97
+ def activation_error_handling
98
+ yield
99
+ nil
100
+ rescue StandardError, LoadError => e
101
+ e
102
+ end
103
+ end
104
+
105
+ m.load_bundler!
106
+
107
+ if m.invoked_as_script?
108
+ load Gem.bin_path("bundler", "bundle")
109
+ end
data/.bin/coderay ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'coderay' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("coderay", "coderay")
data/.bin/pry ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'pry' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("pry", "pry")
data/.bin/rake ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rake' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("rake", "rake")
data/Gemfile CHANGED
@@ -1,8 +1,6 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in stairwell.gemspec
4
6
  gemspec
5
-
6
- gem "rake", "~> 12.0"
7
- gem "minitest", "~> 5.0"
8
- gem "pry"
data/Gemfile.lock CHANGED
@@ -1,48 +1,54 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stairwell (0.1.2)
4
+ stairwell (0.5.0)
5
5
  activerecord (>= 4.2.11)
6
+ rake
6
7
  sqlite3
8
+ zeitwerk (~> 2.5)
7
9
 
8
10
  GEM
9
11
  remote: https://rubygems.org/
10
12
  specs:
11
- activemodel (6.0.3.4)
12
- activesupport (= 6.0.3.4)
13
- activerecord (6.0.3.4)
14
- activemodel (= 6.0.3.4)
15
- activesupport (= 6.0.3.4)
16
- activesupport (6.0.3.4)
13
+ activemodel (7.1.1)
14
+ activesupport (= 7.1.1)
15
+ activerecord (7.1.1)
16
+ activemodel (= 7.1.1)
17
+ activesupport (= 7.1.1)
18
+ timeout (>= 0.4.0)
19
+ activesupport (7.1.1)
20
+ base64
21
+ bigdecimal
17
22
  concurrent-ruby (~> 1.0, >= 1.0.2)
18
- i18n (>= 0.7, < 2)
19
- minitest (~> 5.1)
20
- tzinfo (~> 1.1)
21
- zeitwerk (~> 2.2, >= 2.2.2)
22
- coderay (1.1.3)
23
- concurrent-ruby (1.1.7)
24
- i18n (1.8.5)
23
+ connection_pool (>= 2.2.5)
24
+ drb
25
+ i18n (>= 1.6, < 2)
26
+ minitest (>= 5.1)
27
+ mutex_m
28
+ tzinfo (~> 2.0)
29
+ base64 (0.1.1)
30
+ bigdecimal (3.1.4)
31
+ concurrent-ruby (1.2.2)
32
+ connection_pool (2.4.1)
33
+ drb (2.1.1)
34
+ ruby2_keywords
35
+ i18n (1.14.1)
25
36
  concurrent-ruby (~> 1.0)
26
- method_source (1.0.0)
27
- minitest (5.14.2)
28
- pry (0.13.1)
29
- coderay (~> 1.1)
30
- method_source (~> 1.0)
31
- rake (12.3.3)
32
- sqlite3 (1.4.2)
33
- thread_safe (0.3.6)
34
- tzinfo (1.2.7)
35
- thread_safe (~> 0.1)
36
- zeitwerk (2.4.0)
37
+ minitest (5.20.0)
38
+ mutex_m (0.1.2)
39
+ rake (13.1.0)
40
+ ruby2_keywords (0.0.5)
41
+ sqlite3 (1.6.7-x86_64-darwin)
42
+ timeout (0.4.0)
43
+ tzinfo (2.0.6)
44
+ concurrent-ruby (~> 1.0)
45
+ zeitwerk (2.6.12)
37
46
 
38
47
  PLATFORMS
39
- ruby
48
+ x86_64-darwin-20
40
49
 
41
50
  DEPENDENCIES
42
- minitest (~> 5.0)
43
- pry
44
- rake (~> 12.0)
45
51
  stairwell!
46
52
 
47
53
  BUNDLED WITH
48
- 2.1.4
54
+ 2.4.10
data/README.md CHANGED
@@ -18,6 +18,12 @@ Or install it yourself as:
18
18
 
19
19
  $ gem install stairwell
20
20
 
21
+ ## Why?
22
+ Although ActiveRecord serves as an excellent tool for the majority of database queries, certain scenarios call for more customized queries.
23
+ This project was initially conceived to help transition a development team and their project from PHP to Ruby. This PHP project had thousands of complex SQL queries, thus the necessity of making SQL a first-class citizen in the ruby project enabled a smoother transition.
24
+ So, why not Arel? Arel is a powerful tool, but it's worth noting that it is considered a private API and is likely to remain so for the forseeable future.
25
+ Does this approach make queries less composable? Yes, if you are used to chaining your arel queries and AR scopes then you're probably not going to use this. However, it provides an interface that enables you to leverage SQL securely in your Ruby projects without the need to reinvent the wheel.
26
+
21
27
  ## Usage
22
28
 
23
29
  Define a class in your app that inherits from `Stairwell::Query`. We're going to assume you are in a rails app, but this will work in any ruby app, although ActiveRecord is a dependency of this gem.
@@ -57,7 +63,7 @@ binds = {
57
63
  name: "First",
58
64
  age: 99,
59
65
  active: true,
60
- gpa: 4.2
66
+ gpa: 4.2,
61
67
  date_joined: "2008-08-28",
62
68
  created_at: "2008-08-28 23:41:18",
63
69
  favorite_numbers: [4, 7, 100]
data/Rakefile CHANGED
@@ -1,10 +1,12 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
3
5
 
4
6
  Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- t.libs << "lib"
7
- t.test_files = FileList["test/**/*_test.rb"]
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
8
10
  end
9
11
 
10
- task :default => :test
12
+ task default: :test
data/bin/console CHANGED
@@ -1,14 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "stairwell"
4
+ require 'bundler/setup'
5
+ require 'stairwell'
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
8
9
 
9
10
  # (If you use this, don't forget to add pry to your Gemfile!)
10
- require "pry"
11
- Pry.start
12
11
 
13
- # require "irb"
14
- # IRB.start(__FILE__)
12
+ require 'irb'
13
+ IRB.start(__FILE__)
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Stairwell
2
4
  class BindTransformer
3
-
4
- attr_accessor :sql, :bind_hash, :depleting_bind_hash, :converted_sql
5
+ attr_reader :sql, :bind_hash, :depleting_bind_hash, :converted_sql
5
6
 
6
7
  def initialize(sql, bind_hash)
7
8
  @sql = sql
@@ -16,32 +17,33 @@ module Stairwell
16
17
  # and error will raise
17
18
  # The sql string will then have the appropropriate values substituted
18
19
  # with quoted values to ensure safety.
19
- # Note: $2 is The match for the first, second, etc. parenthesized groups in the last regex
20
- def transform
20
+ def run
21
21
  convert_sql
22
22
  validate_bind_hash
23
23
  converted_sql
24
24
  end
25
25
 
26
+ private
27
+
26
28
  def convert_sql
27
- @converted_sql ||= sql.gsub(/(:?):([a-zA-Z]\w*)/) do |_|
28
- replace = $2.to_sym
29
+ @converted_sql = sql.gsub(/(:?):([a-zA-Z]\w*)/) do |_|
30
+ replace = ::Regexp.last_match(2).to_sym
29
31
  validate_sql(replace)
30
32
  bind_hash[replace].quote
31
33
  end
32
34
  end
33
35
 
34
- private
35
-
36
- def validate_sql(attr)
37
- raise SqlBindMismatch, ":#{attr} in your query is missing from your args" unless bind_hash[attr]
36
+ def validate_sql(attr)
37
+ raise SqlBindMismatch, ":#{attr} in your query is missing from your args" unless bind_hash[attr]
38
38
 
39
- depleting_bind_hash.delete(attr)
40
- end
39
+ depleting_bind_hash.delete(attr)
40
+ end
41
41
 
42
- def validate_bind_hash
43
- raise SqlBindMismatch, ":#{depleting_bind_hash.keys.join(', ')} in your bind hash is missing from your query: #{sql}" unless depleting_bind_hash.empty?
44
- end
42
+ def validate_bind_hash
43
+ return if depleting_bind_hash.empty?
45
44
 
45
+ raise SqlBindMismatch,
46
+ ":#{depleting_bind_hash.keys.join(', ')} in your bind hash is missing from your query: #{sql}"
47
+ end
46
48
  end
47
49
  end
@@ -1,62 +1,33 @@
1
- require "stairwell/bind_transformer"
2
- require "stairwell/types/boolean_type"
3
- require "stairwell/types/column_name_type"
4
- require "stairwell/types/date_time_type"
5
- require "stairwell/types/date_type"
6
- require "stairwell/types/float_type"
7
- require "stairwell/types/integer_type"
8
- require "stairwell/types/in_type"
9
- require "stairwell/types/string_type"
10
- require "stairwell/types/null_type"
11
- require "stairwell/types/table_name_type"
1
+ # frozen_string_literal: true
12
2
 
13
3
  module Stairwell
14
4
  class Query
15
-
16
5
  class << self
17
- attr_accessor :bind_hash, :all_validations, :sql_string
18
-
19
6
  def validate_type(*args)
20
7
  @all_validations ||= {}
21
8
  @all_validations.merge!(Hash[*args])
22
9
  end
23
10
 
24
11
  def sql(**args)
25
- @bind_hash = args
26
- validate!
27
- transformed_sql_string
12
+ raise InvalidBindCount, 'Incorrect amount of args passed' if args.keys.sort != all_validations.keys.sort
13
+
14
+ @type_hash = args.each_with_object({}) do |(name, value), hash|
15
+ hash[name] = TypeObjectAssigner.run(name:, value:, all_validations:)
16
+ end
17
+ transformer.run
28
18
  end
29
19
 
30
20
  def query(string)
31
- @sql_string = string
21
+ @sql_string = string.squish
32
22
  end
33
23
 
34
24
  private
35
25
 
36
- def validate!
37
- raise InvalidBindCount.new("Incorrect amount of args passed") unless correct_args?
38
-
39
- bind_hash.each do |bind_name, bind_value|
40
- type = all_validations[bind_name]
41
- if type.is_a?(Array)
42
- type = type.first
43
- type_object = Types::InType.new(bind_value, type)
44
- end
45
- type_object ||= Object.const_get(TYPE_CLASSES[type]).new(bind_value)
46
-
47
- raise InvalidBindType.new("#{bind_name} is not #{all_validations[bind_name]}") unless type_object.valid?
26
+ attr_reader :type_hash, :all_validations, :sql_string
48
27
 
49
- bind_hash[bind_name] = type_object
50
- end
51
- end
52
-
53
- def transformed_sql_string
54
- BindTransformer.new(sql_string.squish!, bind_hash).transform
55
- end
56
-
57
- def correct_args?
58
- bind_hash.keys.sort == all_validations.keys.sort
59
- end
28
+ def transformer
29
+ BindTransformer.new(sql_string, type_hash)
30
+ end
60
31
  end
61
32
  end
62
33
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stairwell
4
+ class TypeObjectAssigner
5
+ attr_reader :name, :value, :all_validations
6
+
7
+ def self.run(...)
8
+ new(...).run
9
+ end
10
+
11
+ def initialize(name:, value:, all_validations:)
12
+ @name = name
13
+ @value = value
14
+ @all_validations = all_validations
15
+ end
16
+
17
+ def run
18
+ type_object
19
+ end
20
+
21
+ private
22
+
23
+ def proposed_type
24
+ all_validations[name]
25
+ end
26
+
27
+ def type_object
28
+ if proposed_type.is_a?(Array)
29
+ Types::InType.new(value, proposed_type.first)
30
+ else
31
+ Object.const_get(TYPE_CLASSES[proposed_type]).new(value)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,17 +1,32 @@
1
- module Stairwell::Types
2
- class BaseType
3
- attr_reader :value
1
+ # frozen_string_literal: true
4
2
 
5
- def initialize(value)
6
- @value = value
7
- end
3
+ module Stairwell
4
+ module Types
5
+ class BaseType
6
+ attr_reader :value
8
7
 
9
- def quote
10
- connection.quote(value)
11
- end
8
+ def initialize(value)
9
+ @value = value
10
+ validate!
11
+ end
12
+
13
+ def quote
14
+ connection.quote(value)
15
+ end
16
+
17
+ def connection
18
+ @connection ||= ActiveRecord::Base.connection
19
+ end
20
+
21
+ def validate!
22
+ return if valid?
23
+
24
+ raise InvalidBindType, "#{value} is not #{type_name}"
25
+ end
12
26
 
13
- def connection
14
- @connection ||= ActiveRecord::Base.connection
27
+ def type_name
28
+ self.class.name.split('::').last.gsub('Type', '').downcase
29
+ end
15
30
  end
16
31
  end
17
32
  end
@@ -1,9 +1,11 @@
1
- require "stairwell/types/base_type"
1
+ # frozen_string_literal: true
2
2
 
3
- module Stairwell::Types
4
- class BooleanType < BaseType
5
- def valid?
6
- value.is_a?(TrueClass) || value.is_a?(FalseClass)
3
+ module Stairwell
4
+ module Types
5
+ class BooleanType < BaseType
6
+ def valid?
7
+ value.is_a?(TrueClass) || value.is_a?(FalseClass)
8
+ end
7
9
  end
8
10
  end
9
11
  end
@@ -1,13 +1,15 @@
1
- require "stairwell/types/base_type"
1
+ # frozen_string_literal: true
2
2
 
3
- module Stairwell::Types
4
- class ColumnNameType < BaseType
5
- def valid?
6
- value.is_a?(String)
7
- end
3
+ module Stairwell
4
+ module Types
5
+ class ColumnNameType < BaseType
6
+ def valid?
7
+ value.is_a?(String)
8
+ end
8
9
 
9
- def quote
10
- connection.quote_column_name(value)
10
+ def quote
11
+ connection.quote_column_name(value)
12
+ end
11
13
  end
12
14
  end
13
15
  end
@@ -1,9 +1,11 @@
1
- require "stairwell/types/base_type"
1
+ # frozen_string_literal: true
2
2
 
3
- module Stairwell::Types
4
- class DateTimeType < BaseType
5
- def valid?
6
- value.is_a?(String)
3
+ module Stairwell
4
+ module Types
5
+ class DateTimeType < BaseType
6
+ def valid?
7
+ value.is_a?(String)
8
+ end
7
9
  end
8
10
  end
9
11
  end
@@ -1,9 +1,11 @@
1
- require "stairwell/types/base_type"
1
+ # frozen_string_literal: true
2
2
 
3
- module Stairwell::Types
4
- class DateType < BaseType
5
- def valid?
6
- value.is_a?(String)
3
+ module Stairwell
4
+ module Types
5
+ class DateType < BaseType
6
+ def valid?
7
+ value.is_a?(String)
8
+ end
7
9
  end
8
10
  end
9
11
  end
@@ -1,9 +1,11 @@
1
- require "stairwell/types/base_type"
1
+ # frozen_string_literal: true
2
2
 
3
- module Stairwell::Types
4
- class FloatType < BaseType
5
- def valid?
6
- value.is_a?(Float)
3
+ module Stairwell
4
+ module Types
5
+ class FloatType < BaseType
6
+ def valid?
7
+ value.is_a?(Float)
8
+ end
7
9
  end
8
10
  end
9
11
  end
@@ -1,28 +1,30 @@
1
- require "stairwell/types/base_type"
1
+ # frozen_string_literal: true
2
2
 
3
- module Stairwell::Types
4
- class InType
5
- attr_reader :value, :type
3
+ module Stairwell
4
+ module Types
5
+ class InType
6
+ attr_reader :value, :type
6
7
 
7
- def initialize(value, type)
8
- @value = value
9
- @type = type
10
- end
8
+ def initialize(value, type)
9
+ @value = value
10
+ @type = type
11
+ end
11
12
 
12
- def quote
13
- contained_values.map(&:quote).join(", ")
14
- end
13
+ def quote
14
+ contained_values.map(&:quote).join(', ')
15
+ end
15
16
 
16
- def valid?
17
- value.is_a?(Array) && contained_values.all?(&:valid?)
18
- end
17
+ def valid?
18
+ value.is_a?(Array) && contained_values.all?(&:valid?)
19
+ end
19
20
 
20
- private
21
+ private
21
22
 
22
23
  def contained_values
23
24
  value.map do |contained|
24
25
  Object.const_get(Stairwell::TYPE_CLASSES[type]).new(contained)
25
26
  end
26
27
  end
28
+ end
27
29
  end
28
30
  end
@@ -1,9 +1,11 @@
1
- require "stairwell/types/base_type"
1
+ # frozen_string_literal: true
2
2
 
3
- module Stairwell::Types
4
- class IntegerType < BaseType
5
- def valid?
6
- value.is_a?(Integer)
3
+ module Stairwell
4
+ module Types
5
+ class IntegerType < BaseType
6
+ def valid?
7
+ value.is_a?(Integer)
8
+ end
7
9
  end
8
10
  end
9
11
  end
@@ -1,9 +1,11 @@
1
- require "stairwell/types/base_type"
1
+ # frozen_string_literal: true
2
2
 
3
- module Stairwell::Types
4
- class NullType < BaseType
5
- def valid?
6
- value.is_a?(NilClass)
3
+ module Stairwell
4
+ module Types
5
+ class NullType < BaseType
6
+ def valid?
7
+ value.is_a?(NilClass)
8
+ end
7
9
  end
8
10
  end
9
11
  end
@@ -1,9 +1,11 @@
1
- require "stairwell/types/base_type"
1
+ # frozen_string_literal: true
2
2
 
3
- module Stairwell::Types
4
- class StringType < BaseType
5
- def valid?
6
- value.is_a?(String)
3
+ module Stairwell
4
+ module Types
5
+ class StringType < BaseType
6
+ def valid?
7
+ value.is_a?(String)
8
+ end
7
9
  end
8
10
  end
9
11
  end
@@ -1,13 +1,15 @@
1
- require "stairwell/types/base_type"
1
+ # frozen_string_literal: true
2
2
 
3
- module Stairwell::Types
4
- class TableNameType < BaseType
5
- def valid?
6
- value.is_a?(String)
7
- end
3
+ module Stairwell
4
+ module Types
5
+ class TableNameType < BaseType
6
+ def valid?
7
+ value.is_a?(String)
8
+ end
8
9
 
9
- def quote
10
- connection.quote_table_name(value)
10
+ def quote
11
+ connection.quote_table_name(value)
12
+ end
11
13
  end
12
14
  end
13
15
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Stairwell
2
- VERSION = "0.2.0"
4
+ VERSION = '0.5.0'
3
5
  end
data/lib/stairwell.rb CHANGED
@@ -1,7 +1,6 @@
1
- require "active_record"
2
- require "date"
3
- require "stairwell/query"
4
- require "stairwell/version"
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record'
5
4
 
6
5
  module Stairwell
7
6
  class Error < StandardError; end
@@ -10,22 +9,30 @@ module Stairwell
10
9
  class SqlBindMismatch < StandardError; end
11
10
 
12
11
  TYPE_CLASSES = {
13
- string: "Stairwell::Types::StringType",
14
- integer: "Stairwell::Types::IntegerType",
15
- boolean: "Stairwell::Types::BooleanType",
16
- float: "Stairwell::Types::FloatType",
17
- date: "Stairwell::Types::DateType",
18
- date_time: "Stairwell::Types::DateTimeType",
19
- null: "Stairwell::Types::NullType",
20
- column_name: "Stairwell::Types::ColumnNameType",
21
- table_name: "Stairwell::Types::TableNameType"
12
+ string: 'Stairwell::Types::StringType',
13
+ integer: 'Stairwell::Types::IntegerType',
14
+ boolean: 'Stairwell::Types::BooleanType',
15
+ float: 'Stairwell::Types::FloatType',
16
+ date: 'Stairwell::Types::DateType',
17
+ date_time: 'Stairwell::Types::DateTimeType',
18
+ null: 'Stairwell::Types::NullType',
19
+ column_name: 'Stairwell::Types::ColumnNameType',
20
+ table_name: 'Stairwell::Types::TableNameType'
22
21
  }.freeze
23
22
 
24
23
  # for development and testing
25
24
  unless defined?(Rails)
26
- ActiveRecord::Base.establish_connection(
25
+ ::ActiveRecord::Base.establish_connection(
27
26
  adapter: 'sqlite3',
28
27
  database: 'test.db'
29
28
  )
30
29
  end
31
30
  end
31
+
32
+ require 'date'
33
+ require 'zeitwerk'
34
+
35
+ loader = Zeitwerk::Loader.for_gem
36
+ loader.ignore("#{__dir__}/kamal/sshkit_with_ext.rb")
37
+ loader.setup
38
+ loader.eager_load # We need all commands loaded.
data/stairwell.gemspec CHANGED
@@ -1,35 +1,37 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'lib/stairwell/version'
2
4
 
3
5
  Gem::Specification.new do |spec|
4
- spec.name = "stairwell"
6
+ spec.name = 'stairwell'
5
7
  spec.version = Stairwell::VERSION
6
- spec.authors = ["tobyond"]
8
+ spec.authors = ['tobyond']
7
9
 
8
- spec.summary = %q{stairwell for sql}
9
- spec.description = %q{Sanitize and quote raw SQL for rails and any project in ruby}
10
- spec.homepage = "https://github.com/tobyond/stairwell"
11
- spec.license = "MIT"
12
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
10
+ spec.summary = 'stairwell for sql'
11
+ spec.description = 'I actually like SQL, and want to use it in my Ruby projects.'
12
+ spec.homepage = 'https://github.com/tobyond/stairwell'
13
+ spec.license = 'MIT'
14
+ spec.required_ruby_version = Gem::Requirement.new('>= 3.2.0')
13
15
 
14
16
  # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
15
17
 
16
- spec.metadata["homepage_uri"] = spec.homepage
17
- spec.metadata["source_code_uri"] = "https://github.com/tobyond/stairwell"
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = 'https://github.com/tobyond/stairwell'
18
20
  # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
19
21
 
20
22
  # Specify which files should be added to the gem when it is released.
21
23
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
25
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
26
  end
25
- spec.bindir = "exe"
27
+ spec.bindir = 'exe'
26
28
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
- spec.require_paths = ["lib"]
29
+ spec.require_paths = ['lib']
28
30
 
29
31
  spec.add_dependency 'activerecord', '>= 4.2.11'
32
+ spec.add_dependency 'rake'
33
+ spec.add_dependency 'zeitwerk', '~> 2.5'
30
34
 
31
35
  # for development and testing
32
- unless defined?(Rails)
33
- spec.add_dependency 'sqlite3'
34
- end
36
+ spec.add_dependency 'sqlite3' unless defined?(Rails)
35
37
  end
data/test.db CHANGED
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stairwell
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tobyond
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-08 00:00:00.000000000 Z
11
+ date: 2023-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 4.2.11
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: zeitwerk
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.5'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.5'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: sqlite3
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -38,12 +66,16 @@ dependencies:
38
66
  - - ">="
39
67
  - !ruby/object:Gem::Version
40
68
  version: '0'
41
- description: Sanitize and quote raw SQL for rails and any project in ruby
69
+ description: I actually like SQL, and want to use it in my Ruby projects.
42
70
  email:
43
71
  executables: []
44
72
  extensions: []
45
73
  extra_rdoc_files: []
46
74
  files:
75
+ - ".bin/bundle"
76
+ - ".bin/coderay"
77
+ - ".bin/pry"
78
+ - ".bin/rake"
47
79
  - ".gitignore"
48
80
  - ".travis.yml"
49
81
  - Gemfile
@@ -56,6 +88,7 @@ files:
56
88
  - lib/stairwell.rb
57
89
  - lib/stairwell/bind_transformer.rb
58
90
  - lib/stairwell/query.rb
91
+ - lib/stairwell/type_object_assigner.rb
59
92
  - lib/stairwell/types/base_type.rb
60
93
  - lib/stairwell/types/boolean_type.rb
61
94
  - lib/stairwell/types/column_name_type.rb
@@ -84,14 +117,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
84
117
  requirements:
85
118
  - - ">="
86
119
  - !ruby/object:Gem::Version
87
- version: 2.3.0
120
+ version: 3.2.0
88
121
  required_rubygems_version: !ruby/object:Gem::Requirement
89
122
  requirements:
90
123
  - - ">="
91
124
  - !ruby/object:Gem::Version
92
125
  version: '0'
93
126
  requirements: []
94
- rubygems_version: 3.1.2
127
+ rubygems_version: 3.4.10
95
128
  signing_key:
96
129
  specification_version: 4
97
130
  summary: stairwell for sql