Zen Query Versions Save

parascope gem for param-based scope generation

[email protected]

3 years ago

Zen::Query v1.0.0

  • Gem has been released under new name, and the version has been set to 1.0.0
  • Updated functionality is described in README

v1.4.0

5 years ago

New Features

  • Added delayed default params evaluation by passing a block to defaults method. This allows to have default params with dynamic values, such as time- or params-based. Examples:
class MyQuery < Parascope::Query
  defaults page: 1, per_page: 10

  sifter :fresh do
    defaults { {later_than: 1.day.ago} }
  end

  # it is also possible to pass static defaults and block at the same time:
  sifter :old do
    defaults per_page: 20 do
      {older_than: 1.week.ago}
    end
  end
end
  • Credit: dynamic default params feature was requested by @slavone

v1.3.0

5 years ago

New Features

  • Added Query.raise_on_guard_violation(value) option with default value of true (to persist current behavior). When set to false, instead of raising an exception, query scope will be resolved to nil, and query instance will have violation property set with the value of first violated block error message
  • Added ability to specify custom guard block violation message, which can be much more usable and informative than default "guard block violated on ./some_query.rb:3". Example:
class UsersQuery < Parascope::Query
  raise_on_guard_violation false

  # ...

  sift_by(:sort_col, :sort_dir) do |scol, sdir|
    guard(':sort_dir should be "asc" or "desc"') do
      sdir.downcase.in?(%w(asc desc))
    end

    base_scope { |scope| scope.order(scol => sdir) }
  end
end

query = UsersQuery.new(sort_col: 'id', sort_dir: 'there')
query.resolved_scope # => nil
query.violation # => ":sort_dir should be \"asc\" or \"desc\""

v1.2.0

6 years ago

New Features

  • Added following method aliases to honor Sequel users:
    • base_dataset is an alias for base_scope
    • dataset is an alias for scope
    • resolved_dataset and resolve are both aliases for resolved_scope

v1.1.0

6 years ago

New Features

  • :index option now accepts :first and :last values. This comes in handy when you have a base Query class with a query that you want to ensure will be applied last. I.e. something like:
query_by(:page, :per_page, index: :last) do |page, per_page|
  scope.paginate(page, per_page)
end
  • Added query_by!(*fields) and sift_by!(*fields) methods. Unlike their non-bang counterparts, they don't check for presence of values under fields keys in params and will execute declared block in any case, yielding values to it, whatever they are. Note that :if and :unless options still can be used to omit block execution based on specified conditions.

v1.0.3

6 years ago

Patch Updates

  • Fixed wrong query application order on mac os environments. It looks like that under mac os, when sorting already sorted array, it's initial order gets shuffled, which becomes a problem when application order is important. This patch explicitly applies query blocks in order they were defined if they have the same index.
  • Thanks for @piton4eg for debugging this issue. Initial solution was proposed by him in #4, but was actually fixed in 7feda68982ec3b28add19bc57626b89369833f15, since query blocks may have negative and zero indices, which can be a part of Query classes design

v1.0.2

6 years ago

Patch Updates

  • The fact that base_scope blocks are not applied on explicitly passed scope was erroneously considered as a bug and "fixed" in version 1.0.1. But in fact, one can always (and should) use unoptional query blocks in sifter definition to fully replace base_scope functionality when initializing query objects with explicit scope, like so:
class UserQuery < Parascope::Query
  sifter :with_projects do
    query { scope.joins(:projects) }

    # ...
  end
end

query = UserQuery.new(params, scope: some_users)
  • README was updated with a note on this use case.

v1.0.1

6 years ago

Patch Updates

  • Fixed base_scope application on sifted queries that were initialized with explicit scope, i.e. having the following:
class MyQuery < Parascope::Query
  sifter(:foo) do
    base_scope { |scope| scope.foo }
  end
end

# ...

query = MyQuery.new({foo: true}, scope: some_scope)

it is expected that query.resolved_scope would be some_scope.foo. This is now true.

  • This patch also includes README updates done long time ago that were merged into master branch, but not released as separate gem version.

v1.0.0

7 years ago

Breaking Changes

  • Forwardable has been removed from Parascope::Query. You can now safely use convenient ActiveSupport's delegate method in Query classes.
  • UndefinedScopeError and GuardViolationError has been moved from Parascope::Query to Parascope module itself.
  • deprecated UnpermittedError alias has been removed.

New Features

  • Added Parascope::Query.build method to initialize a query object with empty params. So you can now do something like UsersQuery.build(company: company) instead of UsersQuery.new({}, company: company)

Other Updates

  • Updated README: added examples for methods in API section, added "Hints and Tips" section.
  • Massive refactoring of query_spec.rb

v0.2.0

7 years ago

New Features

  • Add support for multi-block sifters, i.e. if multiple sifter blocks fit query, all of them will be applied. Previously, only first block was applied. Erroneously, initial README suggested this feature, but it wasn't really working.
  • Add parameterless query blocks that should always be applied, like query { scope.active }
  • Add conditional querying, i.e. query(if: :active?) { scope.active }. Supported options - :if, :unless. Supported values - String, Symbol (designate name of method to be called), Proc (executed in context of query), arbitrary value (accepted as is).
  • Scopes are resolved in isolation, which means you can use resolved scope of one sifter block as a base scope for another sifter block, for example.
  • resolved_scope accepts also a list of keys that should be evaluated to true in params. I.e. resolved_scope(:paginated) is the same as resolved_scope(paginated: true). Useful in conjunction with sifter(:sifter_name) blocks.

Other Updates

  • Aliases for readability and more convenient usage: query is an alias for query_by, sifter is an alias for sift_by.
  • Guard blocks now fail with GuardViolationError. UnpermittedError left as an alias, but will be removed in future.