Skip to main content

TableSource

Trait TableSource 

Source
pub trait TableSource:
    DataSource
    + Clone
    + 'static {
    type Column<Type>: ColumnLike<Type> + Clone
       where Type: ColumnType;
    type AnyType: ColumnType;
    type Value: Clone + Send + Sync + 'static;
    type Id: Send + Sync + Clone + Hash + Eq + 'static;
    type Source: TableSourceSpec;
    type Condition: Clone + Send + Sync + 'static;

Show 26 methods // Required methods fn create_column<Type: ColumnType>(&self, name: &str) -> Self::Column<Type>; fn to_any_column<Type: ColumnType>( &self, column: Self::Column<Type>, ) -> Self::Column<Self::AnyType>; fn convert_any_column<Type: ColumnType>( &self, any_column: Self::Column<Self::AnyType>, ) -> Option<Self::Column<Type>>; fn expr( &self, template: impl Into<String>, parameters: Vec<ExpressiveEnum<Self::Value>>, ) -> Expression<Self::Value>; fn search_table_condition<E>( &self, table: &Table<Self, E>, search_value: &str, ) -> Self::Condition where E: Entity<Self::Value>, Self: Sized; fn list_table_values<'life0, 'life1, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, ) -> Pin<Box<dyn Future<Output = Result<IndexMap<Self::Id, Record<Self::Value>>>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn get_table_value<'life0, 'life1, 'life2, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, id: &'life2 Self::Id, ) -> Pin<Box<dyn Future<Output = Result<Option<Record<Self::Value>>>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn get_table_some_value<'life0, 'life1, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, ) -> Pin<Box<dyn Future<Output = Result<Option<(Self::Id, Record<Self::Value>)>>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn get_table_count<'life0, 'life1, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, ) -> Pin<Box<dyn Future<Output = Result<i64>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn get_table_sum<'life0, 'life1, 'life2, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, column: &'life2 Self::Column<Self::AnyType>, ) -> Pin<Box<dyn Future<Output = Result<Self::Value>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn get_table_max<'life0, 'life1, 'life2, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, column: &'life2 Self::Column<Self::AnyType>, ) -> Pin<Box<dyn Future<Output = Result<Self::Value>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn get_table_min<'life0, 'life1, 'life2, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, column: &'life2 Self::Column<Self::AnyType>, ) -> Pin<Box<dyn Future<Output = Result<Self::Value>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn insert_table_value<'life0, 'life1, 'life2, 'life3, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, id: &'life2 Self::Id, record: &'life3 Record<Self::Value>, ) -> Pin<Box<dyn Future<Output = Result<Record<Self::Value>>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait; fn replace_table_value<'life0, 'life1, 'life2, 'life3, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, id: &'life2 Self::Id, record: &'life3 Record<Self::Value>, ) -> Pin<Box<dyn Future<Output = Result<Record<Self::Value>>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait; fn patch_table_value<'life0, 'life1, 'life2, 'life3, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, id: &'life2 Self::Id, partial: &'life3 Record<Self::Value>, ) -> Pin<Box<dyn Future<Output = Result<Record<Self::Value>>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait; fn delete_table_value<'life0, 'life1, 'life2, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, id: &'life2 Self::Id, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn delete_table_all_values<'life0, 'life1, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn insert_table_return_id_value<'life0, 'life1, 'life2, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, record: &'life2 Record<Self::Value>, ) -> Pin<Box<dyn Future<Output = Result<Self::Id>> + Send + 'async_trait>> where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait; fn related_in_condition<SourceE: Entity<Self::Value> + 'static>( &self, target_field: &str, source_table: &Table<Self, SourceE>, source_column: &str, ) -> Self::Condition where Self: Sized; fn column_table_values_expr<'a, E, Type: ColumnType>( &'a self, table: &Table<Self, E>, column: &Self::Column<Type>, ) -> AssociatedExpression<'a, Self, Self::Value, Vec<Type>> where E: Entity<Self::Value> + 'static, Self: ExprDataSource<Self::Value> + Sized; // Provided methods fn eq_condition(field: &str, value: &str) -> Result<Self::Condition> { ... } fn eq_value_condition( &self, field: &str, value: Self::Value, ) -> Result<Self::Condition> { ... } fn stream_table_values<'a, E>( &'a self, table: &Table<Self, E>, ) -> Pin<Box<dyn Stream<Item = Result<(Self::Id, Record<Self::Value>)>> + Send + 'a>> where E: Entity<Self::Value> + 'a, Self: Sized { ... } fn related_correlated_condition( &self, target_table: &str, target_field: &str, source_table: &str, source_column: &str, ) -> Self::Condition { ... } fn supports_traversal(&self) -> bool { ... } fn traversal_path_expr( &self, hops: &[&str], column: &str, ) -> Option<Expression<Self::Value>> { ... }
}
Expand description

Trait for table data sources that defines column type separate from execution TableSource represents a data source that can create and manage tables

Required Associated Types§

Source

type Column<Type>: ColumnLike<Type> + Clone where Type: ColumnType

