rokaki 0.13.0 → 0.14.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2659a359499939511a45107cc281e2aecce654ecf587f668e9de52d6fd8e3424
4
- data.tar.gz: 4a5dfa2b6eef83fb731bb558575bdd5072b2c5ff2f4dc3670b11cae9487447ff
3
+ metadata.gz: ed3b16c71be49df063699af31b64190d9aa2db724bd5f6310e458aa33f63025a
4
+ data.tar.gz: c81607decccf33f1e9a71b1e68c3bd478428b22a1f375f9e5554b39ddfc0d8d6
5
5
  SHA512:
6
- metadata.gz: a120036a6621d1ca69631d95fccd5fa3fac82cbb4a630bffcc5a5ea87ec026ef416fda109964eec929d1c8874af7a4dc08e06bab2cd1789779332ae9796b645e
7
- data.tar.gz: 656df3353ae9593cdeaa75ce0b0111728fbbb420d8c4885928fcc334369ceaa07ea09f78a49b93b3ab45ea8d5767b81f9280cd9cf55260690a0a34270947c7ab
6
+ metadata.gz: 18d022ef801a2a978f01d1f142c34fb95171131d30f8f8cbe8837a60fc9ea44c162d48e9f672380a965f578de65b568124686399974918497141e0eca549b29a
7
+ data.tar.gz: 77f547a998d588d4128f6df533ae0e555c8561b402e496b53b66c7daee87e42a7ed3b2152ef5101930abd568ee2b0b268aeb71bb75d841feabb102238d776f49
@@ -35,21 +35,67 @@ jobs:
35
35
  - 1433:1433
36
36
  # No built-in healthcheck; we'll wait in a step using nc
37
37
 
38
+ oracle:
39
+ image: gvenzl/oracle-free:23-slim
40
+ env:
41
+ ORACLE_PASSWORD: "oracle"
42
+ APP_USER: ROKAKI
43
+ APP_USER_PASSWORD: rokaki
44
+ ports:
45
+ - 1521:1521
46
+
38
47
  steps:
39
48
  - uses: actions/checkout@v2
40
49
 
41
50
  - name: Install system dependencies
42
51
  run: |
43
52
  sudo apt-get update
44
- sudo apt-get install -y build-essential libpq-dev default-libmysqlclient-dev freetds-dev netcat-openbsd
53
+ sudo apt-get install -y build-essential libpq-dev default-libmysqlclient-dev freetds-dev netcat-openbsd unzip curl libaio1t64 libaio-dev
54
+ sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1
45
55
 
46
56
  - name: Set up Ruby
47
57
  uses: ruby/setup-ruby@v1
48
58
  with:
49
- # Not needed with a .ruby-version file
50
59
  ruby-version: 3.3.0
51
- # runs 'bundle install' and caches installed gems automatically
52
- bundler-cache: true
60
+ bundler-cache: false # we'll run bundle after Instant Client is present
61
+
62
+ - name: Install Oracle Instant Client (ZIP Basic Lite + SDK)
63
+ run: |
64
+ set -e
65
+ sudo mkdir -p /opt/oracle && cd /opt/oracle
66
+ # Download current 23.5 ZIPs directly from Oracle
67
+ curl -fL -o ic-basic.zip https://download.oracle.com/otn_software/linux/instantclient/2326000/instantclient-basic-linux.x64-23.26.0.0.0.zip
68
+ curl -fL -o ic-sdk.zip https://download.oracle.com/otn_software/linux/instantclient/2326000/instantclient-sdk-linux.x64-23.26.0.0.0.zip
69
+ sudo unzip -q -o ic-basic.zip
70
+ sudo unzip -q -o ic-sdk.zip
71
+ ls /opt/oracle
72
+ cd /opt/oracle/instantclient_23_26 && sudo ln -s ../instantclient_23_26 lib
73
+ cd /opt/oracle/instantclient_23_26 && sudo ln -s sdk/include include
74
+ IC_DIR=/opt/oracle/instantclient_23_26
75
+ echo "OCI_DIR=$IC_DIR" | sudo tee -a $GITHUB_ENV
76
+ echo "OCI_LIB_DIR=$IC_DIR" | sudo tee -a $GITHUB_ENV
77
+ echo "OCI_INC_DIR=$IC_DIR/sdk/include" | sudo tee -a $GITHUB_ENV
78
+ echo "LD_LIBRARY_PATH=$IC_DIR:$LD_LIBRARY_PATH" | sudo tee -a $GITHUB_ENV
79
+
80
+ - name: Bundle install (after Instant Client)
81
+ id: bundleInstallAfterInstantClient
82
+ env:
83
+ ORACLE_HOME: /opt/oracle/instantclient_23_26
84
+ OCI_DIR: ${{ env.OCI_DIR }}
85
+ OCI_LIB_DIR: ${{ env.OCI_LIB_DIR }}
86
+ OCI_INC_DIR: ${{ env.OCI_INC_DIR }}
87
+ LD_LIBRARY_PATH: ${{ env.LD_LIBRARY_PATH }}
88
+ run: |
89
+ ls /opt/oracle/instantclient_23_26
90
+ bundle config set build.ruby-oci8 "--with-instant-client-dir=/opt/oracle/instantclient_23_26 --with-instant-client-include=/opt/oracle/instantclient_23_26/sdk/include --with-instant-client-lib=/opt/oracle/instantclient_23_26"
91
+ bundle install --jobs 4 --retry 3
92
+
93
+ - name: Archive Build Artifact
94
+ if: failure() && steps.bundleInstallAfterInstantClient.outcome == 'failure'
95
+ uses: actions/upload-artifact@v4
96
+ with:
97
+ name: build-mkmf-log
98
+ path: /opt/hostedtoolcache/Ruby/3.3.0/x64/lib/ruby/gems/3.3.0/extensions/x86_64-linux/3.3.0/ruby-oci8-2.2.14/mkmf.log
53
99
 
