activerecord-turbopuffer-adapter 0.1.5 → 0.1.7

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: 8bb295502835167a50a215f96707b208574ac3e6641b3cd9d02c50646b2335b6
4
- data.tar.gz: '09c4fcdaf392f394619a7a1b786a0be832e248edd7449a5d49e804908fd4d94d'
3
+ metadata.gz: dbe88ca95c2999749426d72f89dd7d0327a53d5a08bf6a0b2446340d6b17e173
4
+ data.tar.gz: c6c1611fe66ea9ca7dff51fde19ce3843249d8b91e955aa21ba500d9fe8efe1a
5
5
  SHA512:
6
- metadata.gz: d822446b93294cbca0db8d9cb13a373588e160805d6dc1f1d8e9e88b3d6695ebff58e3cb94fae1715bf0e42850cafb6b88b807b369cc48d174dbeab893e7c35a
7
- data.tar.gz: a22568481e63de3ca8a83a7367a59ac9b1e57853ed2315873c2948cd17a0bf4d4a348e77188e8d2f9deefcc25484b8e128e028948dbe11c4064adbc1909e1ffe
6
+ metadata.gz: 4cd6c79fd3b22a79ca2d18a8ed68765360b7e63c9a3f2d4e3bb82d644553bbf7fcd93a05489f58c3285c5967ec3f2e2f522bafa7e4c1c9debf5190b4f626c85c
7
+ data.tar.gz: c8f7cdae01828498d93c66d345d34bdbf5cda39ff46ff13ec7126bfe97b42bba3d9c4b2337fbce08640755f87d49d42b9283cec227f9605d6b1af02bb9b1f998
data/README.md CHANGED
@@ -56,6 +56,17 @@ class Document < ApplicationRecord
56
56
  end
57
57
  ```
58
58
 
59
+ Alternatively, turbopuffer can generate embeddings for you. Declare `embed` on a string attribute and the vector is computed on write:
60
+
61
+ ```ruby
62
+ class Document < ApplicationRecord
63
+ turbopuffer_attribute "id", "uuid", not_null: 1
64
+ turbopuffer_attribute "body", "string", embed: "openai/text-embedding-3-small"
65
+ end
66
+ ```
67
+
68
+ turbopuffer stores the vector in a computed `embed_body` attribute. `embed` also accepts a hash (`model:`, `attribute:`, `dims:`, `dtype:`) to name the vector attribute or set its size. Embedding is billed per token by model, see https://turbopuffer.com/docs/embedding for the supported models.
69
+
59
70
  ### Creating records
60
71
 
61
72
  ```ruby
@@ -104,6 +115,7 @@ Document.find("018f...")
104
115
 
105
116
  Document.rank_by("vector", "ANN", query_vector).limit(10)
106
117
  Document.rank_by("text", "BM25", "quick walrus").limit(10)
118
+ Document.rank_by("body", "ANN", ["Embed", "sea mammals"]).limit(10)
107
119
 
108
120
  Document.consistency(:eventual).where(published: true)
109
121
 
@@ -151,7 +151,7 @@ module ActiveRecord
151
151
  schema: model.turbopuffer_schema_hash
152
152
  }
153
153
 
154
- if model.turbopuffer_attributes.any?(&:ann)
154
+ if model.turbopuffer_attributes.any? { |attribute| attribute.ann || attribute.embed }
155
155
  tpuf_insert_args[:distance_metric] = model.turbopuffer_distance_metric
156
156
  end
157
157
 
@@ -272,7 +272,7 @@ module ActiveRecord
272
272
 
273
273
  def turbopuffer_select(namespace, query)
274
274
  fields = if query.include_attributes == [ "*" ]
275
- column_definitions(query.namespace).map(&:name)
275
+ column_definitions(query.namespace).reject(&:vector?).map(&:name)
276
276
  else
277
277
  query.include_attributes
278
278
  end
