reifydb-rql 0.4.12

ReifyDB Query Language (RQL) parser and AST
Documentation
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 ReifyDB

use reifydb_core::error::diagnostic::query;
use reifydb_transaction::transaction::Transaction;
use reifydb_type::{err, error, error::Diagnostic, fragment::Fragment};

use crate::{
	Result,
	ast::ast::{Ast, AstFrom},
	bump::BumpBox,
	expression::{AliasExpression, ExpressionCompiler, IdentExpression},
	plan::logical::{
		Compiler, EnvironmentNode, GeneratorNode, InlineDataNode, LogicalPlan, RemoteScanNode, ShapeScanNode,
		VariableSourceNode,
		resolver::{self, ResolvedSource},
	},
};

// Note: Fragment is still imported for use at materialization boundaries (Expression types use owned Fragment)

impl<'bump> Compiler<'bump> {
	pub(crate) fn compile_from(&self, ast: AstFrom<'bump>, tx: &mut Transaction<'_>) -> Result<LogicalPlan<'bump>> {
		match ast {
			AstFrom::Source {
				source,
				..
			} => {
				let resolved_source = resolver::resolve_unresolved_source(&self.catalog, tx, &source)?;
				match resolved_source {
					ResolvedSource::Remote {
						address,
						token,
						local_namespace,
						remote_name,
					} => Ok(LogicalPlan::RemoteScan(RemoteScanNode {
						address,
						token,
						local_namespace,
						remote_name,
					})),
					ResolvedSource::Shape(resolved) => {
						Ok(LogicalPlan::PrimitiveScan(ShapeScanNode {
							source: resolved,
							columns: None,
							index: None,
						}))
					}
				}
			}
			AstFrom::Inline {
				list,
				..
			} => {
				let mut rows = Vec::new();

				for row in list.nodes {
					match row {
						Ast::Inline(row) => {
							let mut alias_fields = Vec::new();
							for field in row.keyed_values {
								if field.key.token.fragment.text().starts_with('#') {
									return Err(error!(
										query::system_column_read_only(
											field.key
												.token
												.fragment
												.to_owned()
										)
									));
								}
								let key_fragment = field.key.token.fragment.to_owned();
								let alias = IdentExpression(key_fragment.clone());
								let expr = ExpressionCompiler::compile(
									BumpBox::into_inner(field.value),
								)?;

								let alias_expr = AliasExpression {
									alias,
									expression: Box::new(expr),
									fragment: key_fragment,
								};
								alias_fields.push(alias_expr);
							}
							rows.push(alias_fields);
						}
						_ => {
							return err!(Diagnostic {
								code: "E0001".to_string(),
								rql: None,
								message: "Expected encoded in static data".to_string(),
								column: None,
								fragment: Fragment::None,
								label: None,
								help: None,
								notes: vec![],
								cause: None,
								operator_chain: None,
							});
						}
					}
				}

				Ok(LogicalPlan::InlineData(InlineDataNode {
					rows,
				}))
			}
			AstFrom::Generator(generator) => {
				let expressions = generator
					.nodes
					.into_iter()
					.map(ExpressionCompiler::compile)
					.collect::<Result<Vec<_>>>()?;

				Ok(LogicalPlan::Generator(GeneratorNode {
					name: generator.name,
					expressions,
				}))
			}
			AstFrom::Variable {
				variable,
				..
			} => {
				// Create a variable source node for regular variables
				let variable_name = variable.token.fragment;
				Ok(LogicalPlan::VariableSource(VariableSourceNode {
					name: variable_name,
				}))
			}

			AstFrom::Environment {
				..
			} => Ok(LogicalPlan::Environment(EnvironmentNode {})),
		}
	}
}