activerecord-turbopuffer-adapter 0.1.6 → 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: 735feec18b7fd1ae5ded62e4ed1be93fc11c72c7f26e4297cdad2959e364f5ae
4
- data.tar.gz: 463e7962478cac322980777e1af86edd02ccf6109e4114afcbdf0738cb1ec635
3
+ metadata.gz: dbe88ca95c2999749426d72f89dd7d0327a53d5a08bf6a0b2446340d6b17e173
4
+ data.tar.gz: c6c1611fe66ea9ca7dff51fde19ce3843249d8b91e955aa21ba500d9fe8efe1a
5
5
  SHA512:
6
- metadata.gz: 961a01ae0f07741adf56396ef8df18ddb94896627d9ccee153b3f191ff34fda091136133ecc52e3c8e09b3726e9a45d70cde91957f1d9241f2cf5c122caabd38
7
- data.tar.gz: ed62e9af80fd247549aecfe079f9d45f05037411dc631e310ef1faae981ba2581682335be96bfee6b3877cad4b8ae2d59936637a9179525349c375e9596671df
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
 
@@ -5,16 +5,20 @@ module Turbopuffer
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
6
  VECTOR_TYPES = %r{\A\[\d+\]|\A\{\}}
7
7
 
8
- 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
9
9
 
10
10
  def initialize(name, type, not_null: 0, filterable: false, full_text_search: false,
11
- ann: false, glob: false, regex: false)
11
+ ann: false, glob: false, regex: false, embed: nil)
12
12
  type = type.to_s
13
13
 
14
14
  unless TYPES.match?(type)
15
15
  raise ArgumentError, "unknown turbopuffer type #{type.inspect} for attribute #{name.inspect}"
16
16
  end
17
17
 
18
+ if embed && type != "string"
19
+ raise ArgumentError, "embed is only supported on string attributes, #{name.inspect} is #{type.inspect}"
20
+ end
21
+
18
22
  @name = name
19
23
  @type = type
20
24
  @filterable = filterable
@@ -22,6 +26,7 @@ module Turbopuffer
22
26
  @ann = ann
23
27
  @glob = glob
24
28
  @regex = regex
29
+ @embed = embed
25
30
 
26
31
  @notnull = not_null
27
32
  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 =
@@ -119,6 +119,7 @@ module Turbopuffer
119
119
  attrs[:ann] = true if attribute.ann
120
120
  attrs[:glob] = true if attribute.glob
121
121
  attrs[:regex] = true if attribute.regex
122
+ attrs[:embed] = attribute.embed if attribute.embed
122
123
  attrs[:sparse_knn] = { distance_metric: "dot_product" } if attribute.type == "{}f16"
123
124
 
124
125
  schema[attribute.name] = attrs
@@ -1,5 +1,5 @@
1
1
  module Turbopuffer
2
2
  module ActiveRecord
3
- VERSION = "0.1.6"
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.6
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-24 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