amiralek commited on
Commit
69125e3
·
verified ·
1 Parent(s): eecbb41

Deploy Mastra SQL agent

Browse files
.dockerignore ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ node_modules
2
+ .mastra
3
+ dist
4
+ .env
5
+ .env.*
6
+ *.db
7
+ *.db-*
8
+ .git
9
+ .gitignore
10
+ output.txt
.env.example ADDED
@@ -0,0 +1 @@
 
 
1
+ OPENAI_API_KEY=
.gitignore ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ output.txt
2
+ node_modules
3
+ dist
4
+ .mastra
5
+ .env.development
6
+ .env
7
+ *.db
8
+ *.db-*
CONTRIBUTING.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contributing
2
+
3
+ This repository is auto-generated from the [Mastra monorepo](https://github.com/mastra-ai/mastra). Pull requests opened here will be ignored.
4
+
5
+ To contribute:
6
+
7
+ 1. Fork the [Mastra monorepo](https://github.com/mastra-ai/mastra)
8
+ 2. Find this template in `templates/template-text-to-sql`
9
+ 3. Make your changes
10
+ 4. Open a pull request against the monorepo
11
+
12
+ A bot syncs accepted changes to this repository.
Dockerfile ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:22-bookworm-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY package.json package-lock.json ./
6
+
7
+ RUN npm ci
8
+
9
+ COPY . .
10
+
11
+ RUN npm run seed
12
+ RUN npm run build -- --studio
13
+
14
+ ENV PORT=7860
15
+ ENV MASTRA_HOST=0.0.0.0
16
+ ENV MASTRA_STUDIO_PATH=studio
17
+
18
+ EXPOSE 7860
19
+
20
+ WORKDIR /app/.mastra/output
21
+
22
+ CMD ["node", "index.mjs"]
README.md CHANGED
@@ -1,12 +1,15 @@
1
  ---
2
- title: My Sql Agent
3
- emoji: 👀
4
- colorFrom: yellow
5
  colorTo: indigo
6
  sdk: docker
 
7
  pinned: false
8
- license: apache-2.0
9
- short_description: Mastra AI agent converting conversational English into SQL.
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
1
  ---
2
+ title: My SQL Agent
3
+ emoji: 🗄️
4
+ colorFrom: blue
5
  colorTo: indigo
6
  sdk: docker
7
+ app_port: 7860
8
  pinned: false
 
 
9
  ---
10
 
11
+ # My SQL Agent
12
+
13
+ A Mastra Text-to-SQL agent deployed with Docker on Hugging Face Spaces.
14
+
15
+ The agent converts natural-language questions into safe SQLite `SELECT` queries and returns results from the sample company database.
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
package.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "template-text-to-sql",
3
+ "version": "1.0.0",
4
+ "description": "A Mastra template for natural language to SQL conversion using a local SQLite database.",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "seed": "tsx src/seed.ts",
8
+ "dev": "tsx src/seed.ts && mastra dev",
9
+ "build": "mastra build",
10
+ "start": "mastra start"
11
+ },
12
+ "license": "Apache-2.0",
13
+ "packageManager": "pnpm@11.3.0",
14
+ "type": "module",
15
+ "engines": {
16
+ "node": ">=22.13.0"
17
+ },
18
+ "dependencies": {
19
+ "@libsql/client": "^0.17.0",
20
+ "@mastra/core": "latest",
21
+ "@mastra/libsql": "latest",
22
+ "@mastra/loggers": "latest",
23
+ "@mastra/memory": "latest",
24
+ "@mastra/observability": "latest",
25
+ "zod": "^4.3.6"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^22.19.7",
29
+ "mastra": "latest",
30
+ "tsx": "^4.19.4",
31
+ "typescript": "^5.9.3"
32
+ }
33
+ }
src/mastra/agents/sql-agent.ts ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Agent } from '@mastra/core/agent';
2
+ import { Memory } from '@mastra/memory';
3
+ import { introspectDatabase } from '../tools/introspect-database';
4
+ import { executeSql } from '../tools/execute-sql';
5
+
6
+ export const sqlAgent = new Agent({
7
+ id: 'sql-agent',
8
+ name: 'SQL Agent',
9
+ model: 'opencode-go/deepseek-v4-flash',
10
+ instructions: `You are a SQL assistant that helps users query a local SQLite database using natural language.
11
+
12
+ ## Tools
13
+
14
+ You have two tools:
15
+ - **introspect-database**: Returns the database schema (tables, columns, types, foreign keys, row counts). Always call this first before writing any SQL so you know what's available.
16
+ - **execute-sql**: Runs a SELECT query and returns the results. Only SELECT queries are allowed.
17
+
18
+ ## Workflow
19
+
20
+ 1. When the user asks a question, first call introspect-database to understand the schema.
21
+ 2. Convert the user's natural language question into a SQLite-compatible SELECT query.
22
+ 3. Call execute-sql with the generated query.
23
+ 4. Present the results in a clear, readable format (use tables when appropriate).
24
+
25
+ ## SQL Guidelines
26
+
27
+ - Generate only SELECT queries. Never generate INSERT, UPDATE, DELETE, DROP, or any other mutating statements.
28
+ - Use SQLite syntax: LIKE instead of ILIKE, no SERIAL, use INTEGER PRIMARY KEY.
29
+ - Use proper JOINs when the question involves data across multiple tables.
30
+ - Use aggregate functions (COUNT, SUM, AVG, MIN, MAX) when the user asks for summaries.
31
+ - Use GROUP BY with aggregate functions.
32
+ - Use ORDER BY and LIMIT for "top N" style questions.
33
+ - Alias columns for readability (e.g., COUNT(*) AS total_employees).
34
+ - When the user's question is ambiguous, explain your interpretation before executing.
35
+
36
+ ## Response Format
37
+
38
+ - Show the SQL query you generated so the user can learn from it.
39
+ - Present results clearly. For tabular data, format as a markdown table.
40
+ - If the query returns no results, explain possible reasons.
41
+ - If you're unsure about the schema, call introspect-database again.`,
42
+ tools: { introspectDatabase, executeSql },
43
+ memory: new Memory(),
44
+ });
src/mastra/index.ts ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Mastra } from '@mastra/core/mastra';
2
+ import { PinoLogger } from '@mastra/loggers';
3
+ import { LibSQLStore } from '@mastra/libsql';
4
+ import {
5
+ Observability,
6
+ MastraStorageExporter,
7
+ MastraPlatformExporter,
8
+ SensitiveDataFilter,
9
+ } from '@mastra/observability';
10
+ import { sqlAgent } from './agents/sql-agent';
11
+
12
+ export const mastra = new Mastra({
13
+ agents: { sqlAgent },
14
+ storage: new LibSQLStore({
15
+ id: 'mastra-storage',
16
+ url: 'file:./mastra.db',
17
+ }),
18
+ logger: new PinoLogger({
19
+ name: 'Mastra Text-to-SQL',
20
+ level: 'info',
21
+ }),
22
+ observability: new Observability({
23
+ configs: {
24
+ default: {
25
+ serviceName: 'text-to-sql',
26
+ exporters: [new MastraStorageExporter(), new MastraPlatformExporter()],
27
+ spanOutputProcessors: [new SensitiveDataFilter()],
28
+ },
29
+ },
30
+ }),
31
+ });
src/mastra/tools/execute-sql.ts ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { createTool } from '@mastra/core/tools';
2
+ import { createClient } from '@libsql/client';
3
+ import { z } from 'zod';
4
+
5
+ const db = createClient({ url: 'file:./data.db' });
6
+
7
+ const BLOCKED_PATTERNS = [
8
+ /\b(INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|TRUNCATE|REPLACE)\b/i,
9
+ /\b(ATTACH|DETACH)\b/i,
10
+ /\b(PRAGMA)\b/i,
11
+ /;.*\S/, // multiple statements
12
+ ];
13
+
14
+ export const executeSql = createTool({
15
+ id: 'execute-sql',
16
+ description: 'Executes a read-only SQL SELECT query against the local SQLite database and returns the results.',
17
+ inputSchema: z.object({
18
+ query: z.string().describe('The SQL SELECT query to execute'),
19
+ }),
20
+ outputSchema: z.object({
21
+ rows: z.array(z.record(z.string(), z.unknown())).describe('Query result rows'),
22
+ rowCount: z.number().describe('Number of rows returned'),
23
+ }),
24
+ execute: async ({ query }) => {
25
+ const trimmed = query.trim().replace(/;$/, '');
26
+
27
+ for (const pattern of BLOCKED_PATTERNS) {
28
+ if (pattern.test(trimmed)) {
29
+ throw new Error('Only SELECT queries are allowed.');
30
+ }
31
+ }
32
+
33
+ if (!/^\s*SELECT\b/i.test(trimmed)) {
34
+ throw new Error('Query must start with SELECT.');
35
+ }
36
+
37
+ const result = await db.execute(trimmed);
38
+
39
+ return {
40
+ rows: result.rows as Record<string, unknown>[],
41
+ rowCount: result.rows.length,
42
+ };
43
+ },
44
+ });
src/mastra/tools/introspect-database.ts ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { createTool } from '@mastra/core/tools';
2
+ import { createClient } from '@libsql/client';
3
+ import { z } from 'zod';
4
+
5
+ const db = createClient({ url: 'file:./data.db' });
6
+
7
+ export const introspectDatabase = createTool({
8
+ id: 'introspect-database',
9
+ description:
10
+ 'Introspects the local SQLite database and returns a description of all tables, columns, foreign keys, and row counts.',
11
+ inputSchema: z.object({}),
12
+ outputSchema: z.object({
13
+ schema: z.string().describe('Human-readable database schema description'),
14
+ }),
15
+ execute: async () => {
16
+ const tables = await db.execute(
17
+ "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_litestream_%' ORDER BY name",
18
+ );
19
+
20
+ const lines: string[] = ['# Database Schema', ''];
21
+
22
+ for (const table of tables.rows) {
23
+ const tableName = table.name as string;
24
+
25
+ const columns = await db.execute(`PRAGMA table_info('${tableName}')`);
26
+ const foreignKeys = await db.execute(`PRAGMA foreign_key_list('${tableName}')`);
27
+ const countResult = await db.execute(`SELECT COUNT(*) as count FROM "${tableName}"`);
28
+ const rowCount = countResult.rows[0].count;
29
+
30
+ lines.push(`## ${tableName} (${rowCount} rows)`);
31
+ lines.push('');
32
+ lines.push('| Column | Type | Nullable | PK |');
33
+ lines.push('|--------|------|----------|----|');
34
+
35
+ for (const col of columns.rows) {
36
+ const nullable = col.notnull ? 'NO' : 'YES';
37
+ const pk = col.pk ? 'YES' : '';
38
+ lines.push(`| ${col.name} | ${col.type || 'ANY'} | ${nullable} | ${pk} |`);
39
+ }
40
+
41
+ if (foreignKeys.rows.length > 0) {
42
+ lines.push('');
43
+ lines.push('**Foreign Keys:**');
44
+ for (const fk of foreignKeys.rows) {
45
+ lines.push(`- ${fk.from} → ${fk.table}.${fk.to}`);
46
+ }
47
+ }
48
+
49
+ lines.push('');
50
+ }
51
+
52
+ return { schema: lines.join('\n') };
53
+ },
54
+ });
src/seed.ts ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { createClient } from '@libsql/client';
2
+ import { mkdirSync } from 'node:fs';
3
+
4
+ const PUBLIC_DIR = 'src/mastra/public';
5
+ const DB_PATH = `file:${PUBLIC_DIR}/data.db`;
6
+
7
+ async function seed() {
8
+ mkdirSync(PUBLIC_DIR, { recursive: true });
9
+ const client = createClient({ url: DB_PATH });
10
+
11
+ // Check if already seeded
12
+ const existing = await client.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='companies'");
13
+ if (existing.rows.length > 0) {
14
+ console.log('Database already seeded, skipping.');
15
+ return;
16
+ }
17
+
18
+ console.log('Seeding database...');
19
+
20
+ await client.executeMultiple(`
21
+ CREATE TABLE companies (
22
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
23
+ name TEXT NOT NULL,
24
+ industry TEXT,
25
+ founded INTEGER,
26
+ employee_count INTEGER,
27
+ revenue INTEGER,
28
+ headquarters TEXT
29
+ );
30
+
31
+ CREATE TABLE departments (
32
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
33
+ company_id INTEGER REFERENCES companies(id),
34
+ name TEXT NOT NULL,
35
+ budget INTEGER,
36
+ head_count INTEGER
37
+ );
38
+
39
+ CREATE TABLE employees (
40
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
41
+ company_id INTEGER REFERENCES companies(id),
42
+ department_id INTEGER REFERENCES departments(id),
43
+ first_name TEXT NOT NULL,
44
+ last_name TEXT NOT NULL,
45
+ email TEXT UNIQUE,
46
+ hire_date TEXT,
47
+ salary INTEGER,
48
+ title TEXT,
49
+ status TEXT DEFAULT 'Active'
50
+ );
51
+
52
+ CREATE TABLE projects (
53
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
54
+ company_id INTEGER REFERENCES companies(id),
55
+ department_id INTEGER REFERENCES departments(id),
56
+ name TEXT NOT NULL,
57
+ status TEXT,
58
+ budget INTEGER,
59
+ start_date TEXT,
60
+ end_date TEXT
61
+ );
62
+
63
+ CREATE TABLE project_assignments (
64
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
65
+ project_id INTEGER REFERENCES projects(id),
66
+ employee_id INTEGER REFERENCES employees(id),
67
+ role TEXT,
68
+ UNIQUE(project_id, employee_id)
69
+ );
70
+
71
+ -- Companies
72
+ INSERT INTO companies (name, industry, founded, employee_count, revenue, headquarters) VALUES
73
+ ('Acme Corp', 'Technology', 2010, 150, 25000000, 'San Francisco, CA'),
74
+ ('Globex Inc', 'Finance', 2005, 300, 80000000, 'New York, NY'),
75
+ ('Initech', 'Healthcare', 2015, 80, 12000000, 'Austin, TX'),
76
+ ('Umbrella Ltd', 'Retail', 2008, 200, 45000000, 'Chicago, IL'),
77
+ ('Stark Industries', 'Manufacturing', 2000, 500, 120000000, 'Detroit, MI');
78
+
79
+ -- Departments
80
+ INSERT INTO departments (company_id, name, budget, head_count) VALUES
81
+ (1, 'Engineering', 5000000, 60),
82
+ (1, 'Marketing', 2000000, 25),
83
+ (1, 'Sales', 3000000, 35),
84
+ (1, 'Human Resources', 1000000, 15),
85
+ (2, 'Investment Banking', 10000000, 80),
86
+ (2, 'Risk Management', 4000000, 40),
87
+ (2, 'Compliance', 2000000, 30),
88
+ (2, 'Technology', 6000000, 50),
89
+ (3, 'Research', 4000000, 30),
90
+ (3, 'Clinical', 3000000, 25),
91
+ (3, 'Operations', 2000000, 15),
92
+ (4, 'Supply Chain', 5000000, 50),
93
+ (4, 'Marketing', 3000000, 40),
94
+ (4, 'Customer Service', 2000000, 35),
95
+ (5, 'Manufacturing', 8000000, 150),
96
+ (5, 'Engineering', 6000000, 100),
97
+ (5, 'Quality Assurance', 3000000, 50);
98
+
99
+ -- Employees
100
+ INSERT INTO employees (company_id, department_id, first_name, last_name, email, hire_date, salary, title, status) VALUES
101
+ (1, 1, 'Alice', 'Chen', 'alice.chen@acme.com', '2018-03-15', 145000, 'Senior Engineer', 'Active'),
102
+ (1, 1, 'Bob', 'Martinez', 'bob.martinez@acme.com', '2020-07-01', 125000, 'Software Engineer', 'Active'),
103
+ (1, 1, 'Carol', 'Johnson', 'carol.johnson@acme.com', '2019-01-10', 155000, 'Staff Engineer', 'Active'),
104
+ (1, 1, 'David', 'Kim', 'david.kim@acme.com', '2021-06-20', 110000, 'Junior Engineer', 'Active'),
105
+ (1, 2, 'Eve', 'Williams', 'eve.williams@acme.com', '2019-11-05', 95000, 'Marketing Manager', 'Active'),
106
+ (1, 2, 'Frank', 'Brown', 'frank.brown@acme.com', '2022-02-14', 75000, 'Marketing Specialist', 'Active'),
107
+ (1, 3, 'Grace', 'Davis', 'grace.davis@acme.com', '2020-09-01', 130000, 'Sales Director', 'Active'),
108
+ (1, 3, 'Henry', 'Wilson', 'henry.wilson@acme.com', '2021-03-22', 85000, 'Sales Representative', 'Active'),
109
+ (1, 4, 'Ivy', 'Taylor', 'ivy.taylor@acme.com', '2017-05-30', 90000, 'HR Manager', 'Active'),
110
+ (2, 5, 'Jack', 'Anderson', 'jack.anderson@globex.com', '2016-08-12', 180000, 'Senior Banker', 'Active'),
111
+ (2, 5, 'Karen', 'Thomas', 'karen.thomas@globex.com', '2018-04-03', 160000, 'Investment Analyst', 'Active'),
112
+ (2, 5, 'Leo', 'Garcia', 'leo.garcia@globex.com', '2020-01-15', 140000, 'Associate Banker', 'Active'),
113
+ (2, 6, 'Maria', 'Rodriguez', 'maria.rodriguez@globex.com', '2017-11-20', 150000, 'Risk Analyst', 'Active'),
114
+ (2, 6, 'Nick', 'Lee', 'nick.lee@globex.com', '2019-06-08', 135000, 'Risk Manager', 'Active'),
115
+ (2, 7, 'Olivia', 'White', 'olivia.white@globex.com', '2021-09-01', 120000, 'Compliance Officer', 'Active'),
116
+ (2, 8, 'Paul', 'Harris', 'paul.harris@globex.com', '2018-02-28', 155000, 'Tech Lead', 'Active'),
117
+ (3, 9, 'Quinn', 'Clark', 'quinn.clark@initech.com', '2019-07-15', 130000, 'Research Scientist', 'Active'),
118
+ (3, 9, 'Rachel', 'Lewis', 'rachel.lewis@initech.com', '2020-10-01', 120000, 'Lab Director', 'Active'),
119
+ (3, 10, 'Sam', 'Walker', 'sam.walker@initech.com', '2021-01-20', 110000, 'Clinical Researcher', 'Active'),
120
+ (3, 11, 'Tina', 'Hall', 'tina.hall@initech.com', '2022-04-10', 85000, 'Operations Manager', 'Active'),
121
+ (4, 12, 'Uma', 'Allen', 'uma.allen@umbrella.com', '2018-06-01', 115000, 'Supply Chain Manager', 'Active'),
122
+ (4, 12, 'Victor', 'Young', 'victor.young@umbrella.com', '2020-03-15', 90000, 'Logistics Coordinator', 'Active'),
123
+ (4, 13, 'Wendy', 'King', 'wendy.king@umbrella.com', '2019-08-20', 100000, 'Brand Manager', 'Active'),
124
+ (4, 14, 'Xavier', 'Scott', 'xavier.scott@umbrella.com', '2021-11-01', 65000, 'Support Specialist', 'Active'),
125
+ (5, 15, 'Yara', 'Green', 'yara.green@stark.com', '2015-04-10', 95000, 'Production Manager', 'Active'),
126
+ (5, 15, 'Zach', 'Adams', 'zach.adams@stark.com', '2017-09-22', 80000, 'Line Supervisor', 'Active'),
127
+ (5, 16, 'Amy', 'Nelson', 'amy.nelson@stark.com', '2016-12-05', 140000, 'Principal Engineer', 'Active'),
128
+ (5, 16, 'Brian', 'Carter', 'brian.carter@stark.com', '2019-02-18', 120000, 'Mechanical Engineer', 'Active'),
129
+ (5, 17, 'Cindy', 'Mitchell', 'cindy.mitchell@stark.com', '2020-07-30', 105000, 'QA Lead', 'Active'),
130
+ (5, 17, 'Derek', 'Roberts', 'derek.roberts@stark.com', '2022-01-10', 85000, 'QA Analyst', 'Active');
131
+
132
+ -- Projects
133
+ INSERT INTO projects (company_id, department_id, name, status, budget, start_date, end_date) VALUES
134
+ (1, 1, 'Cloud Migration', 'In Progress', 500000, '2024-01-15', '2024-12-31'),
135
+ (1, 1, 'Mobile App v2', 'Planning', 300000, '2024-06-01', '2025-03-31'),
136
+ (1, 2, 'Brand Refresh', 'Completed', 150000, '2023-09-01', '2024-02-28'),
137
+ (2, 5, 'Q4 Fund Launch', 'In Progress', 2000000, '2024-03-01', '2024-09-30'),
138
+ (2, 8, 'Trading Platform Upgrade', 'In Progress', 1500000, '2024-02-01', '2024-11-30'),
139
+ (3, 9, 'Drug Trial Phase 2', 'In Progress', 3000000, '2023-06-01', '2025-06-30'),
140
+ (4, 12, 'Warehouse Automation', 'Planning', 800000, '2024-07-01', '2025-04-30'),
141
+ (5, 16, 'EV Battery Design', 'In Progress', 5000000, '2024-01-01', '2025-12-31'),
142
+ (5, 15, 'Assembly Line Retrofit', 'Completed', 2000000, '2023-03-01', '2024-01-31');
143
+
144
+ -- Project Assignments
145
+ INSERT INTO project_assignments (project_id, employee_id, role) VALUES
146
+ (1, 1, 'Tech Lead'),
147
+ (1, 2, 'Developer'),
148
+ (1, 3, 'Architect'),
149
+ (2, 2, 'Developer'),
150
+ (2, 4, 'Developer'),
151
+ (3, 5, 'Project Manager'),
152
+ (3, 6, 'Designer'),
153
+ (4, 10, 'Lead Banker'),
154
+ (4, 11, 'Analyst'),
155
+ (5, 16, 'Tech Lead'),
156
+ (6, 17, 'Lead Researcher'),
157
+ (6, 18, 'Lab Director'),
158
+ (6, 19, 'Researcher'),
159
+ (7, 21, 'Project Manager'),
160
+ (7, 22, 'Coordinator'),
161
+ (8, 27, 'Lead Engineer'),
162
+ (8, 28, 'Engineer'),
163
+ (9, 25, 'Production Lead'),
164
+ (9, 26, 'Supervisor');
165
+ `);
166
+
167
+ console.log('Database seeded with sample company data.');
168
+ console.log('Tables: companies, departments, employees, projects, project_assignments');
169
+ }
170
+
171
+ seed().catch(err => {
172
+ console.error('Failed to seed database:', err);
173
+ process.exit(1);
174
+ });
tsconfig.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ES2022",
5
+ "moduleResolution": "bundler",
6
+ "esModuleInterop": true,
7
+ "forceConsistentCasingInFileNames": true,
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "noEmit": true,
11
+ "outDir": "dist"
12
+ },
13
+ "include": ["src/**/*"]
14
+ }