README.md in rokaki-0.7.0 vs README.md in rokaki-0.8.0.pre.pre

- old
+ new

@@ -1,12 +1,11 @@ # Rokaki [![Gem Version](https://badge.fury.io/rb/rokaki.svg)](https://badge.fury.io/rb/rokaki) -This gem was born out of a desire to dry up filtering services in Rails or any ruby app that uses the concept of `filters`. +This gem was born out of a desire to dry up filtering services in Rails apps or any Ruby app that uses the concept of "filters" or "facets". -It's a simple gem that just provides you with a basic dsl based on the filter params that you might pass through from a web request. - +There are two modes of use `Filterable` and `FilterModel` that can be activated through the use of two mixins respectively, `include Rokaki::Filterable` or `include Rokaki::FilterModel`. ## Installation Add this line to your application's Gemfile: ```ruby @@ -15,46 +14,122 @@ And then execute: $ bundle -## Usage +## `Rokaki::Filterable` - Usage -To use the basic DSL include the `Rokaki::Filterable` module +To use the DSL first include the `Rokaki::Filterable` module in your [por](http://blog.jayfields.com/2007/10/ruby-poro.html) class. +### `#define_filter_keys` +#### A Simple Example + A simple example might be:- ```ruby - class FilterArticles - include Rokaki::Filterable +class FilterArticles + include Rokaki::Filterable - def initialize(filters:) - @filters = filters - @articles = Article - end + def initialize(filters:) + @filters = filters + @articles = Article + end - attr_accessor :filters + attr_accessor :filters - define_filter_keys :date, author: [:first_name, :last_name] + define_filter_keys :date, author: [:first_name, :last_name] - def filter_results - @articles = @articles.where(date: date) if date - @articles = @articles.joins(:author).where(author: { first_name: author_first_name }) if author_first_name - end + def filter_results + @articles = @articles.where(date: date) if date + @articles = @articles.joins(:author).where(author: { first_name: author_first_name }) if author_first_name end +end + +article_filter = FilterArticles.new(filters: { + date: '10-10-10', + author: { + first_name: 'Steve', + last_name: 'Martin' + }}) +article_filter.author_first_name == 'Steve' +article_filter.author_last_name == 'Martin' +article_filter.date == '10-10-10' ``` -This maps attributes `date`, `author_first_name` and `author_last_name` to a filters object with the structure `{ date: '10-10-10', author: { first_name: 'Shteeve' } }`. +In this example Rokaki maps the "flat" attribute "keys" `date`, `author_first_name` and `author_last_name` to a `@filters` object with the expected deep structure `{ date: '10-10-10', author: { first_name: 'Steve' } }`, to make it simple to use them in filter queries. -## Additional options -You can specify a `filter_key_prefix` and a `filter_key_infix` to change the structure of the accessors. +#### A More Complex Example +```ruby +class AdvancedFilterable + include Rokaki::Filterable + + def initialize(filters:) + @fyltrz = filters + end + attr_accessor :fyltrz + + filterable_object_name :fyltrz + filter_key_infix :__ + define_filter_keys :basic, advanced: { + filter_key_1: [:filter_key_2, { filter_key_3: :deep_node }], + filter_key_4: :deep_leaf_array + } +end + + +advanced_filterable = AdvancedFilterable.new(filters: { + basic: 'ABC', + advanced: { + filter_key_1: { + filter_key_2: '123', + filter_key_3: { deep_node: 'NODE' } + }, + filter_key_4: { deep_leaf_array: [1,2,3,4] } + } +}) + +advanced_filterable.advanced__filter_key_4__deep_leaf_array == [1,2,3,4] +advanced_filterable.advanced__filter_key_1__filter_key_3__deep_node == 'NODE' +``` +### `#define_filter_map` + +This method takes a single field in the passed in filters hash and maps it to fields named in the second param, this is useful if you want to search for a single value across many different fields or associated tables simultaneously. + +#### A Simple Example +```ruby +class FilterMap + include Rokaki::Filterable + + def initialize(fylterz:) + @fylterz = fylterz + end + attr_accessor :fylterz + + filterable_object_name :fylterz + define_filter_map :query, :mapped_a, association: :field +end + +filter_map = FilterMap.new(fytlerz: { query: 'H2O' }) + +filter_map.mapped_a == 'H2O' +filter_map.association_field = 'H2O' +``` + +#### Additional `Filterable` options +You can specify several configuration options, for example a `filter_key_prefix` and a `filter_key_infix` to change the structure of the generated filter accessors. + `filter_key_prefix :__` would result in key accessors like `__author_first_name` `filter_key_infix :__` would result in key accessors like `author__first_name` -## ActiveRecord +`filterable_object_name :fylterz` would use an internal filter state object named `@fyltrz` instead of the default `@filters` + + +## `Rokaki::FilterModel` - Usage + +### ActiveRecord Include `Rokaki::FilterModel` in any ActiveRecord model (only AR >= 6.0.0 tested so far) you can generate the filter keys and the actual filter lookup code using the `filters` keyword on a model like so:- ```ruby # Given the models class Author < ActiveRecord::Base @@ -65,11 +140,11 @@ belongs_to :author, inverse_of: :articles, required: true end class ArticleFilter - include FilterModel + include Rokaki::FilterModel filters :date, :title, author: [:first_name, :last_name] attr_accessor :filters @@ -94,11 +169,11 @@ #### 1. The `filter` command syntax ```ruby class ArticleFilter - include FilterModel + include Rokaki::FilterModel filter :article, like: { # you can use ilike here instead if you use postgres and want case insensitive results author: { first_name: :circumfix, @@ -120,11 +195,11 @@ In this syntax you will need to provide three keywords:- `filters`, `like` and `filter_model` if you are not passing in the model type and assigning it to `@model` ```ruby class ArticleFilter - include FilterModel + include Rokaki::FilterModel filters :date, :title, author: [:first_name, :last_name] like title: :circumfix # ilike title: :circumfix # case insensitive postgres mode @@ -139,11 +214,11 @@ Or without the model in the initializer ```ruby class ArticleFilter - include FilterModel + include Rokaki::FilterModel filters :date, :title, author: [:first_name, :last_name] like title: :circumfix filter_model :article @@ -163,11 +238,11 @@ ### Deep nesting You can filter joins both with basic matching and partial matching ```ruby class ArticleFilter - include FilterModel + include Rokaki::FilterModel filter :author, like: { articles: { reviews: { @@ -187,9 +262,11 @@ ### Array params You can pass array params (and partially match them), to filters (search multiple matches) in databases that support it (postgres) by passing the `db` param to the filter keyword, and passing an array of search terms at runtine ```ruby class ArticleFilter + include Rokaki::FilterModel + filter :article, like: { author: { first_name: :circumfix, last_name: :circumfix