@revealui/db 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +137 -0
- package/dist/audit-store.d.ts +56 -0
- package/dist/audit-store.d.ts.map +1 -0
- package/dist/audit-store.js +120 -0
- package/dist/audit-store.js.map +1 -0
- package/dist/client/index.d.ts +214 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +396 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/types.d.ts +109 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +10 -0
- package/dist/client/types.js.map +1 -0
- package/dist/crypto.d.ts +27 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +68 -0
- package/dist/crypto.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/log-transport.d.ts +20 -0
- package/dist/log-transport.d.ts.map +1 -0
- package/dist/log-transport.js +49 -0
- package/dist/log-transport.js.map +1 -0
- package/dist/pool.d.ts +36 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +218 -0
- package/dist/pool.js.map +1 -0
- package/dist/queries/boards.d.ts +138 -0
- package/dist/queries/boards.d.ts.map +1 -0
- package/dist/queries/boards.js +87 -0
- package/dist/queries/boards.js.map +1 -0
- package/dist/queries/code-provenance.d.ts +250 -0
- package/dist/queries/code-provenance.d.ts.map +1 -0
- package/dist/queries/code-provenance.js +130 -0
- package/dist/queries/code-provenance.js.map +1 -0
- package/dist/queries/optimized-queries.d.ts +89 -0
- package/dist/queries/optimized-queries.d.ts.map +1 -0
- package/dist/queries/optimized-queries.js +371 -0
- package/dist/queries/optimized-queries.js.map +1 -0
- package/dist/queries/ticket-comments.d.ts +37 -0
- package/dist/queries/ticket-comments.d.ts.map +1 -0
- package/dist/queries/ticket-comments.js +52 -0
- package/dist/queries/ticket-comments.js.map +1 -0
- package/dist/queries/ticket-labels.d.ts +69 -0
- package/dist/queries/ticket-labels.d.ts.map +1 -0
- package/dist/queries/ticket-labels.js +51 -0
- package/dist/queries/ticket-labels.js.map +1 -0
- package/dist/queries/tickets.d.ts +301 -0
- package/dist/queries/tickets.d.ts.map +1 -0
- package/dist/queries/tickets.js +89 -0
- package/dist/queries/tickets.js.map +1 -0
- package/dist/queries/todos.d.ts +37 -0
- package/dist/queries/todos.d.ts.map +1 -0
- package/dist/queries/todos.js +37 -0
- package/dist/queries/todos.js.map +1 -0
- package/dist/schema/agents.d.ts +1413 -0
- package/dist/schema/agents.d.ts.map +1 -0
- package/dist/schema/agents.js +207 -0
- package/dist/schema/agents.js.map +1 -0
- package/dist/schema/api-keys.d.ts +298 -0
- package/dist/schema/api-keys.d.ts.map +1 -0
- package/dist/schema/api-keys.js +53 -0
- package/dist/schema/api-keys.js.map +1 -0
- package/dist/schema/app-logs.d.ts +168 -0
- package/dist/schema/app-logs.d.ts.map +1 -0
- package/dist/schema/app-logs.js +25 -0
- package/dist/schema/app-logs.js.map +1 -0
- package/dist/schema/audit-log.d.ts +174 -0
- package/dist/schema/audit-log.d.ts.map +1 -0
- package/dist/schema/audit-log.js +37 -0
- package/dist/schema/audit-log.js.map +1 -0
- package/dist/schema/cms.d.ts +1015 -0
- package/dist/schema/cms.d.ts.map +1 -0
- package/dist/schema/cms.js +137 -0
- package/dist/schema/cms.js.map +1 -0
- package/dist/schema/code-provenance.d.ts +488 -0
- package/dist/schema/code-provenance.d.ts.map +1 -0
- package/dist/schema/code-provenance.js +72 -0
- package/dist/schema/code-provenance.js.map +1 -0
- package/dist/schema/collab-edits.d.ts +165 -0
- package/dist/schema/collab-edits.d.ts.map +1 -0
- package/dist/schema/collab-edits.js +21 -0
- package/dist/schema/collab-edits.js.map +1 -0
- package/dist/schema/crdt-operations.d.ts +153 -0
- package/dist/schema/crdt-operations.d.ts.map +1 -0
- package/dist/schema/crdt-operations.js +30 -0
- package/dist/schema/crdt-operations.js.map +1 -0
- package/dist/schema/error-events.d.ts +223 -0
- package/dist/schema/error-events.d.ts.map +1 -0
- package/dist/schema/error-events.js +44 -0
- package/dist/schema/error-events.js.map +1 -0
- package/dist/schema/index.d.ts +130 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +310 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/licenses.d.ts +189 -0
- package/dist/schema/licenses.d.ts.map +1 -0
- package/dist/schema/licenses.js +39 -0
- package/dist/schema/licenses.js.map +1 -0
- package/dist/schema/node-ids.d.ts +122 -0
- package/dist/schema/node-ids.d.ts.map +1 -0
- package/dist/schema/node-ids.js +25 -0
- package/dist/schema/node-ids.js.map +1 -0
- package/dist/schema/pages.d.ts +488 -0
- package/dist/schema/pages.d.ts.map +1 -0
- package/dist/schema/pages.js +70 -0
- package/dist/schema/pages.js.map +1 -0
- package/dist/schema/password-reset-tokens.d.ts +137 -0
- package/dist/schema/password-reset-tokens.d.ts.map +1 -0
- package/dist/schema/password-reset-tokens.js +26 -0
- package/dist/schema/password-reset-tokens.js.map +1 -0
- package/dist/schema/query.d.ts +11 -0
- package/dist/schema/query.d.ts.map +1 -0
- package/dist/schema/query.js +11 -0
- package/dist/schema/query.js.map +1 -0
- package/dist/schema/rate-limits.d.ts +212 -0
- package/dist/schema/rate-limits.d.ts.map +1 -0
- package/dist/schema/rate-limits.js +38 -0
- package/dist/schema/rate-limits.js.map +1 -0
- package/dist/schema/rest.d.ts +31 -0
- package/dist/schema/rest.d.ts.map +1 -0
- package/dist/schema/rest.js +37 -0
- package/dist/schema/rest.js.map +1 -0
- package/dist/schema/sites.d.ts +365 -0
- package/dist/schema/sites.d.ts.map +1 -0
- package/dist/schema/sites.js +62 -0
- package/dist/schema/sites.js.map +1 -0
- package/dist/schema/tickets.d.ts +1118 -0
- package/dist/schema/tickets.d.ts.map +1 -0
- package/dist/schema/tickets.js +150 -0
- package/dist/schema/tickets.js.map +1 -0
- package/dist/schema/todos.d.ts +98 -0
- package/dist/schema/todos.d.ts.map +1 -0
- package/dist/schema/todos.js +12 -0
- package/dist/schema/todos.js.map +1 -0
- package/dist/schema/users.d.ts +503 -0
- package/dist/schema/users.d.ts.map +1 -0
- package/dist/schema/users.js +75 -0
- package/dist/schema/users.js.map +1 -0
- package/dist/schema/vector.d.ts +9 -0
- package/dist/schema/vector.d.ts.map +1 -0
- package/dist/schema/vector.js +9 -0
- package/dist/schema/vector.js.map +1 -0
- package/dist/schema/waitlist.d.ts +151 -0
- package/dist/schema/waitlist.d.ts.map +1 -0
- package/dist/schema/waitlist.js +17 -0
- package/dist/schema/waitlist.js.map +1 -0
- package/dist/schema/yjs-documents.d.ts +116 -0
- package/dist/schema/yjs-documents.d.ts.map +1 -0
- package/dist/schema/yjs-documents.js +15 -0
- package/dist/schema/yjs-documents.js.map +1 -0
- package/dist/types/database.d.ts +740 -0
- package/dist/types/database.d.ts.map +1 -0
- package/dist/types/database.js +151 -0
- package/dist/types/database.js.map +1 -0
- package/dist/types/discover.d.ts +83 -0
- package/dist/types/discover.d.ts.map +1 -0
- package/dist/types/discover.js +271 -0
- package/dist/types/discover.js.map +1 -0
- package/dist/types/extract-relationships.d.ts +115 -0
- package/dist/types/extract-relationships.d.ts.map +1 -0
- package/dist/types/extract-relationships.js +455 -0
- package/dist/types/extract-relationships.js.map +1 -0
- package/dist/types/generate-contracts.d.ts +19 -0
- package/dist/types/generate-contracts.d.ts.map +1 -0
- package/dist/types/generate-contracts.js +128 -0
- package/dist/types/generate-contracts.js.map +1 -0
- package/dist/types/generate-zod-schemas.d.ts +20 -0
- package/dist/types/generate-zod-schemas.d.ts.map +1 -0
- package/dist/types/generate-zod-schemas.js +128 -0
- package/dist/types/generate-zod-schemas.js.map +1 -0
- package/dist/types/generate.d.ts +17 -0
- package/dist/types/generate.d.ts.map +1 -0
- package/dist/types/generate.js +298 -0
- package/dist/types/generate.js.map +1 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +19 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/introspect.d.ts +75 -0
- package/dist/types/introspect.d.ts.map +1 -0
- package/dist/types/introspect.js +187 -0
- package/dist/types/introspect.js.map +1 -0
- package/dist/types/stripe-schema.d.ts +893 -0
- package/dist/types/stripe-schema.d.ts.map +1 -0
- package/dist/types/stripe-schema.js +112 -0
- package/dist/types/stripe-schema.js.map +1 -0
- package/package.json +154 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @revealui/db - Database Package
|
|
3
|
+
*
|
|
4
|
+
* Provides Drizzle ORM schema definitions and database client for RevealUI.
|
|
5
|
+
* Designed for Neon Postgres with pgvector extension.
|
|
6
|
+
*
|
|
7
|
+
* ## Usage
|
|
8
|
+
*
|
|
9
|
+
* ### Core (Schema)
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { users, sites, pages } from '@revealui/db/schema'
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* ### Client
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { getClient } from '@revealui/db/client'
|
|
17
|
+
* const db = getClient()
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* ### Full Package
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import { getClient, users, sites, pages } from '@revealui/db'
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
// Re-export audit store (persistent backend for @revealui/ai audit trail)
|
|
26
|
+
export { DrizzleAuditStore } from './audit-store.js';
|
|
27
|
+
// Re-export client utilities
|
|
28
|
+
export { closeAllPools, createClient, getClient, getPoolMetrics, getRestClient, getVectorClient, resetClient, schema, withTransaction, } from './client/index.js';
|
|
29
|
+
// Re-export everything from core (schema)
|
|
30
|
+
export * from './schema/index.js';
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,0EAA0E;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,6BAA6B;AAC7B,OAAO,EACL,aAAa,EACb,YAAY,EAIZ,SAAS,EACT,cAAc,EACd,aAAa,EACb,eAAe,EACf,WAAW,EACX,MAAM,EACN,eAAe,GAChB,MAAM,mBAAmB,CAAA;AAC1B,0CAA0C;AAC1C,cAAc,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DB Log Transport
|
|
3
|
+
*
|
|
4
|
+
* Returns an onLog handler compatible with the Logger class in @revealui/utils.
|
|
5
|
+
* Persists warn/error/fatal entries to the `app_logs` NeonDB table.
|
|
6
|
+
*
|
|
7
|
+
* Only writes in production (NODE_ENV=production). All writes are fire-and-forget
|
|
8
|
+
* — the handler never throws or blocks the caller.
|
|
9
|
+
*
|
|
10
|
+
* Usage (call once at app startup):
|
|
11
|
+
* import { createDbLogHandler } from '@revealui/db/log-transport'
|
|
12
|
+
* import { logger } from '@revealui/utils/logger'
|
|
13
|
+
*
|
|
14
|
+
* if (process.env.NODE_ENV === 'production') {
|
|
15
|
+
* logger.addLogHandler(createDbLogHandler('api'))
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
import type { LogEntry } from '@revealui/utils/logger';
|
|
19
|
+
export declare function createDbLogHandler(app: string): (entry: LogEntry) => void;
|
|
20
|
+
//# sourceMappingURL=log-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-transport.d.ts","sourceRoot":"","sources":["../src/log-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAMtD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CA2BzE"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DB Log Transport
|
|
3
|
+
*
|
|
4
|
+
* Returns an onLog handler compatible with the Logger class in @revealui/utils.
|
|
5
|
+
* Persists warn/error/fatal entries to the `app_logs` NeonDB table.
|
|
6
|
+
*
|
|
7
|
+
* Only writes in production (NODE_ENV=production). All writes are fire-and-forget
|
|
8
|
+
* — the handler never throws or blocks the caller.
|
|
9
|
+
*
|
|
10
|
+
* Usage (call once at app startup):
|
|
11
|
+
* import { createDbLogHandler } from '@revealui/db/log-transport'
|
|
12
|
+
* import { logger } from '@revealui/utils/logger'
|
|
13
|
+
*
|
|
14
|
+
* if (process.env.NODE_ENV === 'production') {
|
|
15
|
+
* logger.addLogHandler(createDbLogHandler('api'))
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
import { getClient } from './client/index.js';
|
|
19
|
+
import { appLogs } from './schema/app-logs.js';
|
|
20
|
+
const SHIP_LEVELS = new Set(['warn', 'error', 'fatal']);
|
|
21
|
+
export function createDbLogHandler(app) {
|
|
22
|
+
return (entry) => {
|
|
23
|
+
if (!SHIP_LEVELS.has(entry.level))
|
|
24
|
+
return;
|
|
25
|
+
if (process.env.NODE_ENV !== 'production')
|
|
26
|
+
return;
|
|
27
|
+
// Merge context + error into a single data object
|
|
28
|
+
const data = {};
|
|
29
|
+
if (entry.context && Object.keys(entry.context).length > 0) {
|
|
30
|
+
Object.assign(data, entry.context);
|
|
31
|
+
}
|
|
32
|
+
if (entry.error) {
|
|
33
|
+
data.error = entry.error;
|
|
34
|
+
}
|
|
35
|
+
const db = getClient();
|
|
36
|
+
db.insert(appLogs)
|
|
37
|
+
.values({
|
|
38
|
+
level: entry.level,
|
|
39
|
+
message: entry.message,
|
|
40
|
+
app,
|
|
41
|
+
environment: process.env.NODE_ENV ?? 'production',
|
|
42
|
+
requestId: entry.context?.requestId ?? null,
|
|
43
|
+
userId: entry.context?.userId ?? null,
|
|
44
|
+
data: Object.keys(data).length > 0 ? data : null,
|
|
45
|
+
})
|
|
46
|
+
.catch(() => { }); // never throw back to the logger
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=log-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-transport.js","sourceRoot":"","sources":["../src/log-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAE9C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAA;AAEvD,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,OAAO,CAAC,KAAe,EAAQ,EAAE;QAC/B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;YAAE,OAAM;QACzC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;YAAE,OAAM;QAEjD,kDAAkD;QAClD,MAAM,IAAI,GAA4B,EAAE,CAAA;QACxC,IAAI,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3D,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;QACpC,CAAC;QACD,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;QAC1B,CAAC;QAED,MAAM,EAAE,GAAG,SAAS,EAAE,CAAA;QACtB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;aACf,MAAM,CAAC;YACN,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG;YACH,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,YAAY;YACjD,SAAS,EAAG,KAAK,CAAC,OAAO,EAAE,SAAgC,IAAI,IAAI;YACnE,MAAM,EAAG,KAAK,CAAC,OAAO,EAAE,MAA6B,IAAI,IAAI;YAC7D,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;SACjD,CAAC;aACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA,CAAC,iCAAiC;IACtD,CAAC,CAAA;AACH,CAAC"}
|
package/dist/pool.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optimized Database Connection Pool
|
|
3
|
+
*
|
|
4
|
+
* Configured for high performance and reliability
|
|
5
|
+
*/
|
|
6
|
+
import { Pool } from 'pg';
|
|
7
|
+
/**
|
|
8
|
+
* Create connection pool
|
|
9
|
+
*/
|
|
10
|
+
export declare const pool: Pool;
|
|
11
|
+
export declare function checkDatabaseHealth(): Promise<{
|
|
12
|
+
healthy: boolean;
|
|
13
|
+
stats: {
|
|
14
|
+
totalCount: number;
|
|
15
|
+
idleCount: number;
|
|
16
|
+
waitingCount: number;
|
|
17
|
+
};
|
|
18
|
+
}>;
|
|
19
|
+
export declare function getPoolStats(): {
|
|
20
|
+
totalCount: number;
|
|
21
|
+
idleCount: number;
|
|
22
|
+
waitingCount: number;
|
|
23
|
+
maxConnections: number | undefined;
|
|
24
|
+
minConnections: number | undefined;
|
|
25
|
+
utilization: number;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Log pool stats periodically
|
|
29
|
+
*/
|
|
30
|
+
export declare function startPoolMonitoring(intervalMs?: number): void;
|
|
31
|
+
/**
|
|
32
|
+
* Pre-warm the connection pool
|
|
33
|
+
*/
|
|
34
|
+
export declare function warmupPool(): Promise<void>;
|
|
35
|
+
export default pool;
|
|
36
|
+
//# sourceMappingURL=pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,IAAI,EAAoC,MAAM,IAAI,CAAA;AA8E3D;;GAEG;AACH,eAAO,MAAM,IAAI,MAAuB,CAAA;AAuExC,wBAAsB,mBAAmB,IAAI,OAAO,CAAC;IACnD,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE;QACL,UAAU,EAAE,MAAM,CAAA;QAClB,SAAS,EAAE,MAAM,CAAA;QACjB,YAAY,EAAE,MAAM,CAAA;KACrB,CAAA;CACF,CAAC,CAgCD;AAMD,wBAAgB,YAAY;;;;;;;EAS3B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,GAAE,MAAc,QAqB7D;AAMD;;GAEG;AACH,wBAAsB,UAAU,kBA6B/B;AAMD,eAAe,IAAI,CAAA"}
|
package/dist/pool.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optimized Database Connection Pool
|
|
3
|
+
*
|
|
4
|
+
* Configured for high performance and reliability
|
|
5
|
+
*/
|
|
6
|
+
import { getSSLConfig } from '@revealui/utils/database';
|
|
7
|
+
import { logger } from '@revealui/utils/logger';
|
|
8
|
+
import { Pool } from 'pg';
|
|
9
|
+
/**
|
|
10
|
+
* Get SSL configuration based on environment
|
|
11
|
+
*/
|
|
12
|
+
function getPoolSSLConfig() {
|
|
13
|
+
// If DATABASE_URL is available, use it to determine SSL config
|
|
14
|
+
const databaseUrl = process.env.DATABASE_URL || process.env.POSTGRES_URL;
|
|
15
|
+
if (databaseUrl) {
|
|
16
|
+
return getSSLConfig(databaseUrl);
|
|
17
|
+
}
|
|
18
|
+
// Fallback to legacy DATABASE_SSL environment variable
|
|
19
|
+
return process.env.DATABASE_SSL === 'true' ? { rejectUnauthorized: true } : false;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Connection pool configuration optimized for performance
|
|
23
|
+
*/
|
|
24
|
+
const poolConfig = {
|
|
25
|
+
// Connection details
|
|
26
|
+
host: process.env.DATABASE_HOST || 'localhost',
|
|
27
|
+
port: parseInt(process.env.DATABASE_PORT || '5432', 10),
|
|
28
|
+
database: process.env.DATABASE_NAME,
|
|
29
|
+
user: process.env.DATABASE_USER,
|
|
30
|
+
password: process.env.DATABASE_PASSWORD,
|
|
31
|
+
// SSL configuration (auto-detected from connection string if available)
|
|
32
|
+
ssl: getPoolSSLConfig(),
|
|
33
|
+
// ===========================================================================
|
|
34
|
+
// CONNECTION POOL SETTINGS
|
|
35
|
+
// ===========================================================================
|
|
36
|
+
// Maximum number of clients in the pool
|
|
37
|
+
// Higher for high-traffic applications
|
|
38
|
+
max: parseInt(process.env.DATABASE_POOL_MAX || '20', 10),
|
|
39
|
+
// Minimum number of clients in the pool
|
|
40
|
+
// Keeps connections warm
|
|
41
|
+
min: parseInt(process.env.DATABASE_POOL_MIN || '5', 10),
|
|
42
|
+
// Maximum time (ms) a client can be idle before being closed
|
|
43
|
+
// Lower value = more aggressive cleanup
|
|
44
|
+
idleTimeoutMillis: parseInt(process.env.DATABASE_IDLE_TIMEOUT || '30000', 10), // 30 seconds
|
|
45
|
+
// Maximum time (ms) to wait for a connection
|
|
46
|
+
// Fail fast if pool is exhausted
|
|
47
|
+
connectionTimeoutMillis: parseInt(process.env.DATABASE_CONNECTION_TIMEOUT || '5000', 10), // 5 seconds
|
|
48
|
+
// ===========================================================================
|
|
49
|
+
// QUERY SETTINGS
|
|
50
|
+
// ===========================================================================
|
|
51
|
+
// Maximum execution time for queries (PostgreSQL setting)
|
|
52
|
+
// Prevents long-running queries from blocking
|
|
53
|
+
statement_timeout: parseInt(process.env.DATABASE_STATEMENT_TIMEOUT || '10000', 10), // 10 seconds
|
|
54
|
+
// Maximum execution time for queries (Node.js setting)
|
|
55
|
+
query_timeout: parseInt(process.env.DATABASE_QUERY_TIMEOUT || '10000', 10), // 10 seconds
|
|
56
|
+
// ===========================================================================
|
|
57
|
+
// PERFORMANCE SETTINGS
|
|
58
|
+
// ===========================================================================
|
|
59
|
+
// Allow the pool to close when all clients are idle
|
|
60
|
+
// Good for serverless/lambda environments
|
|
61
|
+
allowExitOnIdle: process.env.NODE_ENV !== 'production',
|
|
62
|
+
// Application name (shows in pg_stat_activity)
|
|
63
|
+
application_name: process.env.APP_NAME || 'revealui',
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Create connection pool
|
|
67
|
+
*/
|
|
68
|
+
export const pool = new Pool(poolConfig);
|
|
69
|
+
// ===========================================================================
|
|
70
|
+
// ERROR HANDLING
|
|
71
|
+
// ===========================================================================
|
|
72
|
+
pool.on('error', (err) => {
|
|
73
|
+
logger.error('Unexpected error on idle database client', err instanceof Error ? err : new Error(String(err)));
|
|
74
|
+
});
|
|
75
|
+
pool.on('connect', async (client) => {
|
|
76
|
+
const pid = client.processID;
|
|
77
|
+
logger.info(`Database connection established (PID: ${pid})`);
|
|
78
|
+
try {
|
|
79
|
+
// Set timezone
|
|
80
|
+
await client.query("SET timezone TO 'UTC'");
|
|
81
|
+
// Set statement timeout
|
|
82
|
+
await client.query(`SET statement_timeout TO ${poolConfig.statement_timeout || 10000}`);
|
|
83
|
+
// Enable query statistics
|
|
84
|
+
await client.query('SET track_io_timing = on');
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
logger.error('Error initializing database client', error instanceof Error ? error : new Error(String(error)));
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
pool.on('acquire', (client) => {
|
|
91
|
+
const pid = client.processID;
|
|
92
|
+
logger.debug(`Database client acquired (PID: ${pid})`);
|
|
93
|
+
});
|
|
94
|
+
pool.on('remove', (client) => {
|
|
95
|
+
const pid = client.processID;
|
|
96
|
+
logger.info(`Database client removed (PID: ${pid})`);
|
|
97
|
+
});
|
|
98
|
+
// ===========================================================================
|
|
99
|
+
// GRACEFUL SHUTDOWN
|
|
100
|
+
// ===========================================================================
|
|
101
|
+
async function gracefulShutdown(signal) {
|
|
102
|
+
logger.info('Closing database pool', { signal });
|
|
103
|
+
try {
|
|
104
|
+
await pool.end();
|
|
105
|
+
logger.info('Database pool closed successfully');
|
|
106
|
+
process.exit(0);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
logger.error('Error closing database pool', error instanceof Error ? error : new Error(String(error)));
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
process.on('SIGTERM', () => void gracefulShutdown('SIGTERM'));
|
|
114
|
+
process.on('SIGINT', () => void gracefulShutdown('SIGINT'));
|
|
115
|
+
// ===========================================================================
|
|
116
|
+
// HEALTH CHECK
|
|
117
|
+
// ===========================================================================
|
|
118
|
+
export async function checkDatabaseHealth() {
|
|
119
|
+
try {
|
|
120
|
+
// Test connection
|
|
121
|
+
const client = await pool.connect();
|
|
122
|
+
await client.query('SELECT 1');
|
|
123
|
+
client.release();
|
|
124
|
+
// Get pool stats
|
|
125
|
+
const stats = {
|
|
126
|
+
totalCount: pool.totalCount,
|
|
127
|
+
idleCount: pool.idleCount,
|
|
128
|
+
waitingCount: pool.waitingCount,
|
|
129
|
+
};
|
|
130
|
+
return {
|
|
131
|
+
healthy: true,
|
|
132
|
+
stats,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
logger.error('Database health check failed', error instanceof Error ? error : new Error(String(error)));
|
|
137
|
+
return {
|
|
138
|
+
healthy: false,
|
|
139
|
+
stats: {
|
|
140
|
+
totalCount: pool.totalCount,
|
|
141
|
+
idleCount: pool.idleCount,
|
|
142
|
+
waitingCount: pool.waitingCount,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// ===========================================================================
|
|
148
|
+
// POOL MONITORING
|
|
149
|
+
// ===========================================================================
|
|
150
|
+
export function getPoolStats() {
|
|
151
|
+
return {
|
|
152
|
+
totalCount: pool.totalCount, // Total clients
|
|
153
|
+
idleCount: pool.idleCount, // Idle clients
|
|
154
|
+
waitingCount: pool.waitingCount, // Waiting requests
|
|
155
|
+
maxConnections: poolConfig.max,
|
|
156
|
+
minConnections: poolConfig.min,
|
|
157
|
+
utilization: ((pool.totalCount - pool.idleCount) / (poolConfig.max || 20)) * 100,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Log pool stats periodically
|
|
162
|
+
*/
|
|
163
|
+
export function startPoolMonitoring(intervalMs = 60000) {
|
|
164
|
+
setInterval(() => {
|
|
165
|
+
const stats = getPoolStats();
|
|
166
|
+
logger.info('Database pool stats', {
|
|
167
|
+
...stats,
|
|
168
|
+
utilizationPercent: `${stats.utilization.toFixed(1)}%`,
|
|
169
|
+
timestamp: new Date().toISOString(),
|
|
170
|
+
});
|
|
171
|
+
// Warn if pool is near capacity
|
|
172
|
+
if (stats.utilization > 80) {
|
|
173
|
+
logger.warn('Database pool utilization high', { utilization: stats.utilization });
|
|
174
|
+
}
|
|
175
|
+
// Warn if many requests are waiting
|
|
176
|
+
if (stats.waitingCount > 5) {
|
|
177
|
+
logger.warn('Many requests waiting for database connection', {
|
|
178
|
+
waitingCount: stats.waitingCount,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}, intervalMs);
|
|
182
|
+
}
|
|
183
|
+
// ===========================================================================
|
|
184
|
+
// CONNECTION WARMUP
|
|
185
|
+
// ===========================================================================
|
|
186
|
+
/**
|
|
187
|
+
* Pre-warm the connection pool
|
|
188
|
+
*/
|
|
189
|
+
export async function warmupPool() {
|
|
190
|
+
logger.info('Warming up database pool');
|
|
191
|
+
const warmupConnections = Math.min(poolConfig.min || 5, poolConfig.max || 20);
|
|
192
|
+
const clients = [];
|
|
193
|
+
try {
|
|
194
|
+
// Acquire minimum connections
|
|
195
|
+
for (let i = 0; i < warmupConnections; i++) {
|
|
196
|
+
const client = await pool.connect();
|
|
197
|
+
clients.push(client);
|
|
198
|
+
}
|
|
199
|
+
logger.info(`Warmed up ${warmupConnections} database connections`);
|
|
200
|
+
// Release all clients
|
|
201
|
+
for (const client of clients) {
|
|
202
|
+
client.release();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
logger.error('Error warming up pool', error instanceof Error ? error : new Error(String(error)));
|
|
207
|
+
// Release any acquired clients
|
|
208
|
+
for (const client of clients) {
|
|
209
|
+
client.release();
|
|
210
|
+
}
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// ===========================================================================
|
|
215
|
+
// EXPORTS
|
|
216
|
+
// ===========================================================================
|
|
217
|
+
export default pool;
|
|
218
|
+
//# sourceMappingURL=pool.js.map
|
package/dist/pool.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Board database queries
|
|
3
|
+
*/
|
|
4
|
+
import type { DatabaseClient } from '../client/types.js';
|
|
5
|
+
export declare function getAllBoards(db: DatabaseClient, tenantId?: string): Promise<{
|
|
6
|
+
id: string;
|
|
7
|
+
schemaVersion: string;
|
|
8
|
+
tenantId: string | null;
|
|
9
|
+
name: string;
|
|
10
|
+
slug: string;
|
|
11
|
+
description: string | null;
|
|
12
|
+
ownerId: string | null;
|
|
13
|
+
isDefault: boolean;
|
|
14
|
+
settings: unknown;
|
|
15
|
+
createdAt: Date;
|
|
16
|
+
updatedAt: Date;
|
|
17
|
+
}[]>;
|
|
18
|
+
export declare function getBoardById(db: DatabaseClient, id: string): Promise<{
|
|
19
|
+
id: string;
|
|
20
|
+
schemaVersion: string;
|
|
21
|
+
tenantId: string | null;
|
|
22
|
+
name: string;
|
|
23
|
+
slug: string;
|
|
24
|
+
description: string | null;
|
|
25
|
+
ownerId: string | null;
|
|
26
|
+
isDefault: boolean;
|
|
27
|
+
settings: unknown;
|
|
28
|
+
createdAt: Date;
|
|
29
|
+
updatedAt: Date;
|
|
30
|
+
} | null>;
|
|
31
|
+
export declare function getBoardBySlug(db: DatabaseClient, slug: string, tenantId?: string): Promise<{
|
|
32
|
+
id: string;
|
|
33
|
+
schemaVersion: string;
|
|
34
|
+
tenantId: string | null;
|
|
35
|
+
name: string;
|
|
36
|
+
slug: string;
|
|
37
|
+
description: string | null;
|
|
38
|
+
ownerId: string | null;
|
|
39
|
+
isDefault: boolean;
|
|
40
|
+
settings: unknown;
|
|
41
|
+
createdAt: Date;
|
|
42
|
+
updatedAt: Date;
|
|
43
|
+
} | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Create a board with default kanban columns.
|
|
46
|
+
*/
|
|
47
|
+
export declare function createBoard(db: DatabaseClient, data: {
|
|
48
|
+
id: string;
|
|
49
|
+
name: string;
|
|
50
|
+
slug: string;
|
|
51
|
+
description?: string;
|
|
52
|
+
ownerId?: string;
|
|
53
|
+
tenantId?: string;
|
|
54
|
+
isDefault?: boolean;
|
|
55
|
+
}): Promise<{
|
|
56
|
+
id: string;
|
|
57
|
+
name: string;
|
|
58
|
+
schemaVersion: string;
|
|
59
|
+
createdAt: Date;
|
|
60
|
+
updatedAt: Date;
|
|
61
|
+
ownerId: string | null;
|
|
62
|
+
slug: string;
|
|
63
|
+
description: string | null;
|
|
64
|
+
settings: unknown;
|
|
65
|
+
isDefault: boolean;
|
|
66
|
+
tenantId: string | null;
|
|
67
|
+
} | undefined>;
|
|
68
|
+
export declare function updateBoard(db: DatabaseClient, id: string, data: Partial<{
|
|
69
|
+
name: string;
|
|
70
|
+
slug: string;
|
|
71
|
+
description: string;
|
|
72
|
+
ownerId: string | null;
|
|
73
|
+
}>): Promise<{
|
|
74
|
+
id: string;
|
|
75
|
+
schemaVersion: string;
|
|
76
|
+
tenantId: string | null;
|
|
77
|
+
name: string;
|
|
78
|
+
slug: string;
|
|
79
|
+
description: string | null;
|
|
80
|
+
ownerId: string | null;
|
|
81
|
+
isDefault: boolean;
|
|
82
|
+
settings: unknown;
|
|
83
|
+
createdAt: Date;
|
|
84
|
+
updatedAt: Date;
|
|
85
|
+
} | null>;
|
|
86
|
+
export declare function deleteBoard(db: DatabaseClient, id: string): Promise<void>;
|
|
87
|
+
export declare function getColumnsByBoard(db: DatabaseClient, boardId: string): Promise<{
|
|
88
|
+
id: string;
|
|
89
|
+
boardId: string;
|
|
90
|
+
name: string;
|
|
91
|
+
slug: string;
|
|
92
|
+
position: number;
|
|
93
|
+
wipLimit: number | null;
|
|
94
|
+
color: string | null;
|
|
95
|
+
isDefault: boolean;
|
|
96
|
+
createdAt: Date;
|
|
97
|
+
updatedAt: Date;
|
|
98
|
+
}[]>;
|
|
99
|
+
export declare function createColumn(db: DatabaseClient, data: {
|
|
100
|
+
id: string;
|
|
101
|
+
boardId: string;
|
|
102
|
+
name: string;
|
|
103
|
+
slug: string;
|
|
104
|
+
position: number;
|
|
105
|
+
wipLimit?: number;
|
|
106
|
+
color?: string;
|
|
107
|
+
}): Promise<{
|
|
108
|
+
id: string;
|
|
109
|
+
name: string;
|
|
110
|
+
createdAt: Date;
|
|
111
|
+
updatedAt: Date;
|
|
112
|
+
slug: string;
|
|
113
|
+
isDefault: boolean;
|
|
114
|
+
boardId: string;
|
|
115
|
+
position: number;
|
|
116
|
+
wipLimit: number | null;
|
|
117
|
+
color: string | null;
|
|
118
|
+
} | undefined>;
|
|
119
|
+
export declare function updateColumn(db: DatabaseClient, id: string, data: Partial<{
|
|
120
|
+
name: string;
|
|
121
|
+
slug: string;
|
|
122
|
+
position: number;
|
|
123
|
+
wipLimit: number | null;
|
|
124
|
+
color: string | null;
|
|
125
|
+
}>): Promise<{
|
|
126
|
+
id: string;
|
|
127
|
+
boardId: string;
|
|
128
|
+
name: string;
|
|
129
|
+
slug: string;
|
|
130
|
+
position: number;
|
|
131
|
+
wipLimit: number | null;
|
|
132
|
+
color: string | null;
|
|
133
|
+
isDefault: boolean;
|
|
134
|
+
createdAt: Date;
|
|
135
|
+
updatedAt: Date;
|
|
136
|
+
} | null>;
|
|
137
|
+
export declare function deleteColumn(db: DatabaseClient, id: string): Promise<void>;
|
|
138
|
+
//# sourceMappingURL=boards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boards.d.ts","sourceRoot":"","sources":["../../src/queries/boards.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAWxD,wBAAsB,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,MAAM;;;;;;;;;;;;KAKvE;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM;;;;;;;;;;;;UAGhE;AAED,wBAAsB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;;;;;;;;;;;;UAWvF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,cAAc,EAClB,IAAI,EAAE;IACJ,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;;;;;;;;;;;;eAoBF;AAED,wBAAsB,WAAW,CAC/B,EAAE,EAAE,cAAc,EAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;;;;;;;;;;;;UAS3F;AAED,wBAAsB,WAAW,CAAC,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,iBAE/D;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;KAM1E;AAED,wBAAsB,YAAY,CAChC,EAAE,EAAE,cAAc,EAClB,IAAI,EAAE;IACJ,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;;;;;;;;;;;eAIF;AAED,wBAAsB,YAAY,CAChC,EAAE,EAAE,cAAc,EAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB,CAAC;;;;;;;;;;;UASH;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,iBAEhE"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Board database queries
|
|
3
|
+
*/
|
|
4
|
+
import { eq } from 'drizzle-orm';
|
|
5
|
+
import { boardColumns, boards } from '../schema/tickets.js';
|
|
6
|
+
const DEFAULT_COLUMNS = [
|
|
7
|
+
{ name: 'Backlog', slug: 'backlog', position: 0 },
|
|
8
|
+
{ name: 'To Do', slug: 'todo', position: 1, isDefault: true },
|
|
9
|
+
{ name: 'In Progress', slug: 'in-progress', position: 2 },
|
|
10
|
+
{ name: 'Review', slug: 'review', position: 3 },
|
|
11
|
+
{ name: 'Done', slug: 'done', position: 4 },
|
|
12
|
+
];
|
|
13
|
+
export async function getAllBoards(db, tenantId) {
|
|
14
|
+
if (tenantId) {
|
|
15
|
+
return db.select().from(boards).where(eq(boards.tenantId, tenantId)).orderBy(boards.createdAt);
|
|
16
|
+
}
|
|
17
|
+
return db.select().from(boards).orderBy(boards.createdAt);
|
|
18
|
+
}
|
|
19
|
+
export async function getBoardById(db, id) {
|
|
20
|
+
const result = await db.select().from(boards).where(eq(boards.id, id)).limit(1);
|
|
21
|
+
return result[0] ?? null;
|
|
22
|
+
}
|
|
23
|
+
export async function getBoardBySlug(db, slug, tenantId) {
|
|
24
|
+
const conditions = [eq(boards.slug, slug)];
|
|
25
|
+
if (tenantId)
|
|
26
|
+
conditions.push(eq(boards.tenantId, tenantId));
|
|
27
|
+
const { and } = await import('drizzle-orm');
|
|
28
|
+
const result = await db
|
|
29
|
+
.select()
|
|
30
|
+
.from(boards)
|
|
31
|
+
.where(and(...conditions))
|
|
32
|
+
.limit(1);
|
|
33
|
+
return result[0] ?? null;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a board with default kanban columns.
|
|
37
|
+
*/
|
|
38
|
+
export async function createBoard(db, data) {
|
|
39
|
+
const result = await db.insert(boards).values(data).returning();
|
|
40
|
+
const board = result[0];
|
|
41
|
+
if (board) {
|
|
42
|
+
// Create default columns
|
|
43
|
+
await db.insert(boardColumns).values(DEFAULT_COLUMNS.map((col, _i) => ({
|
|
44
|
+
id: `${board.id}-col-${col.slug}`,
|
|
45
|
+
boardId: board.id,
|
|
46
|
+
name: col.name,
|
|
47
|
+
slug: col.slug,
|
|
48
|
+
position: col.position,
|
|
49
|
+
isDefault: 'isDefault' in col ? col.isDefault : false,
|
|
50
|
+
})));
|
|
51
|
+
}
|
|
52
|
+
return board;
|
|
53
|
+
}
|
|
54
|
+
export async function updateBoard(db, id, data) {
|
|
55
|
+
const result = await db
|
|
56
|
+
.update(boards)
|
|
57
|
+
.set({ ...data, updatedAt: new Date() })
|
|
58
|
+
.where(eq(boards.id, id))
|
|
59
|
+
.returning();
|
|
60
|
+
return result[0] ?? null;
|
|
61
|
+
}
|
|
62
|
+
export async function deleteBoard(db, id) {
|
|
63
|
+
await db.delete(boards).where(eq(boards.id, id));
|
|
64
|
+
}
|
|
65
|
+
export async function getColumnsByBoard(db, boardId) {
|
|
66
|
+
return db
|
|
67
|
+
.select()
|
|
68
|
+
.from(boardColumns)
|
|
69
|
+
.where(eq(boardColumns.boardId, boardId))
|
|
70
|
+
.orderBy(boardColumns.position);
|
|
71
|
+
}
|
|
72
|
+
export async function createColumn(db, data) {
|
|
73
|
+
const result = await db.insert(boardColumns).values(data).returning();
|
|
74
|
+
return result[0];
|
|
75
|
+
}
|
|
76
|
+
export async function updateColumn(db, id, data) {
|
|
77
|
+
const result = await db
|
|
78
|
+
.update(boardColumns)
|
|
79
|
+
.set({ ...data, updatedAt: new Date() })
|
|
80
|
+
.where(eq(boardColumns.id, id))
|
|
81
|
+
.returning();
|
|
82
|
+
return result[0] ?? null;
|
|
83
|
+
}
|
|
84
|
+
export async function deleteColumn(db, id) {
|
|
85
|
+
await db.delete(boardColumns).where(eq(boardColumns.id, id));
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=boards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boards.js","sourceRoot":"","sources":["../../src/queries/boards.ts"],"names":[],"mappings":"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"}
|