use crate::model::*;
use crate::util::Result;
use sqlparser::ast::{DataType, Expr, ObjectName, SequenceOptions, UnaryOperator, Value};
use super::util::unquote_ident;
pub(super) fn parse_create_sequence(
schema: &str,
name: &str,
data_type: Option<&DataType>,
sequence_options: &[SequenceOptions],
owned_by: Option<&ObjectName>,
) -> Result<Sequence> {
let seq_data_type = data_type
.map(|dt| match dt {
DataType::SmallInt(_) => SequenceDataType::SmallInt,
DataType::BigInt(_) => SequenceDataType::BigInt,
DataType::Integer(_) | DataType::Int(_) => SequenceDataType::Integer,
_ => SequenceDataType::Integer,
})
.unwrap_or(SequenceDataType::Integer);
let mut start: Option<i64> = None;
let mut increment: Option<i64> = None;
let mut min_value: Option<i64> = None;
let mut max_value: Option<i64> = None;
let mut cycle = false;
let mut cache: Option<i64> = None;
for option in sequence_options {
match option {
SequenceOptions::IncrementBy(expr, _) => {
increment = extract_i64_from_expr(expr);
}
SequenceOptions::MinValue(Some(expr)) => {
min_value = extract_i64_from_expr(expr);
}
SequenceOptions::MaxValue(Some(expr)) => {
max_value = extract_i64_from_expr(expr);
}
SequenceOptions::StartWith(expr, _) => {
start = extract_i64_from_expr(expr);
}
SequenceOptions::Cache(expr) => {
cache = extract_i64_from_expr(expr);
}
SequenceOptions::Cycle(c) => {
cycle = *c;
}
_ => {}
}
}
let owned_by_parsed = owned_by.and_then(|obj_name| {
let parts: Vec<String> = obj_name
.0
.iter()
.map(|part| unquote_ident(&part.to_string()).to_string())
.collect();
match parts.as_slice() {
[table_schema, table_name, column_name] => Some(SequenceOwner {
table_schema: table_schema.clone(),
table_name: table_name.clone(),
column_name: column_name.clone(),
}),
[table_name, column_name] => Some(SequenceOwner {
table_schema: "public".to_string(),
table_name: table_name.clone(),
column_name: column_name.clone(),
}),
_ => None,
}
});
let increment = increment.or(Some(1));
let is_ascending = increment.unwrap_or(1) > 0;
let cache = cache.or(Some(1));
let min_value = min_value.or(if is_ascending {
Some(1)
} else {
match seq_data_type {
SequenceDataType::SmallInt => Some(-32768),
SequenceDataType::Integer => Some(-2147483648),
SequenceDataType::BigInt => Some(-9223372036854775808),
}
});
let max_value = max_value.or(if is_ascending {
match seq_data_type {
SequenceDataType::SmallInt => Some(32767),
SequenceDataType::Integer => Some(2147483647),
SequenceDataType::BigInt => Some(9223372036854775807),
}
} else {
Some(-1)
});
let start = start.or(if is_ascending { min_value } else { max_value });
Ok(Sequence {
name: name.to_string(),
schema: schema.to_string(),
data_type: seq_data_type,
start,
increment,
min_value,
max_value,
cycle,
cache,
owned_by: owned_by_parsed,
owner: None,
grants: Vec::new(),
comment: None,
})
}
fn extract_i64_from_expr(expr: &Expr) -> Option<i64> {
match expr {
Expr::Value(value_with_span) => {
if let Value::Number(n, _) = &value_with_span.value {
n.parse::<i64>().ok()
} else {
None
}
}
Expr::UnaryOp { op, expr } => {
if matches!(op, UnaryOperator::Minus) {
extract_i64_from_expr(expr).map(|n| -n)
} else {
None
}
}
_ => None,
}
}