Skip to content

Commit

Permalink
Migrate quo to be a Rails Engine, change config to use more standard …
Browse files Browse the repository at this point in the history
…engine like configuration and setup autoloading. Also make derived Quo Query classes use a configurable base class
  • Loading branch information
stevegeek committed Sep 17, 2024
1 parent c061277 commit 1d67ec5
Show file tree
Hide file tree
Showing 15 changed files with 121 additions and 58 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ Gemfile.lock
/.idea/
/.gem_rbs_collection/
rbs_collection.lock.yaml
*.gemfile.lock
15 changes: 15 additions & 0 deletions gemfiles/rails_7.0.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "rails", "~> 7.0"

group :development, :test do
gem "sqlite3"
gem "rake", "~> 13.0"
gem "minitest", "~> 5.0"
gem "standard"
gem "steep"
end

gemspec path: "../"
15 changes: 15 additions & 0 deletions gemfiles/rails_7.1.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "rails", "~> 7.1"

group :development, :test do
gem "sqlite3"
gem "rake", "~> 13.0"
gem "minitest", "~> 5.0"
gem "standard"
gem "steep"
end

gemspec path: "../"
15 changes: 15 additions & 0 deletions gemfiles/rails_7.2.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "rails", "~> 7.2"

group :development, :test do
gem "sqlite3"
gem "rake", "~> 13.0"
gem "minitest", "~> 5.0"
gem "standard"
gem "steep"
end

gemspec path: "../"
50 changes: 21 additions & 29 deletions lib/quo.rb
Original file line number Diff line number Diff line change
@@ -1,39 +1,31 @@
# frozen_string_literal: true

require_relative "quo/version"
require_relative "quo/railtie" if defined?(Rails)
require_relative "quo/query"
require_relative "quo/eager_query"
require_relative "quo/loaded_query"
require_relative "quo/wrapped_query"
require_relative "quo/composed_query"
require_relative "quo/results"
require "quo/engine"

module Quo
class << self
def configuration
@configuration ||= Configuration.new
end
extend ActiveSupport::Autoload

def configure
yield(configuration) if block_given?
configuration
end
end
autoload :Callstack, "quo/utilities/callstack"
autoload :Compose, "quo/utilities/compose"
autoload :Sanitize, "quo/utilities/sanitize"
autoload :Wrap, "quo/utilities/wrap"

autoload :Query
autoload :Results
autoload :ComposedQuery
autoload :EagerQuery
autoload :LoadedQuery
autoload :WrappedQuery

class Configuration
attr_accessor :formatted_query_log,
:query_show_callstack_size,
:logger,
:max_page_size,
:default_page_size
mattr_accessor :base_query_class, default: "Quo::Query"
mattr_accessor :formatted_query_log, default: true
mattr_accessor :query_show_callstack_size, default: 10
mattr_accessor :logger, default: nil
mattr_accessor :max_page_size, default: 200
mattr_accessor :default_page_size, default: 20

def initialize
@formatted_query_log = true
@query_show_callstack_size = 10
@logger = nil
@max_page_size = 200
@default_page_size = 20
end
def self.base_query_class
@@base_query_class.constantize
end
end
2 changes: 1 addition & 1 deletion lib/quo/composed_query.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

module Quo
class ComposedQuery < Quo::Query
class ComposedQuery < Quo.base_query_class
class << self
# Combine two Query classes into a new composed query class
def compose(left_query_class, right_query_class, joins: nil)
Expand Down
2 changes: 1 addition & 1 deletion lib/quo/eager_query.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

module Quo
class EagerQuery < Quo::Query
class EagerQuery < Quo.base_query_class
# Optionally return the `total_count` option if it has been set.
# This is useful when the total count is known and not equal to size
# of wrapped collection.
Expand Down
4 changes: 3 additions & 1 deletion lib/quo/railtie.rb → lib/quo/engine.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module Quo
class Railtie < ::Rails::Railtie
class Engine < ::Rails::Engine
isolate_namespace Quo

rake_tasks do
load "tasks/quo.rake"
end
Expand Down
10 changes: 5 additions & 5 deletions lib/quo/query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def call!(**options)

prop :page, _Nilable(Integer), &COERCE_TO_INT
prop :current_page, _Nilable(Integer), &COERCE_TO_INT
prop(:page_size, _Nilable(Integer), default: -> { Quo.configuration.default_page_size || 20 }, &COERCE_TO_INT)
prop(:page_size, _Nilable(Integer), default: -> { Quo.default_page_size || 20 }, &COERCE_TO_INT)

