Skip to content

Commit

Permalink
start adding filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffpeterson committed Nov 20, 2024
1 parent 340fc59 commit 89b432d
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ source "https://rubygems.org"

gemspec

gem "mutex_m"

gem "bcrypt"
gem "cnc", github: "craft-concept/cnc"
gem "brakeman"
Expand Down
5 changes: 5 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ PATH
remote: .
specs:
cafe_car (0.1.0)
activerecord_where_assoc
haml-rails
image_processing
importmap-rails
Expand Down Expand Up @@ -76,6 +77,8 @@ GEM
activemodel (= 7.2.2)
activesupport (= 7.2.2)
timeout (>= 0.4.0)
activerecord_where_assoc (1.2.0)
activerecord (>= 4.1.0)
activestorage (7.2.2)
actionpack (= 7.2.2)
activejob (= 7.2.2)
Expand Down Expand Up @@ -180,6 +183,7 @@ GEM
mini_magick (4.13.2)
mini_mime (1.1.5)
minitest (5.25.1)
mutex_m (0.2.0)
net-imap (0.5.0)
date
net-protocol
Expand Down Expand Up @@ -357,6 +361,7 @@ DEPENDENCIES
cnc!
faker
image_processing (~> 1.13)
mutex_m
puma
solid_cable
sqlite3
Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions cafe_car.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
end

spec.add_dependency "rails"
spec.add_dependency "activerecord_where_assoc"
spec.add_dependency "propshaft"
spec.add_dependency "haml-rails"
spec.add_dependency "image_processing"
Expand Down
2 changes: 2 additions & 0 deletions lib/cafe_car/controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module CafeCar
module Controller
extend ActiveSupport::Concern

include Pundit::Authorization
include Filtering

class_methods do
def model(model)
Expand Down
6 changes: 6 additions & 0 deletions lib/cafe_car/controller/filtering.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module CafeCar::Controller::Filtering
extend ActiveSupport::Concern

class_methods do
end
end
55 changes: 55 additions & 0 deletions lib/cafe_car/filter_builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module CafeCar
class FilterBuilder
require "activerecord_where_assoc"

attr_reader :scope

def initialize(scope)
@scope = scope
end

def update!(&)
scope = instance_exec(@scope, &)
@scope = scope if scope
self
end

def association?(name) = @scope.reflect_on_association(name).present?

def param!(key, value)
association?(key) ? association!(key, value) : attribute!(key, value)
end

def attribute!(key, value)
@scope.where!(key => value)
self
end

def association!(name, value, ...)
update! do
case value
when true then @scope.where_assoc_exists(name)
when false then @scope.where_assoc_not_exists(name)
else @scope.where_assoc_exists(name) { filtered(value, ...) }
end
end
end

def filter!(params = nil)
params.each { param!(_1, _2) } if params
self
end

def filter(...) = update!(&:all).filter!(...)
end
end

# Article.filtered do
# published
# user { username(/bob/) }
# user.username(/bob/)
# end
#
# Article.filtered(published: true, user: {username: /bob/})
#
# Article.published(true).where_assoc_exists(:user) { where(username: /bob/) }
12 changes: 12 additions & 0 deletions lib/cafe_car/filterable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module CafeCar::Filterable
extend ActiveSupport::Concern

class_methods do
def filtered(params) = filter_builder.filter(params).scope
def filtered!(params) = filter_builder.filter!(params).scope

def filter_builder
CafeCar::FilterBuilder.new(self)
end
end
end
2 changes: 2 additions & 0 deletions lib/cafe_car/model.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module CafeCar::Model
extend ActiveSupport::Concern

include CafeCar::Filterable

class_methods do
def sorted(*args)
return all if args.compact_blank!.empty?
Expand Down
12 changes: 12 additions & 0 deletions test/cafe_car/filterable_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require "test_helper"

class CafeCar::FilterableTest < Minitest::Test
def test_filter_attributes
assert_includes Article.filtered(title: "bob").to_sql, %("title" = 'bob')
end

def test_filter_associations
assert_includes Article.filtered(author: true).to_sql, %(EXISTS)
assert_includes Article.filtered(author: {username: "bob"}).to_sql, %(EXISTS)
end
end

0 comments on commit 89b432d

Please sign in to comment.