///|
/// Indexing and storage behavior for one text field.
pub struct TextOptions {
indexed : Bool
stored : Bool
tokenizer_name : String
}
///|
pub fn TextOptions::new(indexed : Bool, stored : Bool) -> TextOptions {
{ indexed, stored, tokenizer_name: "whitespace" }
}
///|
pub fn valid_tokenizer_name(name : String) -> Bool {
if name.length() == 0 {
return false
}
for ch in name {
if ch.is_whitespace() {
return false
}
}
true
}
///|
/// Selects the named Tokenizer pipeline used for this field at index and query
/// time.
pub fn TextOptions::with_tokenizer(
self : TextOptions,
tokenizer_name : String,
) -> TextOptions {
guard valid_tokenizer_name(tokenizer_name) else {
abort("invalid tokenizer name: \{tokenizer_name}")
}
{ indexed: self.indexed, stored: self.stored, tokenizer_name }
}
///|
pub fn TextOptions::is_indexed(self : TextOptions) -> Bool {
self.indexed
}
///|
pub fn TextOptions::is_stored(self : TextOptions) -> Bool {
self.stored
}
///|
pub fn TextOptions::tokenizer_name(self : TextOptions) -> String {
self.tokenizer_name
}
///|
struct FieldEntry {
name : String
options : TextOptions
}
///|
/// Immutable registry of field names, identifiers, and text options.
pub struct Schema {
fields : ReadOnlyArray[FieldEntry]
}
///|
pub fn Schema::field_count(self : Schema) -> Int {
self.fields.length()
}
///|
pub fn Schema::field_name(self : Schema, field_id : FieldId) -> String? {
if field_id.value < 0 || field_id.value >= self.fields.length() {
None
} else {
Some(self.fields[field_id.value].name)
}
}
///|
pub fn Schema::field(self : Schema, name : String) -> FieldId? {
match self.fields.search_by(entry => entry.name == name) {
Some(index) => Some(FieldId::new(index))
None => None
}
}
///|
pub fn Schema::is_indexed(self : Schema, field_id : FieldId) -> Bool {
match self.options(field_id) {
Some(options) => options.is_indexed()
None => false
}
}
///|
pub fn Schema::is_stored(self : Schema, field_id : FieldId) -> Bool {
match self.options(field_id) {
Some(options) => options.is_stored()
None => false
}
}
///|
/// Returns the Tokenizer registry name configured for one field.
pub fn Schema::tokenizer_name(self : Schema, field_id : FieldId) -> String? {
match self.options(field_id) {
Some(options) => Some(options.tokenizer_name)
None => None
}
}
///|
pub fn Schema::options(self : Schema, field_id : FieldId) -> TextOptions? {
if field_id.value < 0 || field_id.value >= self.fields.length() {
None
} else {
Some(self.fields[field_id.value].options)
}
}
///|
/// Mutable builder that assigns sequential, stable FieldId values.
pub struct SchemaBuilder {
fields : Array[FieldEntry]
}
///|
pub fn SchemaBuilder::new() -> SchemaBuilder {
{ fields: [] }
}
///|
pub fn SchemaBuilder::add_text_field(
self : SchemaBuilder,
name : String,
options : TextOptions,
) -> FieldId {
if self.fields.search_by(entry => entry.name == name) is Some(_) {
abort("duplicate field name: \{name}")
}
let field_id = FieldId::new(self.fields.length())
self.fields.push({ name, options })
field_id
}
///|
pub fn SchemaBuilder::build(self : SchemaBuilder) -> Schema {
let fields : Array[FieldEntry] = []
for entry in self.fields {
fields.push(entry)
}
{ fields: ReadOnlyArray::from_array(fields) }
}
///|
pub fn schemas_equal(left : Schema?, right : Schema?) -> Bool {
match (left, right) {
(None, None) => true
(Some(left), Some(right)) => {
if left.fields.length() != right.fields.length() {
return false
}
for index in 0.. false
}
}