Skip to main content
The query-structure crate provides fundamental types for working with Prisma data models, fields, filters, and query arguments. It serves as the foundation for query building and execution.

Overview

This library defines the internal representation of Prisma schemas and query operations. It bridges the gap between the PSL (Prisma Schema Language) parser and the query execution layer.

Installation

[dependencies]
query-structure = "0.0.0"

Core Types

Model

Represents a Prisma model in the internal data model.
pub type Model = crate::Zipper<ModelId>;

Methods

impl Model {
    pub fn name(&self) -> &str
    pub fn primary_identifier(&self) -> FieldSelection
    pub fn fields(&self) -> Fields<'_>
    pub fn db_name(&self) -> &str
    pub fn is_view(&self) -> bool
    pub fn supports_create_operation(&self) -> bool
    pub fn has_unique_identifier(&self) -> bool
}
name
fn() -> &str
Returns the model name as defined in the schema
primary_identifier
fn() -> FieldSelection
Returns the fields used as the primary identifier for records
db_name
fn() -> &str
Returns the database table/collection name for this model
is_view
fn() -> bool
Returns true if this model is a database view

FieldSelection

A selection of fields from a model.
pub struct FieldSelection {
    selections: Vec<SelectedField>,
}

Methods

impl FieldSelection {
    pub fn new(selections: Vec<SelectedField>) -> Self
    pub fn selections(&self) -> impl ExactSizeIterator<Item = &SelectedField> + '_
    pub fn scalars(&self) -> impl Iterator<Item = &ScalarFieldRef> + '_
    pub fn relations(&self) -> impl Iterator<Item = &RelationSelection>
    pub fn contains(&self, name: &str) -> bool
    pub fn is_superset_of(&self, other: &Self) -> bool
    pub fn merge(self, other: FieldSelection) -> FieldSelection
    pub fn union(selections: Vec<Self>) -> Self
}
selections
fn() -> Iterator
Returns an iterator over all selected fields
scalars
fn() -> Iterator
Returns an iterator over scalar field selections only
is_superset_of
fn(&Self) -> bool
Checks if this selection contains all fields from another selection

SelectedField

Represents a single selected field in a query.
pub enum SelectedField {
    Scalar(ScalarFieldRef),
    Composite(CompositeSelection),
    Relation(RelationSelection),
    Virtual(VirtualSelection),
}
Scalar
ScalarFieldRef
A scalar field like String, Int, DateTime
Composite
CompositeSelection
A composite type field with nested selections
Relation
RelationSelection
A relation field with nested query arguments and selections
Virtual
VirtualSelection
A virtual field like relation count aggregations

QueryArguments

Defines constraints for querying data.
pub struct QueryArguments {
    pub model: Model,
    pub cursor: Option<SelectionResult>,
    pub take: Take,
    pub skip: Option<i64>,
    pub filter: Option<Filter>,
    pub order_by: Vec<OrderBy>,
    pub distinct: Option<FieldSelection>,
    pub ignore_skip: bool,
    pub ignore_take: bool,
    pub relation_load_strategy: Option<RelationLoadStrategy>,
}
model
Model
The model being queried
cursor
Option<SelectionResult>
Cursor position for pagination
take
Take
Number of records to take (can be negative for reverse pagination)
skip
Option<i64>
Number of records to skip
filter
Option<Filter>
Filter conditions (WHERE clause)
order_by
Vec<OrderBy>
Ordering specifications
distinct
Option<FieldSelection>
Fields to apply DISTINCT on
relation_load_strategy
Option<RelationLoadStrategy>
Strategy for loading relations (Join or Query)

Filter

Represents query filter conditions.
pub enum Filter {
    And(Vec<Filter>),
    Or(Vec<Filter>),
    Not(Vec<Filter>),
    Scalar(ScalarFilter),
    ScalarList(ScalarListFilter),
    OneRelationIsNull(OneRelationIsNullFilter),
    Relation(RelationFilter),
    Composite(CompositeFilter),
    BoolFilter(bool),
    Aggregation(AggregationFilter),
    Empty,
}

Filter Constructors

impl Filter {
    pub fn and(filters: Vec<Filter>) -> Self
    pub fn or(filters: Vec<Filter>) -> Self
    pub fn not(filters: Vec<Filter>) -> Self
    pub fn empty() -> Self
    pub fn size(&self) -> usize
}

RelationLoadStrategy

Strategy for loading relation data.
pub enum RelationLoadStrategy {
    Join,  // Use SQL JOINs
    Query, // Use separate queries
}
Join
variant
Load relations using SQL JOIN operations (more efficient, single query)
Query
variant
Load relations using separate queries (application-level joins)

Take

Represents the number of records to take in a query.
pub enum Take {
    All,
    One,
    NegativeOne,
    Some(i64),
}

Methods

impl Take {
    pub fn is_all(self) -> bool
    pub fn is_some(self) -> bool
    pub fn abs(self) -> Option<i64>
    pub fn is_reversed(self) -> bool
}

Module Structure

The crate is organized into several modules:
  • model - Model types and operations
  • field - Field types (scalar, composite, relation)
  • field_selection - Field selection types
  • filter - Filter condition types
  • query_arguments - Query argument types
  • order_by - Ordering specifications
  • record - Record and selection result types
  • write_args - Write operation arguments
  • internal_data_model - Internal representation of schema
  • error - Error types
  • prelude - Commonly used types

Re-exports

The crate re-exports several useful types:
pub use prisma_value::*;  // PrismaValue types
pub use psl::parser_database::walkers;  // Schema walkers
pub use psl::schema_ast::ast::{self, FieldArity};

Type Aliases

pub type Result<T> = std::result::Result<T, DomainError>;
pub type ScalarFieldRef = crate::Zipper<ScalarFieldId>;
pub type CompositeFieldRef = crate::Zipper<CompositeFieldId>;
pub type RelationFieldRef = crate::Zipper<RelationFieldId>;

Dependencies

Key dependencies:
  • psl - Prisma Schema Language parser
  • prisma-value - Prisma value types
  • itertools - Iterator utilities
  • bigdecimal - Decimal number support
  • chrono - Date and time types

Examples

Creating a Field Selection

use query_structure::{FieldSelection, Model};

let model: Model = /* get model */;
let selection = model.primary_identifier();

for field in selection.scalars() {
    println!("Selected field: {}", field.name());
}

Building Query Arguments

use query_structure::{QueryArguments, Filter, Take};

let args = QueryArguments {
    model: my_model,
    cursor: None,
    take: Take::Some(10),
    skip: Some(5),
    filter: Some(Filter::empty()),
    order_by: vec![],
    distinct: None,
    ignore_skip: false,
    ignore_take: false,
    relation_load_strategy: Some(RelationLoadStrategy::Join),
};

Working with Filters

use query_structure::Filter;

let filter = Filter::and(vec![
    /* scalar filters */
]);

if filter.size() > 0 {
    // Apply filter
}

Build docs developers (and LLMs) love