54
100
  - name: Wait for databases to be ready
55
101
  shell: bash
@@ -63,7 +109,24 @@ jobs:
63
109
  for i in {1..120}; do
64
110
  nc -z 127.0.0.1 1433 && echo "SQL Server up" && break || sleep 1
65
111
  done
112
+ for i in {1..180}; do
113
+ nc -z 127.0.0.1 1521 && echo "Oracle up" && break || sleep 1
114
+ done
66
115
 
67
116
  - name: Run tests
117
+ env:
118
+ POSTGRES_HOST: 127.0.0.1
119
+ POSTGRES_USERNAME: postgres
120
+ POSTGRES_PASSWORD: postgres
121
+ SQLSERVER_HOST: 127.0.0.1
122
+ SQLSERVER_PORT: 1433
123
+ SQLSERVER_USERNAME: sa
124
+ SQLSERVER_PASSWORD: 5QL5£rv£r
125
+ ORACLE_HOST: 127.0.0.1
126
+ ORACLE_PORT: 1521
127
+ ORACLE_DATABASE: /freepdb1
128
+ ORACLE_USERNAME: ROKAKI
129
+ ORACLE_PASSWORD: rokaki
130
+ LD_LIBRARY_PATH: ${{ env.LD_LIBRARY_PATH }}
68
131
  run: |
69
132
  ./spec/ordered_run.sh
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rokaki (0.13.0)
4
+ rokaki (0.14.0)
5
5
  activesupport
6
6
 
7
7
  GEM
@@ -13,6 +13,10 @@ GEM
13
13
  activemodel (= 8.0.3)
14
14
  activesupport (= 8.0.3)
15
15
  timeout (>= 0.4.0)
16
+ activerecord-oracle_enhanced-adapter (8.0.0)
17
+ activerecord (~> 8.0.0)
18
+ ruby-oci8
19
+ ruby-plsql (>= 0.6.0)
16
20
  activerecord-sqlserver-adapter (8.0.9)
17
21
  activerecord (~> 8.0.0)
18
22
  tiny_tds
@@ -30,8 +34,8 @@ GEM
30
34
  tzinfo (~> 2.0, >= 2.0.5)
31
35
  uri (>= 0.13.1)
32
36
  base64 (0.3.0)
33
- benchmark (0.4.1)
34
- bigdecimal (3.2.3)
37
+ benchmark (0.5.0)
38
+ bigdecimal (3.3.1)
35
39
  byebug (12.0.0)
36
40
  coderay (1.1.3)
37
41
  concurrent-ruby (1.3.5)
@@ -42,7 +46,7 @@ GEM
42
46
  database_cleaner-core (2.0.1)
43
47
  diff-lcs (1.6.2)
44
48
  drb (2.2.3)
