use std::cmp::Ordering;
use rudb_common::{Error, LogicalType, Result, Value};
use crate::compare::order;
const NULL_PICK: &str = "NULLs are not allowed as list elements in the second input parameter.";
pub(crate) fn before_nulls(
name: &str,
args: &[Value],
returns: &LogicalType,
) -> Option<Result<Value>> {
Some(match (name, args) {
("list_position", [Value::Null, _]) => Ok(Value::Null),
("list_position", [Value::List { values, .. }, needle]) => position(values, needle),
("list_resize" | "list_intersect", [Value::Null, ..]) => Ok(Value::Null),
("list_intersect", [Value::List { .. }, Value::Null]) => listed(Vec::new(), returns),
("list_resize", [Value::List { values, .. }, size, filler @ ..]) => {
resize(values, size, filler.first().unwrap_or(&Value::Null), returns)
}
_ => return None,
})
}
pub(crate) fn value(name: &str, args: &[Value], returns: &LogicalType) -> Option<Result<Value>> {
let list = |values| listed(values, returns);
Some(match (name, args) {
("list_contains", [Value::List { values, .. }, needle]) => {
found(values, needle).map(|at| Value::Boolean(at.is_some()))
}
("list_has_any", [Value::List { values, .. }, Value::List { values: wanted, .. }]) => {
has_any(values, wanted).map(Value::Boolean)
}
("list_has_all", [Value::List { values, .. }, Value::List { values: wanted, .. }]) => {
has_any_missing(values, wanted).map(|missing| Value::Boolean(!missing))
}
("list_distinct", [Value::List { values, .. }]) => distinct(values).and_then(&list),
("list_unique", [Value::List { values, .. }]) => {
distinct(values).map(|kept| Value::UBigInt(kept.len() as u64))
}
("list_intersect", [Value::List { values, .. }, Value::List { values: other, .. }]) => {
intersect(values, other).and_then(&list)
}
("list_where", [Value::List { values, .. }, Value::List { values: mask, .. }]) => {
masked(values, mask).and_then(&list)
}
("list_select", [Value::List { values, .. }, Value::List { values: indexes, .. }]) => {
selected(values, indexes).and_then(&list)
}
("list_sort", [Value::List { values, .. }, spelled @ ..]) => {
let order = spelled.first().map(spelled_order).transpose();
let nulls = spelled.get(1).map(spelled_nulls).transpose();
match (order, nulls) {
(Ok(order), Ok(nulls)) => {
sort(values, order.unwrap_or(false), nulls.unwrap_or(false)).and_then(list)
}
(Err(error), _) | (_, Err(error)) => Err(error),
}
}
("list_reverse_sort", [Value::List { values, .. }, spelled @ ..]) => {
match spelled.first().map(spelled_nulls).transpose() {
Ok(nulls) => sort(values, true, nulls.unwrap_or(false)).and_then(list),
Err(error) => Err(error),
}
}
("list_reverse", [Value::List { values, .. }]) => {
list(values.iter().rev().cloned().collect())
}
("flatten", [Value::List { values, .. }]) => {
let mut flat = Vec::new();
for inner in values {
if let Value::List { values: held, .. } = inner {
flat.extend(held.iter().cloned());
}
}
list(flat)
}
_ => return None,
})
}
fn listed(values: Vec<Value>, returns: &LogicalType) -> Result<Value> {
let LogicalType::List(element) = returns else {
return Err(Error::internal(format!("a list function returning {returns}")));
};
Ok(Value::List { element: (**element).clone(), values })
}
fn same(left: &Value, right: &Value) -> Result<bool> {
Ok(match (left.is_null(), right.is_null()) {
(true, true) => true,
(true, false) | (false, true) => false,
(false, false) => order(left, right)? == Ordering::Equal,
})
}
fn found(values: &[Value], needle: &Value) -> Result<Option<usize>> {
for (at, value) in values.iter().enumerate() {
if same(value, needle)? {
return Ok(Some(at));
}
}
Ok(None)
}
fn position(values: &[Value], needle: &Value) -> Result<Value> {
Ok(match found(values, needle)? {
Some(at) => Value::Integer(i32::try_from(at + 1).map_err(|_| {
Error::out_of_range(format!("a list position of {} does not fit in INTEGER", at + 1))
})?),
None => Value::Null,
})
}
fn sorted(values: &[Value]) -> Result<Vec<&Value>> {
let mut held: Vec<&Value> = values.iter().filter(|value| !value.is_null()).collect();
let mut failed = None;
held.sort_by(|left, right| {
order(left, right).unwrap_or_else(|error| {
failed.get_or_insert(error);
Ordering::Equal
})
});
match failed {
Some(error) => Err(error),
None => Ok(held),
}
}
fn contains(haystack: &[&Value], needle: &Value) -> Result<bool> {
let mut failed = None;
let hit = haystack
.binary_search_by(|probe| {
order(probe, needle).unwrap_or_else(|error| {
failed.get_or_insert(error);
Ordering::Equal
})
})
.is_ok();
match failed {
Some(error) => Err(error),
None => Ok(hit),
}
}
fn has_any(values: &[Value], wanted: &[Value]) -> Result<bool> {
let haystack = sorted(values)?;
for value in wanted.iter().filter(|value| !value.is_null()) {
if contains(&haystack, value)? {
return Ok(true);
}
}
Ok(false)
}
fn has_any_missing(values: &[Value], wanted: &[Value]) -> Result<bool> {
let haystack = sorted(values)?;
for value in wanted.iter().filter(|value| !value.is_null()) {
if !contains(&haystack, value)? {
return Ok(true);
}
}
Ok(false)
}
fn distinct(values: &[Value]) -> Result<Vec<Value>> {
let mut at: Vec<usize> = (0..values.len()).filter(|&at| !values[at].is_null()).collect();
let mut failed = None;
at.sort_by(|&left, &right| match order(&values[left], &values[right]) {
Ok(Ordering::Equal) => left.cmp(&right),
Ok(ordering) => ordering,
Err(error) => {
failed.get_or_insert(error);
Ordering::Equal
}
});
if let Some(error) = failed {
return Err(error);
}
let mut kept = Vec::with_capacity(at.len());
for (index, &here) in at.iter().enumerate() {
if index == 0 || order(&values[at[index - 1]], &values[here])? != Ordering::Equal {
kept.push(here);
}
}
kept.sort_unstable();
Ok(kept.into_iter().map(|at| values[at].clone()).collect())
}
fn intersect(values: &[Value], other: &[Value]) -> Result<Vec<Value>> {
let haystack = sorted(other)?;
let mut kept = Vec::new();
for value in distinct(values)? {
if contains(&haystack, &value)? {
kept.push(value);
}
}
Ok(kept)
}
fn masked(values: &[Value], mask: &[Value]) -> Result<Vec<Value>> {
let mut kept = Vec::new();
for (at, flag) in mask.iter().enumerate() {
match flag {
Value::Boolean(true) => kept.push(values.get(at).cloned().unwrap_or(Value::Null)),
Value::Boolean(false) => {}
Value::Null => return Err(Error::invalid_input(NULL_PICK)),
other => {
return Err(Error::internal(format!(
"list_where with a {} mask",
other.logical_type()
)));
}
}
}
Ok(kept)
}
fn selected(values: &[Value], indexes: &[Value]) -> Result<Vec<Value>> {
let mut kept = Vec::with_capacity(indexes.len());
for index in indexes {
if index.is_null() {
return Err(Error::invalid_input(NULL_PICK));
}
let picked = index
.as_i64()
.and_then(|index| usize::try_from(index).ok())
.and_then(|index| index.checked_sub(1))
.and_then(|at| values.get(at));
kept.push(picked.cloned().unwrap_or(Value::Null));
}
Ok(kept)
}
fn resize(values: &[Value], size: &Value, filler: &Value, returns: &LogicalType) -> Result<Value> {
let size = match size {
Value::Null => 0,
Value::UBigInt(size) => usize::try_from(*size).map_err(|_| {
Error::out_of_range(format!("a list of {size} elements is too long to build"))
})?,
other => {
return Err(Error::internal(format!("list_resize to a {}", other.logical_type())));
}
};
let element = match returns {
LogicalType::List(element) => element,
_ => &LogicalType::Null,
};
let width = element.physical().size().max(1);
if (size as u128) * (width as u128) > MAX_VECTOR_BYTES {
return Err(Error::out_of_range(format!(
"Cannot resize vector to {size} rows: maximum allowed vector size is 128.0 GiB"
)));
}
let mut kept: Vec<Value> = values.iter().take(size).cloned().collect();
kept.resize(size, filler.clone());
listed(kept, returns)
}
const MAX_VECTOR_BYTES: u128 = 1 << 37;
fn spelled_order(spelled: &Value) -> Result<bool> {
let spelled = spelled.to_string().to_uppercase();
match spelled.as_str() {
"ASC" | "ASCENDING" | "DEFAULT" | "ORDER_DEFAULT" => Ok(false),
"DESC" | "DESCENDING" => Ok(true),
_ => Err(unrecognized(&spelled, "OrderType")),
}
}
fn spelled_nulls(spelled: &Value) -> Result<bool> {
let spelled = spelled.to_string().to_uppercase();
match spelled.as_str() {
"NULLS FIRST" | "NULLS_FIRST" => Ok(true),
"NULLS LAST" | "NULLS_LAST" | "DEFAULT" | "ORDER_DEFAULT" => Ok(false),
_ => Err(unrecognized(&spelled, "OrderByNullType")),
}
}
fn unrecognized(spelled: &str, kind: &str) -> Error {
Error::not_implemented(format!(
"Enum value: unrecognized value \"{spelled}\" for enum \"{kind}\""
))
}
fn sort(values: &[Value], descending: bool, nulls_first: bool) -> Result<Vec<Value>> {
let mut held: Vec<Value> = values.iter().filter(|value| !value.is_null()).cloned().collect();
let nulls = values.len() - held.len();
let mut failed = None;
held.sort_by(|left, right| {
let ordering = order(left, right).unwrap_or_else(|error| {
failed.get_or_insert(error);
Ordering::Equal
});
if descending { ordering.reverse() } else { ordering }
});
if let Some(error) = failed {
return Err(error);
}
let mut sorted = Vec::with_capacity(values.len());
if nulls_first {
sorted.resize(nulls, Value::Null);
}
sorted.append(&mut held);
if !nulls_first {
sorted.resize(values.len(), Value::Null);
}
Ok(sorted)
}