use std::marker::PhantomData;
use crate::expr::{Column, ColumnKey, Keyed, Labeled, SqlType};
use crate::scope::{Here, There};
pub struct RowNil;
pub struct RowCons<K, V, Tail> {
value: V,
tail: Tail,
_key: PhantomData<fn() -> K>,
}
impl<K, V, Tail> RowCons<K, V, Tail> {
pub fn value(&self) -> &V {
&self.value
}
pub fn tail(&self) -> &Tail {
&self.tail
}
#[doc(hidden)]
pub fn new(value: V, tail: Tail) -> Self {
RowCons {
value,
tail,
_key: PhantomData,
}
}
#[doc(hidden)]
pub fn into_cell(self) -> (V, Tail) {
(self.value, self.tail)
}
}
mod field {
pub trait Sealed<K, Idx> {}
}
#[diagnostic::on_unimplemented(
message = "`{K}` is not in this query's selection",
label = "a row can only be read by a key the query selected",
note = "add `{K}` to the query's selection list, or `.label(label::..)` the expression you meant — and in a generic helper give each column its own `Idx` parameter, since one shared index matches no row"
)]
pub trait Field<K, Idx>: field::Sealed<K, Idx> {
type Value;
type Rest;
fn peek(&self) -> &Self::Value;
fn pluck(self) -> (Self::Value, Self::Rest);
}
impl<K, V, Tail> field::Sealed<K, Here> for RowCons<K, V, Tail> {}
impl<K, V, Tail> Field<K, Here> for RowCons<K, V, Tail> {
type Value = V;
type Rest = Tail;
fn peek(&self) -> &V {
&self.value
}
fn pluck(self) -> (V, Tail) {
(self.value, self.tail)
}
}
#[diagnostic::do_not_recommend]
impl<K, Other, V, Tail, I> field::Sealed<K, There<I>> for RowCons<Other, V, Tail> where
Tail: Field<K, I>
{
}
impl<K, Other, V, Tail, I> Field<K, There<I>> for RowCons<Other, V, Tail>
where
Tail: Field<K, I>,
{
type Value = <Tail as Field<K, I>>::Value;
type Rest = RowCons<Other, V, <Tail as Field<K, I>>::Rest>;
fn peek(&self) -> &Self::Value {
self.tail.peek()
}
fn pluck(self) -> (Self::Value, Self::Rest) {
let (value, rest) = self.tail.pluck();
(value, RowCons::new(self.value, rest))
}
}
#[doc(hidden)]
pub struct NameChar<const C: char, Rest>(PhantomData<Rest>);
#[doc(hidden)]
pub struct NameEnd;
#[doc(hidden)]
#[macro_export]
macro_rules! type_name {
() => { $crate::row::NameEnd };
($c:literal $(, $rest:literal)*) => {
$crate::row::NameChar<$c, $crate::type_name!($($rest),*)>
};
}
pub trait Named: named::Sealed {
type Name;
const NAME: &'static str;
}
pub(crate) mod named {
pub trait Sealed {}
}
#[doc(hidden)]
pub use named::Sealed as NamedSealed;
pub trait Spelled: Named {}
pub struct Anon;
#[doc(hidden)]
impl NamedSealed for Anon {}
impl Named for Anon {
type Name = NameEnd;
const NAME: &'static str = "?";
}
pub trait FieldValue {
type Value;
}
mod take_named {
pub trait Sealed<F, Idx> {}
}
#[diagnostic::on_unimplemented(
message = "this query's rows have no field matching `{F}`",
label = "the selection needs a column of that name, decoding to that type",
note = "a computed expression is matched by name only once `.label(label::..)` gives it one, and a LEFT/RIGHT/FULL JOIN makes a column decode as `Option<T>`, so a struct filled from one declares `Option<T>`"
)]
pub trait TakeNamed<F, Idx>: take_named::Sealed<F, Idx> {
type Value;
type Rest;
fn take_named(self) -> (Self::Value, Self::Rest);
}
impl<F, K, V, Tail> take_named::Sealed<F, Here> for RowCons<K, V, Tail>
where
K: Spelled,
F: Spelled<Name = <K as Named>::Name> + FieldValue<Value = V>,
{
}
impl<F, K, V, Tail> TakeNamed<F, Here> for RowCons<K, V, Tail>
where
K: Spelled,
F: Spelled<Name = <K as Named>::Name> + FieldValue<Value = V>,
{
type Value = V;
type Rest = Tail;
fn take_named(self) -> (V, Tail) {
(self.value, self.tail)
}
}
#[diagnostic::do_not_recommend]
impl<F, K, V, Tail, I> take_named::Sealed<F, There<I>> for RowCons<K, V, Tail> where
Tail: TakeNamed<F, I>
{
}
impl<F, K, V, Tail, I> TakeNamed<F, There<I>> for RowCons<K, V, Tail>
where
Tail: TakeNamed<F, I>,
{
type Value = <Tail as TakeNamed<F, I>>::Value;
type Rest = RowCons<K, V, <Tail as TakeNamed<F, I>>::Rest>;
fn take_named(self) -> (Self::Value, Self::Rest) {
let (value, rest) = self.tail.take_named();
(value, RowCons::new(self.value, rest))
}
}
mod same_name {
pub trait Sealed<Other> {}
impl<A, B> Sealed<B> for A
where
A: super::Spelled,
B: super::Spelled<Name = <A as super::Named>::Name>,
{
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` can't stand in for `{Other}`",
label = "these two selected items must have the same name",
note = "matched by name: `.label(label::..)` whichever side is spelled wrong — and an unnamed expression (`Anon`) has no name to match with at all"
)]
pub trait SameNameAs<Other>: same_name::Sealed<Other> {}
#[diagnostic::do_not_recommend]
impl<A, B> SameNameAs<B> for A
where
A: Spelled,
B: Spelled<Name = <A as Named>::Name>,
{
}
#[diagnostic::on_unimplemented(
message = "these two selections don't produce the same row",
label = "must select the same names, in the same order, decoding to the same types"
)]
pub trait SameShape<Other> {}
impl SameShape<RowNil> for RowNil {}
impl<K1, K2, V, Tail1, Tail2> SameShape<RowCons<K2, V, Tail2>> for RowCons<K1, V, Tail1>
where
K1: SameNameAs<K2>,
Tail1: SameShape<Tail2>,
{
}
impl<A, B> SameShape<Row<B>> for Row<A> where A: SameShape<B> {}
pub trait RowKey {
type Key;
}
#[diagnostic::do_not_recommend]
impl<C: ColumnKey> RowKey for Column<C> {
type Key = C;
}
#[diagnostic::do_not_recommend]
impl<K, Req, S: SqlType> RowKey for Keyed<K, Req, S> {
type Key = K;
}
#[diagnostic::do_not_recommend]
impl<K, Inner> RowKey for Labeled<K, Inner> {
type Key = K;
}
mod column_names {
pub trait Sealed {}
}
pub trait ColumnNames: column_names::Sealed {
#[doc(hidden)]
fn push_names(out: &mut Vec<&'static str>);
fn names() -> Vec<&'static str> {
let mut out = Vec::new();
Self::push_names(&mut out);
out
}
}
impl column_names::Sealed for RowNil {}
impl ColumnNames for RowNil {
fn push_names(_out: &mut Vec<&'static str>) {}
}
impl<K: Named, V, Tail: ColumnNames> column_names::Sealed for RowCons<K, V, Tail> {}
impl<K: Named, V, Tail: ColumnNames> ColumnNames for RowCons<K, V, Tail> {
fn push_names(out: &mut Vec<&'static str>) {
out.push(<K as Named>::NAME);
Tail::push_names(out);
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` doesn't name a field",
label = "an unlabelled expression has no name to look up",
note = "give it one with `.label(label::..)`, or read it positionally with `into_tuple()`"
)]
pub trait LookupKey: RowKey {}
#[diagnostic::do_not_recommend]
impl<C: ColumnKey> LookupKey for Column<C> {}
#[diagnostic::do_not_recommend]
impl<K: Spelled, Req, S: SqlType> LookupKey for Keyed<K, Req, S> {}
#[diagnostic::do_not_recommend]
impl<K: Spelled, Inner> LookupKey for Labeled<K, Inner> {}
pub struct Row<L>(L);
impl<L> Row<L> {
#[doc(hidden)]
pub fn new(fields: L) -> Self {
Row(fields)
}
pub fn fields(&self) -> &L {
&self.0
}
pub fn get<K: LookupKey, Idx>(&self, _key: K) -> &<L as Field<K::Key, Idx>>::Value
where
L: Field<K::Key, Idx>,
{
self.0.peek()
}
pub fn take<K: LookupKey, Idx>(
self,
_key: K,
) -> (
<L as Field<K::Key, Idx>>::Value,
Row<<L as Field<K::Key, Idx>>::Rest>,
)
where
L: Field<K::Key, Idx>,
{
let (value, rest) = self.0.pluck();
(value, Row::new(rest))
}
#[doc(hidden)]
pub fn peek_key<K, Idx>(&self) -> &<L as Field<K, Idx>>::Value
where
L: Field<K, Idx>,
{
self.0.peek()
}
#[doc(hidden)]
pub fn take_key<K, Idx>(self) -> (<L as Field<K, Idx>>::Value, Row<<L as Field<K, Idx>>::Rest>)
where
L: Field<K, Idx>,
{
let (value, rest) = self.0.pluck();
(value, Row::new(rest))
}
#[doc(hidden)]
pub fn take_named<F, Idx>(
self,
) -> (
<L as TakeNamed<F, Idx>>::Value,
Row<<L as TakeNamed<F, Idx>>::Rest>,
)
where
L: TakeNamed<F, Idx>,
{
let (value, rest) = self.0.take_named();
(value, Row::new(rest))
}
pub fn into_struct<T, Idxs>(self) -> T
where
T: FromRow<L, Idxs>,
{
T::from_row(self)
}
pub fn into_tuple(self) -> L::Values
where
L: RowValues,
{
self.0.into_values()
}
}
pub trait DebugFields {
fn fmt_fields(&self, f: &mut std::fmt::DebugStruct<'_, '_>);
}
impl DebugFields for RowNil {
fn fmt_fields(&self, _f: &mut std::fmt::DebugStruct<'_, '_>) {}
}
impl<K: Named, V: std::fmt::Debug, Tail: DebugFields> DebugFields for RowCons<K, V, Tail> {
fn fmt_fields(&self, f: &mut std::fmt::DebugStruct<'_, '_>) {
f.field(K::NAME, &self.value);
self.tail.fmt_fields(f);
}
}
impl<L: DebugFields> std::fmt::Debug for Row<L> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut s = f.debug_struct("Row");
self.0.fmt_fields(&mut s);
s.finish()
}
}
impl<K, V: Clone, Tail: Clone> Clone for RowCons<K, V, Tail> {
fn clone(&self) -> Self {
RowCons::new(self.value.clone(), self.tail.clone())
}
}
impl Clone for RowNil {
fn clone(&self) -> Self {
RowNil
}
}
impl<L: Clone> Clone for Row<L> {
fn clone(&self) -> Self {
Row(self.0.clone())
}
}
impl<K, V: PartialEq, Tail: PartialEq> PartialEq for RowCons<K, V, Tail> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value && self.tail == other.tail
}
}
impl PartialEq for RowNil {
fn eq(&self, _other: &Self) -> bool {
true
}
}
impl<K, V: Eq, Tail: Eq> Eq for RowCons<K, V, Tail> {}
impl Eq for RowNil {}
impl<L: PartialEq> PartialEq for Row<L> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<L: Eq> Eq for Row<L> {}
pub trait RowValues {
type Values;
fn into_values(self) -> Self::Values;
}
#[diagnostic::on_unimplemented(
message = "this row has no positional view",
label = "`into_tuple`/`into_tuples` stop at 16 fields, however they were selected",
note = "read it by key (`row.get(..)`) or fill a struct with `#[derive(FromRow)]`"
)]
pub trait Prepend<H> {
type Output;
fn prepend(self, head: H) -> Self::Output;
}
impl<H> Prepend<H> for () {
type Output = (H,);
fn prepend(self, head: H) -> (H,) {
(head,)
}
}
macro_rules! prepend_impls {
() => {};
($first:ident $(, $rest:ident)*) => {
#[allow(non_snake_case)]
impl<H, $first $(, $rest)*> Prepend<H> for ($first, $($rest,)*) {
type Output = (H, $first, $($rest,)*);
fn prepend(self, head: H) -> Self::Output {
let ($first, $($rest,)*) = self;
(head, $first, $($rest,)*)
}
}
prepend_impls!($($rest),*);
};
}
prepend_impls!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15
);
impl RowValues for RowNil {
type Values = ();
fn into_values(self) {}
}
impl<K, V, Tail> RowValues for RowCons<K, V, Tail>
where
Tail: RowValues,
Tail::Values: Prepend<V>,
{
type Values = <Tail::Values as Prepend<V>>::Output;
fn into_values(self) -> Self::Values {
self.tail.into_values().prepend(self.value)
}
}
pub trait IntoTuples {
type Tuples;
fn into_tuples(self) -> Self::Tuples;
}
impl<L: RowValues> IntoTuples for Vec<Row<L>> {
type Tuples = Vec<L::Values>;
fn into_tuples(self) -> Vec<L::Values> {
self.into_iter().map(Row::into_tuple).collect()
}
}
pub trait FromRow<L, Idxs>: Sized {
fn from_row(row: Row<L>) -> Self;
}
pub trait IntoStructs {
type Fields;
fn into_structs<T, Idxs>(self) -> Vec<T>
where
T: FromRow<Self::Fields, Idxs>;
}
impl<L> IntoStructs for Vec<Row<L>> {
type Fields = L;
fn into_structs<T, Idxs>(self) -> Vec<T>
where
T: FromRow<L, Idxs>,
{
self.into_iter().map(Row::into_struct).collect()
}
}
macro_rules! expr_key {
($key:ident, $accessor:ident, $method:ident, $doc:literal, $($ch:literal),+) => {
#[doc = $doc]
#[derive(Clone, Copy)]
pub struct $key;
#[doc(hidden)]
impl $crate::row::NamedSealed for $key {}
#[doc(hidden)]
impl $crate::row::Named for $key {
type Name = $crate::type_name!($($ch),+);
const NAME: &'static str = concat!($($ch),+);
}
#[doc(hidden)]
impl $crate::row::Spelled for $key {}
#[doc = $doc]
pub trait $accessor<Idx> {
type Value;
fn $method(&self) -> &Self::Value;
}
impl<L, Idx> $accessor<Idx> for $crate::row::Row<L>
where
L: $crate::row::Field<$key, Idx>,
{
type Value = <L as $crate::row::Field<$key, Idx>>::Value;
fn $method(&self) -> &Self::Value {
self.peek_key::<$key, Idx>()
}
}
};
}
pub(crate) use expr_key;