45
- factory_bot (6.5.5)
49
+ factory_bot (6.5.6)
46
50
  activesupport (>= 6.1.0)
47
51
  ffi (1.17.2-aarch64-linux-gnu)
48
52
  ffi (1.17.2-aarch64-linux-musl)
@@ -81,7 +85,7 @@ GEM
81
85
  logger (1.7.0)
82
86
  lumberjack (1.4.2)
83
87
  method_source (1.1.0)
84
- minitest (5.25.5)
88
+ minitest (5.26.0)
85
89
  mysql2 (0.5.7)
86
90
  bigdecimal
87
91
  nenv (0.3.0)
@@ -108,19 +112,21 @@ GEM
108
112
  ffi (~> 1.0)
109
113
  reline (0.6.2)
110
114
  io-console (~> 0.5)
111
- rspec (3.13.1)
115
+ rspec (3.13.2)
112
116
  rspec-core (~> 3.13.0)
113
117
  rspec-expectations (~> 3.13.0)
114
118
  rspec-mocks (~> 3.13.0)
115
- rspec-core (3.13.5)
119
+ rspec-core (3.13.6)
116
120
  rspec-support (~> 3.13.0)
117
121
  rspec-expectations (3.13.5)
118
122
  diff-lcs (>= 1.2.0, < 2.0)
119
123
  rspec-support (~> 3.13.0)
120
- rspec-mocks (3.13.5)
124
+ rspec-mocks (3.13.6)
121
125
  diff-lcs (>= 1.2.0, < 2.0)
122
126
  rspec-support (~> 3.13.0)
123
127
  rspec-support (3.13.6)
128
+ ruby-oci8 (2.2.14)
129
+ ruby-plsql (0.8.0)
124
130
  securerandom (0.4.1)
125
131
  shellany (0.0.1)
126
132
  sqlite3 (2.7.4-aarch64-linux-gnu)
@@ -147,7 +153,7 @@ GEM
147
153
  bigdecimal (~> 3)
148
154
  tzinfo (2.0.6)
149
155
  concurrent-ruby (~> 1.0)
150
- uri (1.0.3)
156
+ uri (1.0.4)
151
157
 
152
158
  PLATFORMS
153
159
  aarch64-linux
@@ -164,7 +170,8 @@ PLATFORMS
164
170
  x86_64-linux-musl
165
171
 
166
172
  DEPENDENCIES
167
- activerecord
173
+ activerecord (>= 7.1, < 9.0)
174
+ activerecord-oracle_enhanced-adapter (~> 8.0.0)
168
175
  activerecord-sqlserver-adapter
169
176
  bundler (~> 2.0)
170
177
  database_cleaner-active_record
@@ -178,6 +185,7 @@ DEPENDENCIES
178
185
  rake (~> 13.0)
179
186
  rokaki!
180
187
  rspec (~> 3.0)
188
+ ruby-oci8
181
189
  sqlite3
182
190
  tiny_tds
183
191
 
data/docs/adapters.md CHANGED
@@ -4,7 +4,7 @@ title: Database adapters
4
4
  permalink: /adapters
5
5
  ---
6
6
 
7
- Rokaki generates adapter‑aware SQL for PostgreSQL, MySQL, and SQL Server.
7
+ Rokaki generates adapter‑aware SQL for PostgreSQL, MySQL, SQL Server, and Oracle.
8
8
 
9
9
  ## Overview
10
10
 
@@ -40,6 +40,8 @@ module Rokaki
40
40
  'LIKE BINARY'
41
41
  elsif db == :sqlserver
42
42
  'LIKE'
43
+ elsif db == :oracle
44
+ 'LIKE'
43
45
  else
44
46
  'LIKE'
45
47
  end
@@ -52,6 +54,9 @@ module Rokaki
52
54
  'LIKE'
53
55
  elsif db == :sqlserver
54
56
  'LIKE'
57
+ elsif db == :oracle
58
+ # Use 'ILIKE' as a signal; oracle_like will translate to UPPER(column) LIKE UPPER(:q)
59
+ 'ILIKE'
55
60
  else
56
61
  'LIKE'
57
62
  end
@@ -105,6 +110,9 @@ module Rokaki
105
110
  elsif db == :sqlserver
106
111
  # Delegate to helper that supports arrays and escaping with ESCAPE
107
112
  query = "sqlserver_like(@model, \"#{key}\", \"#{type}\", #{filter}, :#{mode})"
