rust_query/
value.rs

1pub mod aggregate;
2mod operations;
3pub mod optional;
4pub mod trivial;
5
6use std::{cell::OnceCell, fmt::Debug, marker::PhantomData, ops::Deref, rc::Rc};
7
8use sea_query::{Alias, JoinType, Nullable, SelectStatement};
9
10use crate::{
11    IntoSelect, Lazy, Select, Table, Transaction,
12    alias::{Field, MyAlias, Scope},
13    ast::{MySelect, Source},
14    db::{Join, TableRow, TableRowInner},
15    mutable::Mutable,
16    mymap::MyMap,
17    private::Joinable,
18    schema::canonical,
19};
20
21#[derive(Default)]
22pub struct ValueBuilder {
23    pub(crate) from: Rc<MySelect>,
24    // only used for tables
25    pub(super) scope: Scope,
26    // implicit joins
27    pub(super) extra: MyMap<Source, MyAlias>,
28    // calculating these results
29    pub(super) forwarded: MyMap<MyTableRef, (&'static str, DynTypedExpr, MyAlias)>,
30}
31
32impl ValueBuilder {
33    pub(crate) fn get_aggr(
34        &mut self,
35        aggr: Rc<SelectStatement>,
36        conds: Vec<sea_query::Expr>,
37    ) -> MyAlias {
38        let source = Source {
39            kind: crate::ast::SourceKind::Aggregate(aggr),
40            conds: conds
41                .into_iter()
42                .enumerate()
43                .map(|(idx, expr)| (Field::U64(MyAlias::new(idx)), expr))
44                .collect(),
45        };
46        let new_alias = || self.scope.new_alias();
47        *self.extra.get_or_init(source, new_alias)
48    }
49
50    pub(crate) fn get_join<T: Table>(
51        &mut self,
52        expr: sea_query::Expr,
53        possible_null: bool,
54    ) -> MyAlias {
55        let join_type = if possible_null {
56            JoinType::LeftJoin
57        } else {
58            JoinType::Join
59        };
60        let source = Source {
61            kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned(), join_type),
62            conds: vec![(Field::Str(T::ID), expr)],
63        };
64        let new_alias = || self.scope.new_alias();
65
66        // TODO: possible optimization to unify the join_type?
67        // e.g. join + left join = join
68        *self.extra.get_or_init(source, new_alias)
69    }
70
71    pub fn get_unique<T: Table>(
72        &mut self,
73        conds: Box<[(&'static str, sea_query::Expr)]>,
74    ) -> sea_query::Expr {
75        let source = Source {
76            kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned(), JoinType::LeftJoin),
77            conds: conds.into_iter().map(|x| (Field::Str(x.0), x.1)).collect(),
78        };
79
80        let new_alias = || self.scope.new_alias();
81        let table = self.extra.get_or_init(source, new_alias);
82        sea_query::Expr::col((*table, Alias::new(T::ID))).into()
83    }
84
85    pub fn get_table<T: Table>(&mut self, table: MyTableRef) -> MyAlias {
86        if Rc::ptr_eq(&self.from.scope_rc, &table.scope_rc) {
87            MyAlias::new(table.idx)
88        } else {
89            let join = Join::<T>::new(table.clone());
90            self.forwarded
91                .get_or_init(table, || {
92                    (
93                        T::NAME,
94                        DynTypedExpr::new(move |b| join.build_expr(b)),
95                        self.scope.new_alias(),
96                    )
97                })
98                .2
99        }
100    }
101}
102
103#[derive(Clone)]
104pub struct MyTableRef {
105    pub(crate) scope_rc: Rc<()>,
106    pub(crate) idx: usize,
107}
108
109impl PartialEq for MyTableRef {
110    fn eq(&self, other: &Self) -> bool {
111        Rc::ptr_eq(&self.scope_rc, &other.scope_rc) && self.idx == other.idx
112    }
113}
114
115pub trait NumTyp: OrdTyp + Clone + Copy {
116    const ZERO: Self;
117    fn into_sea_value(self) -> sea_query::Value;
118}
119
120impl NumTyp for i64 {
121    const ZERO: Self = 0;
122    fn into_sea_value(self) -> sea_query::Value {
123        sea_query::Value::BigInt(Some(self))
124    }
125}
126impl NumTyp for f64 {
127    const ZERO: Self = 0.;
128    fn into_sea_value(self) -> sea_query::Value {
129        sea_query::Value::Double(Some(self))
130    }
131}
132
133pub trait OrdTyp: EqTyp {}
134impl OrdTyp for String {}
135impl OrdTyp for Vec<u8> {}
136impl OrdTyp for i64 {}
137impl OrdTyp for f64 {}
138impl OrdTyp for bool {}
139
140pub trait BuffTyp: MyTyp {}
141impl BuffTyp for String {}
142impl BuffTyp for Vec<u8> {}
143
144#[diagnostic::on_unimplemented(
145    message = "Columns with type `{Self}` can not be checked for equality",
146    note = "`EqTyp` is also implemented for all table types"
147)]
148pub trait EqTyp: MyTyp {}
149
150impl EqTyp for String {}
151impl EqTyp for Vec<u8> {}
152impl EqTyp for i64 {}
153impl EqTyp for f64 {}
154impl EqTyp for bool {}
155#[diagnostic::do_not_recommend]
156impl<T: Table> EqTyp for T {}
157
158/// Typ does not depend on scope, so it gets its own trait
159pub trait Typed {
160    type Typ;
161
162    fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr;
163    fn maybe_optional(&self) -> bool {
164        true
165    }
166
167    fn build_table(&self, b: &mut ValueBuilder) -> MyAlias
168    where
169        Self::Typ: Table,
170    {
171        let expr = self.build_expr(b);
172        b.get_join::<Self::Typ>(expr, self.maybe_optional())
173    }
174}
175
176/// Trait for all values that can be used as expressions in queries.
177///
178/// There is a hierarchy of types that can be used to build queries.
179/// - [TableRow], [i64], [f64], [bool], `&[u8]`, `&str`:
180///   These are the base types for building expressions. They all
181///   implement [IntoExpr] and are [Copy]. Note that [TableRow] is special
182///   because it refers to a table row that is guaranteed to exist.
183/// - [Expr] is the type that all [IntoExpr] values can be converted into.
184///   It has a lot of methods to combine expressions into more complicated expressions.
185///   Next to those, it implements [std::ops::Deref], if the expression is a table expression.
186///   This can be used to get access to the columns of the table, which can themselves be table expressions.
187///   Note that combinators like [crate::optional] and [crate::aggregate] also have [Expr] as return type.
188///
189/// Note that while [Expr] implements [IntoExpr], you may want to use `&Expr` instead.
190/// Using a reference lets you reuse [Expr] without calling [Clone] explicitly.
191pub trait IntoExpr<'column, S> {
192    /// The type of the expression.
193    type Typ: MyTyp;
194
195    /// Turn this value into an [Expr].
196    fn into_expr(self) -> Expr<'column, S, Self::Typ>;
197}
198
199impl<X: MyTyp<Sql: Nullable>> Typed for Option<Rc<dyn Typed<Typ = X>>> {
200    type Typ = Option<X>;
201
202    fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
203        self.as_ref()
204            .map(|x| x.build_expr(b))
205            .unwrap_or(X::Sql::null().into())
206    }
207}
208
209impl<'column, S, T: IntoExpr<'column, S, Typ = X>, X: MyTyp<Sql: Nullable>> IntoExpr<'column, S>
210    for Option<T>
211{
212    type Typ = Option<X>;
213    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
214        Expr::new(self.map(|x| x.into_expr().inner))
215    }
216}
217
218impl Typed for String {
219    type Typ = String;
220    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
221        sea_query::Expr::from(self)
222    }
223}
224
225impl<'column, S> IntoExpr<'column, S> for String {
226    type Typ = String;
227    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
228        Expr::new(self)
229    }
230}
231
232impl<'column, S> IntoExpr<'column, S> for &str {
233    type Typ = String;
234    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
235        Expr::new(self.to_owned())
236    }
237}
238
239impl Typed for Vec<u8> {
240    type Typ = Vec<u8>;
241    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
242        sea_query::Expr::from(self.to_owned())
243    }
244}
245
246impl<'column, S> IntoExpr<'column, S> for Vec<u8> {
247    type Typ = Vec<u8>;
248    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
249        Expr::new(self)
250    }
251}
252
253impl<'column, S> IntoExpr<'column, S> for &[u8] {
254    type Typ = Vec<u8>;
255    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
256        Expr::new(self.to_owned())
257    }
258}
259
260impl Typed for bool {
261    type Typ = bool;
262    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
263        sea_query::Expr::from(*self)
264    }
265}
266
267impl<'column, S> IntoExpr<'column, S> for bool {
268    type Typ = bool;
269    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
270        Expr::new(self)
271    }
272}
273
274impl Typed for i64 {
275    type Typ = i64;
276    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
277        sea_query::Expr::from(*self)
278    }
279}
280
281impl<'column, S> IntoExpr<'column, S> for i64 {
282    type Typ = i64;
283    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
284        Expr::new(self)
285    }
286}
287
288impl Typed for f64 {
289    type Typ = f64;
290    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
291        sea_query::Expr::from(*self)
292    }
293}
294
295impl<'column, S> IntoExpr<'column, S> for f64 {
296    type Typ = f64;
297    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
298        Expr::new(self)
299    }
300}
301
302impl<'column, S, T> IntoExpr<'column, S> for &T
303where
304    T: IntoExpr<'column, S> + Clone,
305{
306    type Typ = T::Typ;
307    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
308        T::into_expr(self.clone())
309    }
310}
311
312/// Use this a value in a query to get the current datetime as a number of seconds.
313#[derive(Clone, Copy)]
314#[deprecated = "Use `Expr::unix_epoch` instead"]
315pub struct UnixEpoch;
316
317#[expect(deprecated)]
318impl Typed for UnixEpoch {
319    type Typ = i64;
320    fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
321        sea_query::Expr::cust("unixepoch('now')").into()
322    }
323}
324
325#[expect(deprecated)]
326impl<'column, S> IntoExpr<'column, S> for UnixEpoch {
327    type Typ = i64;
328    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
329        Expr::new(self)
330    }
331}
332
333pub trait OptTable: MyTyp {
334    type Schema;
335    type Select;
336    type Mutable<'t>;
337    fn select_opt_mutable(
338        val: Expr<'_, Self::Schema, Self>,
339    ) -> Select<'_, Self::Schema, Self::Select>;
340
341    fn into_mutable<'t>(val: Self::Select) -> Self::Mutable<'t>;
342}
343
344impl<T: Table> OptTable for T {
345    type Schema = T::Schema;
346    type Select = (T::Mutable, TableRow<T>);
347    type Mutable<'t> = Mutable<'t, T>;
348    fn select_opt_mutable(
349        val: Expr<'_, Self::Schema, Self>,
350    ) -> Select<'_, Self::Schema, Self::Select> {
351        (T::select_mutable(val.clone()), val).into_select()
352    }
353
354    fn into_mutable<'t>((inner, row_id): Self::Select) -> Self::Mutable<'t> {
355        Mutable::new(inner, row_id)
356    }
357}
358
359impl<T: Table> OptTable for Option<T> {
360    type Schema = T::Schema;
361    type Select = Option<(T::Mutable, TableRow<T>)>;
362    type Mutable<'t> = Option<Mutable<'t, T>>;
363    fn select_opt_mutable(
364        val: Expr<'_, Self::Schema, Self>,
365    ) -> Select<'_, Self::Schema, Self::Select> {
366        crate::optional(|row| {
367            let val = row.and(val);
368            row.then_select((T::select_mutable(val.clone()), val))
369        })
370    }
371
372    fn into_mutable<'t>(val: Self::Select) -> Self::Mutable<'t> {
373        val.map(T::into_mutable)
374    }
375}
376
377pub trait MyTyp: Sized + 'static {
378    type Prev: MyTyp;
379    const NULLABLE: bool = false;
380    const TYP: canonical::ColumnType;
381    const FK: Option<(&'static str, &'static str)> = None;
382    type Out: SecretFromSql;
383    type Lazy<'t>;
384    type Ext<'t>;
385    type Sql;
386    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t>;
387}
388
389pub(crate) trait SecretFromSql: Sized {
390    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self>;
391}
392
393#[diagnostic::do_not_recommend]
394impl<T: Table> MyTyp for T {
395    type Prev = T::MigrateFrom;
396    const TYP: canonical::ColumnType = canonical::ColumnType::Integer;
397    const FK: Option<(&'static str, &'static str)> = Some((T::NAME, T::ID));
398    type Out = TableRow<T>;
399    type Lazy<'t> = Lazy<'t, T>;
400    type Ext<'t> = T::Ext2<'t>;
401    type Sql = i64;
402    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
403        Lazy {
404            id: val,
405            lazy: OnceCell::new(),
406            txn: Transaction::new_ref(),
407        }
408    }
409}
410
411impl<T: Table> SecretFromSql for TableRow<T> {
412    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
413        Ok(TableRow {
414            _local: PhantomData,
415            inner: TableRowInner {
416                _p: PhantomData,
417                idx: value.as_i64()?,
418            },
419        })
420    }
421}
422
423impl MyTyp for i64 {
424    type Prev = Self;
425    const TYP: canonical::ColumnType = canonical::ColumnType::Integer;
426    type Out = Self;
427    type Lazy<'t> = Self;
428    type Ext<'t> = ();
429    type Sql = i64;
430    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
431        val
432    }
433}
434
435impl SecretFromSql for i64 {
436    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
437        value.as_i64()
438    }
439}
440
441impl MyTyp for f64 {
442    type Prev = Self;
443    const TYP: canonical::ColumnType = canonical::ColumnType::Real;
444    type Out = Self;
445    type Lazy<'t> = Self;
446    type Ext<'t> = ();
447    type Sql = f64;
448    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
449        val
450    }
451}
452
453impl SecretFromSql for f64 {
454    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
455        value.as_f64()
456    }
457}
458
459impl MyTyp for bool {
460    type Prev = Self;
461    const TYP: canonical::ColumnType = canonical::ColumnType::Integer;
462    type Out = Self;
463    type Lazy<'t> = Self;
464    type Ext<'t> = ();
465    type Sql = bool;
466    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
467        val
468    }
469}
470
471impl SecretFromSql for bool {
472    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
473        Ok(value.as_i64()? != 0)
474    }
475}
476
477impl MyTyp for String {
478    type Prev = Self;
479    const TYP: canonical::ColumnType = canonical::ColumnType::Text;
480    type Out = Self;
481    type Lazy<'t> = Self;
482    type Ext<'t> = ();
483    type Sql = String;
484    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
485        val
486    }
487}
488assert_impl_all!(String: Nullable);
489
490impl SecretFromSql for String {
491    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
492        Ok(value.as_str()?.to_owned())
493    }
494}
495
496impl MyTyp for Vec<u8> {
497    type Prev = Self;
498    const TYP: canonical::ColumnType = canonical::ColumnType::Blob;
499    type Out = Self;
500    type Lazy<'t> = Self;
501    type Ext<'t> = ();
502    type Sql = Vec<u8>;
503    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
504        val
505    }
506}
507assert_impl_all!(Vec<u8>: Nullable);
508
509impl SecretFromSql for Vec<u8> {
510    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
511        Ok(value.as_blob()?.to_owned())
512    }
513}
514
515impl<T: MyTyp> MyTyp for Option<T> {
516    type Prev = Option<T::Prev>;
517    const TYP: canonical::ColumnType = T::TYP;
518    const NULLABLE: bool = true;
519    const FK: Option<(&'static str, &'static str)> = T::FK;
520    type Out = Option<T::Out>;
521    type Lazy<'t> = Option<T::Lazy<'t>>;
522    type Ext<'t> = ();
523    type Sql = T::Sql;
524    fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
525        val.map(T::out_to_lazy)
526    }
527}
528
529impl<T: SecretFromSql> SecretFromSql for Option<T> {
530    fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
531        if value.data_type() == rusqlite::types::Type::Null {
532            Ok(None)
533        } else {
534            Ok(Some(T::from_sql(value)?))
535        }
536    }
537}
538
539/// This is an expression that can be used in queries.
540///
541/// - The lifetime parameter `'column` specifies which columns need to be in scope.
542/// - The type parameter `S` specifies the expected schema of the query.
543/// - And finally the type paramter `T` specifies the type of the expression.
544///
545/// [Expr] implements [Deref] to have column fields in case the expression has a table type.
546pub struct Expr<'column, S, T: MyTyp> {
547    pub(crate) _local: PhantomData<*const ()>,
548    pub(crate) inner: Rc<dyn Typed<Typ = T>>,
549    pub(crate) _p: PhantomData<&'column ()>,
550    pub(crate) _p2: PhantomData<S>,
551    pub(crate) ext: OnceCell<Box<T::Ext<'static>>>,
552}
553
554impl<S, T: MyTyp> Debug for Expr<'_, S, T> {
555    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
556        write!(f, "Expr of type {}", std::any::type_name::<T>())
557    }
558}
559
560impl<'column, S, T: MyTyp> Expr<'column, S, T> {
561    /// Extremely easy to use API. Should only be used by the macro to implement migrations.
562    #[doc(hidden)]
563    pub fn _migrate<OldS>(prev: impl IntoExpr<'column, OldS>) -> Self {
564        Self::new(MigratedExpr {
565            prev: DynTypedExpr::erase(prev),
566            _p: PhantomData,
567        })
568    }
569}
570
571pub fn adhoc_expr<S, T: MyTyp>(
572    f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr,
573) -> Expr<'static, S, T> {
574    Expr::adhoc(f)
575}
576
577pub fn new_column<'x, S, C: MyTyp, T: Table>(
578    table: impl IntoExpr<'x, S, Typ = T>,
579    name: &'static str,
580) -> Expr<'x, S, C> {
581    let table = table.into_expr().inner;
582    let possible_null = table.maybe_optional();
583    Expr::adhoc_promise(
584        move |b| sea_query::Expr::col((table.build_table(b), Field::Str(name))).into(),
585        possible_null,
586    )
587}
588
589pub fn unique_from_joinable<'inner, T: Table>(
590    j: impl Joinable<'inner, Typ = T>,
591) -> Expr<'inner, T::Schema, Option<T>> {
592    let list = j.conds();
593    ::rust_query::private::adhoc_expr(move |_b| {
594        let list = list
595            .iter()
596            .map(|(name, col)| (*name, (col.func)(_b)))
597            .collect();
598        _b.get_unique::<T>(list)
599    })
600}
601
602struct AdHoc<F, T> {
603    func: F,
604    maybe_optional: bool,
605    _p: PhantomData<T>,
606}
607impl<F: Fn(&mut ValueBuilder) -> sea_query::Expr, T> Typed for AdHoc<F, T> {
608    type Typ = T;
609
610    fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
611        (self.func)(b)
612    }
613    fn maybe_optional(&self) -> bool {
614        self.maybe_optional
615    }
616}
617
618impl<S, T: MyTyp> Expr<'_, S, T> {
619    pub(crate) fn adhoc(f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr) -> Self {
620        Self::new(AdHoc {
621            func: f,
622            maybe_optional: true,
623            _p: PhantomData,
624        })
625    }
626
627    /// Only set `maybe_optional` to `false` if you are absolutely sure that the
628    /// value is not null. The [crate::optional] combinator makes this more difficult.
629    /// There is no reason to use this for values that can not be foreign keys.
630    /// This is used to optimize implicit joins from LEFT JOIN to just JOIN.
631    pub(crate) fn adhoc_promise(
632        f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr,
633        maybe_optional: bool,
634    ) -> Self {
635        Self::new(AdHoc {
636            func: f,
637            maybe_optional,
638            _p: PhantomData,
639        })
640    }
641
642    pub(crate) fn new(val: impl Typed<Typ = T> + 'static) -> Self {
643        Self {
644            _local: PhantomData,
645            inner: Rc::new(val),
646            _p: PhantomData,
647            _p2: PhantomData,
648            ext: OnceCell::new(),
649        }
650    }
651}
652
653impl<S, T: MyTyp> Clone for Expr<'_, S, T> {
654    fn clone(&self) -> Self {
655        Self {
656            _local: PhantomData,
657            inner: self.inner.clone(),
658            _p: self._p,
659            _p2: self._p2,
660            ext: OnceCell::new(),
661        }
662    }
663}
664
665#[derive(Clone)]
666pub struct DynTypedExpr {
667    pub func: Rc<dyn Fn(&mut ValueBuilder) -> sea_query::Expr>,
668}
669
670impl DynTypedExpr {
671    pub fn new(f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr) -> Self {
672        Self { func: Rc::new(f) }
673    }
674    pub fn erase<'x, S>(expr: impl IntoExpr<'x, S>) -> Self {
675        let typed = expr.into_expr().inner;
676        Self::new(move |b| typed.build_expr(b))
677    }
678}
679
680pub struct MigratedExpr<Typ> {
681    prev: DynTypedExpr,
682    _p: PhantomData<Typ>,
683}
684
685impl<Typ> Typed for MigratedExpr<Typ> {
686    type Typ = Typ;
687    fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
688        (self.prev.func)(b)
689    }
690}
691
692impl<'column, S, T: MyTyp> IntoExpr<'column, S> for Expr<'column, S, T> {
693    type Typ = T;
694    fn into_expr(self) -> Expr<'column, S, Self::Typ> {
695        self
696    }
697}
698
699impl<'t, T: Table> Deref for Expr<'t, T::Schema, T> {
700    type Target = T::Ext2<'t>;
701
702    fn deref(&self) -> &Self::Target {
703        T::covariant_ext(self.ext.get_or_init(|| {
704            let expr = Expr {
705                _local: PhantomData,
706                inner: self.inner.clone(),
707                _p: PhantomData::<&'static ()>,
708                _p2: PhantomData,
709                ext: OnceCell::new(),
710            };
711            Box::new(T::build_ext2(&expr))
712        }))
713    }
714}