kiroshi 0.1.0 → 0.1.1
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/README.md +94 -5
- data/lib/kiroshi/filter.rb +41 -30
- data/lib/kiroshi/filter_query/exact.rb +38 -0
- data/lib/kiroshi/filter_query/like.rb +42 -0
- data/lib/kiroshi/filter_query.rb +131 -0
- data/lib/kiroshi/filter_runner.rb +152 -0
- data/lib/kiroshi/filters.rb +12 -5
- data/lib/kiroshi/version.rb +1 -1
- data/lib/kiroshi.rb +157 -3
- data/spec/lib/kiroshi/filter_query/exact_spec.rb +280 -0
- data/spec/lib/kiroshi/filter_query/like_spec.rb +275 -0
- data/spec/lib/kiroshi/filter_query_spec.rb +39 -0
- data/spec/lib/kiroshi/filter_runner_spec.rb +110 -0
- data/spec/lib/kiroshi/filters_spec.rb +63 -0
- data/spec/support/db/schema.rb +14 -0
- data/spec/support/factories/tag.rb +7 -0
- data/spec/support/models/document.rb +2 -0
- data/spec/support/models/tag.rb +7 -0
- metadata +12 -2
@@ -0,0 +1,275 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Kiroshi::FilterQuery::Like, type: :model do
|
6
|
+
describe '#apply' do
|
7
|
+
subject(:query) { described_class.new(filter_runner) }
|
8
|
+
|
9
|
+
let(:filter_runner) { Kiroshi::FilterRunner.new(filter: filter, scope: scope, filters: filters) }
|
10
|
+
let(:filter) { Kiroshi::Filter.new(:name, match: :like) }
|
11
|
+
let(:scope) { Document.all }
|
12
|
+
let(:filter_value) { 'test' }
|
13
|
+
let(:filters) { { name: filter_value } }
|
14
|
+
|
15
|
+
let!(:matching_document) { create(:document, name: 'test_document') }
|
16
|
+
let!(:another_match) { create(:document, name: 'my_test_file') }
|
17
|
+
let!(:non_matching_document) { create(:document, name: 'other_document') }
|
18
|
+
|
19
|
+
let(:expected_sql) do
|
20
|
+
<<~SQL.squish
|
21
|
+
SELECT "documents".* FROM "documents" WHERE (documents.name LIKE '%test%')
|
22
|
+
SQL
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'returns records that partially match the filter value' do
|
26
|
+
expect(query.apply).to include(matching_document)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns multiple records that contain the filter value' do
|
30
|
+
expect(query.apply).to include(another_match)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'does not return records that do not contain the filter value' do
|
34
|
+
expect(query.apply).not_to include(non_matching_document)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'generates correct SQL with LIKE operation' do
|
38
|
+
expect(query.apply.to_sql).to eq(expected_sql)
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when filtering by status attribute' do
|
42
|
+
let(:filter) { Kiroshi::Filter.new(:status, match: :like) }
|
43
|
+
let(:filter_value) { 'pub' }
|
44
|
+
let(:filters) { { status: filter_value } }
|
45
|
+
|
46
|
+
let!(:published_document) { create(:document, status: 'published') }
|
47
|
+
let!(:republished_document) { create(:document, status: 'republished') }
|
48
|
+
let!(:draft_document) { create(:document, status: 'draft') }
|
49
|
+
|
50
|
+
let(:expected_sql) do
|
51
|
+
<<~SQL.squish
|
52
|
+
SELECT "documents".* FROM "documents" WHERE (documents.status LIKE '%pub%')
|
53
|
+
SQL
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'returns documents with partial status match' do
|
57
|
+
expect(query.apply).to include(published_document)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'returns documents with partial match in different positions' do
|
61
|
+
expect(query.apply).to include(republished_document)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'does not return documents without partial status match' do
|
65
|
+
expect(query.apply).not_to include(draft_document)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'generates correct SQL for status filtering' do
|
69
|
+
expect(query.apply.to_sql).to eq(expected_sql)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when filtering with numeric values as strings' do
|
74
|
+
let(:filter) { Kiroshi::Filter.new(:version, match: :like) }
|
75
|
+
let(:filter_value) { '1.2' }
|
76
|
+
let(:filters) { { version: filter_value } }
|
77
|
+
|
78
|
+
let!(:version_match) { create(:document, version: '1.2.3') }
|
79
|
+
let!(:another_version) { create(:document, version: '2.1.2') }
|
80
|
+
let!(:different_version) { create(:document, version: '3.0.0') }
|
81
|
+
|
82
|
+
let(:expected_sql) do
|
83
|
+
<<~SQL.squish
|
84
|
+
SELECT "documents".* FROM "documents" WHERE (documents.version LIKE '%1.2%')
|
85
|
+
SQL
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns documents with partial numeric match' do
|
89
|
+
expect(query.apply).to include(version_match)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'returns documents with partial match in different positions' do
|
93
|
+
expect(query.apply).to include(another_version)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'does not return documents without partial numeric match' do
|
97
|
+
expect(query.apply).not_to include(different_version)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'generates correct SQL for numeric string filtering' do
|
101
|
+
expect(query.apply.to_sql).to eq(expected_sql)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when no records match' do
|
106
|
+
let(:filter_value) { 'nonexistent' }
|
107
|
+
|
108
|
+
let(:expected_sql) do
|
109
|
+
<<~SQL.squish
|
110
|
+
SELECT "documents".* FROM "documents" WHERE (documents.name LIKE '%nonexistent%')
|
111
|
+
SQL
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'returns empty relation' do
|
115
|
+
expect(query.apply).to be_empty
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'still generates valid SQL' do
|
119
|
+
expect(query.apply.to_sql).to eq(expected_sql)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'with case sensitivity' do
|
124
|
+
let(:filter_value) { 'Test' }
|
125
|
+
let!(:lowercase_document) { create(:document, name: 'test_document') }
|
126
|
+
let!(:uppercase_document) { create(:document, name: 'TEST_FILE') }
|
127
|
+
let!(:mixedcase_document) { create(:document, name: 'Test_Document') }
|
128
|
+
let!(:no_match_document) { create(:document, name: 'example') }
|
129
|
+
|
130
|
+
it 'includes documents with exact case match' do
|
131
|
+
expect(query.apply).to include(mixedcase_document)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'includes documents with lowercase match' do
|
135
|
+
expect(query.apply).to include(lowercase_document)
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'includes documents with uppercase match' do
|
139
|
+
expect(query.apply).to include(uppercase_document)
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'excludes documents without any case match' do
|
143
|
+
expect(query.apply).not_to include(no_match_document)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'with special characters in filter value' do
|
148
|
+
let(:filter_value) { 'user@' }
|
149
|
+
let!(:email_document) { create(:document, name: 'user@example.com') }
|
150
|
+
let!(:partial_email_document) { create(:document, name: 'admin_user@test.org') }
|
151
|
+
let!(:no_match_document) { create(:document, name: 'username') }
|
152
|
+
|
153
|
+
it 'includes documents with special character match' do
|
154
|
+
expect(query.apply).to include(email_document)
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'includes documents with partial special character match' do
|
158
|
+
expect(query.apply).to include(partial_email_document)
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'excludes documents without special character match' do
|
162
|
+
expect(query.apply).not_to include(no_match_document)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'with single character filter' do
|
167
|
+
let(:filter_value) { 'a' }
|
168
|
+
let!(:start_match) { create(:document, name: 'apple') }
|
169
|
+
let!(:middle_match) { create(:document, name: 'banana') }
|
170
|
+
let!(:end_match) { create(:document, name: 'extra') }
|
171
|
+
let!(:no_match_document) { create(:document, name: 'test') }
|
172
|
+
|
173
|
+
it 'includes documents with character at start' do
|
174
|
+
expect(query.apply).to include(start_match)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'includes documents with character in middle' do
|
178
|
+
expect(query.apply).to include(middle_match)
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'includes documents with character at end' do
|
182
|
+
expect(query.apply).to include(end_match)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'excludes documents without the character' do
|
186
|
+
expect(query.apply).not_to include(no_match_document)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
context 'when filter has table configured' do
|
191
|
+
let(:scope) { Document.joins(:tags) }
|
192
|
+
let(:filter_value) { 'ruby' }
|
193
|
+
let(:filters) { { name: filter_value } }
|
194
|
+
|
195
|
+
let!(:first_tag) { Tag.find_or_create_by(name: 'ruby') }
|
196
|
+
let!(:second_tag) { Tag.find_or_create_by(name: 'ruby_on_rails') }
|
197
|
+
|
198
|
+
let!(:document_with_ruby_tag) { create(:document, name: 'My Document') }
|
199
|
+
let!(:document_with_rails_tag) { create(:document, name: 'Rails Guide') }
|
200
|
+
let!(:document_without_tag) { create(:document, name: 'Other Document') }
|
201
|
+
|
202
|
+
before do
|
203
|
+
Tag.find_or_create_by(name: 'programming')
|
204
|
+
document_with_ruby_tag.tags << [first_tag]
|
205
|
+
document_with_rails_tag.tags << [second_tag]
|
206
|
+
end
|
207
|
+
|
208
|
+
context 'when filtering by tags table' do
|
209
|
+
let(:filter) { Kiroshi::Filter.new(:name, match: :like, table: :tags) }
|
210
|
+
|
211
|
+
it 'returns documents with tags that partially match the filter value' do
|
212
|
+
expect(query.apply).to include(document_with_ruby_tag)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'returns documents with tags that contain the filter value' do
|
216
|
+
expect(query.apply).to include(document_with_rails_tag)
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'does not return documents without matching tags' do
|
220
|
+
expect(query.apply).not_to include(document_without_tag)
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'generates SQL with tags table qualification' do
|
224
|
+
result_sql = query.apply.to_sql
|
225
|
+
expect(result_sql).to include('tags.name LIKE')
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'generates SQL with correct LIKE pattern for tag name' do
|
229
|
+
result_sql = query.apply.to_sql
|
230
|
+
expect(result_sql).to include("'%ruby%'")
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
context 'when filtering by documents table explicitly' do
|
235
|
+
let(:filter) { Kiroshi::Filter.new(:name, match: :like, table: :documents) }
|
236
|
+
let(:filter_value) { 'Guide' }
|
237
|
+
|
238
|
+
it 'returns documents that partially match the filter value in document name' do
|
239
|
+
expect(query.apply).to include(document_with_rails_tag)
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'does not return documents that do not match document name' do
|
243
|
+
expect(query.apply).not_to include(document_with_ruby_tag)
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'does not return documents without matching document name' do
|
247
|
+
expect(query.apply).not_to include(document_without_tag)
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'generates SQL with documents table qualification' do
|
251
|
+
result_sql = query.apply.to_sql
|
252
|
+
expect(result_sql).to include('documents.name LIKE')
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'generates SQL with correct LIKE pattern for document name' do
|
256
|
+
result_sql = query.apply.to_sql
|
257
|
+
expect(result_sql).to include("'%Guide%'")
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
context 'when table is specified as string' do
|
262
|
+
let(:filter) { Kiroshi::Filter.new(:name, match: :like, table: 'tags') }
|
263
|
+
|
264
|
+
it 'works the same as with symbol table name' do
|
265
|
+
expect(query.apply).to include(document_with_ruby_tag)
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'generates SQL with string table qualification' do
|
269
|
+
result_sql = query.apply.to_sql
|
270
|
+
expect(result_sql).to include('tags.name LIKE')
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Kiroshi::FilterQuery, type: :model do
|
6
|
+
describe '.for' do
|
7
|
+
context 'when match is :exact' do
|
8
|
+
it 'returns the Exact class' do
|
9
|
+
expect(described_class.for(:exact)).to eq(Kiroshi::FilterQuery::Exact)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'when match is :like' do
|
14
|
+
it 'returns the Like class' do
|
15
|
+
expect(described_class.for(:like)).to eq(Kiroshi::FilterQuery::Like)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when match is an unsupported type' do
|
20
|
+
it 'raises ArgumentError for unsupported match type' do
|
21
|
+
expect { described_class.for(:invalid) }.to raise_error(
|
22
|
+
ArgumentError, 'Unsupported match type: invalid'
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'raises ArgumentError for nil match type' do
|
27
|
+
expect { described_class.for(nil) }.to raise_error(
|
28
|
+
ArgumentError, 'Unsupported match type: '
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'raises ArgumentError for string match type' do
|
33
|
+
expect { described_class.for('exact') }.to raise_error(
|
34
|
+
ArgumentError, 'Unsupported match type: exact'
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Kiroshi::FilterRunner, type: :model do
|
6
|
+
describe '#apply' do
|
7
|
+
subject(:runner) { described_class.new(filter: filter, scope: scope, filters: filters) }
|
8
|
+
|
9
|
+
let(:scope) { Document.all }
|
10
|
+
let(:filter_value) { 'test_value' }
|
11
|
+
let(:filters) { { name: filter_value } }
|
12
|
+
let!(:matching_document) { create(:document, name: filter_value) }
|
13
|
+
let!(:non_matching_document) { create(:document, name: 'other_value') }
|
14
|
+
|
15
|
+
context 'when filter match is :exact' do
|
16
|
+
let(:filter) { Kiroshi::Filter.new(:name, match: :exact) }
|
17
|
+
|
18
|
+
it 'returns exact matches' do
|
19
|
+
expect(runner.apply).to include(matching_document)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'does not return non-matching records' do
|
23
|
+
expect(runner.apply).not_to include(non_matching_document)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when filter match is :like' do
|
28
|
+
let(:filter) { Kiroshi::Filter.new(:name, match: :like) }
|
29
|
+
let(:filter_value) { 'test' }
|
30
|
+
let!(:matching_document) { create(:document, name: 'test_document') }
|
31
|
+
let!(:non_matching_document) { create(:document, name: 'other_value') }
|
32
|
+
|
33
|
+
it 'returns partial matches' do
|
34
|
+
expect(runner.apply).to include(matching_document)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not return non-matching records' do
|
38
|
+
expect(runner.apply).not_to include(non_matching_document)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'generates correct SQL with table name prefix' do
|
42
|
+
expected_sql = "SELECT \"documents\".* FROM \"documents\" WHERE (documents.name LIKE '%test%')"
|
43
|
+
expect(runner.apply.to_sql).to eq(expected_sql)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when filter match is not specified (default)' do
|
48
|
+
let(:filter) { Kiroshi::Filter.new(:name) }
|
49
|
+
|
50
|
+
it 'defaults to exact match returning only exact matches' do
|
51
|
+
expect(runner.apply).to include(matching_document)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'defaults to exact match not returning non-matching records' do
|
55
|
+
expect(runner.apply).not_to include(non_matching_document)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when filter value is not present' do
|
60
|
+
let(:filter) { Kiroshi::Filter.new(:name) }
|
61
|
+
let(:filters) { { name: nil } }
|
62
|
+
|
63
|
+
it 'returns the original scope unchanged' do
|
64
|
+
expect(runner.apply).to eq(scope)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'when filter value is empty string' do
|
69
|
+
let(:filter) { Kiroshi::Filter.new(:name) }
|
70
|
+
let(:filters) { { name: '' } }
|
71
|
+
|
72
|
+
it 'returns the original scope unchanged' do
|
73
|
+
expect(runner.apply).to eq(scope)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'when filter attribute is not in filters hash' do
|
78
|
+
let(:filter) { Kiroshi::Filter.new(:status) }
|
79
|
+
let(:filters) { { name: 'test_value' } }
|
80
|
+
|
81
|
+
it 'returns the original scope unchanged' do
|
82
|
+
expect(runner.apply).to eq(scope)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when filters hash is empty' do
|
87
|
+
let(:filter) { Kiroshi::Filter.new(:name) }
|
88
|
+
let(:filters) { {} }
|
89
|
+
|
90
|
+
it 'returns the original scope unchanged' do
|
91
|
+
expect(runner.apply).to eq(scope)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'with multiple attributes' do
|
96
|
+
let(:filter) { Kiroshi::Filter.new(:status, match: :exact) }
|
97
|
+
let(:filters) { { name: 'test_name', status: 'finished' } }
|
98
|
+
let!(:matching_document) { create(:document, name: 'test_name', status: 'finished') }
|
99
|
+
let!(:non_matching_document) { create(:document, name: 'other_name', status: 'processing') }
|
100
|
+
|
101
|
+
it 'filters by the configured attribute only returning the matched' do
|
102
|
+
expect(runner.apply).to include(matching_document)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'does not return non-matching records' do
|
106
|
+
expect(runner.apply).not_to include(non_matching_document)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -90,5 +90,68 @@ RSpec.describe Kiroshi::Filters, type: :model do
|
|
90
90
|
expect(filter_instance.apply(scope)).to eq(scope)
|
91
91
|
end
|
92
92
|
end
|
93
|
+
|
94
|
+
context 'when scope has joined tables with clashing fields' do
|
95
|
+
let(:scope) { Document.joins(:tags) }
|
96
|
+
let(:filters) { { name: 'test_name' } }
|
97
|
+
|
98
|
+
let!(:first_tag) { Tag.find_or_create_by(name: 'ruby') }
|
99
|
+
let!(:second_tag) { Tag.find_or_create_by(name: 'programming') }
|
100
|
+
|
101
|
+
before do
|
102
|
+
filters_class.filter_by :name
|
103
|
+
document.tags << [first_tag, second_tag]
|
104
|
+
other_document.tags << [first_tag]
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'filters by document name, not tag name' do
|
108
|
+
result = filter_instance.apply(scope)
|
109
|
+
expect(result).to include(document)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'does not return documents that do not match document name' do
|
113
|
+
result = filter_instance.apply(scope)
|
114
|
+
expect(result).not_to include(other_document)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'generates SQL that includes documents table qualification for name field' do
|
118
|
+
result = filter_instance.apply(scope)
|
119
|
+
expect(result.to_sql).to include('"documents"."name"')
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'generates SQL that includes the filter value' do
|
123
|
+
result = filter_instance.apply(scope)
|
124
|
+
expect(result.to_sql).to include("'test_name'")
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'when using like filter' do
|
128
|
+
let(:filters) { { name: 'test' } }
|
129
|
+
|
130
|
+
before do
|
131
|
+
filters_class.instance_variable_set(:@filter_configs, [])
|
132
|
+
filters_class.filter_by :name, match: :like
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'filters by document name with LIKE operation' do
|
136
|
+
result = filter_instance.apply(scope)
|
137
|
+
expect(result).to include(document)
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'does not return documents that do not match document name pattern' do
|
141
|
+
result = filter_instance.apply(scope)
|
142
|
+
expect(result).not_to include(other_document)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'generates SQL with table-qualified LIKE operation' do
|
146
|
+
result = filter_instance.apply(scope)
|
147
|
+
expect(result.to_sql).to include('documents.name LIKE')
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'generates SQL with correct LIKE pattern' do
|
151
|
+
result = filter_instance.apply(scope)
|
152
|
+
expect(result.to_sql).to include("'%test%'")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
93
156
|
end
|
94
157
|
end
|
data/spec/support/db/schema.rb
CHANGED
@@ -6,5 +6,19 @@ ActiveRecord::Schema.define do
|
|
6
6
|
create_table :documents, force: true do |t|
|
7
7
|
t.string :name
|
8
8
|
t.string :status
|
9
|
+
t.boolean :active
|
10
|
+
t.integer :priority
|
11
|
+
t.string :version
|
12
|
+
end
|
13
|
+
|
14
|
+
create_table :tags, force: true do |t|
|
15
|
+
t.string :name, null: false
|
16
|
+
t.index :name, unique: true
|
17
|
+
end
|
18
|
+
|
19
|
+
create_table :documents_tags, force: true do |t|
|
20
|
+
t.references :document, null: false, foreign_key: true
|
21
|
+
t.references :tag, null: false, foreign_key: true
|
22
|
+
t.index %i[document_id tag_id], unique: true
|
9
23
|
end
|
10
24
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kiroshi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Darthjee
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-08-
|
11
|
+
date: 2025-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -65,19 +65,29 @@ files:
|
|
65
65
|
- kiroshi.jpg
|
66
66
|
- lib/kiroshi.rb
|
67
67
|
- lib/kiroshi/filter.rb
|
68
|
+
- lib/kiroshi/filter_query.rb
|
69
|
+
- lib/kiroshi/filter_query/exact.rb
|
70
|
+
- lib/kiroshi/filter_query/like.rb
|
71
|
+
- lib/kiroshi/filter_runner.rb
|
68
72
|
- lib/kiroshi/filters.rb
|
69
73
|
- lib/kiroshi/version.rb
|
70
74
|
- spec/integration/readme/.keep
|
71
75
|
- spec/integration/yard/.keep
|
76
|
+
- spec/lib/kiroshi/filter_query/exact_spec.rb
|
77
|
+
- spec/lib/kiroshi/filter_query/like_spec.rb
|
78
|
+
- spec/lib/kiroshi/filter_query_spec.rb
|
79
|
+
- spec/lib/kiroshi/filter_runner_spec.rb
|
72
80
|
- spec/lib/kiroshi/filter_spec.rb
|
73
81
|
- spec/lib/kiroshi/filters_spec.rb
|
74
82
|
- spec/lib/kiroshi_spec.rb
|
75
83
|
- spec/spec_helper.rb
|
76
84
|
- spec/support/db/schema.rb
|
77
85
|
- spec/support/factories/document.rb
|
86
|
+
- spec/support/factories/tag.rb
|
78
87
|
- spec/support/factory_bot.rb
|
79
88
|
- spec/support/models/.keep
|
80
89
|
- spec/support/models/document.rb
|
90
|
+
- spec/support/models/tag.rb
|
81
91
|
- spec/support/shared_examples/.keep
|
82
92
|
homepage: https://github.com/darthjee/kiroshi
|
83
93
|
licenses: []
|