constraints: CHECK-violation friendly error + typing-surface matrix (ADR-0029 §10)
Completes ADR-0029's implementation: the friendly-error layer now names the rule a CHECK violation broke, and the typing-surface matrix covers the whole constraint grammar. CHECK-violation friendly error (ADR-0029 §10): - enrich_dsl_failure gains a CHECK branch — it reads the column from the engine's `CHECK constraint failed: <column>` message, then resolves the table, the offending value, and the column's compiled CHECK expression. - FailureContext / TranslateContext carry the resolved check_rule; translate_check renders "the value <v> breaks the rule `<rule>`" when it is known, falling back to the plain hint otherwise. Typing-surface matrix: a new `constraints` submodule, 14 cells covering the create-table / add-column constraint suffix and the add-constraint / drop-constraint commands (174 → 188). 16 tests added (1 translate unit, 1 enrichment integration, 14 matrix cells).
This commit is contained in:
+63
@@ -0,0 +1,63 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"add column to Customers: note (text) \" cursor=37"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "add column to Customers: note (text) ",
|
||||
cursor: 37,
|
||||
state: Valid,
|
||||
hint: Some(
|
||||
Candidates {
|
||||
items: [
|
||||
Candidate {
|
||||
text: "not",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "unique",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "default",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "check",
|
||||
kind: Keyword,
|
||||
},
|
||||
],
|
||||
selected: None,
|
||||
},
|
||||
),
|
||||
completion: Some(
|
||||
Completion {
|
||||
replaced_range: (
|
||||
37,
|
||||
37,
|
||||
),
|
||||
partial_prefix: "",
|
||||
candidates: [
|
||||
Candidate {
|
||||
text: "not",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "unique",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "default",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "check",
|
||||
kind: Keyword,
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
parse_result: Ok(
|
||||
"AddColumn",
|
||||
),
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"add column to Customers: note (text) check (note like 'A%')\" cursor=59"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "add column to Customers: note (text) check (note like 'A%')",
|
||||
cursor: 59,
|
||||
state: Valid,
|
||||
hint: Some(
|
||||
Prose(
|
||||
"no such column `note` on table `Customers`",
|
||||
),
|
||||
),
|
||||
completion: Some(
|
||||
Completion {
|
||||
replaced_range: (
|
||||
59,
|
||||
59,
|
||||
),
|
||||
partial_prefix: "",
|
||||
candidates: [
|
||||
Candidate {
|
||||
text: "not",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "unique",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "default",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "check",
|
||||
kind: Keyword,
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
parse_result: Ok(
|
||||
"AddColumn",
|
||||
),
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"add constraint unique to Orders.\" cursor=32"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "add constraint unique to Orders.",
|
||||
cursor: 32,
|
||||
state: IncompleteAtEof,
|
||||
hint: Some(
|
||||
Candidates {
|
||||
items: [
|
||||
Candidate {
|
||||
text: "CustId",
|
||||
kind: Identifier,
|
||||
},
|
||||
Candidate {
|
||||
text: "OrderId",
|
||||
kind: Identifier,
|
||||
},
|
||||
Candidate {
|
||||
text: "Total",
|
||||
kind: Identifier,
|
||||
},
|
||||
],
|
||||
selected: None,
|
||||
},
|
||||
),
|
||||
completion: Some(
|
||||
Completion {
|
||||
replaced_range: (
|
||||
32,
|
||||
32,
|
||||
),
|
||||
partial_prefix: "",
|
||||
candidates: [
|
||||
Candidate {
|
||||
text: "CustId",
|
||||
kind: Identifier,
|
||||
},
|
||||
Candidate {
|
||||
text: "OrderId",
|
||||
kind: Identifier,
|
||||
},
|
||||
Candidate {
|
||||
text: "Total",
|
||||
kind: Identifier,
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
parse_result: Err(
|
||||
"Invalid(at_eof)",
|
||||
),
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"add constraint \" cursor=15"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "add constraint ",
|
||||
cursor: 15,
|
||||
state: IncompleteAtEof,
|
||||
hint: Some(
|
||||
Candidates {
|
||||
items: [
|
||||
Candidate {
|
||||
text: "not",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "unique",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "default",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "check",
|
||||
kind: Keyword,
|
||||
},
|
||||
],
|
||||
selected: None,
|
||||
},
|
||||
),
|
||||
completion: Some(
|
||||
Completion {
|
||||
replaced_range: (
|
||||
15,
|
||||
15,
|
||||
),
|
||||
partial_prefix: "",
|
||||
candidates: [
|
||||
Candidate {
|
||||
text: "not",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "unique",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "default",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "check",
|
||||
kind: Keyword,
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
parse_result: Err(
|
||||
"Invalid(at_eof)",
|
||||
),
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"add constraint not null to \" cursor=27"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "add constraint not null to ",
|
||||
cursor: 27,
|
||||
state: IncompleteAtEof,
|
||||
hint: Some(
|
||||
Candidates {
|
||||
items: [
|
||||
Candidate {
|
||||
text: "Customers",
|
||||
kind: Identifier,
|
||||
},
|
||||
Candidate {
|
||||
text: "Orders",
|
||||
kind: Identifier,
|
||||
},
|
||||
],
|
||||
selected: None,
|
||||
},
|
||||
),
|
||||
completion: Some(
|
||||
Completion {
|
||||
replaced_range: (
|
||||
27,
|
||||
27,
|
||||
),
|
||||
partial_prefix: "",
|
||||
candidates: [
|
||||
Candidate {
|
||||
text: "Customers",
|
||||
kind: Identifier,
|
||||
},
|
||||
Candidate {
|
||||
text: "Orders",
|
||||
kind: Identifier,
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
parse_result: Err(
|
||||
"Invalid(at_eof)",
|
||||
),
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"add \" cursor=4"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "add ",
|
||||
cursor: 4,
|
||||
state: IncompleteAtEof,
|
||||
hint: Some(
|
||||
Candidates {
|
||||
items: [
|
||||
Candidate {
|
||||
text: "column",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "index",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "constraint",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "1:n",
|
||||
kind: Keyword,
|
||||
},
|
||||
],
|
||||
selected: None,
|
||||
},
|
||||
),
|
||||
completion: Some(
|
||||
Completion {
|
||||
replaced_range: (
|
||||
4,
|
||||
4,
|
||||
),
|
||||
partial_prefix: "",
|
||||
candidates: [
|
||||
Candidate {
|
||||
text: "column",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "index",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "constraint",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "1:n",
|
||||
kind: Keyword,
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
parse_result: Err(
|
||||
"Invalid(at_eof)",
|
||||
),
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"drop \" cursor=5"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "drop ",
|
||||
cursor: 5,
|
||||
state: IncompleteAtEof,
|
||||
hint: Some(
|
||||
Candidates {
|
||||
items: [
|
||||
Candidate {
|
||||
text: "column",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "relationship",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "table",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "index",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "constraint",
|
||||
kind: Keyword,
|
||||
},
|
||||
],
|
||||
selected: None,
|
||||
},
|
||||
),
|
||||
completion: Some(
|
||||
Completion {
|
||||
replaced_range: (
|
||||
5,
|
||||
5,
|
||||
),
|
||||
partial_prefix: "",
|
||||
candidates: [
|
||||
Candidate {
|
||||
text: "column",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "relationship",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "table",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "index",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "constraint",
|
||||
kind: Keyword,
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
parse_result: Err(
|
||||
"Invalid(at_eof)",
|
||||
),
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"add constraint check (Total >= 0) to Orders.Total\" cursor=49"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "add constraint check (Total >= 0) to Orders.Total",
|
||||
cursor: 49,
|
||||
state: Valid,
|
||||
hint: Some(
|
||||
Prose(
|
||||
"Submit with Enter",
|
||||
),
|
||||
),
|
||||
completion: None,
|
||||
parse_result: Ok(
|
||||
"AddConstraint",
|
||||
),
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"add constraint default 0 to Orders.Total\" cursor=40"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "add constraint default 0 to Orders.Total",
|
||||
cursor: 40,
|
||||
state: Valid,
|
||||
hint: Some(
|
||||
Prose(
|
||||
"Submit with Enter",
|
||||
),
|
||||
),
|
||||
completion: None,
|
||||
parse_result: Ok(
|
||||
"AddConstraint",
|
||||
),
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"add constraint not null to Customers.Name\" cursor=41"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "add constraint not null to Customers.Name",
|
||||
cursor: 41,
|
||||
state: Valid,
|
||||
hint: Some(
|
||||
Prose(
|
||||
"Submit with Enter",
|
||||
),
|
||||
),
|
||||
completion: None,
|
||||
parse_result: Ok(
|
||||
"AddConstraint",
|
||||
),
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"drop constraint unique from Customers.Name\" cursor=42"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "drop constraint unique from Customers.Name",
|
||||
cursor: 42,
|
||||
state: Valid,
|
||||
hint: Some(
|
||||
Prose(
|
||||
"Submit with Enter",
|
||||
),
|
||||
),
|
||||
completion: None,
|
||||
parse_result: Ok(
|
||||
"DropConstraint",
|
||||
),
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"create table Ages with pk age(int) check (age >= 0)\" cursor=51"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "create table Ages with pk age(int) check (age >= 0)",
|
||||
cursor: 51,
|
||||
state: Valid,
|
||||
hint: Some(
|
||||
Prose(
|
||||
"Submit with Enter",
|
||||
),
|
||||
),
|
||||
completion: None,
|
||||
parse_result: Ok(
|
||||
"CreateTable",
|
||||
),
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"create table Books with pk isbn(text) default '000'\" cursor=51"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "create table Books with pk isbn(text) default '000'",
|
||||
cursor: 51,
|
||||
state: Valid,
|
||||
hint: Some(
|
||||
Prose(
|
||||
"Submit with Enter",
|
||||
),
|
||||
),
|
||||
completion: None,
|
||||
parse_result: Ok(
|
||||
"CreateTable",
|
||||
),
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
---
|
||||
source: tests/typing_surface/constraints.rs
|
||||
description: "input=\"drop constraint \" cursor=16"
|
||||
expression: "& a"
|
||||
---
|
||||
Assessment {
|
||||
input: "drop constraint ",
|
||||
cursor: 16,
|
||||
state: IncompleteAtEof,
|
||||
hint: Some(
|
||||
Candidates {
|
||||
items: [
|
||||
Candidate {
|
||||
text: "not",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "unique",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "default",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "check",
|
||||
kind: Keyword,
|
||||
},
|
||||
],
|
||||
selected: None,
|
||||
},
|
||||
),
|
||||
completion: Some(
|
||||
Completion {
|
||||
replaced_range: (
|
||||
16,
|
||||
16,
|
||||
),
|
||||
partial_prefix: "",
|
||||
candidates: [
|
||||
Candidate {
|
||||
text: "not",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "unique",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "default",
|
||||
kind: Keyword,
|
||||
},
|
||||
Candidate {
|
||||
text: "check",
|
||||
kind: Keyword,
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
parse_result: Err(
|
||||
"Invalid(at_eof)",
|
||||
),
|
||||
}
|
||||
Reference in New Issue
Block a user