Skip to content

Commit

Permalink
Merge pull request #9 from SeaQL/pg-discovery-writer
Browse files Browse the repository at this point in the history
Postgres Discovery & Writer Module
  • Loading branch information
tyt2y3 authored Aug 7, 2021
2 parents 6736eec + 5cfe0cc commit fdfb9d8
Show file tree
Hide file tree
Showing 44 changed files with 4,287 additions and 88 deletions.
79 changes: 69 additions & 10 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,81 @@
name: Rust
name: sea-schema

on:
push:
branches: [ master ]
branches:
- master
pull_request:
branches: [ master ]
branches:
- master

env:
CARGO_TERM_COLOR: always

jobs:
build:

test:
name: Unit Test
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2

- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true

- uses: Swatinem/rust-cache@v1

- uses: actions-rs/cargo@v1
with:
command: build
args: >
--all
- uses: actions-rs/cargo@v1
with:
command: test

postgres:
name: Postgres
runs-on: ubuntu-20.04
strategy:
matrix:
version: [13.3, 12.7, 11.12, 10.17, 9.6.22]
project: [live]
services:
postgres:
image: postgres:${{ matrix.version }}
env:
POSTGRES_HOST: 127.0.0.1
POSTGRES_USER: sea
POSTGRES_PASSWORD: sea
ports:
- "5432:5432"
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
- uses: actions/checkout@v2

- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true

- uses: Swatinem/rust-cache@v1

- uses: actions-rs/cargo@v1
with:
command: build
args: >
--manifest-path tests/${{ matrix.project }}/postgres/Cargo.toml
- uses: actions-rs/cargo@v1
with:
command: test
args: >
--manifest-path tests/${{ matrix.project }}/postgres/Cargo.toml
9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
[workspace]
members = [
".",
"tests/discovery",
"tests/writer",
"tests/discovery/mysql",
"tests/discovery/postgres",
"tests/writer/mysql",
"tests/writer/postgres",
"tests/live/postgres",
]

[package]
Expand All @@ -28,7 +31,7 @@ path = "src/lib.rs"
[dependencies]
futures = { version = "0.3", optional = true }
sea-schema-derive = { version = "0.1.0", path = "sea-schema-derive" }
sea-query = { version = "^0.12" }
sea-query = { version = "^0.12", git = "https://github.com/SeaQL/sea-query.git" }
serde = { version = "^1", features = ["derive"], optional = true }
sqlx = { version = "^0", optional = true }

Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub mod mysql;
#[cfg_attr(docsrs, doc(cfg(feature = "postgres")))]
pub mod postgres;

pub use sea_query;

pub(crate) mod parser;
pub(crate) mod sqlx_types;
pub(crate) mod util;
Expand Down
7 changes: 3 additions & 4 deletions src/postgres/def/column.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#[cfg(feature = "with-serde")]
use serde::{Deserialize, Serialize};

