turbopuffer-ruby 0.2.0.pre.alpha.1

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.
Files changed (194) hide show
  1. checksums.yaml +7 -0
  2. data/.ignore +2 -0
  3. data/CHANGELOG.md +60 -0
  4. data/README.md +291 -0
  5. data/SECURITY.md +27 -0
  6. data/lib/turbopuffer/client.rb +130 -0
  7. data/lib/turbopuffer/errors.rb +214 -0
  8. data/lib/turbopuffer/file_part.rb +55 -0
  9. data/lib/turbopuffer/internal/namespace_page.rb +86 -0
  10. data/lib/turbopuffer/internal/transport/base_client.rb +563 -0
  11. data/lib/turbopuffer/internal/transport/pooled_net_requester.rb +209 -0
  12. data/lib/turbopuffer/internal/type/array_of.rb +167 -0
  13. data/lib/turbopuffer/internal/type/base_model.rb +534 -0
  14. data/lib/turbopuffer/internal/type/base_page.rb +55 -0
  15. data/lib/turbopuffer/internal/type/boolean.rb +77 -0
  16. data/lib/turbopuffer/internal/type/converter.rb +300 -0
  17. data/lib/turbopuffer/internal/type/enum.rb +152 -0
  18. data/lib/turbopuffer/internal/type/file_input.rb +108 -0
  19. data/lib/turbopuffer/internal/type/hash_of.rb +187 -0
  20. data/lib/turbopuffer/internal/type/request_parameters.rb +42 -0
  21. data/lib/turbopuffer/internal/type/union.rb +252 -0
  22. data/lib/turbopuffer/internal/type/unknown.rb +81 -0
  23. data/lib/turbopuffer/internal/util.rb +914 -0
  24. data/lib/turbopuffer/internal.rb +20 -0
  25. data/lib/turbopuffer/models/attribute_schema.rb +19 -0
  26. data/lib/turbopuffer/models/attribute_schema_config.rb +48 -0
  27. data/lib/turbopuffer/models/attribute_type.rb +7 -0
  28. data/lib/turbopuffer/models/client_namespaces_params.rb +38 -0
  29. data/lib/turbopuffer/models/columns.rb +64 -0
  30. data/lib/turbopuffer/models/distance_metric.rb +19 -0
  31. data/lib/turbopuffer/models/full_text_search.rb +20 -0
  32. data/lib/turbopuffer/models/full_text_search_config.rb +72 -0
  33. data/lib/turbopuffer/models/id.rb +19 -0
  34. data/lib/turbopuffer/models/include_attributes.rb +22 -0
  35. data/lib/turbopuffer/models/language.rb +32 -0
  36. data/lib/turbopuffer/models/namespace_delete_all_params.rb +20 -0
  37. data/lib/turbopuffer/models/namespace_delete_all_response.rb +19 -0
  38. data/lib/turbopuffer/models/namespace_hint_cache_warm_params.rb +20 -0
  39. data/lib/turbopuffer/models/namespace_hint_cache_warm_response.rb +26 -0
  40. data/lib/turbopuffer/models/namespace_metadata.rb +35 -0
  41. data/lib/turbopuffer/models/namespace_metadata_params.rb +20 -0
  42. data/lib/turbopuffer/models/namespace_multi_query_params.rb +73 -0
  43. data/lib/turbopuffer/models/namespace_multi_query_response.rb +51 -0
  44. data/lib/turbopuffer/models/namespace_query_params.rb +119 -0
  45. data/lib/turbopuffer/models/namespace_query_response.rb +41 -0
  46. data/lib/turbopuffer/models/namespace_recall_params.rb +57 -0
  47. data/lib/turbopuffer/models/namespace_recall_response.rb +39 -0
  48. data/lib/turbopuffer/models/namespace_schema_params.rb +20 -0
  49. data/lib/turbopuffer/models/namespace_schema_response.rb +8 -0
  50. data/lib/turbopuffer/models/namespace_summary.rb +19 -0
  51. data/lib/turbopuffer/models/namespace_update_schema_params.rb +29 -0
  52. data/lib/turbopuffer/models/namespace_update_schema_response.rb +9 -0
  53. data/lib/turbopuffer/models/namespace_write_params.rb +158 -0
  54. data/lib/turbopuffer/models/namespace_write_response.rb +67 -0
  55. data/lib/turbopuffer/models/query.rb +63 -0
  56. data/lib/turbopuffer/models/query_billing.rb +26 -0
  57. data/lib/turbopuffer/models/query_performance.rb +63 -0
  58. data/lib/turbopuffer/models/row.rb +38 -0
  59. data/lib/turbopuffer/models/tokenizer.rb +17 -0
  60. data/lib/turbopuffer/models/vector.rb +22 -0
  61. data/lib/turbopuffer/models/vector_encoding.rb +16 -0
  62. data/lib/turbopuffer/models/write_billing.rb +26 -0
  63. data/lib/turbopuffer/models.rb +101 -0
  64. data/lib/turbopuffer/namespace.rb +22 -0
  65. data/lib/turbopuffer/request_options.rb +77 -0
  66. data/lib/turbopuffer/resources/namespaces.rb +311 -0
  67. data/lib/turbopuffer/version.rb +5 -0
  68. data/lib/turbopuffer.rb +94 -0
  69. data/manifest.yaml +15 -0
  70. data/rbi/turbopuffer/client.rbi +91 -0
  71. data/rbi/turbopuffer/errors.rbi +178 -0
  72. data/rbi/turbopuffer/file_part.rbi +37 -0
  73. data/rbi/turbopuffer/internal/namespace_page.rbi +22 -0
  74. data/rbi/turbopuffer/internal/transport/base_client.rbi +298 -0
  75. data/rbi/turbopuffer/internal/transport/pooled_net_requester.rbi +80 -0
  76. data/rbi/turbopuffer/internal/type/array_of.rbi +104 -0
  77. data/rbi/turbopuffer/internal/type/base_model.rbi +304 -0
  78. data/rbi/turbopuffer/internal/type/base_page.rbi +43 -0
  79. data/rbi/turbopuffer/internal/type/boolean.rbi +58 -0
  80. data/rbi/turbopuffer/internal/type/converter.rbi +162 -0
  81. data/rbi/turbopuffer/internal/type/enum.rbi +82 -0
  82. data/rbi/turbopuffer/internal/type/file_input.rbi +59 -0
  83. data/rbi/turbopuffer/internal/type/hash_of.rbi +104 -0
  84. data/rbi/turbopuffer/internal/type/request_parameters.rbi +31 -0
  85. data/rbi/turbopuffer/internal/type/union.rbi +121 -0
  86. data/rbi/turbopuffer/internal/type/unknown.rbi +58 -0
  87. data/rbi/turbopuffer/internal/util.rbi +487 -0
  88. data/rbi/turbopuffer/internal.rbi +18 -0
  89. data/rbi/turbopuffer/models/attribute_schema.rbi +17 -0
  90. data/rbi/turbopuffer/models/attribute_schema_config.rbi +92 -0
  91. data/rbi/turbopuffer/models/attribute_type.rbi +7 -0
  92. data/rbi/turbopuffer/models/client_namespaces_params.rbi +71 -0
  93. data/rbi/turbopuffer/models/columns.rbi +82 -0
  94. data/rbi/turbopuffer/models/distance_metric.rbi +27 -0
  95. data/rbi/turbopuffer/models/full_text_search.rbi +19 -0
  96. data/rbi/turbopuffer/models/full_text_search_config.rbi +116 -0
  97. data/rbi/turbopuffer/models/id.rbi +16 -0
  98. data/rbi/turbopuffer/models/include_attributes.rbi +24 -0
  99. data/rbi/turbopuffer/models/language.rbi +36 -0
  100. data/rbi/turbopuffer/models/namespace_delete_all_params.rbi +41 -0
  101. data/rbi/turbopuffer/models/namespace_delete_all_response.rbi +31 -0
  102. data/rbi/turbopuffer/models/namespace_hint_cache_warm_params.rbi +41 -0
  103. data/rbi/turbopuffer/models/namespace_hint_cache_warm_response.rbi +38 -0
  104. data/rbi/turbopuffer/models/namespace_metadata.rbi +54 -0
  105. data/rbi/turbopuffer/models/namespace_metadata_params.rbi +41 -0
  106. data/rbi/turbopuffer/models/namespace_multi_query_params.rbi +175 -0
  107. data/rbi/turbopuffer/models/namespace_multi_query_response.rbi +111 -0
  108. data/rbi/turbopuffer/models/namespace_query_params.rbi +241 -0
  109. data/rbi/turbopuffer/models/namespace_query_response.rbi +73 -0
  110. data/rbi/turbopuffer/models/namespace_recall_params.rbi +93 -0
  111. data/rbi/turbopuffer/models/namespace_recall_response.rbi +59 -0
  112. data/rbi/turbopuffer/models/namespace_schema_params.rbi +41 -0
  113. data/rbi/turbopuffer/models/namespace_schema_response.rbi +11 -0
  114. data/rbi/turbopuffer/models/namespace_summary.rbi +28 -0
  115. data/rbi/turbopuffer/models/namespace_update_schema_params.rbi +80 -0
  116. data/rbi/turbopuffer/models/namespace_update_schema_response.rbi +11 -0
  117. data/rbi/turbopuffer/models/namespace_write_params.rbi +290 -0
  118. data/rbi/turbopuffer/models/namespace_write_response.rbi +101 -0
  119. data/rbi/turbopuffer/models/query.rbi +106 -0
  120. data/rbi/turbopuffer/models/query_billing.rbi +46 -0
  121. data/rbi/turbopuffer/models/query_performance.rbi +82 -0
  122. data/rbi/turbopuffer/models/row.rbi +47 -0
  123. data/rbi/turbopuffer/models/tokenizer.rbi +22 -0
  124. data/rbi/turbopuffer/models/vector.rbi +22 -0
  125. data/rbi/turbopuffer/models/vector_encoding.rbi +22 -0
  126. data/rbi/turbopuffer/models/write_billing.rbi +49 -0
  127. data/rbi/turbopuffer/models.rbi +64 -0
  128. data/rbi/turbopuffer/namespace.rbi +8 -0
  129. data/rbi/turbopuffer/request_options.rbi +59 -0
  130. data/rbi/turbopuffer/resources/namespaces.rbi +243 -0
  131. data/rbi/turbopuffer/version.rbi +5 -0
  132. data/sig/turbopuffer/client.rbs +41 -0
  133. data/sig/turbopuffer/errors.rbs +110 -0
  134. data/sig/turbopuffer/file_part.rbs +21 -0
  135. data/sig/turbopuffer/internal/namespace_page.rbs +13 -0
  136. data/sig/turbopuffer/internal/transport/base_client.rbs +131 -0
  137. data/sig/turbopuffer/internal/transport/pooled_net_requester.rbs +45 -0
  138. data/sig/turbopuffer/internal/type/array_of.rbs +48 -0
  139. data/sig/turbopuffer/internal/type/base_model.rbs +102 -0
  140. data/sig/turbopuffer/internal/type/base_page.rbs +24 -0
  141. data/sig/turbopuffer/internal/type/boolean.rbs +26 -0
  142. data/sig/turbopuffer/internal/type/converter.rbs +62 -0
  143. data/sig/turbopuffer/internal/type/enum.rbs +32 -0
  144. data/sig/turbopuffer/internal/type/file_input.rbs +25 -0
  145. data/sig/turbopuffer/internal/type/hash_of.rbs +48 -0
  146. data/sig/turbopuffer/internal/type/request_parameters.rbs +19 -0
  147. data/sig/turbopuffer/internal/type/union.rbs +52 -0
  148. data/sig/turbopuffer/internal/type/unknown.rbs +26 -0
  149. data/sig/turbopuffer/internal/util.rbs +185 -0
  150. data/sig/turbopuffer/internal.rbs +9 -0
  151. data/sig/turbopuffer/models/attribute_schema.rbs +11 -0
  152. data/sig/turbopuffer/models/attribute_schema_config.rbs +45 -0
  153. data/sig/turbopuffer/models/attribute_type.rbs +5 -0
  154. data/sig/turbopuffer/models/client_namespaces_params.rbs +38 -0
  155. data/sig/turbopuffer/models/columns.rbs +42 -0
  156. data/sig/turbopuffer/models/distance_metric.rbs +17 -0
  157. data/sig/turbopuffer/models/full_text_search.rbs +11 -0
  158. data/sig/turbopuffer/models/full_text_search_config.rbs +68 -0
  159. data/sig/turbopuffer/models/id.rbs +11 -0
  160. data/sig/turbopuffer/models/include_attributes.rbs +13 -0
  161. data/sig/turbopuffer/models/language.rbs +48 -0
  162. data/sig/turbopuffer/models/namespace_delete_all_params.rbs +25 -0
  163. data/sig/turbopuffer/models/namespace_delete_all_response.rbs +13 -0
  164. data/sig/turbopuffer/models/namespace_hint_cache_warm_params.rbs +25 -0
  165. data/sig/turbopuffer/models/namespace_hint_cache_warm_response.rbs +17 -0
  166. data/sig/turbopuffer/models/namespace_metadata.rbs +30 -0
  167. data/sig/turbopuffer/models/namespace_metadata_params.rbs +25 -0
  168. data/sig/turbopuffer/models/namespace_multi_query_params.rbs +86 -0
  169. data/sig/turbopuffer/models/namespace_multi_query_response.rbs +53 -0
  170. data/sig/turbopuffer/models/namespace_query_params.rbs +125 -0
  171. data/sig/turbopuffer/models/namespace_query_response.rbs +39 -0
  172. data/sig/turbopuffer/models/namespace_recall_params.rbs +56 -0
  173. data/sig/turbopuffer/models/namespace_recall_response.rbs +26 -0
  174. data/sig/turbopuffer/models/namespace_schema_params.rbs +25 -0
  175. data/sig/turbopuffer/models/namespace_schema_response.rbs +8 -0
  176. data/sig/turbopuffer/models/namespace_summary.rbs +13 -0
  177. data/sig/turbopuffer/models/namespace_update_schema_params.rbs +37 -0
  178. data/sig/turbopuffer/models/namespace_update_schema_response.rbs +8 -0
  179. data/sig/turbopuffer/models/namespace_write_params.rbs +156 -0
  180. data/sig/turbopuffer/models/namespace_write_response.rbs +56 -0
  181. data/sig/turbopuffer/models/query.rbs +61 -0
  182. data/sig/turbopuffer/models/query_billing.rbs +25 -0
  183. data/sig/turbopuffer/models/query_performance.rbs +45 -0
  184. data/sig/turbopuffer/models/row.rbs +24 -0
  185. data/sig/turbopuffer/models/tokenizer.rbs +15 -0
  186. data/sig/turbopuffer/models/vector.rbs +13 -0
  187. data/sig/turbopuffer/models/vector_encoding.rbs +14 -0
  188. data/sig/turbopuffer/models/write_billing.rbs +27 -0
  189. data/sig/turbopuffer/models.rbs +61 -0
  190. data/sig/turbopuffer/namespace.rbs +5 -0
  191. data/sig/turbopuffer/request_options.rbs +36 -0
  192. data/sig/turbopuffer/resources/namespaces.rbs +81 -0
  193. data/sig/turbopuffer/version.rbs +3 -0
  194. metadata +251 -0
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Turbopuffer
4
+ module Internal
5
+ module Type
6
+ # @api private
7
+ #
8
+ # @abstract
9
+ #
10
+ # @generic Elem
11
+ #
12
+ # Hash of items of a given type.
13
+ class HashOf
14
+ include Turbopuffer::Internal::Type::Converter
15
+ include Turbopuffer::Internal::Util::SorbetRuntimeSupport
16
+
17
+ private_class_method :new
18
+
19
+ # @overload [](type_info, spec = {})
20
+ #
21
+ # @param type_info [Hash{Symbol=>Object}, Proc, Turbopuffer::Internal::Type::Converter, Class]
22
+ #
23
+ # @param spec [Hash{Symbol=>Object}] .
24
+ #
25
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
26
+ #
27
+ # @option spec [Proc] :enum
28
+ #
29
+ # @option spec [Proc] :union
30
+ #
31
+ # @option spec [Boolean] :"nil?"
32
+ #
33
+ # @return [self]
34
+ def self.[](...) = new(...)
35
+
36
+ # @api public
37
+ #
38
+ # @param other [Object]
39
+ #
40
+ # @return [Boolean]
41
+ def ===(other)
42
+ type = item_type
43
+ case other
44
+ in Hash
45
+ other.all? do |key, val|
46
+ case [key, val]
47
+ in [Symbol | String, ^type]
48
+ true
49
+ else
50
+ false
51
+ end
52
+ end
53
+ else
54
+ false
55
+ end
56
+ end
57
+
58
+ # @api public
59
+ #
60
+ # @param other [Object]
61
+ #
62
+ # @return [Boolean]
63
+ def ==(other)
64
+ # rubocop:disable Layout/LineLength
65
+ other.is_a?(Turbopuffer::Internal::Type::HashOf) && other.nilable? == nilable? && other.item_type == item_type
66
+ # rubocop:enable Layout/LineLength
67
+ end
68
+
69
+ # @api public
70
+ #
71
+ # @return [Integer]
72
+ def hash = [self.class, item_type].hash
73
+
74
+ # @api private
75
+ #
76
+ # @param value [Hash{Object=>Object}, Object]
77
+ #
78
+ # @param state [Hash{Symbol=>Object}] .
79
+ #
80
+ # @option state [Boolean] :translate_names
81
+ #
82
+ # @option state [Boolean] :strictness
83
+ #
84
+ # @option state [Hash{Symbol=>Object}] :exactness
85
+ #
86
+ # @option state [Class<StandardError>] :error
87
+ #
88
+ # @option state [Integer] :branched
89
+ #
90
+ # @return [Hash{Symbol=>Object}, Object]
91
+ def coerce(value, state:)
92
+ exactness = state.fetch(:exactness)
93
+
94
+ unless value.is_a?(Hash)
95
+ exactness[:no] += 1
96
+ state[:error] = TypeError.new("#{value.class} can't be coerced into #{Hash}")
97
+ return value
98
+ end
99
+
100
+ target = item_type
101
+ exactness[:yes] += 1
102
+ value
103
+ .to_h do |key, val|
104
+ k = key.is_a?(String) ? key.to_sym : key
105
+ v =
106
+ case [nilable?, val]
107
+ in [true, nil]
108
+ exactness[:yes] += 1
109
+ nil
110
+ else
111
+ Turbopuffer::Internal::Type::Converter.coerce(target, val, state: state)
112
+ end
113
+
114
+ exactness[:no] += 1 unless k.is_a?(Symbol)
115
+ [k, v]
116
+ end
117
+ end
118
+
119
+ # @api private
120
+ #
121
+ # @param value [Hash{Object=>Object}, Object]
122
+ #
123
+ # @param state [Hash{Symbol=>Object}] .
124
+ #
125
+ # @option state [Boolean] :can_retry
126
+ #
127
+ # @return [Hash{Symbol=>Object}, Object]
128
+ def dump(value, state:)
129
+ target = item_type
130
+ if value.is_a?(Hash)
131
+ value.transform_values do
132
+ Turbopuffer::Internal::Type::Converter.dump(target, _1, state: state)
133
+ end
134
+ else
135
+ super
136
+ end
137
+ end
138
+
139
+ # @api private
140
+ #
141
+ # @return [Object]
142
+ def to_sorbet_type
143
+ T::Hash[Turbopuffer::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(item_type)]
144
+ end
145
+
146
+ # @api private
147
+ #
148
+ # @return [generic<Elem>]
149
+ protected def item_type = @item_type_fn.call
150
+
151
+ # @api private
152
+ #
153
+ # @return [Boolean]
154
+ protected def nilable? = @nilable
155
+
156
+ # @api private
157
+ #
158
+ # @param type_info [Hash{Symbol=>Object}, Proc, Turbopuffer::Internal::Type::Converter, Class]
159
+ #
160
+ # @param spec [Hash{Symbol=>Object}] .
161
+ #
162
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
163
+ #
164
+ # @option spec [Proc] :enum
165
+ #
166
+ # @option spec [Proc] :union
167
+ #
168
+ # @option spec [Boolean] :"nil?"
169
+ def initialize(type_info, spec = {})
170
+ @item_type_fn = Turbopuffer::Internal::Type::Converter.type_info(type_info || spec)
171
+ @nilable = spec.fetch(:nil?, false)
172
+ end
173
+
174
+ # @api private
175
+ #
176
+ # @param depth [Integer]
177
+ #
178
+ # @return [String]
179
+ def inspect(depth: 0)
180
+ items = Turbopuffer::Internal::Type::Converter.inspect(item_type, depth: depth.succ)
181
+
182
+ "#{self.class}[#{[items, nilable? ? 'nil' : nil].compact.join(' | ')}]"
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Turbopuffer
4
+ module Internal
5
+ module Type
6
+ # @api private
7
+ module RequestParameters
8
+ # @!attribute request_options
9
+ # Options to specify HTTP behaviour for this request.
10
+ #
11
+ # @return [Turbopuffer::RequestOptions, Hash{Symbol=>Object}]
12
+
13
+ # @param mod [Module]
14
+ def self.included(mod)
15
+ raise ArgumentError.new(mod) unless mod <= Turbopuffer::Internal::Type::BaseModel
16
+
17
+ mod.optional(:request_options, Turbopuffer::RequestOptions)
18
+ end
19
+
20
+ # @api private
21
+ module Converter
22
+ # @api private
23
+ #
24
+ # @param params [Object]
25
+ #
26
+ # @return [Array(Object, Hash{Symbol=>Object})]
27
+ def dump_request(params)
28
+ state = {can_retry: true}
29
+ case (dumped = dump(params, state: state))
30
+ in Hash
31
+ options = Turbopuffer::Internal::Util.coerce_hash!(dumped[:request_options]).to_h
32
+ request_options = state.fetch(:can_retry) ? options : {**options, max_retries: 0}
33
+ [dumped.except(:request_options), request_options]
34
+ else
35
+ [dumped, nil]
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,252 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Turbopuffer
4
+ module Internal
5
+ module Type
6
+ # @api private
7
+ #
8
+ # @example
9
+ # # `attribute_schema` is a `Turbopuffer::AttributeSchema`
10
+ # case attribute_schema
11
+ # when Turbopuffer::AttributeType
12
+ # # ...
13
+ # when Turbopuffer::AttributeSchemaConfig
14
+ # puts(attribute_schema.ann)
15
+ # else
16
+ # puts(attribute_schema)
17
+ # end
18
+ module Union
19
+ include Turbopuffer::Internal::Type::Converter
20
+ include Turbopuffer::Internal::Util::SorbetRuntimeSupport
21
+
22
+ # @api private
23
+ #
24
+ # All of the specified variant info for this union.
25
+ #
26
+ # @return [Array<Array(Symbol, Proc)>]
27
+ private def known_variants = (@known_variants ||= [])
28
+
29
+ # @api private
30
+ #
31
+ # @return [Array<Array(Symbol, Object)>]
32
+ protected def derefed_variants
33
+ known_variants.map { |key, variant_fn| [key, variant_fn.call] }
34
+ end
35
+
36
+ # All of the specified variants for this union.
37
+ #
38
+ # @return [Array<Object>]
39
+ def variants = derefed_variants.map(&:last)
40
+
41
+ # @api private
42
+ #
43
+ # @param property [Symbol]
44
+ private def discriminator(property)
45
+ case property
46
+ in Symbol
47
+ @discriminator = property
48
+ end
49
+ end
50
+
51
+ # @api private
52
+ #
53
+ # @param key [Symbol, Hash{Symbol=>Object}, Proc, Turbopuffer::Internal::Type::Converter, Class]
54
+ #
55
+ # @param spec [Hash{Symbol=>Object}, Proc, Turbopuffer::Internal::Type::Converter, Class] .
56
+ #
57
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
58
+ #
59
+ # @option spec [Proc] :enum
60
+ #
61
+ # @option spec [Proc] :union
62
+ #
63
+ # @option spec [Boolean] :"nil?"
64
+ private def variant(key, spec = nil)
65
+ variant_info =
66
+ case key
67
+ in Symbol
68
+ [key, Turbopuffer::Internal::Type::Converter.type_info(spec)]
69
+ in Proc | Turbopuffer::Internal::Type::Converter | Class | Hash
70
+ [nil, Turbopuffer::Internal::Type::Converter.type_info(key)]
71
+ end
72
+
73
+ known_variants << variant_info
74
+ end
75
+
76
+ # @api private
77
+ #
78
+ # @param value [Object]
79
+ #
80
+ # @return [Turbopuffer::Internal::Type::Converter, Class, nil]
81
+ private def resolve_variant(value)
82
+ case [@discriminator, value]
83
+ in [_, Turbopuffer::Internal::Type::BaseModel]
84
+ value.class
85
+ in [Symbol, Hash]
86
+ key = value.fetch(@discriminator) do
87
+ value.fetch(@discriminator.to_s, Turbopuffer::Internal::OMIT)
88
+ end
89
+
90
+ return nil if key == Turbopuffer::Internal::OMIT
91
+
92
+ key = key.to_sym if key.is_a?(String)
93
+ known_variants.find { |k,| k == key }&.last&.call
94
+ else
95
+ nil
96
+ end
97
+ end
98
+
99
+ # rubocop:disable Style/HashEachMethods
100
+ # rubocop:disable Style/CaseEquality
101
+
102
+ # @api public
103
+ #
104
+ # @param other [Object]
105
+ #
106
+ # @return [Boolean]
107
+ def ===(other)
108
+ known_variants.any? do |_, variant_fn|
109
+ variant_fn.call === other
110
+ end
111
+ end
112
+
113
+ # @api public
114
+ #
115
+ # @param other [Object]
116
+ #
117
+ # @return [Boolean]
118
+ def ==(other)
119
+ Turbopuffer::Internal::Type::Union === other && other.derefed_variants == derefed_variants
120
+ end
121
+
122
+ # @api public
123
+ #
124
+ # @return [Integer]
125
+ def hash = variants.hash
126
+
127
+ # @api private
128
+ #
129
+ # Tries to efficiently coerce the given value to one of the known variants.
130
+ #
131
+ # If the value cannot match any of the known variants, the coercion is considered
132
+ # non-viable and returns the original value.
133
+ #
134
+ # @param value [Object]
135
+ #
136
+ # @param state [Hash{Symbol=>Object}] .
137
+ #
138
+ # @option state [Boolean] :translate_names
139
+ #
140
+ # @option state [Boolean] :strictness
141
+ #
142
+ # @option state [Hash{Symbol=>Object}] :exactness
143
+ #
144
+ # @option state [Class<StandardError>] :error
145
+ #
146
+ # @option state [Integer] :branched
147
+ #
148
+ # @return [Object]
149
+ def coerce(value, state:)
150
+ if (target = resolve_variant(value))
151
+ return Turbopuffer::Internal::Type::Converter.coerce(target, value, state: state)
152
+ end
153
+
154
+ strictness = state.fetch(:strictness)
155
+ exactness = state.fetch(:exactness)
156
+
157
+ alternatives = []
158
+ known_variants.each do |_, variant_fn|
159
+ target = variant_fn.call
160
+ exact = state[:exactness] = {yes: 0, no: 0, maybe: 0}
161
+ state[:branched] += 1
162
+
163
+ coerced = Turbopuffer::Internal::Type::Converter.coerce(target, value, state: state)
164
+ yes, no, maybe = exact.values
165
+ if (no + maybe).zero? || (!strictness && yes.positive?)
166
+ exact.each { exactness[_1] += _2 }
167
+ state[:exactness] = exactness
168
+ return coerced
169
+ elsif maybe.positive?
170
+ alternatives << [[-yes, -maybe, no], exact, coerced]
171
+ end
172
+ end
173
+
174
+ case alternatives.sort_by!(&:first)
175
+ in []
176
+ exactness[:no] += 1
177
+ state[:error] = ArgumentError.new("no matching variant for #{value.inspect}")
178
+ value
179
+ in [[_, exact, coerced], *]
180
+ exact.each { exactness[_1] += _2 }
181
+ coerced
182
+ end
183
+ .tap { state[:exactness] = exactness }
184
+ ensure
185
+ state[:strictness] = strictness
186
+ end
187
+
188
+ # @api private
189
+ #
190
+ # @param value [Object]
191
+ #
192
+ # @param state [Hash{Symbol=>Object}] .
193
+ #
194
+ # @option state [Boolean] :can_retry
195
+ #
196
+ # @return [Object]
197
+ def dump(value, state:)
198
+ if (target = resolve_variant(value))
199
+ return Turbopuffer::Internal::Type::Converter.dump(target, value, state: state)
200
+ end
201
+
202
+ known_variants.each do
203
+ target = _2.call
204
+ if target === value
205
+ return Turbopuffer::Internal::Type::Converter.dump(
206
+ target,
207
+ value,
208
+ state: state
209
+ )
210
+ end
211
+ end
212
+
213
+ super
214
+ end
215
+
216
+ # @api private
217
+ #
218
+ # @return [Object]
219
+ def to_sorbet_type
220
+ types = variants.map { Turbopuffer::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(_1) }.uniq
221
+ case types
222
+ in []
223
+ T.noreturn
224
+ in [type]
225
+ type
226
+ else
227
+ T.any(*types)
228
+ end
229
+ end
230
+
231
+ # rubocop:enable Style/CaseEquality
232
+ # rubocop:enable Style/HashEachMethods
233
+
234
+ # @api private
235
+ #
236
+ # @param depth [Integer]
237
+ #
238
+ # @return [String]
239
+ def inspect(depth: 0)
240
+ if depth.positive?
241
+ return is_a?(Module) ? super() : self.class.name
242
+ end
243
+
244
+ members = variants.map { Turbopuffer::Internal::Type::Converter.inspect(_1, depth: depth.succ) }
245
+ prefix = is_a?(Module) ? name : self.class.name
246
+
247
+ "#{prefix}[#{members.join(' | ')}]"
248
+ end
249
+ end
250
+ end
251
+ end
252
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Turbopuffer
4
+ module Internal
5
+ module Type
6
+ # @api private
7
+ #
8
+ # @abstract
9
+ #
10
+ # When we don't know what to expect for the value.
11
+ class Unknown
12
+ extend Turbopuffer::Internal::Type::Converter
13
+ extend Turbopuffer::Internal::Util::SorbetRuntimeSupport
14
+
15
+ # rubocop:disable Lint/UnusedMethodArgument
16
+
17
+ private_class_method :new
18
+
19
+ # @api public
20
+ #
21
+ # @param other [Object]
22
+ #
23
+ # @return [Boolean]
24
+ def self.===(other) = true
25
+
26
+ # @api public
27
+ #
28
+ # @param other [Object]
29
+ #
30
+ # @return [Boolean]
31
+ def self.==(other) = other.is_a?(Class) && other <= Turbopuffer::Internal::Type::Unknown
32
+
33
+ class << self
34
+ # @api private
35
+ #
36
+ # No coercion needed for Unknown type.
37
+ #
38
+ # @param value [Object]
39
+ #
40
+ # @param state [Hash{Symbol=>Object}] .
41
+ #
42
+ # @option state [Boolean] :translate_names
43
+ #
44
+ # @option state [Boolean] :strictness
45
+ #
46
+ # @option state [Hash{Symbol=>Object}] :exactness
47
+ #
48
+ # @option state [Class<StandardError>] :error
49
+ #
50
+ # @option state [Integer] :branched
51
+ #
52
+ # @return [Object]
53
+ def coerce(value, state:)
54
+ state.fetch(:exactness)[:yes] += 1
55
+ value
56
+ end
57
+
58
+ # @!method dump(value, state:)
59
+ # @api private
60
+ #
61
+ # @param value [Object]
62
+ #
63
+ # @param state [Hash{Symbol=>Object}] .
64
+ #
65
+ # @option state [Boolean] :can_retry
66
+ #
67
+ # @return [Object]
68
+
69
+ # @api private
70
+ #
71
+ # @return [Object]
72
+ def to_sorbet_type
73
+ T.anything
74
+ end
75
+ end
76
+
77
+ # rubocop:enable Lint/UnusedMethodArgument
78
+ end
79
+ end
80
+ end
81
+ end