fixing problems
This commit is contained in:
211
common/src/catalog_storage.rs
Normal file
211
common/src/catalog_storage.rs
Normal 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('"', "\"\""))
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user