Source

type AnyType: ColumnType

Source

type Value: Clone + Send + Sync + 'static

Source

type Id: Send + Sync + Clone + Hash + Eq + 'static

Source

type Source: TableSourceSpec

How this backend names its source. Most backends use String; SQL/SurrealDB backends use SelectSource<Self::Select> so a table can be sourced from an arbitrary sub-SELECT. See crate::source.

Source

type Condition: Clone + Send + Sync + 'static

The condition type stored by Table. SQL/SurrealDB backends use Expression<Self::Value>; document-oriented backends like MongoDB can use a native filter type (e.g. bson::Document).

Required Methods§

Source

fn create_column<Type: ColumnType>(&self, name: &str) -> Self::Column<Type>

Create a new column with the given name

Source

fn to_any_column<Type: ColumnType>( &self, column: Self::Column<Type>, ) -> Self::Column<Self::AnyType>

Convert a typed column to type-erased column

Source

fn convert_any_column<Type: ColumnType>( &self, any_column: Self::Column<Self::AnyType>, ) -> Option<Self::Column<Type>>

Attempt to convert a type-erased column back to typed column

Source

fn expr( &self, template: impl Into<String>, parameters: Vec<ExpressiveEnum<Self::Value>>, ) -> Expression<Self::Value>

Create an expression from a template and parameters, similar to Expression::new

Source

fn search_table_condition<E>( &self, table: &Table<Self, E>, search_value: &str, ) -> Self::Condition
where E: Entity<Self::Value>, Self: Sized,

Create a search condition matching search_value across the table’s searchable fields. This is a server-side capability — it pushes the match down to the backend’s query engine.

Different vendors implement search differently:

  • SQL: field LIKE '%value%' (returns Expression)
  • SurrealDB: field CONTAINS 'value' (returns Expression)
  • MongoDB: { field: { $regex: 'value' } } (returns MongoCondition)

Contract for backends that cannot search server-side (e.g. CSV, redb): return a condition that yields an ErrorKind::Unsupported error when it is resolved — never a silent match-all (which leaks every row as if filtered) and never a panic. Searching loaded/in-memory data is the Lens/Diorama layer’s responsibility, not the backend’s.

Source

fn list_table_values<'life0, 'life1, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, ) -> Pin<Box<dyn Future<Output = Result<IndexMap<Self::Id, Record<Self::Value>>>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get all data from a table as Record values with IDs (for ReadableValueSet implementation)

Source

fn get_table_value<'life0, 'life1, 'life2, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, id: &'life2 Self::Id, ) -> Pin<Box<dyn Future<Output = Result<Option<Record<Self::Value>>>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Get a single record by ID as Record value (for ReadableValueSet implementation).

Returns Ok(None) when no record exists with the given ID.

Source

fn get_table_some_value<'life0, 'life1, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, ) -> Pin<Box<dyn Future<Output = Result<Option<(Self::Id, Record<Self::Value>)>>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get some data from a table as Record value with ID (for ReadableValueSet implementation)

Source

fn get_table_count<'life0, 'life1, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, ) -> Pin<Box<dyn Future<Output = Result<i64>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Get count of records in the table

Source

fn get_table_sum<'life0, 'life1, 'life2, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, column: &'life2 Self::Column<Self::AnyType>, ) -> Pin<Box<dyn Future<Output = Result<Self::Value>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Get sum of a column in the table (returns native value type)

Source

fn get_table_max<'life0, 'life1, 'life2, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, column: &'life2 Self::Column<Self::AnyType>, ) -> Pin<Box<dyn Future<Output = Result<Self::Value>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Get maximum value of a column in the table (returns native value type)

Source

fn get_table_min<'life0, 'life1, 'life2, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, column: &'life2 Self::Column<Self::AnyType>, ) -> Pin<Box<dyn Future<Output = Result<Self::Value>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Get minimum value of a column in the table (returns native value type)

Source

fn insert_table_value<'life0, 'life1, 'life2, 'life3, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, id: &'life2 Self::Id, record: &'life3 Record<Self::Value>, ) -> Pin<Box<dyn Future<Output = Result<Record<Self::Value>>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Insert a record as Record value (for WritableValueSet implementation)

Source

fn replace_table_value<'life0, 'life1, 'life2, 'life3, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, id: &'life2 Self::Id, record: &'life3 Record<Self::Value>, ) -> Pin<Box<dyn Future<Output = Result<Record<Self::Value>>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Replace a record as Record value (for WritableValueSet implementation)

Source

fn patch_table_value<'life0, 'life1, 'life2, 'life3, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, id: &'life2 Self::Id, partial: &'life3 Record<Self::Value>, ) -> Pin<Box<dyn Future<Output = Result<Record<Self::Value>>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Patch a record as Record value (for WritableValueSet implementation)

Source

fn delete_table_value<'life0, 'life1, 'life2, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, id: &'life2 Self::Id, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Delete a record by ID (for WritableValueSet implementation)

Source

