activerecord-turbopuffer-adapter 0.1.8 → 0.1.9

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: f7e4579b0235c712aef39dedae94abdb3e8053ef5b04fff2e46ee38c0fd5710a
4
- data.tar.gz: dadc48af421f105ed95d7964b7929ced1dd613217fdda1b88b00a58c291867cf
3
+ metadata.gz: fde17eff7db3a885b55a20550170a189c505ef52afc6bbdfded1f9b5dfcc9a76
4
+ data.tar.gz: 4ee793a06d003d5d69c6d3748c7a74331d6bd4c5db1df6c4ec79fba22f408fea
5
5
  SHA512:
6
- metadata.gz: 6037d2898aa914ed3990f238ac00b86c4b710d630fd3aa7c9dd3af9200f768736b9207cf8cedf079c01d60fd8fce614cdafdaa5873241b1c7a47fa1f6bb4b9df
7
- data.tar.gz: 8b6c7caf5e1b82fbed33da7e5e06e1232cf9603aab035b6a9ef8540223047020429927721928911c80512c778fbdef5a52b1628ca0110ac4414d0419f18a9aed
6
+ metadata.gz: b716b0601df52af79a1d6edbba112630504f356fb2e6c7b91ad00ac6e41485809b43849eb58d8399f0238190db6ea3f5bd3b0b490f0658b17e2d138132f24b7c
7
+ data.tar.gz: 7b79a130b932801f07c98ec849cb9838c8c86246c432464b64aa2c9c079d8432146bb189986886169f614f395fb5e1c00a7b5ccc56a76424d4fbe1ca3ef6b290
data/README.md CHANGED
@@ -109,6 +109,7 @@ Document.where(tags: nil)
109
109
  Document.where(scores: 90..)
110
110
 
111
111
  Document.order(:title).limit(20)
112
+ Document.order(:title).limit(20).offset(20)
112
113
  Document.group(:title).count
113
114
  Document.count
114
115
  Document.find("018f...")
@@ -128,7 +129,7 @@ Document
128
129
  .limit(10)