@@ -3,17 +3,22 @@ module Turbopuffer
3
3
  module Schema
4
4
  class Attribute
5
5
  TYPES = %r{\A(?:\[\])?(?:string|uuid|int|uint|float|bool|datetime)\z|\Abytes\z|\A\[\d+\](?:f16|f32|i8)\z|\A\{\}f16\z}
6
+ VECTOR_TYPES = %r{\A\[\d+\]|\A\{\}}
6
7
 
7
- attr_reader :name, :type, :filterable, :full_text_search, :ann, :glob, :regex, :notnull
8
+ attr_reader :name, :type, :filterable, :full_text_search, :ann, :glob, :regex, :embed, :notnull
8
9
 
9
10
  def initialize(name, type, not_null: 0, filterable: false, full_text_search: false,
10
- ann: false, glob: false, regex: false)
11
+ ann: false, glob: false, regex: false, embed: nil)
11
12
  type = type.to_s
12
13
 
13
14
  unless TYPES.match?(type)
14
15
  raise ArgumentError, "unknown turbopuffer type #{type.inspect} for attribute #{name.inspect}"
15
16
  end
16
17
 
18
+ if embed && type != "string"
19
+ raise ArgumentError, "embed is only supported on string attributes, #{name.inspect} is #{type.inspect}"
20
+ end
21
+
17
22
  @name = name
18
23
  @type = type
19
24
  @filterable = filterable
@@ -21,9 +26,12 @@ module Turbopuffer
21
26
  @ann = ann
22
27
  @glob = glob
23
28
  @regex = regex
29
+ @embed = embed
24
30
 
25
31
  @notnull = not_null
26
32
  end
33
+
34
+ def vector? = VECTOR_TYPES.match?(type)
27
35
  end
28
36
  end
29
37
  end
@@ -48,10 +48,10 @@ module Turbopuffer
48
48
  end
49
49
 
50
50
  class_methods do
51
- def turbopuffer_attribute(name, type, not_null: 0, filterable: false,
52
- full_text_search: false, ann: false, glob: false, regex: false)
51
+ def turbopuffer_attribute(name, type, not_null: 0, filterable: false, full_text_search: false,
52
+ ann: false, glob: false, regex: false, embed: nil)
53
53
  attribute = ::Turbopuffer::ActiveRecord::Schema::Attribute.new(
54
- name.to_s, type, not_null:, filterable:, full_text_search:, ann:, glob:, regex:
54
+ name.to_s, type, not_null:, filterable:, full_text_search:, ann:, glob:, regex:, embed:
55
55
  )
56
56
 
57
57
  self.turbopuffer_attributes =
@@ -78,6 +78,10 @@ module Turbopuffer
78
78
  order(::Arel::Nodes::RankByNode.new(expression))
79
79
  end
80
80
 
81
+ def with_vectors
82
+ select(*turbopuffer_attributes.map(&:name))
83
+ end
84
+
81
85
  def glob(pattern, case_sensitive: true)
82
86
  ::Turbopuffer::ActiveRecord::Glob.new(pattern, case_sensitive:)
83
87
  end
@@ -115,6 +119,7 @@ module Turbopuffer
115
119
  attrs[:ann] = true if attribute.ann
116
120
  attrs[:glob] = true if attribute.glob
117
121
  attrs[:regex] = true if attribute.regex
122
+ attrs[:embed] = attribute.embed if attribute.embed
118
123
  attrs[:sparse_knn] = { distance_metric: "dot_product" } if attribute.type == "{}f16"
119
124
 
120
125
  schema[attribute.name] = attrs
@@ -1,5 +1,5 @@
1
1
  module Turbopuffer
2
2
  module ActiveRecord
3
- VERSION = "0.1.5"
3
+ VERSION = "0.1.7"
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.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Monette
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-09-23 00:00:00.000000000 Z
10
+ date: 2026-10-06 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activerecord