storage-kit 0.0.1

Portable database and transactional state-store Kit.
Documentation
use std::collections::BTreeMap;

use serde_json::Value;

use crate::{QueryResponse, StorageError, TextSearchRequest};

use super::super::mapper;
use super::{SurrealManager, shared};

pub(super) async fn text(
    db: &SurrealManager,
    request: TextSearchRequest,
) -> Result<QueryResponse, StorageError> {
    let scope = db.scope(&request.query.scope.locator)?;
    let field = request.query.options.text_field.clone().ok_or_else(|| {
        db.unsupported(
            "TEXT_FIELD_SELECTION",
            "SurrealDB text search requires a selected text field",
        )
    })?;
    let projection = mapper::projection_clause(&request.query.scope.projection)?;
    let record = match request.query.scope.projection {
        crate::Projection::All => "$this".to_owned(),
        crate::Projection::Columns(_) => format!("(SELECT {projection} FROM $this)[0]"),
    };
    let where_text = format!("{} @1@ $query", mapper::quote_ident(&field));
    let where_sql = match request.query.scope.filter.as_ref() {
        Some(filter) => format!(
            " WHERE ({where_text}) AND ({})",
            mapper::compile_filter(filter)?
        ),
        None => format!(" WHERE {where_text}"),
    };
    let limit_sql =
        mapper::limit_offset_clause(request.query.options.limit, request.query.options.offset);
    let sql = format!(
        "SELECT * FROM (SELECT VALUE {{ record: {record}, score: search::score(1) }} FROM {}{where_sql}) ORDER BY score DESC {limit_sql};",
        scope.table()
    );

    let mut binds = BTreeMap::new();
    binds.insert("query".into(), Value::String(request.text));
    let rows: Value = scope.run_take(sql, binds, 0).await?;
    shared::SurrealScoring::RelevanceEnvelope.response(rows, None)
}