113
+ elsif db == :oracle
114
+ # Oracle helper handles case-insensitive via UPPER() when type is 'ILIKE'
115
+ query = "oracle_like(@model, \"#{key}\", \"#{type}\", #{filter}, :#{mode})"
108
116
  else
109
117
  query = "@model.where(\"#{key} #{type} :query\", "
110
118
  query += "query: \"%\#{#{filter}}%\")" if mode == :circumfix
@@ -139,10 +139,11 @@ module Rokaki
139
139
  where = where.join
140
140
 
141
141
  if search_mode
142
- if db == :sqlserver
142
+ if db == :sqlserver || db == :oracle
143
143
  key_leaf = "#{keys.last.to_s.pluralize}.#{leaf}"
144
+ helper = db == :sqlserver ? 'sqlserver_like' : 'oracle_like'
144
145
  @filter_methods << "def #{prefix}filter#{infix}#{name};"\
145
- "sqlserver_like(@model.joins(#{joins}), \"#{key_leaf}\", \"#{type}\", #{prefix}#{name}, :#{search_mode}); end;"
146
+ "#{helper}(@model.joins(#{joins}), \"#{key_leaf}\", \"#{type}\", #{prefix}#{name}, :#{search_mode}); end;"
146
147
 
147
148
  @filter_templates << "@model = #{prefix}filter#{infix}#{name} if #{prefix}#{name};"
148
149
  else
@@ -197,7 +197,7 @@ module Rokaki
197
197
  # Compute key_leaf (qualified column) like other branches
198
198
  key_leaf = keys.last ? "#{keys.last.to_s.pluralize}.#{leaf}" : leaf
199
199
 
200
- if db == :sqlserver
200
+ if db == :sqlserver || db == :oracle
201
201
  # Build relation base with joins
202
202
  if join_map.empty?
203
203
  rel_expr = "@model"
@@ -207,7 +207,11 @@ module Rokaki
207
207
  rel_expr = "@model.joins(**#{join_map})"
208
208
  end
209
209
 
210
- filter_query = "sqlserver_like(#{rel_expr}, \"#{key_leaf}\", \"#{type.to_s.upcase}\", #{filter_name}, :#{search_mode})"
210
+ if db == :sqlserver
211
+ filter_query = "sqlserver_like(#{rel_expr}, \"#{key_leaf}\", \"#{type.to_s.upcase}\", #{filter_name}, :#{search_mode})"
212
+ else
213
+ filter_query = "oracle_like(#{rel_expr}, \"#{key_leaf}\", \"#{type.to_s.upcase}\", #{filter_name}, :#{search_mode})"
214
+ end
211
215
  else
