search fix to new architecture2
This commit is contained in:
@@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use tantivy::schema::{
|
||||
Field, IndexRecordOption, JsonObjectOptions, Schema, Term, TextFieldIndexing, TextOptions,
|
||||
INDEXED, STORED, STRING,
|
||||
FAST, INDEXED, STORED, STRING,
|
||||
};
|
||||
use tantivy::tokenizer::{
|
||||
AsciiFoldingFilter, LowerCaser, NgramTokenizer, RawTokenizer, RemoveLongFilter,
|
||||
@@ -11,6 +11,10 @@ use tantivy::tokenizer::{
|
||||
use tantivy::Index;
|
||||
|
||||
pub const F_PG_ID: &str = "pg_id";
|
||||
pub const F_ROW_REVISION: &str = "row_revision";
|
||||
pub const F_IS_ARCHIVED: &str = "is_archived";
|
||||
pub const F_TABLE_DEFINITION_ID: &str = "table_definition_id";
|
||||
pub const F_VERSION_NUMBER: &str = "version_number";
|
||||
pub const F_TABLE_NAME: &str = "table_name";
|
||||
pub const F_ROW_KEY: &str = "row_key";
|
||||
pub const F_ALL_TEXT: &str = "all_text";
|
||||
@@ -19,7 +23,7 @@ pub const F_DATA_NGRAM: &str = "data_ngram";
|
||||
pub const F_DATA_EXACT: &str = "data_exact";
|
||||
pub const JOURNAL_TABLE_NAME: &str = "general_ledger";
|
||||
pub const ARCHIVED_ROW_KEY_PREFIX: &str = "__archive__:";
|
||||
pub const SEARCH_INDEX_FORMAT_DIRECTORY: &str = "v2";
|
||||
pub const SEARCH_INDEX_FORMAT_DIRECTORY: &str = "v3";
|
||||
|
||||
/// Root for the current on-disk index format. The format component prevents
|
||||
/// an executable with new projection semantics from opening old documents.
|
||||
@@ -84,6 +88,38 @@ pub fn normalize_exact(input: &str) -> String {
|
||||
out
|
||||
}
|
||||
|
||||
/// Canonicalizes an exact constraint with the same scalar spelling used by
|
||||
/// the indexer. Catalog field types are public type names, not PostgreSQL type
|
||||
/// names, so this deliberately matches the catalog vocabulary.
|
||||
pub fn canonical_exact_search_value(input: &str, field_type: &str) -> Result<String, String> {
|
||||
let normalized_type = field_type.trim().to_ascii_lowercase();
|
||||
if matches!(normalized_type.as_str(), "numeric" | "money")
|
||||
|| normalized_type.starts_with("decimal(")
|
||||
{
|
||||
return input
|
||||
.parse::<rust_decimal::Decimal>()
|
||||
.map(|value| value.normalize().to_string())
|
||||
.map_err(|error| format!("Exact numeric search value is invalid: {error}"));
|
||||
}
|
||||
if matches!(normalized_type.as_str(), "int" | "bigint")
|
||||
|| normalized_type.starts_with("link(")
|
||||
{
|
||||
return input
|
||||
.parse::<i64>()
|
||||
.map(|value| value.to_string())
|
||||
.map_err(|error| format!("Exact integer search value is invalid: {error}"));
|
||||
}
|
||||
Ok(input.to_string())
|
||||
}
|
||||
|
||||
/// Canonical spelling for a JSON number stored in a Tantivy text term.
|
||||
pub fn canonical_search_number(input: &str) -> String {
|
||||
input
|
||||
.parse::<rust_decimal::Decimal>()
|
||||
.map(|value| value.normalize().to_string())
|
||||
.unwrap_or_else(|_| input.to_string())
|
||||
}
|
||||
|
||||
/// Normalizes a column name to the JSON-key form used at index time.
|
||||
pub fn normalize_column_name(column: &str) -> String {
|
||||
column.to_ascii_lowercase()
|
||||
@@ -93,7 +129,11 @@ pub fn normalize_column_name(column: &str) -> String {
|
||||
pub fn create_search_schema() -> Schema {
|
||||
let mut schema_builder = Schema::builder();
|
||||
|
||||
schema_builder.add_u64_field(F_PG_ID, INDEXED | STORED);
|
||||
schema_builder.add_u64_field(F_PG_ID, INDEXED | STORED | FAST);
|
||||
schema_builder.add_u64_field(F_ROW_REVISION, STORED | FAST);
|
||||
schema_builder.add_u64_field(F_IS_ARCHIVED, INDEXED | STORED | FAST);
|
||||
schema_builder.add_u64_field(F_TABLE_DEFINITION_ID, STORED | FAST);
|
||||
schema_builder.add_u64_field(F_VERSION_NUMBER, STORED | FAST);
|
||||
schema_builder.add_text_field(F_TABLE_NAME, STRING | STORED);
|
||||
schema_builder.add_text_field(F_ROW_KEY, STRING | STORED);
|
||||
schema_builder.add_text_field(F_ALL_TEXT, text_options(TOK_WORD));
|
||||
@@ -197,6 +237,10 @@ pub fn json_path_term(field: Field, column: &str, text: &str) -> Term {
|
||||
/// Returns all required schema fields or fails loudly on mismatch.
|
||||
pub struct SchemaFields {
|
||||
pub pg_id: Field,
|
||||
pub row_revision: Field,
|
||||
pub is_archived: Field,
|
||||
pub table_definition_id: Field,
|
||||
pub version_number: Field,
|
||||
pub table_name: Field,
|
||||
pub row_key: Field,
|
||||
pub all_text: Field,
|
||||
@@ -209,6 +253,10 @@ impl SchemaFields {
|
||||
pub fn from(schema: &Schema) -> tantivy::Result<Self> {
|
||||
Ok(Self {
|
||||
pg_id: get_field(schema, F_PG_ID)?,
|
||||
row_revision: get_field(schema, F_ROW_REVISION)?,
|
||||
is_archived: get_field(schema, F_IS_ARCHIVED)?,
|
||||
table_definition_id: get_field(schema, F_TABLE_DEFINITION_ID)?,
|
||||
version_number: get_field(schema, F_VERSION_NUMBER)?,
|
||||
table_name: get_field(schema, F_TABLE_NAME)?,
|
||||
row_key: get_field(schema, F_ROW_KEY)?,
|
||||
all_text: get_field(schema, F_ALL_TEXT)?,
|
||||
@@ -221,7 +269,9 @@ impl SchemaFields {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{archived_search_row_key, parse_archived_search_row_key};
|
||||
use super::{
|
||||
archived_search_row_key, canonical_exact_search_value, parse_archived_search_row_key,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn archived_row_key_round_trips_stable_identity() {
|
||||
@@ -230,6 +280,19 @@ mod tests {
|
||||
assert_eq!(parse_archived_search_row_key("customers:7"), None);
|
||||
assert_eq!(parse_archived_search_row_key("__archive__:42:7"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exact_scalar_values_follow_catalog_field_types() {
|
||||
assert_eq!(canonical_exact_search_value("001", "int").unwrap(), "1");
|
||||
assert_eq!(canonical_exact_search_value("001", "bigint").unwrap(), "1");
|
||||
assert_eq!(canonical_exact_search_value("001", "link(adresar)").unwrap(), "1");
|
||||
assert_eq!(canonical_exact_search_value("10.50", "numeric").unwrap(), "10.5");
|
||||
assert_eq!(canonical_exact_search_value("10.50", "money").unwrap(), "10.5");
|
||||
assert_eq!(
|
||||
canonical_exact_search_value("10.50", "decimal(12, 2)").unwrap(),
|
||||
"10.5"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_field(schema: &Schema, name: &str) -> tantivy::Result<Field> {
|
||||
|
||||
Reference in New Issue
Block a user