use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct Document {
pub operations: Vec<Operation>,
}
#[derive(Debug, Clone)]
pub enum Operation {
Query(Query),
Mutation(Mutation),
Subscription(Subscription),
Schema(Schema),
Migration(Migration),
FragmentDefinition(FragmentDef),
Introspection(IntrospectionQuery),
Handler(HandlerDef),
}
#[derive(Debug, Clone)]
pub struct Query {
pub name: Option<String>,
pub variable_definitions: Vec<VariableDefinition>,
pub directives: Vec<Directive>,
pub selection_set: Vec<Selection>,
pub variables_values: HashMap<String, Value>,
}
#[derive(Debug, Clone)]
pub struct Mutation {
pub name: Option<String>,
pub variable_definitions: Vec<VariableDefinition>,
pub directives: Vec<Directive>,
pub operations: Vec<MutationOperation>,
pub variables_values: HashMap<String, Value>,
}
#[derive(Debug, Clone)]
pub struct Subscription {
pub name: Option<String>,
pub variable_definitions: Vec<VariableDefinition>,
pub directives: Vec<Directive>,
pub selection_set: Vec<Selection>,
pub variables_values: HashMap<String, Value>,
}
#[derive(Debug, Clone)]
pub struct Schema {
pub operations: Vec<SchemaOp>,
}
#[derive(Debug, Clone)]
pub enum SchemaOp {
DefineCollection {
name: String,
if_not_exists: bool,
fields: Vec<FieldDef>,
directives: Vec<Directive>,
},
AlterCollection {
name: String,
actions: Vec<AlterAction>,
},
DropCollection {
name: String,
if_exists: bool,
},
}
#[derive(Debug, Clone)]
pub enum AlterAction {
AddField {
field: FieldDef,
default: Option<Value>,
},
DropField(String),
RenameField {
from: String,
to: String,
},
ModifyField(FieldDef),
}
#[derive(Debug, Clone)]
pub struct Migration {
pub steps: Vec<MigrationStep>,
}
#[derive(Debug, Clone)]
pub struct MigrationStep {
pub version: String,
pub actions: Vec<MigrationAction>,
}
#[derive(Debug, Clone)]
pub enum MigrationAction {
Schema(SchemaOp),
DataMigration(DataMigration),
}
#[derive(Debug, Clone)]
pub struct DataMigration {
pub collection: String,
pub transforms: Vec<DataTransform>,
}
#[derive(Debug, Clone)]
pub struct DataTransform {
pub field: String,
pub expression: String, pub filter: Option<Filter>,
}
#[derive(Debug, Clone)]
pub struct HandlerDef {
pub name: String,
pub trigger: HandlerTrigger,
pub action: MutationOperation,
}
#[derive(Debug, Clone, PartialEq)]
pub enum HandlerTrigger {
JobCompleted,
JobFailed,
Insert { collection: Option<String> },
Update { collection: Option<String> },
Delete { collection: Option<String> },
Custom(String),
}
#[derive(Debug, Clone)]
pub struct FieldDef {
pub name: String,
pub field_type: TypeAnnotation,
pub directives: Vec<Directive>,
}
#[derive(Debug, Clone)]
pub struct VariableDefinition {
pub name: String,
pub var_type: TypeAnnotation,
pub default_value: Option<Value>,
}
#[derive(Debug, Clone)]
pub struct TypeAnnotation {
pub name: String,
pub is_array: bool,
pub is_required: bool,
}
#[derive(Debug, Clone)]
pub struct Directive {
pub name: String,
pub arguments: Vec<Argument>,
}
#[derive(Debug, Clone)]
pub struct Field {
pub alias: Option<String>,
pub name: String,
pub arguments: Vec<Argument>,
pub directives: Vec<Directive>,
pub selection_set: Vec<Selection>,
pub computed_expression: Option<Expression>,
}
#[derive(Debug, Clone)]
pub struct Argument {
pub name: String,
pub value: Value,
}
#[derive(Debug, Clone)]
pub struct MutationOperation {
pub alias: Option<String>,
pub operation: MutationOp,
pub directives: Vec<Directive>,
pub selection_set: Vec<Selection>,
}
#[derive(Debug, Clone)]
pub enum MutationOp {
Insert {
collection: String,
data: Value,
},
InsertMany {
collection: String,
data: Value,
},
Update {
collection: String,
filter: Option<Filter>,
data: Value,
},
Upsert {
collection: String,
filter: Option<Filter>,
data: Value,
},
Delete {
collection: String,
filter: Option<Filter>,
},
EnqueueJob {
job_type: String,
payload: Value,
priority: JobPriority,
scheduled_at: Option<String>,
max_retries: Option<u32>,
},
EnqueueJobs {
job_type: String,
payloads: Vec<Value>,
priority: JobPriority,
max_retries: Option<u32>,
},
Import {
collection: String,
data: Vec<Value>,
},
Export {
collection: String,
format: String,
},
Transaction {
operations: Vec<MutationOperation>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JobPriority {
Low,
Normal,
High,
Critical,
}
#[derive(Debug, Clone)]
pub enum Filter {
Eq(String, Value),
Ne(String, Value),
Gt(String, Value),
Gte(String, Value),
Lt(String, Value),
Lte(String, Value),
In(String, Value),
NotIn(String, Value),
Contains(String, Value),
ContainsAny(String, Value),
ContainsAll(String, Value),
StartsWith(String, Value),
EndsWith(String, Value),
Matches(String, Value),
IsNull(String),
IsNotNull(String),
And(Vec<Filter>),
Or(Vec<Filter>),
Not(Box<Filter>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Null,
Boolean(bool),
Int(i64),
Float(f64),
String(String),
Array(Vec<Value>),
Object(HashMap<String, Value>),
Variable(String),
Enum(String),
}
impl From<bool> for Value {
fn from(v: bool) -> Self {
Value::Boolean(v)
}
}
impl From<i32> for Value {
fn from(v: i32) -> Self {
Value::Int(v as i64)
}
}
impl From<i64> for Value {
fn from(v: i64) -> Self {
Value::Int(v)
}
}
impl From<f32> for Value {
fn from(v: f32) -> Self {
Value::Float(v as f64)
}
}
impl From<f64> for Value {
fn from(v: f64) -> Self {
Value::Float(v)
}
}
impl From<String> for Value {
fn from(v: String) -> Self {
Value::String(v)
}
}
impl From<&str> for Value {
fn from(v: &str) -> Self {
Value::String(v.to_string())
}
}
impl From<uuid::Uuid> for Value {
fn from(v: uuid::Uuid) -> Self {
Value::String(v.to_string())
}
}
impl From<crate::types::Value> for Value {
fn from(v: crate::types::Value) -> Self {
match v {
crate::types::Value::Null => Value::Null,
crate::types::Value::Bool(b) => Value::Boolean(b),
crate::types::Value::Int(i) => Value::Int(i),
crate::types::Value::Float(f) => Value::Float(f),
crate::types::Value::String(s) => Value::String(s),
crate::types::Value::Uuid(u) => Value::String(u.to_string()),
crate::types::Value::DateTime(dt) => Value::String(dt.to_rfc3339()),
crate::types::Value::Array(arr) => {
Value::Array(arr.into_iter().map(Value::from).collect())
}
crate::types::Value::Object(obj) => {
let mut map = HashMap::new();
for (k, v) in obj {
map.insert(k, Value::from(v));
}
Value::Object(map)
}
}
}
}
#[derive(Debug, Clone)]
pub struct FragmentDef {
pub name: String,
pub type_condition: String,
pub selection_set: Vec<Selection>,
}
#[derive(Debug, Clone)]
pub struct IntrospectionQuery {
pub arguments: Vec<Argument>,
pub fields: Vec<String>,
}
#[derive(Debug, Clone)]
pub enum Selection {
Field(Field),
FragmentSpread(String),
InlineFragment(InlineFragment),
ComputedField(ComputedField),
}
#[derive(Debug, Clone)]
pub struct InlineFragment {
pub type_condition: String,
pub selection_set: Vec<Selection>,
}
#[derive(Debug, Clone)]
pub struct ComputedField {
pub alias: String,
pub expression: ComputedExpression,
}
#[derive(Debug, Clone)]
pub enum ComputedExpression {
TemplateString(String),
FunctionCall {
name: String,
args: Vec<Expression>,
},
PipeExpression {
base: Box<Expression>,
operations: Vec<PipeOp>,
},
SqlExpression(String),
AggregateFunction {
name: String,
field: String,
},
StandardExpression(Expression),
}
#[derive(Debug, Clone)]
pub struct PipeOp {
pub function: String,
pub args: Vec<Expression>,
}
#[derive(Debug, Clone)]
pub enum Expression {
Literal(Value),
FieldAccess(Vec<String>),
Variable(String),
FunctionCall {
name: String,
args: Vec<Expression>,
},
Binary {
op: BinaryOp,
left: Box<Expression>,
right: Box<Expression>,
},
Unary {
op: UnaryOp,
expr: Box<Expression>,
},
Ternary {
condition: Box<Expression>,
then_expr: Box<Expression>,
else_expr: Box<Expression>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
Add,
Sub,
Mul,
Div,
Mod,
Eq,
Ne,
Gt,
Gte,
Lt,
Lte,
And,
Or,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
Not,
Neg,
}
#[derive(Debug, Clone)]
pub enum SpecialSelection {
Aggregate(AggregateSelection),
GroupBy(GroupBySelection),
Lookup(LookupSelection),
PageInfo(PageInfoSelection),
Edges(EdgesSelection),
Downsample(DownsampleSelection),
WindowFunction(WindowFunctionSelection),
}
#[derive(Debug, Clone)]
pub struct AggregateSelection {
pub fields: Vec<AggregateField>,
}
#[derive(Debug, Clone)]
pub struct AggregateField {
pub function: String,
pub field: Option<String>,
}
#[derive(Debug, Clone)]
pub struct GroupBySelection {
pub field: Option<String>,
pub fields: Option<Vec<String>>,
pub interval: Option<String>,
pub result_fields: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct LookupSelection {
pub collection: String,
pub local_field: String,
pub foreign_field: String,
pub filter: Option<Filter>,
pub selection_set: Vec<Selection>,
}
#[derive(Debug, Clone)]
pub struct PageInfoSelection {
pub fields: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct EdgesSelection {
pub fields: Vec<EdgeField>,
}
#[derive(Debug, Clone)]
pub enum EdgeField {
Cursor,
Node(Vec<Selection>),
}
#[derive(Debug, Clone)]
pub struct DownsampleSelection {
pub interval: String,
pub aggregation: String,
pub selection_set: Vec<Selection>,
}
#[derive(Debug, Clone)]
pub struct WindowFunctionSelection {
pub alias: String,
pub field: String,
pub function: String,
pub window_size: i64,
}
#[derive(Debug, Clone)]
pub struct WhereClause {
pub filter: Filter,
}
#[derive(Debug, Clone)]
pub struct OrderByClause {
pub orderings: Vec<Ordering>,
}
#[derive(Debug, Clone)]
pub struct Ordering {
pub field: String,
pub direction: SortDirection,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SortDirection {
Asc,
Desc,
}
#[derive(Debug, Clone)]
pub struct SearchArgs {
pub query: String,
pub fields: Vec<String>,
pub fuzzy: bool,
pub min_score: Option<f64>,
}
#[derive(Debug, Clone)]
pub struct ValidateArgs {
pub rules: Vec<ValidationRule>,
}
#[derive(Debug, Clone)]
pub struct ValidationRule {
pub field: String,
pub constraints: Vec<ValidationConstraint>,
}
#[derive(Debug, Clone)]
pub enum ValidationConstraint {
Format(String),
Min(f64),
Max(f64),
MinLength(i64),
MaxLength(i64),
Pattern(String),
}
impl From<Vec<Value>> for Value {
fn from(v: Vec<Value>) -> Self {
Value::Array(v)
}
}
impl<const N: usize> From<[Value; N]> for Value {
fn from(v: [Value; N]) -> Self {
Value::Array(v.into_iter().collect())
}
}