use super::constraints;
use super::Type;
use super::{NotNull, Type};

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
Expand All @@ -16,7 +15,7 @@ pub struct ColumnInfo {
pub default: Option<ColumnExpression>,
/// The generation expression for this column, if it is a generated colum
pub generated: Option<ColumnExpression>,
pub not_null: Option<constraints::NotNull>,
pub not_null: Option<NotNull>,
// TODO:
// /// A constraint that ensures the value of a column is unique among all other rows in the table
// pub unique: Option<Vec<constraints::Unique>>,
Expand All @@ -36,7 +35,7 @@ pub type ColumnType = Type;

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub struct ColumnExpression(String);
pub struct ColumnExpression(pub String);

impl ColumnExpression {
pub fn from_option_string(maybe_string: Option<String>) -> Option<ColumnExpression> {
Expand Down
33 changes: 31 additions & 2 deletions src/postgres/def/constraints.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#[cfg(feature = "with-serde")]
use serde::{Deserialize, Serialize};

use crate as sea_schema;

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
/// An enum consisting of all constraints
Expand All @@ -17,6 +19,7 @@ pub enum Constraint {
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
/// A constraint which states that a value must satisfy the following Boolean expression
pub struct Check {
pub name: String,
/// The Boolean expression that must be satisfied
pub expr: String,
/// If marked with NO INHERIT, the constraint will not propogate to child tables
Expand All @@ -27,6 +30,7 @@ pub struct Check {
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
/// The constraint that a value must not be null
pub struct NotNull;

impl NotNull {
pub fn from_bool(boolean: bool) -> Option<NotNull> {
if boolean {
Expand All @@ -40,21 +44,45 @@ impl NotNull {
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
/// That each set of values for these columns must be unique across the whole table
pub struct Unique(pub Vec<String>);
pub struct Unique {
pub name: String,
pub columns: Vec<String>,
}

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
/// A constraint stating that the given columns act as a unique identifier for rows in the table.
/// This implies that the columns are not null and are unique together
pub struct PrimaryKey(pub Vec<String>);
pub struct PrimaryKey {
pub name: String,
pub columns: Vec<String>,
}

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
/// A constraint that column references the values appearing in the row of another table
pub struct References {
pub name: String,
pub columns: Vec<String>,
pub table: String,
pub foreign_columns: Vec<String>,
pub on_update: Option<ForeignKeyAction>,
pub on_delete: Option<ForeignKeyAction>,
}

#[derive(Clone, Debug, PartialEq, sea_schema_derive::Name)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub enum ForeignKeyAction {
#[name = "CASCADE"]
Cascade,
#[name = "SET NULL"]
SetNull,
#[name = "SET DEFAULT"]
SetDefault,
#[name = "RESTRICT"]
Restrict,
#[name = "NO ACTION"]
NoAction,
}

#[derive(Clone, Debug, PartialEq)]
Expand All @@ -63,6 +91,7 @@ pub struct References {
/// expressions using the specified operators, at least one of these operator comparisons returns
/// false or null
pub struct Exclusion {
pub name: String,
pub using: String,
pub columns: Vec<String>,
pub operation: String,
Expand Down
11 changes: 7 additions & 4 deletions src/postgres/def/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ pub struct TableDef {
pub columns: Vec<ColumnInfo>,

pub check_constraints: Vec<Check>,
pub unique_keys: Vec<Unique>,
pub references: Vec<References>,

pub of_type: Option<Type>,
pub not_null_constraints: Vec<NotNull>,
pub unique_constraints: Vec<Unique>,
pub primary_key_constraints: Vec<PrimaryKey>,
pub reference_constraints: Vec<References>,
pub exclusion_constraints: Vec<Exclusion>,
// FIXME: Duplication? TableInfo also have of_type
// pub of_type: Option<Type>,
// TODO:
// pub inherets: Vec<String>,
}
103 changes: 96 additions & 7 deletions src/postgres/def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ pub enum Type {

// Character types
/// Variable-length character array with limit
Varchar,
Varchar(StringAttr),
/// Fixed-length character array; blank padded
Char,
Char(StringAttr),
/// Variable, unlimited length character array
Text,

Expand All @@ -44,13 +44,15 @@ pub enum Type {

// Date/Time types
/// Date and time
Timestamp,
Timestamp(TimeAttr),
TimestampWithTimeZone(TimeAttr),
/// Date without time of day
Date,
/// Time without date
Time,
Time(TimeAttr),
TimeWithTimeZone(TimeAttr),
/// Time interval
Interval,
Interval(IntervalAttr),

/// One byte boolean value
Boolean,
Expand Down Expand Up @@ -86,7 +88,7 @@ pub enum Type {
MacAddr8,

/// Fixed length bit string
Bit,
Bit(BitAttr),

// Text search types
/// A sorted list of distincp lexemes which are words that have been normalized to merge different
Expand Down Expand Up @@ -152,8 +154,48 @@ impl Type {
"smallserial" | "serial2" => Type::SmallSerial,
"serial" | "serial4" => Type::Serial,
"bigserial" | "serial8" => Type::BigSerial,
"money" => Type::Money,
"character varying" | "varchar" => Type::Varchar(StringAttr::default()),
"character" | "char" => Type::Char(StringAttr::default()),
"text" => Type::Text,
"bytea" => Type::Bytea,
"timestamp" | "timestamp without time zone" => Type::Timestamp(TimeAttr::default()),
"timestamp with time zone" => Type::TimestampWithTimeZone(TimeAttr::default()),
"date" => Type::Date,
"time" | "time without time zone" => Type::Time(TimeAttr::default()),
"time with time zone" => Type::TimeWithTimeZone(TimeAttr::default()),
"interval" => Type::Interval(IntervalAttr::default()),
"boolean" => Type::Boolean,
// "" => Type::Enum,
"point" => Type::Point,
"line" => Type::Line,
"lseg" => Type::Lseg,
"box" => Type::Box,
"path" => Type::Path,
"polygon" => Type::Polygon,
"circle" => Type::Circle,
"cidr" => Type::Cidr,
"inet" => Type::Inet,
"macaddr" => Type::MacAddr,
"macaddr8" => Type::MacAddr8,
"bit" => Type::Bit(BitAttr::default()),
"tsvector" => Type::TsVector,
"tsquery" => Type::TsQuery,
"uuid" => Type::Uuid,
"xml" => Type::Xml,
"json" => Type::Json,
"array" => Type::Array,
// "" => Type::Composite,
"int4range" => Type::Int4Range,
"int8range" => Type::Int8Range,
"numrange" => Type::NumRange,
"tsrange" => Type::TsRange,
"tstzrange" => Type::TsTzRange,
"daterange" => Type::DateRange,
// "" => Type::Domain,
"pg_lsn" => Type::PgLsn,

_ => Type::Unknown(format!("{} is unknown or unimplemented", name)),
_ => Type::Unknown(name.to_owned()),
}
}
}
Expand All @@ -170,8 +212,55 @@ pub struct ArbitraryPrecisionNumericAttr {
pub scale: Option<u16>,
}

#[derive(Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub struct StringAttr {
pub length: Option<u16>,
}

#[derive(Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub struct TimeAttr {
pub precision: Option<u16>,
}

#[derive(Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub struct IntervalAttr {
pub field: Option<String>,
pub precision: Option<u16>,
}

#[derive(Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub struct BitAttr {
pub length: Option<u16>,
}

impl Type {
pub fn has_numeric_attr(&self) -> bool {
matches!(self, Type::Numeric(_) | Type::Decimal(_))
}

pub fn has_string_attr(&self) -> bool {
matches!(self, Type::Varchar(_) | Type::Char(_))
}

pub fn has_time_attr(&self) -> bool {
matches!(
self,
Type::Timestamp(_)
| Type::TimestampWithTimeZone(_)
| Type::Time(_)
| Type::TimeWithTimeZone(_)
)
}

pub fn has_interval_attr(&self) -> bool {
matches!(self, Type::Interval(_))
}

pub fn has_bit_attr(&self) -> bool {
matches!(self, Type::Bit(_))
}
}
Loading

0 comments on commit fdfb9d8

Please sign in to comment.