2022-05-14 12:35:08 +00:00
|
|
|
use crate::ctx::Context;
|
2022-02-06 01:14:56 +00:00
|
|
|
use crate::dbs::Statement;
|
2023-07-06 14:57:42 +00:00
|
|
|
use crate::dbs::{Options, Transaction};
|
|
|
|
use crate::doc::{CursorDoc, Document};
|
2022-02-06 01:14:56 +00:00
|
|
|
use crate::err::Error;
|
2023-05-29 11:46:41 +00:00
|
|
|
use crate::idx::ft::FtIndex;
|
2023-08-01 09:57:05 +00:00
|
|
|
use crate::idx::trees::store::TreeStoreType;
|
2023-05-29 11:46:41 +00:00
|
|
|
use crate::idx::IndexKeyBase;
|
2022-04-09 09:09:01 +00:00
|
|
|
use crate::sql::array::Array;
|
2023-05-29 11:46:41 +00:00
|
|
|
use crate::sql::index::Index;
|
|
|
|
use crate::sql::scoring::Scoring;
|
|
|
|
use crate::sql::statements::DefineIndexStatement;
|
2023-08-01 07:30:13 +00:00
|
|
|
use crate::sql::{Ident, Part, Thing, Value};
|
2023-05-29 11:46:41 +00:00
|
|
|
use crate::{key, kvs};
|
2022-01-13 07:00:50 +00:00
|
|
|
|
2022-02-13 19:03:00 +00:00
|
|
|
impl<'a> Document<'a> {
|
2022-02-06 01:14:56 +00:00
|
|
|
pub async fn index(
|
|
|
|
&self,
|
2022-05-14 12:35:08 +00:00
|
|
|
ctx: &Context<'_>,
|
2022-04-09 09:09:01 +00:00
|
|
|
opt: &Options,
|
2023-07-06 14:57:42 +00:00
|
|
|
txn: &Transaction,
|
2022-05-13 20:46:56 +00:00
|
|
|
_stm: &Statement<'_>,
|
2022-02-06 01:14:56 +00:00
|
|
|
) -> Result<(), Error> {
|
2023-07-05 21:26:13 +00:00
|
|
|
// Check indexes
|
2022-08-25 13:49:33 +00:00
|
|
|
if !opt.indexes {
|
|
|
|
return Ok(());
|
|
|
|
}
|
2022-04-09 09:09:01 +00:00
|
|
|
// Check if forced
|
|
|
|
if !opt.force && !self.changed() {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
// Check if the table is a view
|
2023-07-06 14:57:42 +00:00
|
|
|
if self.tb(opt, txn).await?.drop {
|
2022-04-09 09:09:01 +00:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
// Get the record id
|
|
|
|
let rid = self.id.as_ref().unwrap();
|
|
|
|
// Loop through all index statements
|
2023-07-06 14:57:42 +00:00
|
|
|
for ix in self.ix(opt, txn).await?.iter() {
|
2022-04-09 09:09:01 +00:00
|
|
|
// Calculate old values
|
2023-08-01 07:30:13 +00:00
|
|
|
let o = build_opt_values(ctx, opt, txn, ix, &self.initial).await?;
|
2023-05-29 11:46:41 +00:00
|
|
|
|
2022-04-09 09:09:01 +00:00
|
|
|
// Calculate new values
|
2023-08-01 07:30:13 +00:00
|
|
|
let n = build_opt_values(ctx, opt, txn, ix, &self.current).await?;
|
2023-05-29 11:46:41 +00:00
|
|
|
|
2022-04-09 09:09:01 +00:00
|
|
|
// Update the index entries
|
|
|
|
if opt.force || o != n {
|
2023-05-29 11:46:41 +00:00
|
|
|
// Claim transaction
|
|
|
|
let mut run = txn.lock().await;
|
|
|
|
|
|
|
|
// Store all the variable and parameters required by the index operation
|
2023-08-01 07:30:13 +00:00
|
|
|
let mut ic = IndexOperation::new(opt, ix, o, n, rid);
|
2023-05-29 11:46:41 +00:00
|
|
|
|
|
|
|
// Index operation dispatching
|
|
|
|
match &ix.index {
|
|
|
|
Index::Uniq => ic.index_unique(&mut run).await?,
|
|
|
|
Index::Idx => ic.index_non_unique(&mut run).await?,
|
|
|
|
Index::Search {
|
|
|
|
az,
|
|
|
|
sc,
|
|
|
|
hl,
|
2023-06-19 18:41:13 +00:00
|
|
|
order,
|
2023-06-21 18:31:15 +00:00
|
|
|
} => ic.index_full_text(&mut run, az, *order, sc, *hl).await?,
|
2022-04-09 09:09:01 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Carry on
|
2022-02-06 01:14:56 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2023-08-01 07:30:13 +00:00
|
|
|
}
|
2023-05-29 11:46:41 +00:00
|
|
|
|
2023-08-01 07:30:13 +00:00
|
|
|
/// Extract from the given document, the values required by the index and put then in an array.
|
|
|
|
/// Eg. IF the index is composed of the columns `name` and `instrument`
|
|
|
|
/// Given this doc: { "id": 1, "instrument":"piano", "name":"Tobie" }
|
|
|
|
/// It will return: ["Tobie", "piano"]
|
|
|
|
async fn build_opt_values(
|
|
|
|
ctx: &Context<'_>,
|
|
|
|
opt: &Options,
|
|
|
|
txn: &Transaction,
|
|
|
|
ix: &DefineIndexStatement,
|
|
|
|
doc: &CursorDoc<'_>,
|
|
|
|
) -> Result<Option<Vec<Value>>, Error> {
|
|
|
|
if !doc.doc.is_some() {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
let mut o = Vec::with_capacity(ix.cols.len());
|
|
|
|
for i in ix.cols.iter() {
|
|
|
|
let v = i.compute(ctx, opt, txn, Some(doc)).await?;
|
|
|
|
o.push(v);
|
|
|
|
}
|
|
|
|
Ok(Some(o))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Extract from the given document, the values required by the index and put then in an array.
|
|
|
|
/// Eg. IF the index is composed of the columns `name` and `instrument`
|
|
|
|
/// Given this doc: { "id": 1, "instrument":"piano", "name":"Tobie" }
|
|
|
|
/// It will return: ["Tobie", "piano"]
|
|
|
|
struct Indexable(Vec<(Value, bool)>);
|
|
|
|
|
|
|
|
impl Indexable {
|
|
|
|
fn new(vals: Vec<Value>, ix: &DefineIndexStatement) -> Self {
|
|
|
|
let mut source = Vec::with_capacity(vals.len());
|
|
|
|
for (v, i) in vals.into_iter().zip(ix.cols.0.iter()) {
|
|
|
|
let f = matches!(i.0.last(), Some(&Part::Flatten));
|
|
|
|
source.push((v, f));
|
|
|
|
}
|
|
|
|
Self(source)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl IntoIterator for Indexable {
|
|
|
|
type Item = Array;
|
|
|
|
type IntoIter = Combinator;
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
|
|
Combinator::new(self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Combinator {
|
|
|
|
iterators: Vec<Box<dyn ValuesIterator>>,
|
|
|
|
has_next: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Combinator {
|
|
|
|
fn new(source: Vec<(Value, bool)>) -> Self {
|
|
|
|
let mut iterators: Vec<Box<dyn ValuesIterator>> = Vec::new();
|
|
|
|
// We create an iterator for each idiom
|
|
|
|
for (v, f) in source {
|
|
|
|
if !f {
|
|
|
|
// Iterator for not flattened values
|
|
|
|
if let Value::Array(v) = v {
|
|
|
|
iterators.push(Box::new(MultiValuesIterator {
|
|
|
|
vals: v.0,
|
|
|
|
done: false,
|
|
|
|
current: 0,
|
|
|
|
}));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
iterators.push(Box::new(SingleValueIterator(v)));
|
|
|
|
}
|
|
|
|
Self {
|
|
|
|
iterators,
|
|
|
|
has_next: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Iterator for Combinator {
|
|
|
|
type Item = Array;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
if !self.has_next {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
let mut o = Vec::with_capacity(self.iterators.len());
|
|
|
|
// Create the combination and advance to the next
|
|
|
|
self.has_next = false;
|
|
|
|
for i in &mut self.iterators {
|
|
|
|
o.push(i.current().clone());
|
|
|
|
if !self.has_next {
|
|
|
|
// We advance only one iterator per iteration
|
|
|
|
if i.next() {
|
|
|
|
self.has_next = true;
|
|
|
|
}
|
|
|
|
}
|
2023-05-29 11:46:41 +00:00
|
|
|
}
|
2023-08-01 07:30:13 +00:00
|
|
|
let o = Array::from(o);
|
|
|
|
Some(o)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
trait ValuesIterator: Send {
|
|
|
|
fn next(&mut self) -> bool;
|
|
|
|
fn current(&self) -> &Value;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct MultiValuesIterator {
|
|
|
|
vals: Vec<Value>,
|
|
|
|
done: bool,
|
|
|
|
current: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ValuesIterator for MultiValuesIterator {
|
|
|
|
fn next(&mut self) -> bool {
|
|
|
|
if self.done {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if self.current == self.vals.len() - 1 {
|
|
|
|
self.done = true;
|
|
|
|
return false;
|
2023-05-29 11:46:41 +00:00
|
|
|
}
|
2023-08-01 07:30:13 +00:00
|
|
|
self.current += 1;
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn current(&self) -> &Value {
|
|
|
|
self.vals.get(self.current).unwrap_or(&Value::Null)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct SingleValueIterator(Value);
|
|
|
|
|
|
|
|
impl ValuesIterator for SingleValueIterator {
|
|
|
|
fn next(&mut self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
|
|
|
fn current(&self) -> &Value {
|
|
|
|
&self.0
|
2023-05-29 11:46:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct IndexOperation<'a> {
|
|
|
|
opt: &'a Options,
|
|
|
|
ix: &'a DefineIndexStatement,
|
2023-08-01 07:30:13 +00:00
|
|
|
/// The old values (if existing)
|
|
|
|
o: Option<Vec<Value>>,
|
|
|
|
/// The new values (if existing)
|
|
|
|
n: Option<Vec<Value>>,
|
2023-05-29 11:46:41 +00:00
|
|
|
rid: &'a Thing,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> IndexOperation<'a> {
|
|
|
|
fn new(
|
|
|
|
opt: &'a Options,
|
|
|
|
ix: &'a DefineIndexStatement,
|
2023-08-01 07:30:13 +00:00
|
|
|
o: Option<Vec<Value>>,
|
|
|
|
n: Option<Vec<Value>>,
|
2023-05-29 11:46:41 +00:00
|
|
|
rid: &'a Thing,
|
|
|
|
) -> Self {
|
|
|
|
Self {
|
|
|
|
opt,
|
|
|
|
ix,
|
|
|
|
o,
|
|
|
|
n,
|
|
|
|
rid,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-29 08:46:48 +00:00
|
|
|
fn get_unique_index_key(&self, v: &'a Array) -> key::index::Index {
|
|
|
|
crate::key::index::Index::new(
|
|
|
|
self.opt.ns(),
|
|
|
|
self.opt.db(),
|
|
|
|
&self.ix.what,
|
|
|
|
&self.ix.name,
|
|
|
|
v,
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-08-01 07:30:13 +00:00
|
|
|
fn get_non_unique_index_key(&self, v: &'a Array) -> key::index::Index {
|
2023-08-29 08:46:48 +00:00
|
|
|
crate::key::index::Index::new(
|
2023-05-29 11:46:41 +00:00
|
|
|
self.opt.ns(),
|
|
|
|
self.opt.db(),
|
|
|
|
&self.ix.what,
|
|
|
|
&self.ix.name,
|
2023-08-01 07:30:13 +00:00
|
|
|
v,
|
|
|
|
Some(&self.rid.id),
|
2023-05-29 11:46:41 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-08-29 08:46:48 +00:00
|
|
|
async fn index_unique(&mut self, run: &mut kvs::Transaction) -> Result<(), Error> {
|
2023-05-29 11:46:41 +00:00
|
|
|
// Delete the old index data
|
2023-08-01 07:30:13 +00:00
|
|
|
if let Some(o) = self.o.take() {
|
|
|
|
let i = Indexable::new(o, self.ix);
|
|
|
|
for o in i {
|
2023-08-29 08:46:48 +00:00
|
|
|
let key = self.get_unique_index_key(&o);
|
|
|
|
match run.delc(key, Some(self.rid)).await {
|
|
|
|
Err(Error::TxConditionNotMet) => Ok(()),
|
|
|
|
Err(e) => Err(e),
|
|
|
|
Ok(v) => Ok(v),
|
|
|
|
}?
|
2023-08-01 07:30:13 +00:00
|
|
|
}
|
2023-05-29 11:46:41 +00:00
|
|
|
}
|
|
|
|
// Create the new index data
|
2023-08-01 07:30:13 +00:00
|
|
|
if let Some(n) = self.n.take() {
|
|
|
|
let i = Indexable::new(n, self.ix);
|
|
|
|
for n in i {
|
2023-08-29 08:46:48 +00:00
|
|
|
if !n.is_all_none_or_null() {
|
|
|
|
let key = self.get_unique_index_key(&n);
|
|
|
|
if run.putc(key, self.rid, None).await.is_err() {
|
|
|
|
let key = self.get_unique_index_key(&n);
|
|
|
|
let val = run.get(key).await?.unwrap();
|
|
|
|
let rid: Thing = val.into();
|
|
|
|
return self.err_index_exists(rid, n);
|
|
|
|
}
|
2023-08-01 07:30:13 +00:00
|
|
|
}
|
2023-05-29 11:46:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-08-29 08:46:48 +00:00
|
|
|
async fn index_non_unique(&mut self, run: &mut kvs::Transaction) -> Result<(), Error> {
|
2023-05-29 11:46:41 +00:00
|
|
|
// Delete the old index data
|
2023-08-01 07:30:13 +00:00
|
|
|
if let Some(o) = self.o.take() {
|
|
|
|
let i = Indexable::new(o, self.ix);
|
|
|
|
for o in i {
|
2023-08-29 08:46:48 +00:00
|
|
|
let key = self.get_non_unique_index_key(&o);
|
|
|
|
match run.delc(key, Some(self.rid)).await {
|
|
|
|
Err(Error::TxConditionNotMet) => Ok(()),
|
|
|
|
Err(e) => Err(e),
|
|
|
|
Ok(v) => Ok(v),
|
|
|
|
}?
|
2023-08-01 07:30:13 +00:00
|
|
|
}
|
2023-05-29 11:46:41 +00:00
|
|
|
}
|
|
|
|
// Create the new index data
|
2023-08-01 07:30:13 +00:00
|
|
|
if let Some(n) = self.n.take() {
|
|
|
|
let i = Indexable::new(n, self.ix);
|
|
|
|
for n in i {
|
2023-08-29 08:46:48 +00:00
|
|
|
let key = self.get_non_unique_index_key(&n);
|
|
|
|
if run.putc(key, self.rid, None).await.is_err() {
|
|
|
|
let key = self.get_non_unique_index_key(&n);
|
|
|
|
let val = run.get(key).await?.unwrap();
|
|
|
|
let rid: Thing = val.into();
|
|
|
|
return self.err_index_exists(rid, n);
|
2023-07-21 18:40:59 +00:00
|
|
|
}
|
2023-05-29 11:46:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-08-29 08:46:48 +00:00
|
|
|
fn err_index_exists(&self, rid: Thing, n: Array) -> Result<(), Error> {
|
2023-05-29 11:46:41 +00:00
|
|
|
Err(Error::IndexExists {
|
2023-08-29 08:46:48 +00:00
|
|
|
thing: rid,
|
2023-05-29 11:46:41 +00:00
|
|
|
index: self.ix.name.to_string(),
|
|
|
|
value: match n.len() {
|
|
|
|
1 => n.first().unwrap().to_string(),
|
|
|
|
_ => n.to_string(),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-06-21 18:31:15 +00:00
|
|
|
async fn index_full_text(
|
2023-05-29 11:46:41 +00:00
|
|
|
&self,
|
|
|
|
run: &mut kvs::Transaction,
|
2023-06-19 18:41:13 +00:00
|
|
|
az: &Ident,
|
|
|
|
order: u32,
|
2023-06-21 18:31:15 +00:00
|
|
|
scoring: &Scoring,
|
|
|
|
hl: bool,
|
2023-05-29 11:46:41 +00:00
|
|
|
) -> Result<(), Error> {
|
|
|
|
let ikb = IndexKeyBase::new(self.opt, self.ix);
|
2023-06-19 18:41:13 +00:00
|
|
|
let az = run.get_az(self.opt.ns(), self.opt.db(), az.as_str()).await?;
|
2023-08-01 09:57:05 +00:00
|
|
|
let mut ft = FtIndex::new(run, az, ikb, order, scoring, hl, TreeStoreType::Write).await?;
|
2023-05-29 11:46:41 +00:00
|
|
|
if let Some(n) = &self.n {
|
2023-07-11 18:22:31 +00:00
|
|
|
ft.index_document(run, self.rid, n).await?;
|
2023-05-29 11:46:41 +00:00
|
|
|
} else {
|
2023-07-11 18:22:31 +00:00
|
|
|
ft.remove_document(run, self.rid).await?;
|
2023-05-29 11:46:41 +00:00
|
|
|
}
|
2023-07-11 18:22:31 +00:00
|
|
|
ft.finish(run).await
|
2023-05-29 11:46:41 +00:00
|
|
|
}
|
2022-02-06 01:14:56 +00:00
|
|
|
}
|