fn delete_table_all_values<'life0, 'life1, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Delete all records (for WritableValueSet implementation)

Source

fn insert_table_return_id_value<'life0, 'life1, 'life2, 'async_trait, E>( &'life0 self, table: &'life1 Table<Self, E>, record: &'life2 Record<Self::Value>, ) -> Pin<Box<dyn Future<Output = Result<Self::Id>> + Send + 'async_trait>>
where E: Entity<Self::Value> + 'async_trait, Self: Sized + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Insert a record and return generated ID (for InsertableValueSet implementation)

Source

fn related_in_condition<SourceE: Entity<Self::Value> + 'static>( &self, target_field: &str, source_table: &Table<Self, SourceE>, source_column: &str, ) -> Self::Condition
where Self: Sized,

Build a condition for “target_field IN (values of source_column from source_table)”.

Used by the relationship traversal system (get_ref_as) to filter a target table by foreign key values from a source table.

Each backend implements this natively:

  • SQL backends build a subquery: "id" IN (SELECT "bakery_id" FROM "client" WHERE ...)
  • MongoDB builds a deferred { field: { "$in": [...] } } document
  • CSV fetches values in memory and builds an IN condition
Source

fn column_table_values_expr<'a, E, Type: ColumnType>( &'a self, table: &Table<Self, E>, column: &Self::Column<Type>, ) -> AssociatedExpression<'a, Self, Self::Value, Vec<Type>>
where E: Entity<Self::Value> + 'static, Self: ExprDataSource<Self::Value> + Sized,

Return an associated expression that, when resolved, yields all values of the given typed column from this table (respecting current conditions).

For query-language backends, this can be a subquery expression. For simple backends (CSV), this uses a DeferredFn that loads data and extracts the column values at execution time.

The returned AssociatedExpression can be:

  • Executed directly: .get().await -> Result<Vec<Type>>
  • Composed into expressions: used via Expressive trait in in_() conditions
let fk_col = source.get_column::<String>("bakery_id").unwrap();
let fk_values = source.data_source().column_table_values_expr(&source, &fk_col);
// Execute: let ids = fk_values.get().await?;
// Or compose: target.add_condition(target["id"].in_((fk_values)));

Provided Methods§

Source

fn eq_condition(field: &str, value: &str) -> Result<Self::Condition>

Build a textual field == value condition.

Generic UIs (e.g. CLI argument parsers) only have strings on hand, so they need a way to construct a Self::Condition without knowing the backend’s native expression type. Backends that don’t support raw text filtering can leave the default, which returns an error.

Source

fn eq_value_condition( &self, field: &str, value: Self::Value, ) -> Result<Self::Condition>

Build a field == value condition with a typed Self::Value.

Sibling of TableSource::eq_condition for the case where the caller already has a native-typed value in hand (e.g. Reference::resolve_from_row pulling a join value out of a Record<Self::Value>). Avoids going through string serialization and avoids the Expression → T::Condition coercion that some document backends only support via a panic stub.

Backends that participate in row-based reference traversal override; the default returns an error so existing impls compile.

Source

fn stream_table_values<'a, E>( &'a self, table: &Table<Self, E>, ) -> Pin<Box<dyn Stream<Item = Result<(Self::Id, Record<Self::Value>)>> + Send + 'a>>
where E: Entity<Self::Value> + 'a, Self: Sized,

Stream all records from a table as (Id, Record) pairs.

Default implementation wraps list_table_values into a stream. Backends with native streaming (e.g. REST APIs with pagination) can override this to yield records incrementally.

Source

fn related_correlated_condition( &self, target_table: &str, target_field: &str, source_table: &str, source_column: &str, ) -> Self::Condition

Build a correlated condition: target_table.target_field = source_table.source_column.

Used by get_subquery_as / get_subquery_erased for embedding correlated subqueries inside SELECT expressions (e.g. (SELECT COUNT(*) FROM order WHERE order.client_id = client.id)), and by the generic implicit-reference lowering. SQL and SurrealDB backends produce table-qualified equality; backends without correlated subqueries leave the default (which panics — they must also keep supports_traversal false).

Source

fn supports_traversal(&self) -> bool

Whether this backend can lower a dotted active column ("country.name") into its own query — a nested correlated subquery for SQL, a native idiom path for SurrealDB. Backends that can build neither (e.g. MongoDB, CSV, REST) leave the default false, and Table::with_active_columns rejects dotted names against them at build time rather than at fetch time.

Source

fn traversal_path_expr( &self, hops: &[&str], column: &str, ) -> Option<Expression<Self::Value>>

Build a backend-native path expression for a dotted active column, tried before the generic correlated-subquery chain.

hops holds each traversed relation’s foreign-key/link field (not its registry name — a relation named owner over a link field client must lower to client.…), and column the final field. The default returns None, so backends fall back to the generic chain built on related_correlated_condition. SurrealDB overrides this to emit an idiom path (batch.golf_course.name, each segment escaped separately); multi-hop comes for free. The returned expression is unaliased — select() aliases it to the dotted name.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§