fixing problems

This commit is contained in:
Priec
2026-09-12 22:10:22 +02:00
parent 156d1c4464
commit 905c5a622b
6 changed files with 228 additions and 38 deletions

View File

@@ -0,0 +1,211 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ColumnType {
BigInt,
Integer,
Numeric,
Date,
TextArray,
Boolean,
Text,
Uuid,
Timestamp,
Json,
}
impl ColumnType {
pub fn from_postgres_type(kind: &str) -> Option<Self> {
match kind {
"int8" => Some(Self::BigInt),
"int4" => Some(Self::Integer),
"numeric" => Some(Self::Numeric),
"date" => Some(Self::Date),
"_text" => Some(Self::TextArray),
"bool" => Some(Self::Boolean),
"text" => Some(Self::Text),
"uuid" => Some(Self::Uuid),
"timestamptz" => Some(Self::Timestamp),
"jsonb" => Some(Self::Json),
_ => None,
}
}
pub fn text_representation(self) -> bool {
matches!(self, Self::Uuid | Self::Json | Self::TextArray)
}
pub fn field_type(self) -> &'static str {
match self {
Self::BigInt => "BIGINT",
Self::Integer => "INT",
Self::Numeric => "NUMERIC",
Self::Date => "DATE",
Self::TextArray => "TEXT",
Self::Boolean => "BOOLEAN",
Self::Text => "TEXT",
Self::Uuid => "TEXT",
Self::Timestamp => "instant(6)",
Self::Json => "TEXT",
}
}
pub fn postgres_type(self) -> &'static str {
match self {
Self::BigInt => "int8",
Self::Integer => "int4",
Self::Numeric => "numeric",
Self::Date => "date",
Self::TextArray => "_text",
Self::Boolean => "bool",
Self::Text => "text",
Self::Uuid => "uuid",
Self::Timestamp => "timestamptz",
Self::Json => "jsonb",
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ColumnSpec {
pub physical_name: String,
pub column_type: ColumnType,
pub not_null: bool,
}
impl ColumnSpec {
pub fn new(name: &str, column_type: ColumnType) -> Self {
Self {
physical_name: name.into(),
column_type,
not_null: false,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DeletionPolicy {
None,
SoftDelete,
ManagedSoftDelete,
}
impl DeletionPolicy {
pub fn is_soft_delete(self) -> bool {
matches!(self, Self::SoftDelete | Self::ManagedSoftDelete)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum HistoryPolicy {
CurrentOnly,
ManagedVersions,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum NavigationPolicy {
Direct,
Tracked,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum RowScope {
All,
Profile { column: String },
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RowWritePolicy {
Module,
Catalog,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LinkSpec {
pub column: String,
pub target_table: String,
pub version_column: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ProjectionSpec {
pub output_column: String,
pub link_column: String,
pub source_column: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct StorageSpec {
pub schema: String,
pub relation: String,
pub columns: Vec<ColumnSpec>,
pub row_scope: RowScope,
pub row_writes: RowWritePolicy,
pub links: Vec<LinkSpec>,
pub projections: Vec<ProjectionSpec>,
pub deletion: DeletionPolicy,
pub history: HistoryPolicy,
pub navigation: NavigationPolicy,
pub created_at: Option<String>,
}
impl StorageSpec {
pub fn catalog_managed(&self) -> bool {
self.row_writes == RowWritePolicy::Catalog
}
pub fn read_sql(&self, schema_id: i64) -> String {
let storage = self;
let mut columns = vec!["id".to_string()];
columns.extend(storage.columns.iter().map(|column| {
let name = quote(&column.physical_name);
if column.column_type.text_representation() {
format!("{name}::TEXT AS {name}")
} else {
name
}
}));
columns.extend(storage.links.iter().map(|link| quote(&link.version_column)));
columns.push(match storage.deletion {
DeletionPolicy::None => "FALSE AS deleted".into(),
DeletionPolicy::SoftDelete | DeletionPolicy::ManagedSoftDelete => "deleted".into(),
});
match storage.history {
HistoryPolicy::CurrentOnly => columns.extend([
"1::BIGINT AS version".into(),
if storage.deletion == DeletionPolicy::ManagedSoftDelete {
"row_revision".into()
} else { "1::BIGINT AS row_revision".into() },
]),
HistoryPolicy::ManagedVersions => {
columns.extend(["version".into(), "row_revision".into()])
}
}
columns.push(match &storage.created_at {
Some(column) => format!("{} AS created_at", quote(column)),
None => "NULL::TIMESTAMPTZ AS created_at".into(),
});
let predicate = match &storage.row_scope {
RowScope::All => String::new(),
RowScope::Profile { column } => {
format!(" WHERE {} = {}", quote(column), schema_id)
}
};
let relation = format!("{}.{}", quote(&storage.schema), quote(&storage.relation));
format!("(SELECT {} FROM {relation}{predicate})", columns.join(", "))
}
}
fn quote(identifier: &str) -> String {
format!("\"{}\"", identifier.replace('"', "\"\""))
}

View File

@@ -3,6 +3,7 @@
#[cfg_attr(not(feature = "tantivy"), path = "search_light.rs")]
pub mod search;
pub mod alias;
pub mod catalog_storage;
pub mod decimal;
pub mod grpc_error;
pub mod money;