129
130
  ```
130
131
 
131
- > Note that turbopuffer has a limit on the maximum number of documents returned (https://turbopuffer.com/docs/query#param-limit), so Document.all.to_a etc. will only return at most 10,000 items
132
+ > Note that turbopuffer has a limit on the maximum number of documents returned (https://turbopuffer.com/docs/query#param-limit), so Document.all.to_a etc. will only return at most 10,000 items, and `limit` plus `offset` must stay within that
132
133
 
133
134
  > Eventual reads are cheaper but may not include writes from the last few seconds. Set a default with `turbopuffer_consistency "eventual"` in a model or `consistency: eventual` in `database.yml`. Strong is the default.
134
135
 
@@ -279,9 +279,11 @@ module ActiveRecord
279
279
 
280
280
  tpuf_query_args = {
281
281
  include_attributes: fields,
282
- top_k: query.top_k.present? ? query.top_k : 10_000
282
+ top_k: query.top_k.present? ? query.top_k : 10_000 - query.offset.to_i
283
283
  }
284
284
 
285
+ tpuf_query_args[:offset] = query.offset if query.offset
286
+
285
287
  tpuf_query_args[:rank_by] = query.rank_by.first if query.rank_by.present?
286
288
  tpuf_query_args[:filters] = query.filters if query.filters
287
289
  consistency = consistency_for(query)
@@ -12,7 +12,8 @@ module Arel::Visitors
12
12
  aggregate_by: @aggregate_by,
13
13
  upsert_rows: @upsert_rows,
14
14
  consistency: @consistency,
15
- namespace_override: @namespace_override
15
+ namespace_override: @namespace_override,
16
+ offset: @offset
16
17
  }
17
18
  end
18
19
  def to_s = JSON.generate(to_h)
@@ -22,10 +23,10 @@ module Arel::Visitors
22
23
  alias == eql?
23
24
 
24
25
  attr_reader :op, :namespace, :filters, :top_k, :rank_by, :include_attributes, :upsert_rows, :aggregate_by, :group_by,
25
- :consistency, :namespace_override
26
+ :consistency, :namespace_override, :offset
26
27
 
27
- def initialize(op:, namespace:, filters: nil, top_k: nil, rank_by: nil, include_attributes: nil,
28
- upsert_rows: nil, aggregate_by: nil, group_by: nil, consistency: nil, namespace_override: nil)
28
+ def initialize(op:, namespace:, filters: nil, top_k: nil, rank_by: nil, include_attributes: nil, upsert_rows: nil,
29
+ aggregate_by: nil, group_by: nil, consistency: nil, namespace_override: nil, offset: nil)
29
30
  @op = op
30
31
  @namespace = namespace
31
32
  @filters = filters
@@ -37,6 +38,7 @@ module Arel::Visitors
37
38
  @upsert_rows = upsert_rows
38
39
  @consistency = consistency
39
40
  @namespace_override = namespace_override
41
+ @offset = offset
40
42
  end
41
43
  end
42
44
 
@@ -100,7 +102,6 @@ module Arel::Visitors
100
102
  end
101
103
 
102
104
  def visit_Arel_Nodes_SelectStatement(o)
103
- raise NotImplementedError, "offset is not supported, filter on a sortable attribute for cursor pagination" if o.offset
104
105
  # https://turbopuffer.com/docs/query#ordering-by-attributes: "Ordering by
105
106
  # multiple attributes isn't yet implemented."
106
107
  raise NotImplementedError, "one ranking per query, sort in Ruby after loading" if o.orders.size > 1
@@ -113,6 +114,8 @@ module Arel::Visitors
113
114
  aggregates, attributes = core.projections.partition { |p| aggregate?(p) }
114
115
  aggregate = aggregates.first
115
116
 
117
+ raise NotImplementedError, "offset is not supported on aggregate queries" if o.offset && aggregate
118
+
116
119
  filters = core.wheres.map { |w| visit(w) }
117
120
  counted = aggregate && counted_attribute(aggregate)
118
121
  filters << [ visit(counted), "NotEq", nil ] if counted
@@ -127,7 +130,8 @@ module Arel::Visitors
127
130
  group_by: core.groups.map { |g| visit(g) },
128
131
  aggregate_by: aggregate && visit(aggregate),
129
132
  consistency: consistency_hint(core.optimizer_hints),
130
- namespace_override: namespace_annotation(core.comment)
133
+ namespace_override: namespace_annotation(core.comment),
134
+ offset: o.offset && visit(o.offset)
131
135
  )
132
136
  end
133
137
 
@@ -207,6 +211,10 @@ module Arel::Visitors
207
211
  visit(o.left)
208
212
  end
209
213
 
214
+ def visit_Arel_Nodes_TableAlias(o)
215
+ raise NotImplementedError, "subqueries are not supported, count a limited or offset relation in Ruby after loading"
216
+ end
217
+
210
218
  def visit_Arel_Table(o) = o.name
211
219
 
212
220
  # filters
@@ -293,6 +301,7 @@ module Arel::Visitors
293
301
  def visit_Arel_Nodes_Casted(o) = o.value_for_database
294
302
  def visit_Arel_Nodes_Quoted(o) = o.expr
295
303
  def visit_Arel_Nodes_Limit(o) = visit(o.expr)
304
+ def visit_Arel_Nodes_Offset(o) = visit(o.expr)
296
305
  def visit_Arel_Nodes_Ascending(o) = [ visit(o.expr), "asc" ]
297
306
  def visit_Arel_Nodes_Descending(o) = [ visit(o.expr), "desc" ]
298
307
 
@@ -1,5 +1,5 @@
1
1
  module Turbopuffer
2
2
  module ActiveRecord
3
- VERSION = "0.1.8"
3
+ VERSION = "0.1.9"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-turbopuffer-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Monette
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-10-07 00:00:00.000000000 Z
10
+ date: 2026-10-11 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activerecord
@@ -57,7 +57,7 @@ dependencies:
57
57
  requirements:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: '2.4'
60
+ version: '2.5'
61
61
  - - "<"
62
62
  - !ruby/object:Gem::Version
63
63
  version: '3'
@@ -67,7 +67,7 @@ dependencies:
67
67
  requirements:
68
68
  - - ">="
69
69
  - !ruby/object:Gem::Version
70
- version: '2.4'
70
+ version: '2.5'
71
71
  - - "<"
72
72
  - !ruby/object:Gem::Version
73
73
  version: '3'