infotable 0.1.0 → 1.0.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: fcc9d70ae1c44035698031c04e51a334a77d3d8985fe41ca987b623a571b056b
4
- data.tar.gz: 22469f7a9cca784d2452897de1169eef204dd3f992c055dc89f39f1dbb84b78f
3
+ metadata.gz: d4a4640087a4326652f422f2748a16221c9e005461f36d3b9210aeaf4fc6dce3
4
+ data.tar.gz: '0069f48d64135d4ec5e3be03028e3e3358f9cc58c8602ad46e04944decc1a139'
5
5
  SHA512:
6
- metadata.gz: fc8b744dfed6976d6e225f50106bb6c6cdfc00fd61625904d02d2aba7676ecf4e9e36129bee6b986e1fec9537e62543f8d958e4fb631d346af8f8966a4eb6285
7
- data.tar.gz: 762d41b80a2ea2aef2e504586cf6da9098525da095d52aee5a5ed74625a4de3f66059ed9d89ff82f936277f4c6e55643e9e94e950fd01fafa2087fc9cc41a2c0
6
+ metadata.gz: 635b5d4406155421a2e97cd1c8e133ea4aaded835fc962ae90e829a76b808413928e6c68b0f0bd9692abc210b27931cc989695f1faa90b0d5ea108fdbecc22fe
7
+ data.tar.gz: 9064104eecee455e18e5b2c32e1fe76ad19a7d705716e299c622f115aff80a892ca9b42fb0ff3310da00ec4b9769c42e7845a25a9c7c65a47c4d780a29223f41
data/README.md CHANGED
@@ -44,7 +44,7 @@ That's it! You now have a fully functional datatable with sorting and pagination
44
44
 
45
45
  - Rails 8.0+
46
46
  - Ruby 3.3+
47
- - PostgreSQL (filters use `ILIKE`, `HAVING` and `CAST(... AS numeric)`; other databases are not supported)
47
+ - PostgreSQL or SQLite (other databases are not supported). On SQLite, text filters and search ignore case for ASCII letters only (`ś` does not match `Ś`); PostgreSQL matches all letters
48
48
  - [Pagy](https://github.com/ddnexus/pagy) 43 (installed as a dependency)
49
49
  - Tailwind CSS v4 (via `tailwindcss-rails` gem) - **Required for styling**
50
50
  - Hotwire (Turbo + Stimulus)
@@ -119,7 +119,7 @@ module Infotable
119
119
 
120
120
  case op
121
121
  when "contains"
122
- result = result.public_send(filter_method, "#{column_ref} ILIKE ?", "%#{sanitize_like(value)}%") if value.present?
122
+ result = result.public_send(filter_method, like(column_ref), "%#{sanitize_like(value)}%") if value.present?
123
123
  when "exact"
124
124
  if is_virtual
125
125
  result = result.having("LOWER(#{column_ref}) = LOWER(?)", value) if value.present?
@@ -127,11 +127,11 @@ module Infotable
127
127
  result = result.where("LOWER(#{column_ref}) = LOWER(?)", value) if value.present?
128
128
  end
129
129
  when "not_contain"
130
- result = result.public_send(filter_method, "NOT #{column_ref} ILIKE ?", "%#{sanitize_like(value)}%") if value.present?
130
+ result = result.public_send(filter_method, like(column_ref, negate: true), "%#{sanitize_like(value)}%") if value.present?
131
131
  when "starts_with"
132
- result = result.public_send(filter_method, "#{column_ref} ILIKE ?", "#{sanitize_like(value)}%") if value.present?
132
+ result = result.public_send(filter_method, like(column_ref), "#{sanitize_like(value)}%") if value.present?
133
133
  when "ends_with"
134
- result = result.public_send(filter_method, "#{column_ref} ILIKE ?", "%#{sanitize_like(value)}") if value.present?
134
+ result = result.public_send(filter_method, like(column_ref), "%#{sanitize_like(value)}") if value.present?
135
135
  when "is_empty"
136
136
  result = result.public_send(filter_method, "#{column_ref} IS NULL OR #{column_ref} = ''")
137
137
  when "is_not_empty"
@@ -299,6 +299,10 @@ module Infotable
299
299
  DECLARED_TYPES[column[:type]]
300
300
  end
301
301
 
302
+ def like(column_ref, negate: false)
303
+ Infotable::Sql.like(query.model.connection, column_ref, negate: negate)
304
+ end
305
+
302
306
  # Helper to sanitize LIKE values
303
307
  def sanitize_like(value)
304
308
  return "" if value.blank?
@@ -1,5 +1,5 @@
1
1
  module Infotable
2
- # Global search: every whitespace-separated term must match (ILIKE) at least one
2
+ # Global search: every whitespace-separated term must match (case-insensitively) at least one
3
3
  # searchable column. Non-text columns are matched on their text representation.
4
4
  class SearchProcessor
5
5
  MAX_TERMS = 5
@@ -19,8 +19,8 @@ module Infotable
19
19
 
20
20
  terms.reduce(query) do |relation, word|
21
21
  pattern = "%#{ActiveRecord::Base.sanitize_sql_like(word)}%"
22
- conditions = columns.map { "CAST(#{column_ref(_1)} AS text) ILIKE :pattern" }
23
- relation.where(conditions.join(" OR "), pattern: pattern)
22
+ conditions = columns.map { Infotable::Sql.like(query.model.connection, "CAST(#{column_ref(_1)} AS text)") }
23
+ relation.where(conditions.join(" OR "), *[ pattern ] * columns.size)
24
24
  end
25
25
  end
26
26
 
@@ -0,0 +1,22 @@
1
+ module Infotable
2
+ # The few SQL fragments that differ between databases (PostgreSQL, SQLite).
3
+ module Sql
4
+ module_function
5
+
6
+ def postgresql?(connection)
7
+ connection.adapter_name.match?(/postg/i)
8
+ end
9
+
10
+ def sqlite?(connection)
11
+ connection.adapter_name.match?(/sqlite/i)
12
+ end
13
+
14
+ # Case-insensitive LIKE with one bind placeholder. SQLite's LIKE ignores case for ASCII only;
15
+ # PostgreSQL gets a real ILIKE.
16
+ def like(connection, ref, negate: false)
17
+ operator = postgresql?(connection) ? "ILIKE ?" : "LIKE ?"
18
+ operator += " ESCAPE '\\'" if sqlite?(connection) # SQLite has no default escape character
19
+ "#{'NOT ' if negate}#{ref} #{operator}"
20
+ end
21
+ end
22
+ end
@@ -1,3 +1,3 @@
1
1
  module Infotable
2
- VERSION = "0.1.0"
2
+ VERSION = "1.0.0"
3
3
  end
data/lib/infotable.rb CHANGED
@@ -10,6 +10,7 @@ module Infotable
10
10
  autoload :FilterProcessor, "infotable/filter_processor"
11
11
  autoload :BatchActions, "infotable/batch_actions"
12
12
  autoload :SearchProcessor, "infotable/search_processor"
13
+ autoload :Sql, "infotable/sql"
13
14
  autoload :TableResolver, "infotable/table_resolver"
14
15
 
15
16
  # Formatters
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: infotable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub Cieślar
@@ -184,6 +184,7 @@ files:
184
184
  - lib/infotable/formatters/link_formatter.rb
185
185
  - lib/infotable/formatters/percent_formatter.rb
186
186
  - lib/infotable/search_processor.rb
187
+ - lib/infotable/sql.rb
187
188
  - lib/infotable/table_resolver.rb
188
189
  - lib/infotable/version.rb
189
190
  - lib/tasks/infotable.rake