# TODO: maybe deprecate these, they are set using the chainable method and when merging we can handle them separately?
prop :group, _Nilable(_Any), reader: false, writer: false
Expand All @@ -54,7 +54,7 @@ def call!(**options)

# def after_initialization
# @current_page = options[:page]&.to_i || options[:current_page]&.to_i
# @page_size = options[:page_size]&.to_i || Quo.configuration.default_page_size || 20
# @page_size = options[:page_size]&.to_i || Quo.default_page_size || 20
# end

def page_index
Expand Down Expand Up @@ -246,7 +246,7 @@ def unwrap_unpaginated
private

def formatted_queries?
!!Quo.configuration.formatted_query_log
!!Quo.formatted_query_log
end

# 'trim' a query, ie remove comments and remove newlines
Expand Down Expand Up @@ -283,14 +283,14 @@ def configured_query
def sanitised_page_size
if page_size&.positive?
given_size = page_size.to_i
max_page_size = Quo.configuration.max_page_size || 200
max_page_size = Quo.max_page_size || 200
if given_size > max_page_size
max_page_size
else
given_size
end
else
Quo.configuration.default_page_size || 20
Quo.default_page_size || 20
end
end

Expand Down
4 changes: 2 additions & 2 deletions lib/quo/utilities/callstack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ module Utilities
module Callstack
def debug_callstack
return unless Rails.env.development?
callstack_size = Quo.configuration.query_show_callstack_size
callstack_size = Quo.query_show_callstack_size
return unless callstack_size&.positive?
working_dir = Dir.pwd
exclude = %r{/(gems/|rubies/|query\.rb)}
stack = Kernel.caller.grep_v(exclude).map { |l| l.gsub(working_dir + "/", "") }
stack_to_display = stack[0..callstack_size]
message = "\n[Query stack]: -> #{stack_to_display&.join("\n &> ")}\n"
message += " (truncated to #{callstack_size} most recent)" if callstack_size && stack.size > callstack_size
logger = Quo.configuration.logger&.call
logger = Quo.logger&.call
logger&.info(message)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/quo/wrapped_query.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

module Quo
class WrappedQuery < Quo::Query
class WrappedQuery < Quo.base_query_class
def self.wrap(query = nil, props: {}, &block)
klass = Class.new(self) do
props.each do |name, type|
Expand Down
13 changes: 0 additions & 13 deletions sig/quo.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,4 @@ module Quo
def error: (String) -> void
def debug: (String) -> void
end

class Configuration
attr_accessor formatted_query_log: bool?
attr_accessor query_show_callstack_size: Integer?
attr_accessor logger: _Logger?
attr_accessor max_page_size: Integer?
attr_accessor default_page_size: Integer?

def initialize: () -> void
end
attr_reader self.configuration: Configuration

def self.configure: () { (Configuration config) -> void } -> void
end
7 changes: 7 additions & 0 deletions test/dummy/app/queries/application_query.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class ApplicationQuery < Quo::Query
def hello
"world"
end
end
10 changes: 5 additions & 5 deletions test/dummy/config/initializers/quo.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Quo.configure do |config|
config.formatted_query_log = true
config.query_show_callstack_size = 5
config.logger = -> { Rails.logger }
end
Quo.formatted_query_log = true
Quo.query_show_callstack_size = 5
Quo.logger = -> { Rails.logger }
Quo.base_query_class = "ApplicationQuery"

29 changes: 29 additions & 0 deletions test/quo/custom_base_class_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

require_relative "../test_helper"

class Quo::CustomBaseClassTest < ActiveSupport::TestCase
def setup
a1 = Author.create!(name: "John")
a2 = Author.create!(name: "Jane")
p1 = Post.create!(title: "Post 1", author: a1)
p2 = Post.create!(title: "Post 2", author: a2)
Comment.create!(post: p1, body: "abc", read: false)
Comment.create!(post: p2, body: "def", read: false, spam_score: 0.8)

@q1 = Quo::WrappedQuery.wrap(props: {since_date: Time}) do
Comment.recent(since_date)
end
@q2 = Quo::WrappedQuery.wrap(props: {spam_score: Float}) do
Comment.not_spam(spam_score)
end
end

test "wrapped query inherits from custom base class" do
assert_kind_of ApplicationQuery, @q1.new(since_date: 1.day.ago)
assert_equal "world", @q1.new(since_date: 1.day.ago).hello

klass = Quo::ComposedQuery.compose(Comment.recent, Comment.not_spam)
assert_kind_of ApplicationQuery, klass.new
end
end

0 comments on commit 1d67ec5

Please sign in to comment.