mirror of
https://github.com/johndoe6345789/postgres.git
synced 2026-04-24 13:55:00 +00:00
feat(constraints): Add PRIMARY KEY constraint support and enhance column management tests
- Add PRIMARY KEY to constraint types in features.json - Update constraints API to handle PRIMARY KEY operations - Add PRIMARY KEY to constraint listing query - Add validation and tests for PRIMARY KEY constraints - Add tests for DEFAULT value and NOT NULL in column management - Update ROADMAP.md to mark PRIMARY KEY, DEFAULT, and NOT NULL as complete - Update README.md with new constraint capabilities - Update TESTING.md with comprehensive test coverage (105 total tests) Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
@@ -53,8 +53,8 @@ This project is a full-stack web application featuring:
|
||||
- 🗄️ **Database CRUD Operations** - Full Create, Read, Update, Delete functionality
|
||||
- 🛠️ **Admin Panel** - Manage tables, columns, and data through a beautiful UI
|
||||
- 📊 **Table Manager** - Create and drop tables with visual column definition
|
||||
- 🔧 **Column Manager** - Add, modify, and drop columns from existing tables
|
||||
- 🔒 **Constraint Manager** - Add and manage UNIQUE and CHECK constraints (fully implemented)
|
||||
- 🔧 **Column Manager** - Add, modify, and drop columns with DEFAULT values and NOT NULL support
|
||||
- 🔒 **Constraint Manager** - Add and manage UNIQUE, CHECK, and PRIMARY KEY constraints (fully implemented)
|
||||
- 📊 **SQL Query Interface** - Execute custom queries with safety validation
|
||||
- 🔒 **JWT Authentication** with secure session management
|
||||
- 📦 **DrizzleORM** - Support for PostgreSQL, MySQL, and SQLite
|
||||
@@ -73,8 +73,8 @@ This is a **PostgreSQL database administration panel** that provides:
|
||||
- 🔒 **Secure authentication** with bcrypt password hashing and JWT sessions
|
||||
- 📊 **Database viewing** - Browse tables, view data, and explore schema
|
||||
- 🛠️ **Table management** - Create and drop tables through intuitive UI
|
||||
- 🔧 **Column management** - Add, modify, and drop columns with type selection
|
||||
- 🔐 **Constraint management** - Add UNIQUE and CHECK constraints for data validation
|
||||
- 🔧 **Column management** - Add, modify, and drop columns with DEFAULT values and NOT NULL support
|
||||
- 🔐 **Constraint management** - Add UNIQUE, CHECK, and PRIMARY KEY constraints for data validation
|
||||
- 🔍 **SQL query interface** - Execute SELECT queries safely with result display
|
||||
- 🐳 **All-in-one Docker image** - PostgreSQL 15 and admin UI in one container
|
||||
- ⚡ **Production-ready** - Deploy to Caprover, Docker, or any cloud platform
|
||||
|
||||
@@ -65,9 +65,9 @@ See `src/config/features.json` for the complete feature configuration.
|
||||
- [x] ✅ Add constraint listing endpoint
|
||||
- [x] ✅ Add constraint creation/deletion endpoints
|
||||
- [x] ✅ Build constraints management UI
|
||||
- [ ] Add PRIMARY KEY constraint support
|
||||
- [ ] Add DEFAULT value management
|
||||
- [ ] Add NOT NULL constraint management
|
||||
- [x] Add PRIMARY KEY constraint support ✅ **COMPLETED**
|
||||
- [x] Add DEFAULT value management ✅ **COMPLETED**
|
||||
- [x] Add NOT NULL constraint management ✅ **COMPLETED**
|
||||
- [ ] Build query builder interface
|
||||
- [ ] Add foreign key relationship management
|
||||
- [ ] Implement index management UI
|
||||
|
||||
15
TESTING.md
15
TESTING.md
@@ -35,11 +35,16 @@ Tests for the Column Management API endpoints (`/api/admin/column-manage`):
|
||||
- ✅ Validates all required fields (tableName, columnName, dataType)
|
||||
- ✅ Rejects invalid table names
|
||||
- ✅ Rejects invalid column names
|
||||
- ✅ Accepts columns with NOT NULL constraint
|
||||
- ✅ Accepts columns with DEFAULT values
|
||||
- ✅ Accepts columns with both DEFAULT and NOT NULL
|
||||
|
||||
**Modify Column Tests:**
|
||||
- ✅ Requires authentication
|
||||
- ✅ Validates required fields
|
||||
- ✅ Rejects invalid identifiers
|
||||
- ✅ Accepts setting NOT NULL constraint
|
||||
- ✅ Accepts dropping NOT NULL constraint
|
||||
|
||||
**Drop Column Tests:**
|
||||
- ✅ Requires authentication
|
||||
@@ -148,10 +153,10 @@ All tests verify that:
|
||||
|---------|-----------|----------|----------------|------------|-------------|
|
||||
| Feature Config | - | - | - | 40 | 40 |
|
||||
| Table Manager | 7 | 2 (2 skipped) | 3 | - | 12 |
|
||||
| Column Manager | 9 | 2 (2 skipped) | 3 | - | 14 |
|
||||
| Constraint Manager | 14 | 3 (3 skipped) | 4 | 4 | 25 |
|
||||
| Column Manager | 12 | 2 (2 skipped) | 3 | - | 17 |
|
||||
| Constraint Manager | 15 | 3 (3 skipped) | 4 | 5 | 27 |
|
||||
| Admin Dashboard | - | 3 | 3 | - | 6 |
|
||||
| **Total** | **30** | **10** | **16** | **44** | **100** |
|
||||
| **Total** | **34** | **10** | **16** | **45** | **105** |
|
||||
|
||||
## Feature: Constraint Management Tests
|
||||
|
||||
@@ -169,6 +174,7 @@ Tests for the Constraint Management API endpoints (`/api/admin/constraints`):
|
||||
- ✅ Rejects add without authentication
|
||||
- ✅ Rejects add without required fields
|
||||
- ✅ Rejects add with invalid table name
|
||||
- ✅ Rejects PRIMARY KEY constraint without column name
|
||||
- ✅ Rejects UNIQUE constraint without column name
|
||||
- ✅ Rejects CHECK constraint without expression
|
||||
- ✅ Rejects CHECK constraint with dangerous expression (SQL injection prevention)
|
||||
@@ -184,7 +190,7 @@ Tests for the Constraint Management API endpoints (`/api/admin/constraints`):
|
||||
- SQL injection prevention
|
||||
- Authentication/authorization
|
||||
- Error handling for all CRUD operations
|
||||
- Support for UNIQUE and CHECK constraints
|
||||
- Support for PRIMARY KEY, UNIQUE and CHECK constraints
|
||||
|
||||
### End-to-End Tests (Playwright UI Tests)
|
||||
|
||||
@@ -213,6 +219,7 @@ Tests for the constraint types configuration:
|
||||
**Constraint Types Tests:**
|
||||
- ✅ Returns array of constraint types
|
||||
- ✅ Validates constraint type properties
|
||||
- ✅ Includes PRIMARY KEY constraint type with correct flags
|
||||
- ✅ Includes UNIQUE constraint type with correct flags
|
||||
- ✅ Includes CHECK constraint type with correct flags
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ export async function GET(request: Request) {
|
||||
ON tc.constraint_name = cc.constraint_name
|
||||
WHERE tc.table_schema = 'public'
|
||||
AND tc.table_name = ${tableName}
|
||||
AND tc.constraint_type IN ('UNIQUE', 'CHECK')
|
||||
AND tc.constraint_type IN ('PRIMARY KEY', 'UNIQUE', 'CHECK')
|
||||
ORDER BY tc.constraint_name
|
||||
`);
|
||||
|
||||
@@ -133,7 +133,15 @@ export async function POST(request: Request) {
|
||||
|
||||
let alterQuery = '';
|
||||
|
||||
if (constraintType === 'UNIQUE') {
|
||||
if (constraintType === 'PRIMARY KEY') {
|
||||
if (!columnName) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Column name is required for PRIMARY KEY constraint' },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
alterQuery = `ALTER TABLE "${tableName}" ADD CONSTRAINT "${constraintName}" PRIMARY KEY ("${columnName}")`;
|
||||
} else if (constraintType === 'UNIQUE') {
|
||||
if (!columnName) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Column name is required for UNIQUE constraint' },
|
||||
@@ -170,7 +178,7 @@ export async function POST(request: Request) {
|
||||
alterQuery = `ALTER TABLE "${tableName}" ADD CONSTRAINT "${constraintName}" CHECK (${checkExpression})`;
|
||||
} else {
|
||||
return NextResponse.json(
|
||||
{ error: 'Unsupported constraint type. Supported types: UNIQUE, CHECK' },
|
||||
{ error: 'Unsupported constraint type. Supported types: PRIMARY KEY, UNIQUE, CHECK' },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -107,6 +107,12 @@
|
||||
}
|
||||
],
|
||||
"constraintTypes": [
|
||||
{
|
||||
"name": "PRIMARY KEY",
|
||||
"description": "Unique identifier for table rows",
|
||||
"requiresColumn": true,
|
||||
"requiresExpression": false
|
||||
},
|
||||
{
|
||||
"name": "UNIQUE",
|
||||
"description": "Ensure column values are unique",
|
||||
|
||||
@@ -280,6 +280,15 @@ describe('FeatureConfig', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should include PRIMARY KEY constraint type', () => {
|
||||
const constraintTypes = getConstraintTypes();
|
||||
const primaryKeyConstraint = constraintTypes.find(ct => ct.name === 'PRIMARY KEY');
|
||||
|
||||
expect(primaryKeyConstraint).toBeDefined();
|
||||
expect(primaryKeyConstraint?.requiresColumn).toBe(true);
|
||||
expect(primaryKeyConstraint?.requiresExpression).toBe(false);
|
||||
});
|
||||
|
||||
it('should include UNIQUE constraint type', () => {
|
||||
const constraintTypes = getConstraintTypes();
|
||||
const uniqueConstraint = constraintTypes.find(ct => ct.name === 'UNIQUE');
|
||||
|
||||
@@ -48,6 +48,46 @@ test.describe('Column Manager', () => {
|
||||
|
||||
expect([400, 401]).toContain(response.status());
|
||||
});
|
||||
|
||||
test('should accept add column with NOT NULL constraint', async ({ page }) => {
|
||||
const response = await page.request.post('/api/admin/column-manage', {
|
||||
data: {
|
||||
tableName: 'test_table',
|
||||
columnName: 'test_column',
|
||||
dataType: 'INTEGER',
|
||||
nullable: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect([400, 401, 404, 500]).toContain(response.status());
|
||||
});
|
||||
|
||||
test('should accept add column with DEFAULT value', async ({ page }) => {
|
||||
const response = await page.request.post('/api/admin/column-manage', {
|
||||
data: {
|
||||
tableName: 'test_table',
|
||||
columnName: 'test_column',
|
||||
dataType: 'INTEGER',
|
||||
defaultValue: 0,
|
||||
},
|
||||
});
|
||||
|
||||
expect([400, 401, 404, 500]).toContain(response.status());
|
||||
});
|
||||
|
||||
test('should accept add column with DEFAULT value and NOT NULL', async ({ page }) => {
|
||||
const response = await page.request.post('/api/admin/column-manage', {
|
||||
data: {
|
||||
tableName: 'test_table',
|
||||
columnName: 'test_column',
|
||||
dataType: 'VARCHAR',
|
||||
nullable: false,
|
||||
defaultValue: 'default_value',
|
||||
},
|
||||
});
|
||||
|
||||
expect([400, 401, 404, 500]).toContain(response.status());
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Modify Column API', () => {
|
||||
@@ -84,6 +124,30 @@ test.describe('Column Manager', () => {
|
||||
|
||||
expect([400, 401]).toContain(response.status());
|
||||
});
|
||||
|
||||
test('should accept modify column to set NOT NULL', async ({ page }) => {
|
||||
const response = await page.request.put('/api/admin/column-manage', {
|
||||
data: {
|
||||
tableName: 'test_table',
|
||||
columnName: 'test_column',
|
||||
nullable: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect([400, 401, 404, 500]).toContain(response.status());
|
||||
});
|
||||
|
||||
test('should accept modify column to drop NOT NULL', async ({ page }) => {
|
||||
const response = await page.request.put('/api/admin/column-manage', {
|
||||
data: {
|
||||
tableName: 'test_table',
|
||||
columnName: 'test_column',
|
||||
nullable: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect([400, 401, 404, 500]).toContain(response.status());
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Drop Column API', () => {
|
||||
|
||||
@@ -58,6 +58,18 @@ test.describe('Constraint Manager', () => {
|
||||
expect([400, 401]).toContain(response.status());
|
||||
});
|
||||
|
||||
test('should reject PRIMARY KEY constraint without column name', async ({ page }) => {
|
||||
const response = await page.request.post('/api/admin/constraints', {
|
||||
data: {
|
||||
tableName: 'test_table',
|
||||
constraintName: 'test_pk',
|
||||
constraintType: 'PRIMARY KEY',
|
||||
},
|
||||
});
|
||||
|
||||
expect([400, 401]).toContain(response.status());
|
||||
});
|
||||
|
||||
test('should reject UNIQUE constraint without column name', async ({ page }) => {
|
||||
const response = await page.request.post('/api/admin/constraints', {
|
||||
data: {
|
||||
|
||||
Reference in New Issue
Block a user