Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
3a04e5e
chore(dbml-parse): add npm command for linting
huydo862003 Oct 14, 2025
03d826c
doc(dbml-parse): minor correction to comment of NormalExpressionNode
huydo862003 Oct 14, 2025
c550de1
feat(dbml-parse): support constraint setting in validator
huydo862003 Oct 14, 2025
1149425
feat(dbml-parse): support constraint setting in binder
huydo862003 Oct 14, 2025
0efe858
fix(dbml-parse): incorrectly put the column setting validation logic …
huydo862003 Oct 15, 2025
9985944
feat(dbml-parse): support validation of constraint element
huydo862003 Oct 15, 2025
b834961
fix(dbml-parse): rename PKey to PrimaryKey
huydo862003 Oct 15, 2025
c1b63da
fix(dbml-parse): support constraints in TablePartial and binder, add …
huydo862003 Oct 15, 2025
03672cc
feat(dbml-parse): support interpreting constraints
huydo862003 Oct 15, 2025
6346b8d
feat(dbml-core): support constraints in model_structure
huydo862003 Oct 15, 2025
f2cbd43
fix(dbml-core): add constraintIds in exportChildIds in table model st…
huydo862003 Oct 15, 2025
5e3f1b8
feat(dbml-core): support constraints in dbml model exporter
huydo862003 Oct 15, 2025
ca5cf72
feat(dbml-core): support mysql model exporter
huydo862003 Oct 15, 2025
086c6f7
feat(dbml-parse): support constraints in oracle model exporter and fi…
huydo862003 Oct 15, 2025
48d2c94
test(dbml-core): mysql model exporter constraint test
huydo862003 Oct 15, 2025
57041e6
feat(dbml-core): support constraint in postgres model exporter
huydo862003 Oct 15, 2025
b421dd9
fix(dbml-core): dbml exporter incorrectly access constraints on field
huydo862003 Oct 15, 2025
2ca4e97
feat(dbml-parse): support constraints in mssql model exporter
huydo862003 Oct 15, 2025
f416cc9
fix(dbml-core): deduplicate named constraints inside table partials
huydo862003 Oct 15, 2025
88a6b49
feat(dbml-core): support constraints in mssql parser
huydo862003 Oct 16, 2025
0a74be0
test(dbml-core): constraint model structure tests
huydo862003 Oct 16, 2025
9cf7d95
feat(dbml-core): support constraints in mysql parser
huydo862003 Oct 16, 2025
16a3a20
feat(dbml-core): support constraints in postgresql parser & remove CO…
huydo862003 Oct 16, 2025
543edc3
test(dbml-core): update tests
huydo862003 Oct 16, 2025
3df44eb
fix(dbml-core): safely escape backticks in dbml exporter
huydo862003 Oct 16, 2025
3a79cd9
fix(dbml-core): no longer escape backticks in function expressions be…
huydo862003 Oct 16, 2025
0ed2e35
feat(dbml-core): support constraints in schemarb parser
huydo862003 Oct 16, 2025
3d0a7b3
feat(dbml-parse): support autocompletion related to constraints
huydo862003 Oct 16, 2025
3b47eba
test(dbml-core): readd old test
huydo862003 Oct 16, 2025
22d682e
chore(dbml-core): update types
huydo862003 Oct 17, 2025
cde6875
fix(dbml-parse): typo in error message
huydo862003 Oct 17, 2025
b8718ce
v3.15.0-alpha.0
huydo862003 Oct 17, 2025
05fce15
fix(dbml-parse): add constraints into getElementKind
huydo862003 Oct 20, 2025
97942ff
fix: lint & importing non-existent files
huydo862003 Oct 20, 2025
58a1d0b
fix(dbml-core): remove converting CHECK constraints into ENUM in DBML
huydo862003 Oct 22, 2025
e5253d1
test(dbml-core): update mssql test after removing support for parsing…
huydo862003 Oct 22, 2025
c211c24
fix(dbml-core): change expression field type in constraint.d.ts
huydo862003 Oct 22, 2025
65c5d50
test(dbml-core): mssql importer tests after removing support of conve…
huydo862003 Oct 22, 2025
ebd49d9
test(dbml-core): remove newline at the end of mssql test outputs
huydo862003 Oct 22, 2025
1048416
doc(dbml-core): comment on removing CONSTRAINT from plsql_unreserved_…
huydo862003 Oct 22, 2025
3ebb302
fix(dbml-core): use templated string in schemarb
huydo862003 Oct 22, 2025
e1d8c95
fix(dbml-cli): mssql tests related to removing support of converting …
huydo862003 Oct 22, 2025
95e05b2
doc: update dbml syntax
huydo862003 Oct 23, 2025
db01132
chore: revert package.json version
huydo862003 Oct 23, 2025
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
22 changes: 22 additions & 0 deletions dbml-homepage/docs/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ outlines the full syntax documentations of DBML.
- [Column Definition](#column-definition)
- [Column Settings](#column-settings)
- [Default Value](#default-value)
- [Constraint Definition](#constraint-definition)
- [Constraint Settings](#constraint-settings)
- [Index Definition](#index-definition)
- [Index Settings](#index-settings)
- [Relationships & Foreign Key Definitions](#relationships--foreign-key-definitions)
Expand Down Expand Up @@ -177,6 +179,7 @@ The list of column settings you can use:
- `unique`: mark the column unique
- `default: some_value`: set a default value of the column, please refer to the 'Default Value' section below
- `increment`: mark the column as auto-increment
- ``constraint: `check expression` ``: add a check expression to this column. Multiple constraints can be defined on a column. For constraints involving multiple columns, refer to the 'Constraints' section

**Note:** You can use a workaround for un-supported settings by adding the setting name into the column type name, such as `id "bigint unsigned" [pk]`

Expand All @@ -202,6 +205,25 @@ Table users {
rating integer [default: 10]
}
```
## Constraint Definition

Constraints allow users to specify custom checks on one or many columns. These checks can be used to enforce constraints on the possible values of one or many columns, which are otherwise impossible to express.

```text
Table users {
id integer
wealth integer
debt integer

constraints {
`debt + wealth >= 0` [name: 'chk_positive_money']
}
}
```

### Constraint Settings

- `name`: name of constraint

## Index Definition

Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,10 @@
Enum "users_pjs_enum" {
"created2"
"running2"
"done2"
"failure2"
}

Enum "users_pjs2_enum" {
"created2"
"running2"
"done2"
"failure2"
}

Enum "users_pg_enum" {
"male"
"female"
}

Enum "users_pg2_enum" {
"male2"
"female2"
}

Table "users" {
"id" int [pk]
"name" nvarchar(255)
"pjs" users_pjs_enum [not null]
"pjs2" users_pjs2_enum [not null]
"pg" users_pg_enum [not null]
"pg2" users_pg2_enum [not null]
"pjs" nvarchar(255) [not null, constraint: `[pjs] IN ('created2', 'running2', 'done2', 'failure2')`]
"pjs2" nvarchar(255) [not null, constraint: `[pjs2] IN ('created2', 'running2', 'done2', 'failure2')`]
"pg" nvarchar(255) [not null, constraint: `[pg] IN ('male', 'female')`]
"pg2" nvarchar(255) [not null, constraint: `[pg2] IN ('male2', 'female2')`]
}

Table "products" {
Expand All @@ -48,37 +24,13 @@ Ref:"ecommerce"."users"."id" < "schemaA"."products"."name"

Ref:"users"."id" < "schemaA"."locations"."name"

Enum "ecommerce"."users_ejs_enum" {
"created2"
"running2"
"done2"
"failure2"
}

Enum "ecommerce"."users_ejs2_enum" {
"created2"
"running2"
"done2"
"failure2"
}

Enum "ecommerce"."users_eg_enum" {
"male"
"female"
}

Enum "ecommerce"."users_eg2_enum" {
"male2"
"female2"
}

Table "ecommerce"."users" {
"id" int [pk]
"name" nvarchar(255)
"ejs" ecommerce.users_ejs_enum [not null]
"ejs2" ecommerce.users_ejs2_enum [not null]
"eg" ecommerce.users_eg_enum [not null]
"eg2" ecommerce.users_eg2_enum [not null]
"ejs" nvarchar(255) [not null, constraint: `[ejs] IN ('created2', 'running2', 'done2', 'failure2')`]
"ejs2" nvarchar(255) [not null, constraint: `[ejs2] IN ('created2', 'running2', 'done2', 'failure2')`]
"eg" nvarchar(255) [not null, constraint: `[eg] IN ('male', 'female')`]
"eg2" nvarchar(255) [not null, constraint: `[eg2] IN ('male2', 'female2')`]

Indexes {
(name, ejs) [name: "idx_1"]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
-- Comprehensive test for CHECK constraints in MSSQL
-- Tests various edge cases including brackets, quotes, complex expressions

-- Test 1: Column-level constraints with simple conditions
CREATE TABLE products (
id INT PRIMARY KEY,
price DECIMAL(10,2) CHECK (price > 0),
quantity INT CHECK (quantity >= 0),
discount DECIMAL(5,2) CHECK (discount >= 0 AND discount <= 100)
);

-- Test 2: Table-level named constraints
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
age INT,
salary DECIMAL(10,2),
CONSTRAINT chk_age CHECK (age >= 18 AND age <= 65),
CONSTRAINT chk_salary CHECK (salary > 0)
);

-- Test 3: Constraints with bracket-quoted identifiers (MSSQL style)
CREATE TABLE [special_table] (
[id] INT PRIMARY KEY,
[price] DECIMAL CHECK ([price] > 0),
[status] VARCHAR(20) CHECK ([status] IN ('active', 'inactive'))
);

-- Test 4: Constraints with complex expressions
CREATE TABLE [transactions] (
txn_id INT PRIMARY KEY,
amount DECIMAL(10,2),
fee DECIMAL(10,2),
total DECIMAL(10,2),
CHECK (total = amount + fee),
CHECK (amount > 0 OR fee > 0)
);

-- Test 5: Constraints with string comparisons and LIKE
CREATE TABLE contacts (
contact_id INT PRIMARY KEY,
email VARCHAR(100) CHECK (email LIKE '%@%'),
phone VARCHAR(20) CHECK (phone LIKE '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]')
);

-- Test 6: Constraints with IN operator and multiple values
CREATE TABLE orders (
order_id INT PRIMARY KEY,
status VARCHAR(20) CHECK (status IN ('pending', 'processing', 'shipped', 'delivered', 'cancelled')),
priority INT CHECK (priority IN (1, 2, 3, 4, 5))
);

-- Test 7: Constraints with NOT IN
CREATE TABLE users (
user_id INT PRIMARY KEY,
role VARCHAR(20) CHECK (role NOT IN ('banned', 'deleted', 'suspended'))
);

-- Test 8: Constraints with nested parentheses
CREATE TABLE ranges (
range_id INT PRIMARY KEY,
min_val INT,
max_val INT,
CHECK ((min_val >= 0) AND (max_val <= 100) AND (min_val < max_val))
);

-- Test 9: Constraints with CASE expressions
CREATE TABLE inventory (
item_id INT PRIMARY KEY,
stock INT,
status VARCHAR(20),
CHECK (
CASE
WHEN status = 'active' THEN stock
WHEN status = 'discontinued' THEN 0
ELSE 1
END >= 0
)
);

-- Test 10: Multiple constraints on same table (mixed column and table level)
CREATE TABLE accounts (
account_id INT PRIMARY KEY,
balance DECIMAL(15,2) CHECK (balance >= 0),
overdraft_limit DECIMAL(15,2) CHECK (overdraft_limit >= 0),
CONSTRAINT chk_balance_overdraft CHECK (balance + overdraft_limit >= 0)
);

-- Test 11: ALTER TABLE ADD CONSTRAINT (named)
CREATE TABLE shipments (
shipment_id INT PRIMARY KEY,
weight DECIMAL(10,2),
cost DECIMAL(10,2)
);

ALTER TABLE shipments ADD CONSTRAINT chk_weight CHECK (weight > 0);
ALTER TABLE shipments ADD CONSTRAINT chk_cost CHECK (cost >= 0);

-- Test 12: ALTER TABLE ADD CONSTRAINT (unnamed - MSSQL auto-generates name)
CREATE TABLE payments (
payment_id INT PRIMARY KEY,
amount DECIMAL(10,2)
);

ALTER TABLE payments ADD CHECK (amount > 0);

-- Test 13: Constraints with mathematical expressions
CREATE TABLE pricing (
price_id INT PRIMARY KEY,
base_price DECIMAL(10,2),
discount_pct DECIMAL(5,2),
final_price DECIMAL(10,2),
CHECK (final_price = base_price * (1 - discount_pct / 100))
);

-- Test 14: Constraints with COALESCE and NULL handling
CREATE TABLE settings (
setting_id INT PRIMARY KEY,
value VARCHAR(100),
default_value VARCHAR(100),
CHECK (COALESCE(value, default_value) IS NOT NULL)
);

-- Test 15: Constraints with date/time operations
CREATE TABLE bookings (
booking_id INT PRIMARY KEY,
check_in DATE,
check_out DATE,
CHECK (check_out > check_in),
CHECK (check_in >= GETDATE())
);

-- Test 16: Constraints with string functions
CREATE TABLE documents (
doc_id INT PRIMARY KEY,
title VARCHAR(200),
content VARCHAR(MAX),
CHECK (LEN(title) > 0),
CHECK (LEN(content) >= 10)
);

-- Test 17: Multiple CHECK constraints with OR conditions
CREATE TABLE events (
event_id INT PRIMARY KEY,
status VARCHAR(20),
cancelled BIT,
CHECK (status = 'active' OR status = 'completed' OR cancelled = 1)
);

-- Test 18: Constraints with BETWEEN
CREATE TABLE grades (
grade_id INT PRIMARY KEY,
score INT,
CHECK (score BETWEEN 0 AND 100)
);

-- Test 19: Named constraints with brackets in names
CREATE TABLE products_special (
product_id INT PRIMARY KEY,
code VARCHAR(50),
CONSTRAINT [chk_code_format] CHECK (code LIKE '[A-Z][A-Z][A-Z]-[0-9][0-9][0-9][0-9]')
);

-- Test 20: Constraint with bit column
CREATE TABLE features (
feature_id INT PRIMARY KEY,
is_enabled BIT,
is_premium BIT,
CHECK (is_enabled = 1 OR is_premium = 0)
);

-- Test 21: Constraints with ISNULL (MSSQL specific)
CREATE TABLE configs (
config_id INT PRIMARY KEY,
value1 INT,
value2 INT,
CHECK (ISNULL(value1, 0) + ISNULL(value2, 0) > 0)
);

-- Test 22: Multiple ALTER TABLE statements on same table
CREATE TABLE audit_log (
log_id INT PRIMARY KEY,
severity INT,
message VARCHAR(MAX)
);

ALTER TABLE audit_log ADD CONSTRAINT chk_severity_range CHECK (severity BETWEEN 1 AND 5);
ALTER TABLE audit_log ADD CONSTRAINT chk_message_length CHECK (LEN(message) > 0);
ALTER TABLE audit_log ADD CHECK (severity > 0);

-- Test 23: Constraints with comparison operators
CREATE TABLE limits (
limit_id INT PRIMARY KEY,
min_value INT,
max_value INT,
CHECK (max_value > min_value),
CHECK (min_value >= 0),
CHECK (max_value <= 1000)
);

-- Test 24: Constraints with != and <> operators
CREATE TABLE statuses (
status_id INT PRIMARY KEY,
current_status VARCHAR(20),
previous_status VARCHAR(20),
CHECK (current_status != previous_status),
CHECK (current_status <> '')
);

-- Test 25: Table with brackets in names and constraint expressions
CREATE TABLE [order_items] (
[order_item_id] INT PRIMARY KEY,
[order_id] INT,
[quantity] INT,
[unit_price] DECIMAL(10,2),
CHECK ([quantity] > 0),
CONSTRAINT [chk_price_positive] CHECK ([unit_price] > 0)
);

-- Test 26: Constraint with modulo operator
CREATE TABLE sequences (
seq_id INT PRIMARY KEY,
value INT,
CHECK (value % 2 = 0)
);

-- Test 27: Constraint with ABS function
CREATE TABLE temperatures (
temp_id INT PRIMARY KEY,
celsius DECIMAL(5,2),
CHECK (ABS(celsius) < 100)
);

-- Test 28: Constraint with CHARINDEX
CREATE TABLE emails (
email_id INT PRIMARY KEY,
email_address VARCHAR(100),
CHECK (CHARINDEX('@', email_address) > 0)
);

-- Test 29: Constraint with UPPER/LOWER
CREATE TABLE codes (
code_id INT PRIMARY KEY,
code VARCHAR(50),
CHECK (code = UPPER(code))
);

-- Test 30: Complex multi-column constraint
CREATE TABLE order_discounts (
discount_id INT PRIMARY KEY,
order_total DECIMAL(10,2),
discount_pct DECIMAL(5,2),
discount_amt DECIMAL(10,2),
final_total DECIMAL(10,2),
CONSTRAINT chk_discount_calculation CHECK (
(discount_amt = order_total * discount_pct / 100) AND
(final_total = order_total - discount_amt) AND
(final_total >= 0)
)
);
Loading
Loading