Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/docs/ban-create-domain-with-constraint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
id: ban-create-domain-with-constraint
title: ban-create-domain-with-constraint
---

## problem

<!-- TODO -->

## solution

<!-- TODO -->

## links

<!-- TODO -->
1 change: 1 addition & 0 deletions docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ module.exports = {
"require-concurrent-index-creation",
"require-concurrent-index-deletion",
"transaction-nesting",
"ban-create-domain-with-constraint",
// generator::new-rule-above
],
},
Expand Down
5 changes: 5 additions & 0 deletions docs/src/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@ const rules = [
tags: ["schema"],
description: "Prevent forbidden use of transactions during concurrent index creation.",
},
{
name: "ban-create-domain-with-constraint",
tags: ["TODO"],
description: "TODO",
},
// generator::new-rule-above
]

Expand Down
10 changes: 10 additions & 0 deletions linter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extern crate lazy_static;
use crate::errors::CheckSqlError;
use crate::rules::adding_required_field;
use crate::rules::ban_concurrent_index_creation_in_transaction;
use crate::rules::ban_create_domain_with_constraint;
use crate::rules::ban_drop_not_null;
use crate::rules::prefer_big_int;
use crate::rules::prefer_identity;
Expand Down Expand Up @@ -119,6 +120,15 @@ lazy_static! {
),
],
},
SquawkRule {
name: RuleViolationKind::BanCreateDomainWithConstraint,
func: ban_create_domain_with_constraint,
messages: vec![
ViolationMessage::Note(
"Domains with constraints have poor support for online migrations".into()
),
],
},
SquawkRule {
name: RuleViolationKind::BanDropColumn,
func: ban_drop_column,
Expand Down
66 changes: 66 additions & 0 deletions linter/src/rules/ban_create_domain_with_constraint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use crate::{
versions::Version,
violations::{RuleViolation, RuleViolationKind},
};

use squawk_parser::ast::{RawStmt, Stmt};

#[must_use]
pub fn ban_create_domain_with_constraint(
tree: &[RawStmt],
_pg_version: Option<Version>,
_assume_in_transaction: bool,
) -> Vec<RuleViolation> {
let mut errs = vec![];
for raw_stmt in tree {
match &raw_stmt.stmt {
Stmt::CreateDomainStmt(stmt) if stmt.constraints.len() > 0 => {
println!("X: {:?}", &raw_stmt.stmt);
println!("{}", serde_json::to_string_pretty(&stmt).unwrap());
errs.push(RuleViolation::new(
RuleViolationKind::BanCreateDomainWithConstraint,
raw_stmt.into(),
None,
));
}
_ => continue,
}
}
errs
}

#[cfg(test)]
mod test_rules {
use crate::{
check_sql_with_rule,
violations::{RuleViolation, RuleViolationKind},
};
use insta::assert_debug_snapshot;

fn lint_sql(sql: &str) -> Vec<RuleViolation> {
check_sql_with_rule(
sql,
&RuleViolationKind::BanCreateDomainWithConstraint,
None,
false,
)
.unwrap()
}

#[test]
fn ban_create_domain_without_constraint_is_ok() {
let sql = r#"
CREATE DOMAIN domain_name_1 AS TEXT;
CREATE DOMAIN domain_name_2 AS CHARACTER VARYING;
"#;
assert_eq!(lint_sql(sql), vec![]);
}

#[test]
fn ban_create_domain_with_constraint_works() {
let sql = r#"
CREATE DOMAIN domain_name_3 AS NUMERIC(15,5) CHECK (value > 0);
"#;
assert_debug_snapshot!(lint_sql(sql));
}
}
2 changes: 2 additions & 0 deletions linter/src/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,5 @@ pub mod adding_required_field;
pub use adding_required_field::*;
pub mod ban_concurrent_index_creation_in_transaction;
pub use ban_concurrent_index_creation_in_transaction::*;
pub mod ban_create_domain_with_constraint;
pub use ban_create_domain_with_constraint::*;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
source: linter/src/rules/ban_create_domain_with_constraint.rs
expression: lint_sql(sql)

---
[
RuleViolation {
kind: BanCreateDomainWithConstraint,
span: Span {
start: 0,
len: Some(
67,
),
},
messages: [
Note(
"Domains with constraints have poor support for online migrations",
),
],
},
]
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
source: linter/src/lib.rs
expression: rule_names

---
[
"adding-field-with-default",
Expand All @@ -10,6 +11,7 @@ expression: rule_names
"adding-serial-primary-key-field",
"ban-char-field",
"ban-concurrent-index-creation-in-transaction",
"ban-create-domain-with-constraint",
"ban-drop-column",
"ban-drop-database",
"ban-drop-not-null",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
source: linter/src/lib.rs
expression: "rule_names.join(\"\\n\")"

---
adding-field-with-default
adding-foreign-key-constraint
Expand All @@ -9,6 +10,7 @@ adding-required-field
adding-serial-primary-key-field
ban-char-field
ban-concurrent-index-creation-in-transaction
ban-create-domain-with-constraint
ban-drop-column
ban-drop-database
ban-drop-not-null
Expand Down
2 changes: 2 additions & 0 deletions linter/src/violations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ pub enum RuleViolationKind {
AddingRequiredField,
#[serde(rename = "ban-concurrent-index-creation-in-transaction")]
BanConcurrentIndexCreationInTransaction,
#[serde(rename = "ban-create-domain-with-constraint")]
BanCreateDomainWithConstraint,
// generator::new-rule-above
}

Expand Down
12 changes: 11 additions & 1 deletion parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,16 @@ pub struct AlterTableStmt {
pub missing_ok: bool,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct CreateDomainStmt {
#[serde(rename = "domainname")]
pub domain_name: Vec<QualifiedName>,
#[serde(rename = "typeName")]
pub typename: Value,
#[serde(default)]
pub constraints: Vec<Value>,
}

/// Source: <https://github.com/pganalyze/libpg_query/blob/b2790f8140721ff7f047167ecd7d44267b0a3880/src/pg_query_enum_defs.c#L249-L257>
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub enum DropBehavior {
Expand Down Expand Up @@ -928,7 +938,7 @@ pub enum Stmt {
CreateSeqStmt(Value),
AlterSeqStmt(Value),
DefineStmt(Value),
CreateDomainStmt(Value),
CreateDomainStmt(CreateDomainStmt),
CreateOpClassStmt(Value),
CreateOpFamilyStmt(Value),
AlterOpFamilyStmt(Value),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,38 @@
---
source: parser/src/parse.rs
expression: res

---
Ok(
[
RawStmt {
stmt: CreateDomainStmt(
Object({
"constraints": Array([
CreateDomainStmt {
domain_name: [
QualifiedName {
string: PGString {
sval: "us_postal_code",
},
},
],
typename: Object({
"location": Number(
33,
),
"names": Array([
Object({
"String": Object({
"sval": String(
"text",
),
}),
}),
]),
"typemod": Number(
-1,
),
}),
constraints: [
Object({
"Constraint": Object({
"contype": String(
Expand Down Expand Up @@ -127,34 +152,8 @@ Ok(
}),
}),
}),
]),
"domainname": Array([
Object({
"String": Object({
"sval": String(
"us_postal_code",
),
}),
}),
]),
"typeName": Object({
"location": Number(
33,
),
"names": Array([
Object({
"String": Object({
"sval": String(
"text",
),
}),
}),
]),
"typemod": Number(
-1,
),
}),
}),
],
},
),
stmt_location: 0,
stmt_len: Some(
Expand Down
Loading