Skip to content

Commit

Permalink
query fixups
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffpeterson committed Nov 27, 2024
1 parent 8548248 commit 2f55fb4
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 26 deletions.
42 changes: 30 additions & 12 deletions lib/cafe_car/query_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ class QueryBuilder
require "activerecord_where_assoc"

Op = Struct.new(:op, :rhs) do
def op = self[:op].to_sym
def flop = self[:op].to_s.tr("<>", "><").to_sym
def initialize(op, rhs)
super(op.to_sym, rhs)
end

def flop = op.to_s.tr("<>", "><").to_sym
def map = Op.new(op, yield(rhs))

def arel(node) = node.public_send(arel_op, rhs)
Expand Down Expand Up @@ -37,13 +40,28 @@ def parse_time(value)
nil
end

def parse(key, value)
new_value = parse_value(key, value)
if new_value != value
parse(key, new_value)
else
new_value
end
end

def parse_value(key, value)
case value
in Op(rhs: /^=(.*)$/)
parse_value(key, Op.new("#{value.op}=", $1))
Op.new("#{value.op}=", $1)
in Op(op: (:< | :>=), rhs: Range)
value.map(&:begin)
in Op(op: (:> | :<=), rhs: Range)
value.map(&:end)
in Range
Range.new(parse_value(key, value.begin), parse_value(key, value.end), value.exclude_end?)
in Array, Op
Range.new(parse_value(key, value.begin),
parse_value(key, value.end),
value.exclude_end?)
in Array | Op
value.map { parse_value(key, _1) }
in String
case column(key)&.type || reflection(key)&.macro
Expand Down Expand Up @@ -79,11 +97,11 @@ def arel!(node) = @scope.where!(node)

def param!(key, value)
case key
when /^(.*)\s*!$/
when /^(.*?)\s*!$/
not! { param!($1, value) }
when /^(.*)\s*~$/
when /^(.*?)\s*~$/
param!($1, Regexp.new(value, Regexp::IGNORECASE))
when /^(.*)\s*([<>]=?)$/
when /^(.*?)\s*([<>]=?)$/
param!($1, Op.new($2, value))
when method(:association?)
association!(key, value)
Expand All @@ -101,8 +119,8 @@ def attribute!(key, value)
in _, Regexp
@scope.where!(arel(key).matches_regexp(value.source, !value.casefold?))
in _, Op
@scope.where!(parse_value(key, value).arel(arel(key)))
else @scope.where!(key => parse_value(key, value))
@scope.where!(parse(key, value).arel(arel(key)))
else @scope.where!(key => parse(key, value))
end
end

Expand All @@ -112,9 +130,9 @@ def association!(name, value, ...)
when true then @scope.where_assoc_exists(name)
when false then @scope.where_assoc_not_exists(name)
when Integer, Range, /^\d+$/
@scope.where_assoc_count(parse_value(name, value), :==, name)
@scope.where_assoc_count(parse(name, value), :==, name)
when Op
value = parse_value(name, value)
value = parse(name, value)
@scope.where_assoc_count(value.rhs, value.flop, name)
else @scope.where_assoc_exists(name) { all.query!(value, ...) }
end
Expand Down
4 changes: 4 additions & 0 deletions test/cafe_car/queryable_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,9 @@ class QueryableTest < ActiveSupport::TestCase
assert_empty User.query(articles: 99)
refute_empty User.query(articles!: 99)
end

# test "time spans" do
# assert_empty User.query("created_at >": "today")
# end
end
end
13 changes: 1 addition & 12 deletions test/dummy/config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,7 @@
module Dummy
class Application < Rails::Application
config.load_defaults Rails::VERSION::STRING.to_f

# Please, add to the `ignore` list any other `lib` subdirectories that do
# not contain `.rb` files, or that should not be reloaded or eager loaded.
# Common ones are `templates`, `generators`, or `middleware`, for example.
config.autoload_lib(ignore: %w[assets tasks])

# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
# in config/environments, which are processed later.
#
# config.time_zone = "Central Time (US & Canada)"
# config.eager_load_paths << Rails.root.join("extras")
config.time_zone = ENV["TZ"] || "America/Detroit"
end
end
4 changes: 2 additions & 2 deletions test/dummy/factories.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
end

trait :published do
published_at { Faker::Time.between(from: 5.years.ago, to: Time.now) }
published_at { Faker::Time.between(from: 5.years.ago, to: Time.current) }
end

trait :draft do
published_at { Faker::Time.between(from: Time.now, to: 1.month.from_now) }
published_at { Faker::Time.between(from: Time.current, to: 1.month.from_now) }
end
end
end

0 comments on commit 2f55fb4

Please sign in to comment.