rokaki 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/pages.yml +31 -0
- data/.github/workflows/spec.yml +30 -0
- data/Gemfile.lock +16 -1
- data/README.md +18 -7
- data/docs/Gemfile +17 -0
- data/docs/_config.yml +26 -0
- data/docs/adapters.md +46 -0
- data/docs/configuration.md +63 -0
- data/docs/index.md +75 -0
- data/docs/usage.md +100 -0
- data/lib/rokaki/filter_model/basic_filter.rb +11 -0
- data/lib/rokaki/filter_model/nested_filter.rb +28 -12
- data/lib/rokaki/filter_model/nested_like_filters.rb +41 -15
- data/lib/rokaki/filter_model.rb +81 -4
- data/lib/rokaki/version.rb +1 -1
- data/rokaki.gemspec +3 -0
- metadata +37 -3
- data/CODE_OF_CONDUCT.md +0 -74
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dcbf82920cbfeff8466f6ccd583f1a66652082e087c2d6641806be8720dd8d6c
|
|
4
|
+
data.tar.gz: 4165d387e1fba3820fc302ef414f0019077067a1dca7d307943030f0aec99207
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8e5d866b175e0799ad9bff2cbb8660e8ebca48785e508223e7583452eb7e95e56c1c35f15ff8625fc456365651b82efff40636579f90469d9909f650f6ee2b1d
|
|
7
|
+
data.tar.gz: e974f32a7626a94fb618295ea9600e9747af73bd35986f9e843a81b4bc6168c98180ef85d150fc1ad96ff4fa4700daae5d16d75596bc2d3dd9279ba8d6a98c64
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Build documentation (no deploy)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main, master ]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build-docs:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
env:
|
|
12
|
+
BUNDLE_GEMFILE: docs/Gemfile
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout
|
|
15
|
+
uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Setup Ruby
|
|
18
|
+
uses: ruby/setup-ruby@v1
|
|
19
|
+
with:
|
|
20
|
+
ruby-version: '3.3.0'
|
|
21
|
+
bundler-cache: true
|
|
22
|
+
|
|
23
|
+
- name: Build site
|
|
24
|
+
run: |
|
|
25
|
+
bundle exec jekyll build -s docs -d _site
|
|
26
|
+
|
|
27
|
+
- name: Upload built site artifact
|
|
28
|
+
uses: actions/upload-artifact@v4
|
|
29
|
+
with:
|
|
30
|
+
name: site
|
|
31
|
+
path: _site
|
data/.github/workflows/spec.yml
CHANGED
|
@@ -25,8 +25,24 @@ jobs:
|
|
|
25
25
|
- 5432:5432
|
|
26
26
|
# needed because the postgres container does not provide a healthcheck
|
|
27
27
|
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
|
|
28
|
+
|
|
29
|
+
sqlserver:
|
|
30
|
+
image: mcr.microsoft.com/mssql/server:2022-latest
|
|
31
|
+
env:
|
|
32
|
+
ACCEPT_EULA: "Y"
|
|
33
|
+
MSSQL_SA_PASSWORD: "5QL5£rv£r"
|
|
34
|
+
ports:
|
|
35
|
+
- 1433:1433
|
|
36
|
+
# No built-in healthcheck; we'll wait in a step using nc
|
|
37
|
+
|
|
28
38
|
steps:
|
|
29
39
|
- uses: actions/checkout@v2
|
|
40
|
+
|
|
41
|
+
- name: Install system dependencies
|
|
42
|
+
run: |
|
|
43
|
+
sudo apt-get update
|
|
44
|
+
sudo apt-get install -y build-essential libpq-dev default-libmysqlclient-dev freetds-dev netcat-openbsd
|
|
45
|
+
|
|
30
46
|
- name: Set up Ruby
|
|
31
47
|
uses: ruby/setup-ruby@v1
|
|
32
48
|
with:
|
|
@@ -34,6 +50,20 @@ jobs:
|
|
|
34
50
|
ruby-version: 3.3.0
|
|
35
51
|
# runs 'bundle install' and caches installed gems automatically
|
|
36
52
|
bundler-cache: true
|
|
53
|
+
|
|
54
|
+
- name: Wait for databases to be ready
|
|
55
|
+
shell: bash
|
|
56
|
+
run: |
|
|
57
|
+
for i in {1..60}; do
|
|
58
|
+
nc -z 127.0.0.1 3306 && echo "MySQL up" && break || sleep 1
|
|
59
|
+
done
|
|
60
|
+
for i in {1..60}; do
|
|
61
|
+
nc -z 127.0.0.1 5432 && echo "Postgres up" && break || sleep 1
|
|
62
|
+
done
|
|
63
|
+
for i in {1..120}; do
|
|
64
|
+
nc -z 127.0.0.1 1433 && echo "SQL Server up" && break || sleep 1
|
|
65
|
+
done
|
|
66
|
+
|
|
37
67
|
- name: Run tests
|
|
38
68
|
run: |
|
|
39
69
|
./spec/ordered_run.sh
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
rokaki (0.
|
|
4
|
+
rokaki (0.12.0)
|
|
5
5
|
activesupport
|
|
6
6
|
|
|
7
7
|
GEM
|
|
@@ -13,6 +13,9 @@ GEM
|
|
|
13
13
|
activemodel (= 8.0.3)
|
|
14
14
|
activesupport (= 8.0.3)
|
|
15
15
|
timeout (>= 0.4.0)
|
|
16
|
+
activerecord-sqlserver-adapter (8.0.9)
|
|
17
|
+
activerecord (~> 8.0.0)
|
|
18
|
+
tiny_tds
|
|
16
19
|
activesupport (8.0.3)
|
|
17
20
|
base64
|
|
18
21
|
benchmark (>= 0.3)
|
|
@@ -132,6 +135,16 @@ GEM
|
|
|
132
135
|
sqlite3 (2.7.4-x86_64-linux-musl)
|
|
133
136
|
thor (1.4.0)
|
|
134
137
|
timeout (0.4.3)
|
|
138
|
+
tiny_tds (3.3.0)
|
|
139
|
+
bigdecimal (~> 3)
|
|
140
|
+
tiny_tds (3.3.0-aarch64-linux-gnu)
|
|
141
|
+
bigdecimal (~> 3)
|
|
142
|
+
tiny_tds (3.3.0-aarch64-linux-musl)
|
|
143
|
+
bigdecimal (~> 3)
|
|
144
|
+
tiny_tds (3.3.0-x86_64-linux-gnu)
|
|
145
|
+
bigdecimal (~> 3)
|
|
146
|
+
tiny_tds (3.3.0-x86_64-linux-musl)
|
|
147
|
+
bigdecimal (~> 3)
|
|
135
148
|
tzinfo (2.0.6)
|
|
136
149
|
concurrent-ruby (~> 1.0)
|
|
137
150
|
uri (1.0.3)
|
|
@@ -152,6 +165,7 @@ PLATFORMS
|
|
|
152
165
|
|
|
153
166
|
DEPENDENCIES
|
|
154
167
|
activerecord
|
|
168
|
+
activerecord-sqlserver-adapter
|
|
155
169
|
bundler (~> 2.0)
|
|
156
170
|
database_cleaner-active_record
|
|
157
171
|
factory_bot
|
|
@@ -165,6 +179,7 @@ DEPENDENCIES
|
|
|
165
179
|
rokaki!
|
|
166
180
|
rspec (~> 3.0)
|
|
167
181
|
sqlite3
|
|
182
|
+
tiny_tds
|
|
168
183
|
|
|
169
184
|
BUNDLED WITH
|
|
170
185
|
2.5.3
|
data/README.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# Rokaki
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/rb/rokaki)
|
|
4
|
+
[](https://github.com/tevio/rokaki/actions/workflows/spec.yml)
|
|
4
5
|
|
|
5
|
-
This gem was
|
|
6
|
+
This gem was written to dry up filtering services in ActiveRecord based Rails apps or any plain Ruby app looking to implement "filters" or "faceted" search.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
The overall vision is to abstract away all of the lower level repetitive SQL and relational code to allow you to write model filters in a simple, relatively intuitive way, using ruby hashes and arrays mostly.
|
|
9
|
+
|
|
10
|
+
The DSL allows you to construct complex search models to filter results through without writing any SQL. I would recommend the reader to consult the specs in order to understand the features and syntax in detail, an intermediate understanding of Ruby and rspec TDD, and basic relational logic are recommended.
|
|
11
|
+
|
|
12
|
+
There are two modes of use, `Filterable` (designed for plain Ruby) and `FilterModel` (designed for Rails) that can be activated through the use of two mixins respectively, `include Rokaki::Filterable` or `include Rokaki::FilterModel`.
|
|
8
13
|
## Installation
|
|
9
14
|
|
|
10
15
|
Add this line to your application's Gemfile:
|
|
@@ -137,7 +142,7 @@ You can specify several configuration options, for example a `filter_key_prefix`
|
|
|
137
142
|
## `Rokaki::FilterModel` - Usage
|
|
138
143
|
|
|
139
144
|
### ActiveRecord
|
|
140
|
-
Include `Rokaki::FilterModel` in any ActiveRecord model (only AR >=
|
|
145
|
+
Include `Rokaki::FilterModel` in any ActiveRecord model (only AR >= 8.0.3 tested so far) you can generate the filter keys and the actual filter lookup code using the `filters` keyword on a model like so:-
|
|
141
146
|
|
|
142
147
|
```ruby
|
|
143
148
|
# Given the models
|
|
@@ -173,7 +178,7 @@ You can also filter collections of fields, simply pass an array of filter values
|
|
|
173
178
|
|
|
174
179
|
|
|
175
180
|
### Partial matching
|
|
176
|
-
You can use `like`
|
|
181
|
+
You can use `like` or the case insensitive `ilike` to perform a partial match on a specific field, there are 3 options:- `:prefix`, `:circumfix` and `:suffix`. There are two syntaxes you can use for this:-
|
|
177
182
|
|
|
178
183
|
#### 1. The `filter` command syntax
|
|
179
184
|
|
|
@@ -183,7 +188,7 @@ class ArticleFilter
|
|
|
183
188
|
include Rokaki::FilterModel
|
|
184
189
|
|
|
185
190
|
filter :article,
|
|
186
|
-
like: { # you can use ilike here instead if you
|
|
191
|
+
like: { # you can use ilike here instead if you want case insensitive results
|
|
187
192
|
author: {
|
|
188
193
|
first_name: :circumfix,
|
|
189
194
|
last_name: :circumfix
|
|
@@ -323,7 +328,7 @@ class ArticleFilter
|
|
|
323
328
|
|
|
324
329
|
filters :date, :title, author: [:first_name, :last_name]
|
|
325
330
|
like title: :circumfix
|
|
326
|
-
# ilike title: :circumfix # case insensitive
|
|
331
|
+
# ilike title: :circumfix # case insensitive mode
|
|
327
332
|
|
|
328
333
|
attr_accessor :filters
|
|
329
334
|
|
|
@@ -436,7 +441,13 @@ docker pull mysql
|
|
|
436
441
|
docker run --name rokaki-mysql -e MYSQL_ROOT_PASSWORD=rokaki -e MYSQL_PASSWORD=rokaki -e MYSQL_DATABASE=rokaki -e MYSQL_USER=rokaki -d -p 3306:3306 mysql:latest mysqld
|
|
437
442
|
```
|
|
438
443
|
|
|
439
|
-
|
|
444
|
+
### Specialised test runner
|
|
445
|
+
The test suite is designed to run against all supported database backends, since this can cause problems with timing and connection pools, the recommended way to run the tests is via a shell script.
|
|
446
|
+
|
|
447
|
+
From the rokaki root directory run: `./spec/ordered_run.sh`. This is the same script that runs on the Github CI here: [](https://github.com/tevio/rokaki/actions/workflows/spec.yml)
|
|
448
|
+
|
|
449
|
+
### Standard test runner (only recommended for development cycles)
|
|
450
|
+
You can still run `rake spec` to run the tests, there's no guarantee they will all pass due to race conditions from using multiple db backends (see above), but this mode is recommended for focusing on specific backends or tests during development (comment out what you don't want). You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
440
451
|
|
|
441
452
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
442
453
|
|
data/docs/Gemfile
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# docs/Gemfile
|
|
2
|
+
source "https://rubygems.org"
|
|
3
|
+
|
|
4
|
+
# Static site generator
|
|
5
|
+
gem "jekyll", "~> 4.4"
|
|
6
|
+
|
|
7
|
+
# Theme used by docs/_config.yml
|
|
8
|
+
gem "minima", "~> 2.5"
|
|
9
|
+
|
|
10
|
+
# GitHub-flavored Markdown support
|
|
11
|
+
gem "kramdown-parser-gfm", "~> 1.1"
|
|
12
|
+
|
|
13
|
+
# Ruby 3+ local serving requires webrick
|
|
14
|
+
gem "webrick", "~> 1.8"
|
|
15
|
+
|
|
16
|
+
# Ensure compatibility with workflow expectation
|
|
17
|
+
gem "rake", "~> 13.3"
|
data/docs/_config.yml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
title: Rokaki
|
|
2
|
+
description: A DSL for filtering data in web requests (ActiveRecord)
|
|
3
|
+
# For project pages (https://<user>.github.io/<repo>), set:
|
|
4
|
+
# url: "https://tevio.github.io"
|
|
5
|
+
# baseurl: "/rokaki"
|
|
6
|
+
# This ensures theme assets like /assets/main.css resolve under /rokaki/ on GitHub Pages.
|
|
7
|
+
baseurl: "/rokaki"
|
|
8
|
+
url: "https://tevio.github.io"
|
|
9
|
+
theme: minima
|
|
10
|
+
|
|
11
|
+
# Build settings
|
|
12
|
+
markdown: kramdown
|
|
13
|
+
kramdown:
|
|
14
|
+
input: GFM
|
|
15
|
+
|
|
16
|
+
# Exclude existing generated RDoc folder from site
|
|
17
|
+
exclude:
|
|
18
|
+
- doc/
|
|
19
|
+
- pkg/
|
|
20
|
+
- spec/
|
|
21
|
+
- Gemfile
|
|
22
|
+
- Gemfile.lock
|
|
23
|
+
- Rakefile
|
|
24
|
+
- rokaki.gemspec
|
|
25
|
+
- Guardfile
|
|
26
|
+
- README.md
|
data/docs/adapters.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: Database adapters
|
|
4
|
+
permalink: /adapters
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Rokaki generates adapter‑aware SQL for PostgreSQL, MySQL, and SQL Server.
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
- PostgreSQL
|
|
12
|
+
- Case‑insensitive: `ILIKE`
|
|
13
|
+
- Case‑sensitive: `LIKE`
|
|
14
|
+
- Multi‑term: `ANY (ARRAY[...])`
|
|
15
|
+
- MySQL
|
|
16
|
+
- Case‑insensitive: `LIKE`
|
|
17
|
+
- Case‑sensitive: `LIKE BINARY`
|
|
18
|
+
- Nested‑like filters may use `REGEXP` where designed in the library
|
|
19
|
+
- SQL Server
|
|
20
|
+
- Uses `LIKE` with safe escaping
|
|
21
|
+
- Multi‑term input expands to OR‑chained predicates (e.g., `(col LIKE :q0 OR col LIKE :q1 ...)`) with `ESCAPE '\\'`
|
|
22
|
+
- Case sensitivity follows DB collation by default; future versions may add inline `COLLATE` options
|
|
23
|
+
|
|
24
|
+
## LIKE modes
|
|
25
|
+
|
|
26
|
+
All adapters support the same modes, which you declare via the values in your `like` mapping (there is no `modes:` option):
|
|
27
|
+
|
|
28
|
+
- `prefix` → `%term`
|
|
29
|
+
- `suffix` → `term%`
|
|
30
|
+
- `circumfix` → `%term%` (synonyms supported: `:parafix`, `:confix`, `:ambifix`)
|
|
31
|
+
|
|
32
|
+
Example:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
# Declare modes via like-mapping values (no block DSL)
|
|
36
|
+
like title: :circumfix
|
|
37
|
+
like author: { first_name: :prefix }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
When you pass an array of terms, Rokaki composes adapter‑appropriate SQL that matches any of the terms.
|
|
41
|
+
|
|
42
|
+
## Notes on case sensitivity
|
|
43
|
+
|
|
44
|
+
- PostgreSQL: `ILIKE` is case‑insensitive; `LIKE` is case‑sensitive depending on collation/LC settings but generally treated as case‑sensitive for ASCII.
|
|
45
|
+
- MySQL: `LIKE` case sensitivity depends on column collation; `LIKE BINARY` forces byte comparison (case‑sensitive for ASCII).
|
|
46
|
+
- SQL Server: The server/database/column collation determines sensitivity. Rokaki currently defers to your DB’s default. If you need deterministic behavior regardless of DB defaults, consider using a case‑sensitive collation on the column or open an issue to discuss inline `COLLATE` options.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: Configuration
|
|
4
|
+
permalink: /configuration
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
This page covers configuration, environment overrides, and tips for running the test suite across adapters.
|
|
8
|
+
|
|
9
|
+
## Environment variables
|
|
10
|
+
|
|
11
|
+
Rokaki's test helpers (used in the specs) support environment variable overrides for all adapters. These are useful when your local databases run on non‑default ports or hosts.
|
|
12
|
+
|
|
13
|
+
### SQL Server
|
|
14
|
+
- `SQLSERVER_HOST` (default: `localhost`)
|
|
15
|
+
- `SQLSERVER_PORT` (default: `1433`)
|
|
16
|
+
- `SQLSERVER_USERNAME` (default: `sa`)
|
|
17
|
+
- `SQLSERVER_PASSWORD`
|
|
18
|
+
- `SQLSERVER_DATABASE` (default: `rokaki`)
|
|
19
|
+
|
|
20
|
+
### MySQL
|
|
21
|
+
- `MYSQL_HOST` (default: `127.0.0.1`)
|
|
22
|
+
- `MYSQL_PORT` (default: `3306`)
|
|
23
|
+
- `MYSQL_USERNAME` (default: `rokaki`)
|
|
24
|
+
- `MYSQL_PASSWORD` (default: `rokaki`)
|
|
25
|
+
- `MYSQL_DATABASE` (default: `rokaki`)
|
|
26
|
+
|
|
27
|
+
### PostgreSQL
|
|
28
|
+
- `POSTGRES_HOST` (default: `127.0.0.1`)
|
|
29
|
+
- `POSTGRES_PORT` (default: `5432`)
|
|
30
|
+
- `POSTGRES_USERNAME` (default: `postgres`)
|
|
31
|
+
- `POSTGRES_PASSWORD` (default: `postgres`)
|
|
32
|
+
- `POSTGRES_DATABASE` (default: `rokaki`)
|
|
33
|
+
|
|
34
|
+
## SQL Server notes
|
|
35
|
+
|
|
36
|
+
- Rokaki uses `LIKE` with proper escaping and OR expansion for arrays of terms.
|
|
37
|
+
- Case sensitivity follows your database/column collation. Future versions may allow inline `COLLATE` options.
|
|
38
|
+
|
|
39
|
+
## Running tests locally
|
|
40
|
+
|
|
41
|
+
Ensure you have Ruby (see `.ruby-version`), then install dependencies and run specs.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
bundle install
|
|
45
|
+
./spec/ordered_run.sh
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or run a single adapter suite, for example SQL Server:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
bundle exec rspec spec/lib/03_sqlserver_aware_spec.rb
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
If your SQL Server listens on a different port (e.g., 1434), set an override:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
export SQLSERVER_PORT=1434
|
|
58
|
+
bundle exec rspec spec/lib/03_sqlserver_aware_spec.rb
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## GitHub Actions
|
|
62
|
+
|
|
63
|
+
The repository includes CI that starts MySQL (9.4), PostgreSQL (13), and SQL Server (2022) services and runs the ordered spec suite. See `.github/workflows/spec.yml`.
|
data/docs/index.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: home
|
|
3
|
+
title: Rokaki
|
|
4
|
+
permalink: /
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Rokaki is a small Ruby library that helps you build safe, composable filters for ActiveRecord queries in web requests.
|
|
8
|
+
|
|
9
|
+
- Works with PostgreSQL, MySQL, and SQL Server
|
|
10
|
+
- Supports simple and nested filters
|
|
11
|
+
- LIKE-based matching with prefix/suffix/circumfix modes (circumfix also accepts synonyms: parafix, confix, ambifix)
|
|
12
|
+
- Array-of-terms matching (adapter-aware)
|
|
13
|
+
|
|
14
|
+
Get started below or jump to:
|
|
15
|
+
- [Usage](./usage)
|
|
16
|
+
- [Database adapters](./adapters)
|
|
17
|
+
- [Configuration](./configuration)
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
Add to your application's Gemfile:
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
gem "rokaki", "~> 0.11"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Then:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
bundle install
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick start
|
|
34
|
+
|
|
35
|
+
Use `Rokaki::FilterModel` and declare mappings with method arguments (no block DSL).
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
class ArticleQuery
|
|
39
|
+
include Rokaki::FilterModel
|
|
40
|
+
|
|
41
|
+
# Tell Rokaki which model to query and which DB adapter semantics to use
|
|
42
|
+
filter_model :article, db: :postgres # or :mysql, :sqlserver
|
|
43
|
+
|
|
44
|
+
# Map a single query key (:q) to multiple LIKE targets on Article
|
|
45
|
+
define_query_key :q
|
|
46
|
+
like title: :circumfix, content: :circumfix
|
|
47
|
+
|
|
48
|
+
# Nested LIKEs on associated models are expressed with hashes
|
|
49
|
+
like author: { first_name: :prefix, last_name: :suffix }
|
|
50
|
+
|
|
51
|
+
attr_accessor :filters
|
|
52
|
+
def initialize(filters: {})
|
|
53
|
+
@filters = filters
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# In a controller/service:
|
|
58
|
+
filtered = ArticleQuery.new(filters: params).results
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Where `params` can include keys like `q`, `author_first_name`, `author_last_name`, etc. The LIKE mode for each key is defined in your `like` mapping (e.g., `title: :circumfix`), and Rokaki builds the appropriate `WHERE` clauses safely and adapter‑aware.
|
|
62
|
+
|
|
63
|
+
## Matching modes
|
|
64
|
+
|
|
65
|
+
- prefix: matches values that start with given term(s)
|
|
66
|
+
- suffix: matches values that end with given term(s)
|
|
67
|
+
- circumfix: matches values that contain given term(s)
|
|
68
|
+
|
|
69
|
+
All modes accept either a single string or an array of terms.
|
|
70
|
+
|
|
71
|
+
## Next steps
|
|
72
|
+
|
|
73
|
+
- Learn the full DSL and examples in [Usage](./usage)
|
|
74
|
+
- See adapter specifics (PostgreSQL/MySQL/SQL Server) in [Database adapters](./adapters)
|
|
75
|
+
- Configure connections and environment variables in [Configuration](./configuration)
|
data/docs/usage.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: Usage
|
|
4
|
+
permalink: /usage
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
This page shows how to use Rokaki to define filters and apply them to ActiveRecord relations.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Add the gem to your Gemfile and bundle:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
gem "rokaki", "~> 0.11"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bundle install
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Basic setup
|
|
22
|
+
|
|
23
|
+
Include `Rokaki::Filterable` in models you want to filter, and define a `filter_map` with fields and nested associations.
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
class Author < ActiveRecord::Base
|
|
27
|
+
has_many :articles
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class ArticleQuery
|
|
31
|
+
include Rokaki::FilterModel
|
|
32
|
+
belongs_to :author
|
|
33
|
+
|
|
34
|
+
# Choose model and adapter
|
|
35
|
+
filter_model :article, db: :postgres # or :mysql, :sqlserver
|
|
36
|
+
|
|
37
|
+
# Map a single query key (:q) to multiple LIKE targets
|
|
38
|
+
define_query_key :q
|
|
39
|
+
like title: :circumfix, content: :circumfix
|
|
40
|
+
|
|
41
|
+
# Nested LIKEs via hash mapping (no block DSL)
|
|
42
|
+
like author: { first_name: :prefix, last_name: :suffix }
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Applying filters
|
|
47
|
+
|
|
48
|
+
Call `Model.filter(params)` to build a relation based on supported keys.
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
params = {
|
|
52
|
+
title_prefix: "Intro",
|
|
53
|
+
q: ["ruby", "rails"],
|
|
54
|
+
author_last_name: "martin"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
filtered = Article.filter(params)
|
|
58
|
+
# => ActiveRecord::Relation (chainable)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
You can keep chaining other scopes/clauses:
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
Article.filter(params).order(published: :desc).limit(20)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## LIKE modes and affix options
|
|
68
|
+
|
|
69
|
+
Declare the LIKE mode via the value in your `like` mapping (there is no `modes:` option). For example: `like title: :prefix`.
|
|
70
|
+
|
|
71
|
+
- `prefix` → matches strings that start with a term (pattern: `%term`)
|
|
72
|
+
- `suffix` → matches strings that end with a term (pattern: `term%`)
|
|
73
|
+
- `circumfix` → matches strings that contain a term (pattern: `%term%`)
|
|
74
|
+
- Synonyms supported: `:parafix`, `:confix`, `:ambifix` (all behave the same as `:circumfix`)
|
|
75
|
+
|
|
76
|
+
Each accepts a single string or an array of strings. Rokaki generates adapter‑aware SQL:
|
|
77
|
+
|
|
78
|
+
- PostgreSQL: `LIKE`/`ILIKE` with `ANY (ARRAY[...])`
|
|
79
|
+
- MySQL: `LIKE`/`LIKE BINARY` and, in nested-like contexts, `REGEXP` where designed
|
|
80
|
+
- SQL Server: `LIKE` with safe escaping; arrays expand into OR chains of parameterized `LIKE` predicates
|
|
81
|
+
|
|
82
|
+
## Nested filters
|
|
83
|
+
|
|
84
|
+
Use `nested :association` to scope filters to joined tables. Rokaki handles the necessary joins and qualified columns.
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
filter_map do
|
|
88
|
+
nested :author do
|
|
89
|
+
like :first_name, key: :author_first
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Params would include `author_first`, `author_first_prefix`, etc.
|
|
95
|
+
|
|
96
|
+
## Customization tips
|
|
97
|
+
|
|
98
|
+
- Use `key:` to map a filter to a different params key.
|
|
99
|
+
- Combine multiple filters; Rokaki composes them with `AND` by default.
|
|
100
|
+
- For advanced cases, write custom filters in your app by extending the DSL (see source for `BasicFilter`/`NestedFilter`).
|
|
@@ -38,6 +38,10 @@ module Rokaki
|
|
|
38
38
|
'LIKE'
|
|
39
39
|
elsif db == :mysql
|
|
40
40
|
'LIKE BINARY'
|
|
41
|
+
elsif db == :sqlserver
|
|
42
|
+
'LIKE'
|
|
43
|
+
else
|
|
44
|
+
'LIKE'
|
|
41
45
|
end
|
|
42
46
|
end
|
|
43
47
|
|
|
@@ -46,6 +50,10 @@ module Rokaki
|
|
|
46
50
|
'ILIKE'
|
|
47
51
|
elsif db == :mysql
|
|
48
52
|
'LIKE'
|
|
53
|
+
elsif db == :sqlserver
|
|
54
|
+
'LIKE'
|
|
55
|
+
else
|
|
56
|
+
'LIKE'
|
|
49
57
|
end
|
|
50
58
|
end
|
|
51
59
|
|
|
@@ -94,6 +102,9 @@ module Rokaki
|
|
|
94
102
|
if db == :postgres
|
|
95
103
|
query = "@model.where(\"#{key} #{type} ANY (ARRAY[?])\", "
|
|
96
104
|
query += "prepare_terms(#{filter}, :#{mode}))"
|
|
105
|
+
elsif db == :sqlserver
|
|
106
|
+
# Delegate to helper that supports arrays and escaping with ESCAPE
|
|
107
|
+
query = "sqlserver_like(@model, \"#{key}\", \"#{type}\", #{filter}, :#{mode})"
|
|
97
108
|
else
|
|
98
109
|
query = "@model.where(\"#{key} #{type} :query\", "
|
|
99
110
|
query += "query: \"%\#{#{filter}}%\")" if mode == :circumfix
|
|
@@ -70,6 +70,10 @@ module Rokaki
|
|
|
70
70
|
'LIKE'
|
|
71
71
|
elsif db == :mysql
|
|
72
72
|
'LIKE BINARY'
|
|
73
|
+
elsif db == :sqlserver
|
|
74
|
+
'LIKE'
|
|
75
|
+
else
|
|
76
|
+
'LIKE'
|
|
73
77
|
end
|
|
74
78
|
end
|
|
75
79
|
|
|
@@ -78,6 +82,10 @@ module Rokaki
|
|
|
78
82
|
'ILIKE'
|
|
79
83
|
elsif db == :mysql
|
|
80
84
|
'LIKE'
|
|
85
|
+
elsif db == :sqlserver
|
|
86
|
+
'LIKE'
|
|
87
|
+
else
|
|
88
|
+
'LIKE'
|
|
81
89
|
end
|
|
82
90
|
end
|
|
83
91
|
|
|
@@ -131,19 +139,27 @@ module Rokaki
|
|
|
131
139
|
where = where.join
|
|
132
140
|
|
|
133
141
|
if search_mode
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
search_mode: search_mode,
|
|
139
|
-
key: keys.last.to_s.pluralize,
|
|
140
|
-
leaf: leaf
|
|
141
|
-
)
|
|
142
|
+
if db == :sqlserver
|
|
143
|
+
key_leaf = "#{keys.last.to_s.pluralize}.#{leaf}"
|
|
144
|
+
@filter_methods << "def #{prefix}filter#{infix}#{name};"\
|
|
145
|
+
"sqlserver_like(@model.joins(#{joins}), \"#{key_leaf}\", \"#{type}\", #{prefix}#{name}, :#{search_mode}); end;"
|
|
142
146
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
@filter_templates << "@model = #{prefix}filter#{infix}#{name} if #{prefix}#{name};"
|
|
148
|
+
else
|
|
149
|
+
query = build_like_query(
|
|
150
|
+
type: type,
|
|
151
|
+
query: '',
|
|
152
|
+
filter: "#{prefix}#{name}",
|
|
153
|
+
search_mode: search_mode,
|
|
154
|
+
key: keys.last.to_s.pluralize,
|
|
155
|
+
leaf: leaf
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
@filter_methods << "def #{prefix}filter#{infix}#{name};"\
|
|
159
|
+
"@model.joins(#{joins}).#{query}; end;"
|
|
160
|
+
|
|
161
|
+
@filter_templates << "@model = #{prefix}filter#{infix}#{name} if #{prefix}#{name};"
|
|
162
|
+
end
|
|
147
163
|
else
|
|
148
164
|
@filter_methods << "def #{prefix}filter#{infix}#{name};"\
|
|
149
165
|
"@model.joins(#{joins}).where(#{where}); end;"
|
|
@@ -194,22 +194,37 @@ module Rokaki
|
|
|
194
194
|
leaf = nil
|
|
195
195
|
leaf = keys.pop
|
|
196
196
|
|
|
197
|
+
# Compute key_leaf (qualified column) like other branches
|
|
198
|
+
key_leaf = keys.last ? "#{keys.last.to_s.pluralize}.#{leaf}" : leaf
|
|
199
|
+
|
|
200
|
+
if db == :sqlserver
|
|
201
|
+
# Build relation base with joins
|
|
202
|
+
if join_map.empty?
|
|
203
|
+
rel_expr = "@model"
|
|
204
|
+
elsif join_map.is_a?(Array)
|
|
205
|
+
rel_expr = "@model.joins(*#{join_map})"
|
|
206
|
+
else
|
|
207
|
+
rel_expr = "@model.joins(**#{join_map})"
|
|
208
|
+
end
|
|
197
209
|
|
|
198
|
-
|
|
199
|
-
type: type,
|
|
200
|
-
query: '',
|
|
201
|
-
filter: filter_name,
|
|
202
|
-
search_mode: search_mode,
|
|
203
|
-
key: keys.last,
|
|
204
|
-
leaf: leaf
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
if join_map.empty?
|
|
208
|
-
filter_query = "@model.#{query}"
|
|
209
|
-
elsif join_map.is_a?(Array)
|
|
210
|
-
filter_query = "@model.joins(*#{join_map}).#{query}"
|
|
210
|
+
filter_query = "sqlserver_like(#{rel_expr}, \"#{key_leaf}\", \"#{type.to_s.upcase}\", #{filter_name}, :#{search_mode})"
|
|
211
211
|
else
|
|
212
|
-
|
|
212
|
+
query = build_like_query(
|
|
213
|
+
type: type,
|
|
214
|
+
query: '',
|
|
215
|
+
filter: filter_name,
|
|
216
|
+
search_mode: search_mode,
|
|
217
|
+
key: keys.last,
|
|
218
|
+
leaf: leaf
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
if join_map.empty?
|
|
222
|
+
filter_query = "@model.#{query}"
|
|
223
|
+
elsif join_map.is_a?(Array)
|
|
224
|
+
filter_query = "@model.joins(*#{join_map}).#{query}"
|
|
225
|
+
else
|
|
226
|
+
filter_query = "@model.joins(**#{join_map}).#{query}"
|
|
227
|
+
end
|
|
213
228
|
end
|
|
214
229
|
|
|
215
230
|
if mode == or_key
|
|
@@ -225,9 +240,20 @@ module Rokaki
|
|
|
225
240
|
if db == :postgres
|
|
226
241
|
query = "where(\"#{key_leaf} #{type.to_s.upcase} ANY (ARRAY[?])\", "
|
|
227
242
|
query += "prepare_terms(#{filter}, :#{search_mode}))"
|
|
228
|
-
|
|
243
|
+
elsif db == :mysql
|
|
229
244
|
query = "where(\"#{key_leaf} #{type.to_s.upcase} :query\", "
|
|
230
245
|
query += "query: prepare_regex_terms(#{filter}, :#{search_mode}))"
|
|
246
|
+
else # :sqlserver and others
|
|
247
|
+
query = "where(\"#{key_leaf} #{type.to_s.upcase} :query\", "
|
|
248
|
+
if search_mode == :circumfix
|
|
249
|
+
query += "query: \"%\#{#{filter}}%\")"
|
|
250
|
+
elsif search_mode == :prefix
|
|
251
|
+
query += "query: \"%\#{#{filter}}\")"
|
|
252
|
+
elsif search_mode == :suffix
|
|
253
|
+
query += "query: \"\#{#{filter}}%\")"
|
|
254
|
+
else
|
|
255
|
+
query += "query: \"%\#{#{filter}}%\")"
|
|
256
|
+
end
|
|
231
257
|
end
|
|
232
258
|
|
|
233
259
|
query
|
data/lib/rokaki/filter_model.rb
CHANGED
|
@@ -19,6 +19,56 @@ module Rokaki
|
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
# Escape special LIKE characters in SQL Server patterns: %, _, [ and \\
|
|
23
|
+
def escape_like(term)
|
|
24
|
+
term.to_s.gsub(/[\\%_\[]/) { |m| "\\#{m}" }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Build LIKE patterns with proper prefix/suffix/circumfix and escaping for SQL Server
|
|
28
|
+
# Returns a String when param is scalar, or an Array of Strings when param is an Array
|
|
29
|
+
def prepare_like_terms(param, mode)
|
|
30
|
+
if Array === param
|
|
31
|
+
case mode
|
|
32
|
+
when :circumfix
|
|
33
|
+
param.map { |t| "%#{escape_like(t)}%" }
|
|
34
|
+
when :prefix
|
|
35
|
+
param.map { |t| "%#{escape_like(t)}" }
|
|
36
|
+
when :suffix
|
|
37
|
+
param.map { |t| "#{escape_like(t)}%" }
|
|
38
|
+
else
|
|
39
|
+
param.map { |t| "%#{escape_like(t)}%" }
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
case mode
|
|
43
|
+
when :circumfix
|
|
44
|
+
"%#{escape_like(param)}%"
|
|
45
|
+
when :prefix
|
|
46
|
+
"%#{escape_like(param)}"
|
|
47
|
+
when :suffix
|
|
48
|
+
"#{escape_like(param)}%"
|
|
49
|
+
else
|
|
50
|
+
"%#{escape_like(param)}%"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Compose a SQL Server LIKE relation supporting arrays of terms (OR chained)
|
|
56
|
+
# column should be a fully qualified column expression, e.g., "authors.first_name" or "cs.title"
|
|
57
|
+
# type is usually "LIKE"
|
|
58
|
+
def sqlserver_like(model, column, type, value, mode)
|
|
59
|
+
terms = prepare_like_terms(value, mode)
|
|
60
|
+
if terms.is_a?(Array)
|
|
61
|
+
return model.none if terms.empty?
|
|
62
|
+
rel = model.where("#{column} #{type} :q0 ESCAPE '\\'", q0: terms[0])
|
|
63
|
+
terms[1..-1]&.each_with_index do |t, i|
|
|
64
|
+
rel = rel.or(model.where("#{column} #{type} :q#{i + 1} ESCAPE '\\'", "q#{i + 1}".to_sym => t))
|
|
65
|
+
end
|
|
66
|
+
rel
|
|
67
|
+
else
|
|
68
|
+
model.where("#{column} #{type} :q ESCAPE '\\'", q: terms)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
22
72
|
def prepare_regex_terms(param, mode)
|
|
23
73
|
if Array === param
|
|
24
74
|
param_map = param.map { |term| ".*#{term}.*" } if mode == :circumfix
|
|
@@ -53,6 +103,23 @@ module Rokaki
|
|
|
53
103
|
|
|
54
104
|
private
|
|
55
105
|
|
|
106
|
+
def normalize_like_modes(obj)
|
|
107
|
+
case obj
|
|
108
|
+
when Hash
|
|
109
|
+
obj.each_with_object({}) do |(k, v), h|
|
|
110
|
+
h[k] = normalize_like_modes(v)
|
|
111
|
+
end
|
|
112
|
+
when Array
|
|
113
|
+
obj.map { |e| normalize_like_modes(e) }
|
|
114
|
+
when Symbol
|
|
115
|
+
# Treat alternative affixes as circumfix
|
|
116
|
+
return :circumfix if [:parafix, :confix, :ambifix].include?(obj)
|
|
117
|
+
obj
|
|
118
|
+
else
|
|
119
|
+
obj
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
56
123
|
def filter_map(model, query_key, options)
|
|
57
124
|
filter_model(model)
|
|
58
125
|
@filter_map_query_key = query_key
|
|
@@ -187,6 +254,10 @@ module Rokaki
|
|
|
187
254
|
elsif @_filter_db == :mysql
|
|
188
255
|
# 'LIKE BINARY'
|
|
189
256
|
'REGEXP'
|
|
257
|
+
elsif @_filter_db == :sqlserver
|
|
258
|
+
'LIKE'
|
|
259
|
+
else
|
|
260
|
+
'LIKE'
|
|
190
261
|
end
|
|
191
262
|
end
|
|
192
263
|
|
|
@@ -196,22 +267,28 @@ module Rokaki
|
|
|
196
267
|
elsif @_filter_db == :mysql
|
|
197
268
|
# 'LIKE'
|
|
198
269
|
'REGEXP'
|
|
270
|
+
elsif @_filter_db == :sqlserver
|
|
271
|
+
'LIKE'
|
|
272
|
+
else
|
|
273
|
+
'LIKE'
|
|
199
274
|
end
|
|
200
275
|
end
|
|
201
276
|
|
|
202
277
|
def like(args)
|
|
203
278
|
raise ArgumentError, 'argument mush be a hash' unless args.is_a? Hash
|
|
204
|
-
|
|
279
|
+
normalized = normalize_like_modes(args)
|
|
280
|
+
@_like_semantics = (@_like_semantics || {}).merge(normalized)
|
|
205
281
|
|
|
206
|
-
like_keys = LikeKeys.new(
|
|
282
|
+
like_keys = LikeKeys.new(normalized)
|
|
207
283
|
like_filters(like_keys, term_type: case_sensitive)
|
|
208
284
|
end
|
|
209
285
|
|
|
210
286
|
def ilike(args)
|
|
211
287
|
raise ArgumentError, 'argument mush be a hash' unless args.is_a? Hash
|
|
212
|
-
|
|
288
|
+
normalized = normalize_like_modes(args)
|
|
289
|
+
@i_like_semantics = (@i_like_semantics || {}).merge(normalized)
|
|
213
290
|
|
|
214
|
-
like_keys = LikeKeys.new(
|
|
291
|
+
like_keys = LikeKeys.new(normalized)
|
|
215
292
|
like_filters(like_keys, term_type: case_insensitive)
|
|
216
293
|
end
|
|
217
294
|
|
data/lib/rokaki/version.rb
CHANGED
data/rokaki.gemspec
CHANGED
|
@@ -47,5 +47,8 @@ Gem::Specification.new do |spec|
|
|
|
47
47
|
spec.add_development_dependency 'mysql2'
|
|
48
48
|
spec.add_development_dependency 'sqlite3'
|
|
49
49
|
spec.add_development_dependency 'database_cleaner-active_record'
|
|
50
|
+
# For SQL Server testing
|
|
51
|
+
spec.add_development_dependency 'tiny_tds'
|
|
52
|
+
spec.add_development_dependency 'activerecord-sqlserver-adapter'
|
|
50
53
|
|
|
51
54
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rokaki
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Steve Martin
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-10-
|
|
11
|
+
date: 2025-10-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -206,6 +206,34 @@ dependencies:
|
|
|
206
206
|
- - ">="
|
|
207
207
|
- !ruby/object:Gem::Version
|
|
208
208
|
version: '0'
|
|
209
|
+
- !ruby/object:Gem::Dependency
|
|
210
|
+
name: tiny_tds
|
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
|
212
|
+
requirements:
|
|
213
|
+
- - ">="
|
|
214
|
+
- !ruby/object:Gem::Version
|
|
215
|
+
version: '0'
|
|
216
|
+
type: :development
|
|
217
|
+
prerelease: false
|
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
219
|
+
requirements:
|
|
220
|
+
- - ">="
|
|
221
|
+
- !ruby/object:Gem::Version
|
|
222
|
+
version: '0'
|
|
223
|
+
- !ruby/object:Gem::Dependency
|
|
224
|
+
name: activerecord-sqlserver-adapter
|
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
|
226
|
+
requirements:
|
|
227
|
+
- - ">="
|
|
228
|
+
- !ruby/object:Gem::Version
|
|
229
|
+
version: '0'
|
|
230
|
+
type: :development
|
|
231
|
+
prerelease: false
|
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
233
|
+
requirements:
|
|
234
|
+
- - ">="
|
|
235
|
+
- !ruby/object:Gem::Version
|
|
236
|
+
version: '0'
|
|
209
237
|
description: A dsl for filtering data in web requests
|
|
210
238
|
email:
|
|
211
239
|
- steve@martian.media
|
|
@@ -214,12 +242,12 @@ extensions: []
|
|
|
214
242
|
extra_rdoc_files: []
|
|
215
243
|
files:
|
|
216
244
|
- ".github/workflows/codeql-analysis.yml"
|
|
245
|
+
- ".github/workflows/pages.yml"
|
|
217
246
|
- ".github/workflows/spec.yml"
|
|
218
247
|
- ".gitignore"
|
|
219
248
|
- ".rspec"
|
|
220
249
|
- ".ruby-version"
|
|
221
250
|
- ".travis.yml"
|
|
222
|
-
- CODE_OF_CONDUCT.md
|
|
223
251
|
- Gemfile
|
|
224
252
|
- Gemfile.lock
|
|
225
253
|
- Guardfile
|
|
@@ -228,6 +256,12 @@ files:
|
|
|
228
256
|
- Rakefile
|
|
229
257
|
- bin/console
|
|
230
258
|
- bin/setup
|
|
259
|
+
- docs/Gemfile
|
|
260
|
+
- docs/_config.yml
|
|
261
|
+
- docs/adapters.md
|
|
262
|
+
- docs/configuration.md
|
|
263
|
+
- docs/index.md
|
|
264
|
+
- docs/usage.md
|
|
231
265
|
- lib/rokaki.rb
|
|
232
266
|
- lib/rokaki/filter_model.rb
|
|
233
267
|
- lib/rokaki/filter_model/basic_filter.rb
|
data/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# Contributor Covenant Code of Conduct
|
|
2
|
-
|
|
3
|
-
## Our Pledge
|
|
4
|
-
|
|
5
|
-
In the interest of fostering an open and welcoming environment, we as
|
|
6
|
-
contributors and maintainers pledge to making participation in our project and
|
|
7
|
-
our community a harassment-free experience for everyone, regardless of age, body
|
|
8
|
-
size, disability, ethnicity, gender identity and expression, level of experience,
|
|
9
|
-
nationality, personal appearance, race, religion, or sexual identity and
|
|
10
|
-
orientation.
|
|
11
|
-
|
|
12
|
-
## Our Standards
|
|
13
|
-
|
|
14
|
-
Examples of behavior that contributes to creating a positive environment
|
|
15
|
-
include:
|
|
16
|
-
|
|
17
|
-
* Using welcoming and inclusive language
|
|
18
|
-
* Being respectful of differing viewpoints and experiences
|
|
19
|
-
* Gracefully accepting constructive criticism
|
|
20
|
-
* Focusing on what is best for the community
|
|
21
|
-
* Showing empathy towards other community members
|
|
22
|
-
|
|
23
|
-
Examples of unacceptable behavior by participants include:
|
|
24
|
-
|
|
25
|
-
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
26
|
-
advances
|
|
27
|
-
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
28
|
-
* Public or private harassment
|
|
29
|
-
* Publishing others' private information, such as a physical or electronic
|
|
30
|
-
address, without explicit permission
|
|
31
|
-
* Other conduct which could reasonably be considered inappropriate in a
|
|
32
|
-
professional setting
|
|
33
|
-
|
|
34
|
-
## Our Responsibilities
|
|
35
|
-
|
|
36
|
-
Project maintainers are responsible for clarifying the standards of acceptable
|
|
37
|
-
behavior and are expected to take appropriate and fair corrective action in
|
|
38
|
-
response to any instances of unacceptable behavior.
|
|
39
|
-
|
|
40
|
-
Project maintainers have the right and responsibility to remove, edit, or
|
|
41
|
-
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
42
|
-
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
43
|
-
permanently any contributor for other behaviors that they deem inappropriate,
|
|
44
|
-
threatening, offensive, or harmful.
|
|
45
|
-
|
|
46
|
-
## Scope
|
|
47
|
-
|
|
48
|
-
This Code of Conduct applies both within project spaces and in public spaces
|
|
49
|
-
when an individual is representing the project or its community. Examples of
|
|
50
|
-
representing a project or community include using an official project e-mail
|
|
51
|
-
address, posting via an official social media account, or acting as an appointed
|
|
52
|
-
representative at an online or offline event. Representation of a project may be
|
|
53
|
-
further defined and clarified by project maintainers.
|
|
54
|
-
|
|
55
|
-
## Enforcement
|
|
56
|
-
|
|
57
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
58
|
-
reported by contacting the project team at steve@martian.media. All
|
|
59
|
-
complaints will be reviewed and investigated and will result in a response that
|
|
60
|
-
is deemed necessary and appropriate to the circumstances. The project team is
|
|
61
|
-
obligated to maintain confidentiality with regard to the reporter of an incident.
|
|
62
|
-
Further details of specific enforcement policies may be posted separately.
|
|
63
|
-
|
|
64
|
-
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
65
|
-
faith may face temporary or permanent repercussions as determined by other
|
|
66
|
-
members of the project's leadership.
|
|
67
|
-
|
|
68
|
-
## Attribution
|
|
69
|
-
|
|
70
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
71
|
-
available at [http://contributor-covenant.org/version/1/4][version]
|
|
72
|
-
|
|
73
|
-
[homepage]: http://contributor-covenant.org
|
|
74
|
-
[version]: http://contributor-covenant.org/version/1/4/
|