212
216
  query = build_like_query(
213
217
  type: type,
@@ -69,6 +69,27 @@ module Rokaki
69
69
  end
70
70
  end
71
71
 
72
+ # Compose an Oracle LIKE relation supporting arrays of terms and case-insensitive path via UPPER()
73
+ # type_signal: 'LIKE' for case-sensitive semantics; 'ILIKE' to indicate case-insensitive (we will translate)
74
+ def oracle_like(model, column, type_signal, value, mode)
75
+ terms = prepare_like_terms(value, mode)
76
+ ci = (type_signal.to_s.upcase == 'ILIKE')
77
+ col_expr = ci ? "UPPER(#{column})" : column
78
+ build_term = proc { |t| ci ? t.to_s.upcase : t }
79
+
80
+ if terms.is_a?(Array)
81
+ return model.none if terms.empty?
82
+ first = build_term.call(terms[0])
83
+ rel = model.where("#{col_expr} LIKE :q0 ESCAPE '\\'", q0: first)
84
+ terms[1..-1]&.each_with_index do |t, i|
85
+ rel = rel.or(model.where("#{col_expr} LIKE :q#{i + 1} ESCAPE '\\'", "q#{i + 1}".to_sym => build_term.call(t)))
86
+ end
87
+ rel
88
+ else
89
+ model.where("#{col_expr} LIKE :q ESCAPE '\\'", q: build_term.call(terms))
90
+ end
91
+ end
92
+
72
93
  def prepare_regex_terms(param, mode)
73
94
  if Array === param
74
95
  param_map = param.map { |term| ".*#{term}.*" } if mode == :circumfix
@@ -327,6 +348,8 @@ module Rokaki
327
348
  'REGEXP'
328
349
  elsif @_filter_db == :sqlserver
329
350
  'LIKE'
351
+ elsif @_filter_db == :oracle
352
+ 'LIKE'
330
353
  else
331
354
  'LIKE'
332
355
  end
@@ -340,6 +363,9 @@ module Rokaki
340
363
  'REGEXP'
341
364
  elsif @_filter_db == :sqlserver
342
365
  'LIKE'
366
+ elsif @_filter_db == :oracle
367
+ # Use 'ILIKE' as a signal for case-insensitive; oracle_like will translate to UPPER(column) LIKE UPPER(:q)
368
+ 'ILIKE'
343
369
  else
344
370
  'LIKE'
345
371
  end
@@ -77,7 +77,7 @@ module Rokaki
77
77
  @filter_key_prefix ||= prefix
78
78
  end
79
79
 
80
- def filter_key_infix(infix = :_)
80
+ def filter_key_infix(infix = :__)
81
81
  @filter_key_infix ||= infix
82
82
  end
83
83
 
@@ -170,6 +170,8 @@ module Rokaki
170
170
  # Enhance `filters` to support block mode accumulation
171
171
  def filters(*filter_keys)
172
172
  if instance_variable_defined?(:@__in_filterable_block) && @__in_filterable_block
173
+ @__block_filters ||= []
174
+ @__ctx_stack ||= []
173
175
  filter_keys.each do |fk|
174
176
  @__block_filters << wrap_in_context(fk)
175
177
  end
@@ -1,3 +1,3 @@
1
1
  module Rokaki
2
- VERSION = "0.13.0"
2
+ VERSION = "0.14.0"
3
3
  end
data/rokaki.gemspec CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
 
33
33
  spec.add_dependency 'activesupport'
34
34
 
35
- spec.add_development_dependency 'activerecord'
35
+ spec.add_development_dependency 'activerecord', '>= 7.1', '< 9.0'
36
36
  spec.add_development_dependency 'bundler', '~> 2.0'
37
37
  spec.add_development_dependency 'pry'
38
38
  spec.add_development_dependency 'pry-byebug'
@@ -50,5 +50,8 @@ Gem::Specification.new do |spec|
50
50
  # For SQL Server testing
51
51
  spec.add_development_dependency 'tiny_tds'
52
52
  spec.add_development_dependency 'activerecord-sqlserver-adapter'
53
+ # For Oracle testing (optional). Enable by setting WITH_ORACLE=1 before bundling.
54
+ spec.add_development_dependency 'ruby-oci8'
55
+ spec.add_development_dependency 'activerecord-oracle_enhanced-adapter', '~> 8.0.0'
53
56
 
54
57
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rokaki
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Martin
@@ -30,14 +30,20 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '7.1'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '9.0'
34
37
  type: :development
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
41
  - - ">="
39
42
  - !ruby/object:Gem::Version
40
- version: '0'
43
+ version: '7.1'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '9.0'
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: bundler
43
49
  requirement: !ruby/object:Gem::Requirement
@@ -234,6 +240,34 @@ dependencies:
234
240
  - - ">="
235
241
  - !ruby/object:Gem::Version
236
242
  version: '0'
243
+ - !ruby/object:Gem::Dependency
244
+ name: ruby-oci8
245
+ requirement: !ruby/object:Gem::Requirement
246
+ requirements:
247
+ - - ">="
248
+ - !ruby/object:Gem::Version
249
+ version: '0'
250
+ type: :development
251
+ prerelease: false
252
+ version_requirements: !ruby/object:Gem::Requirement
253
+ requirements:
254
+ - - ">="
255
+ - !ruby/object:Gem::Version
256
+ version: '0'
257
+ - !ruby/object:Gem::Dependency
258
+ name: activerecord-oracle_enhanced-adapter
259
+ requirement: !ruby/object:Gem::Requirement
260
+ requirements:
261
+ - - "~>"
262
+ - !ruby/object:Gem::Version
263
+ version: 8.0.0
264
+ type: :development
265
+ prerelease: false
266
+ version_requirements: !ruby/object:Gem::Requirement
267
+ requirements:
268
+ - - "~>"
269
+ - !ruby/object:Gem::Version
270
+ version: 8.0.0
237
271
  description: A dsl for filtering data in web requests
238
272
  email:
239
273
  - steve@martian.media