Class: Zvec::Doc
- Inherits:
-
Object
- Object
- Zvec::Doc
- Defined in:
- lib/zvec/doc.rb
Overview
A document (row) in a zvec collection. Wraps the C++ Doc object and provides Ruby-friendly field access with automatic type coercion.
Documents can be created with or without a schema. With a schema, values are coerced and validated against declared field types and vector dimensions. Without a schema, types are auto-detected.
Instance Attribute Summary collapse
-
#ext_doc ⇒ Ext::Doc
readonly
The underlying C++ document object.
Class Method Summary collapse
-
.from_ext(ext_doc, schema: nil) ⇒ Zvec::Doc
Wrap a C++ Doc::Ptr into a Ruby Doc.
Instance Method Summary collapse
-
#[](field_name) ⇒ Object?
Read a field value by name (bracket accessor).
-
#[]=(field_name, value) ⇒ void
Write a field value by name (bracket accessor).
-
#empty? ⇒ Boolean
True if no fields have been set.
-
#field_names ⇒ Array<String>
Names of all fields set on this document.
-
#get(field_name) ⇒ Object?
Get a field value by name.
-
#initialize(pk: nil, fields: {}, schema: nil) ⇒ Doc
constructor
Create a new document.
-
#pk ⇒ String
The primary key.
-
#pk=(value) ⇒ void
Set the primary key.
-
#score ⇒ Float
The similarity score (set after search queries).
-
#set(field_name, value) ⇒ void
Set a field value.
-
#to_h ⇒ Hash{String => Object}
Convert the document to a plain Ruby Hash.
-
#to_s ⇒ String
Human-readable representation.
Constructor Details
#initialize(pk: nil, fields: {}, schema: nil) ⇒ Doc
Create a new document.
35 36 37 38 39 40 |
# File 'lib/zvec/doc.rb', line 35 def initialize(pk: nil, fields: {}, schema: nil) @ext_doc = Ext::Doc.new @ext_doc.pk = pk.to_s if pk @schema = schema fields.each { |k, v| set(k, v) } if schema end |
Instance Attribute Details
#ext_doc ⇒ Ext::Doc (readonly)
Returns the underlying C++ document object.
25 26 27 |
# File 'lib/zvec/doc.rb', line 25 def ext_doc @ext_doc end |
Class Method Details
.from_ext(ext_doc, schema: nil) ⇒ Zvec::Doc
Wrap a C++ Doc::Ptr into a Ruby Doc.
209 210 211 212 213 214 |
# File 'lib/zvec/doc.rb', line 209 def self.from_ext(ext_doc, schema: nil) doc = allocate doc.instance_variable_set(:@ext_doc, ext_doc) doc.instance_variable_set(:@schema, schema) doc end |
Instance Method Details
#[](field_name) ⇒ Object?
Read a field value by name (bracket accessor).
67 68 69 |
# File 'lib/zvec/doc.rb', line 67 def [](field_name) get(field_name) end |
#[]=(field_name, value) ⇒ void
This method returns an undefined value.
Write a field value by name (bracket accessor).
79 80 81 |
# File 'lib/zvec/doc.rb', line 79 def []=(field_name, value) set(field_name, value) end |
#empty? ⇒ Boolean
Returns true if no fields have been set.
183 184 185 |
# File 'lib/zvec/doc.rb', line 183 def empty? @ext_doc.empty? end |
#field_names ⇒ Array<String>
Returns names of all fields set on this document.
178 179 180 |
# File 'lib/zvec/doc.rb', line 178 def field_names @ext_doc.field_names end |
#get(field_name) ⇒ Object?
Get a field value by name. Uses the schema getter if available, otherwise tries common types in order.
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/zvec/doc.rb', line 155 def get(field_name) field_name = field_name.to_s return nil unless @ext_doc.has?(field_name) return nil unless @ext_doc.has_value?(field_name) if @schema type = @schema.field_type(field_name) if type getter = DataTypes::GETTER_FOR[type] return @ext_doc.send(getter, field_name) if getter end end # Try common types in order %i[get_string get_int64 get_float get_double get_bool get_float_vector get_string_array].each do |m| val = @ext_doc.send(m, field_name) return val unless val.nil? end nil end |
#pk ⇒ String
Returns the primary key.
43 44 45 |
# File 'lib/zvec/doc.rb', line 43 def pk @ext_doc.pk end |
#pk=(value) ⇒ void
This method returns an undefined value.
Set the primary key.
51 52 53 |
# File 'lib/zvec/doc.rb', line 51 def pk=(value) @ext_doc.pk = value.to_s end |
#score ⇒ Float
Returns the similarity score (set after search queries).
56 57 58 |
# File 'lib/zvec/doc.rb', line 56 def score @score || @ext_doc.score end |
#set(field_name, value) ⇒ void
This method returns an undefined value.
Set a field value. When a schema is present, the value is coerced to the declared type and validated. Without a schema, the type is auto-detected from the Ruby value.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/zvec/doc.rb', line 97 def set(field_name, value) field_name = field_name.to_s raise ArgumentError, "Field name must be a non-empty string" if field_name.strip.empty? return @ext_doc.set_null(field_name) if value.nil? if @schema type = @schema.field_type(field_name) if type coerced = DataTypes.coerce_value(value, type, field_name: field_name) setter = DataTypes::SETTER_FOR[type] if setter # Validate vector dimension if schema has dimension info if DataTypes::VECTOR_TYPES.include?(type) && coerced.is_a?(Array) expected_dim = @schema.field_dimension(field_name) if expected_dim && !coerced.empty? && coerced.size != expected_dim raise DimensionError, "Vector dimension mismatch for field '#{field_name}': " \ "expected #{expected_dim}, got #{coerced.size}" end end return @ext_doc.send(setter, field_name, coerced) end end end # Auto-detect type (schema-less mode) case value when String then @ext_doc.set_string(field_name, value) when Integer then @ext_doc.set_int64(field_name, value) when Float then @ext_doc.set_double(field_name, value) when TrueClass, FalseClass then @ext_doc.set_bool(field_name, value) when Array detected = DataTypes.detect_type(value) case detected when Ext::DataType::ARRAY_STRING @ext_doc.set_string_array(field_name, value.map { |v| v.nil? ? "" : v.to_s }) else # Default: treat as float vector coerced = value.map { |v| v.nil? ? 0.0 : v.to_f } @ext_doc.set_float_vector(field_name, coerced) end else raise ArgumentError, "Unsupported value type #{value.class} for field '#{field_name}'" end end |
#to_h ⇒ Hash{String => Object}
Convert the document to a plain Ruby Hash.
193 194 195 196 197 |
# File 'lib/zvec/doc.rb', line 193 def to_h h = { "pk" => pk, "score" => score } field_names.each { |f| h[f] = get(f) } h end |
#to_s ⇒ String
Returns human-readable representation.
200 201 202 |
# File 'lib/zvec/doc.rb', line 200 def to_s @ext_doc.to_s end |