@databridgeai/core 1.0.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/README.md +94 -0
- package/dist/formatter.d.ts +11 -0
- package/dist/formatter.d.ts.map +1 -0
- package/dist/formatter.js +44 -0
- package/dist/formatter.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/mongo-adapter.d.ts +18 -0
- package/dist/mongo-adapter.d.ts.map +1 -0
- package/dist/mongo-adapter.js +186 -0
- package/dist/mongo-adapter.js.map +1 -0
- package/dist/postgres-adapter.d.ts +21 -0
- package/dist/postgres-adapter.d.ts.map +1 -0
- package/dist/postgres-adapter.js +177 -0
- package/dist/postgres-adapter.js.map +1 -0
- package/dist/types.d.ts +107 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +30 -0
- package/dist/types.js.map +1 -0
- package/dist/validator.d.ts +16 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +270 -0
- package/dist/validator.js.map +1 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# @databridgeai/core
|
|
2
|
+
|
|
3
|
+
**Shared types, validators, and database adapters for the DataBridge AI platform.**
|
|
4
|
+
|
|
5
|
+
This is an internal dependency used by other `@databridgeai/*` packages. You typically don't need to install this directly.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @databridgeai/core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Types
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import type {
|
|
17
|
+
SchemaMetadata,
|
|
18
|
+
TableSchema,
|
|
19
|
+
ColumnSchema,
|
|
20
|
+
QueryDSL,
|
|
21
|
+
QueryResult,
|
|
22
|
+
ChatRequest,
|
|
23
|
+
ChatResponse,
|
|
24
|
+
UserContext,
|
|
25
|
+
ProjectRegistration,
|
|
26
|
+
DbAdapter,
|
|
27
|
+
UsageLogEntry,
|
|
28
|
+
} from '@databridgeai/core';
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Key Types
|
|
32
|
+
|
|
33
|
+
### QueryDSL
|
|
34
|
+
The intermediate query representation generated by the AI:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
interface QueryDSL {
|
|
38
|
+
table: string;
|
|
39
|
+
select?: string[];
|
|
40
|
+
where?: Record<string, any>;
|
|
41
|
+
orderBy?: { column: string; direction: 'asc' | 'desc' }[];
|
|
42
|
+
limit?: number;
|
|
43
|
+
offset?: number;
|
|
44
|
+
groupBy?: string[];
|
|
45
|
+
aggregate?: { function: string; column: string; alias: string }[];
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### SchemaMetadata
|
|
50
|
+
Describes your database structure:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
interface SchemaMetadata {
|
|
54
|
+
tables: TableSchema[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface TableSchema {
|
|
58
|
+
name: string;
|
|
59
|
+
columns: ColumnSchema[];
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Database Adapters
|
|
64
|
+
|
|
65
|
+
Execute validated QueryDSL against your database:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { PostgresAdapter, MongoAdapter } from '@databridgeai/core';
|
|
69
|
+
|
|
70
|
+
// Postgres
|
|
71
|
+
const pgAdapter = new PostgresAdapter(pool);
|
|
72
|
+
const result = await pgAdapter.execute(queryDSL, tenantContext);
|
|
73
|
+
|
|
74
|
+
// MongoDB
|
|
75
|
+
const mongoAdapter = new MongoAdapter(db);
|
|
76
|
+
const result = await mongoAdapter.execute(queryDSL, tenantContext);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Validators
|
|
80
|
+
|
|
81
|
+
Validate QueryDSL against a schema before execution:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { validateQueryDSL } from '@databridgeai/core';
|
|
85
|
+
|
|
86
|
+
const errors = validateQueryDSL(queryDSL, schema);
|
|
87
|
+
if (errors.length > 0) {
|
|
88
|
+
throw new Error(`Invalid query: ${errors.join(', ')}`);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { QueryResult } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Formats query execution results into a human-readable summary string
|
|
4
|
+
* suitable for feeding back to the LLM.
|
|
5
|
+
*/
|
|
6
|
+
export declare function formatResultForLLM(result: QueryResult): string;
|
|
7
|
+
/**
|
|
8
|
+
* Formats query results as a compact JSON payload for the chat response.
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatResultForResponse(result: QueryResult): Record<string, any>;
|
|
11
|
+
//# sourceMappingURL=formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../src/formatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAoB9D;AASD;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,WAAW,GAClB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAMrB"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatResultForLLM = formatResultForLLM;
|
|
4
|
+
exports.formatResultForResponse = formatResultForResponse;
|
|
5
|
+
/**
|
|
6
|
+
* Formats query execution results into a human-readable summary string
|
|
7
|
+
* suitable for feeding back to the LLM.
|
|
8
|
+
*/
|
|
9
|
+
function formatResultForLLM(result) {
|
|
10
|
+
if (result.rowCount === 0) {
|
|
11
|
+
return "No results found.";
|
|
12
|
+
}
|
|
13
|
+
const header = `Found ${result.rowCount} result(s) in ${result.executionTimeMs}ms:\n`;
|
|
14
|
+
// For small result sets, render as a simple table
|
|
15
|
+
if (result.rowCount <= 20) {
|
|
16
|
+
const keys = Object.keys(result.rows[0]);
|
|
17
|
+
const rows = result.rows.map((row) => keys.map((k) => formatValue(row[k])).join(" | "));
|
|
18
|
+
const headerRow = keys.join(" | ");
|
|
19
|
+
const separator = keys.map(() => "---").join(" | ");
|
|
20
|
+
return `${header}\n${headerRow}\n${separator}\n${rows.join("\n")}`;
|
|
21
|
+
}
|
|
22
|
+
// For larger result sets, return JSON
|
|
23
|
+
return `${header}\n${JSON.stringify(result.rows, null, 2)}`;
|
|
24
|
+
}
|
|
25
|
+
function formatValue(value) {
|
|
26
|
+
if (value === null || value === undefined)
|
|
27
|
+
return "NULL";
|
|
28
|
+
if (value instanceof Date)
|
|
29
|
+
return value.toISOString();
|
|
30
|
+
if (typeof value === "object")
|
|
31
|
+
return JSON.stringify(value);
|
|
32
|
+
return String(value);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Formats query results as a compact JSON payload for the chat response.
|
|
36
|
+
*/
|
|
37
|
+
function formatResultForResponse(result) {
|
|
38
|
+
return {
|
|
39
|
+
rows: result.rows,
|
|
40
|
+
rowCount: result.rowCount,
|
|
41
|
+
executionTimeMs: result.executionTimeMs,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["../src/formatter.ts"],"names":[],"mappings":";;AAMA,gDAoBC;AAYD,0DAQC;AA5CD;;;GAGG;AACH,SAAgB,kBAAkB,CAAC,MAAmB;IACpD,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,MAAM,CAAC,QAAQ,iBAAiB,MAAM,CAAC,eAAe,OAAO,CAAC;IAEtF,kDAAkD;IAClD,IAAI,MAAM,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACnC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CACjD,CAAC;QACF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpD,OAAO,GAAG,MAAM,KAAK,SAAS,KAAK,SAAS,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACrE,CAAC;IAED,sCAAsC;IACtC,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED,SAAS,WAAW,CAAC,KAAU;IAC7B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACzD,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC;IACtD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5D,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,SAAgB,uBAAuB,CACrC,MAAmB;IAEnB,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,eAAe,EAAE,MAAM,CAAC,eAAe;KACxC,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { type QueryDSL, type QueryFilter, type QuerySort, type QueryPagination, type QueryJoin, type QueryAggregation, type FilterOperator, type JoinType, type AggregationType, type SortDirection, type SchemaMetadata, type TableMetadata, type FieldMetadata, type RelationMetadata, type UserContext, type ChatRequest, type ChatResponse, type QueryResult, type ValidationError, type ProjectRegistration, type UsageLogEntry, type DbAdapter, MAX_JOINS, MAX_LIMIT, DEFAULT_LIMIT, NUMERIC_TYPES, } from "./types";
|
|
2
|
+
export { validateQuery, injectTenantFilter, applyDefaults, } from "./validator";
|
|
3
|
+
export { PostgresAdapter } from "./postgres-adapter";
|
|
4
|
+
export { MongoAdapter } from "./mongo-adapter";
|
|
5
|
+
export { formatResultForLLM, formatResultForResponse } from "./formatter";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,SAAS,EAEd,SAAS,EACT,SAAS,EACT,aAAa,EACb,aAAa,GACd,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,aAAa,GACd,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─── @databridgeai/core ───────────────────────────────────────────
|
|
3
|
+
// Shared types, validation, adapters, and utilities.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.formatResultForResponse = exports.formatResultForLLM = exports.MongoAdapter = exports.PostgresAdapter = exports.applyDefaults = exports.injectTenantFilter = exports.validateQuery = exports.NUMERIC_TYPES = exports.DEFAULT_LIMIT = exports.MAX_LIMIT = exports.MAX_JOINS = void 0;
|
|
6
|
+
var types_1 = require("./types");
|
|
7
|
+
// Constants
|
|
8
|
+
Object.defineProperty(exports, "MAX_JOINS", { enumerable: true, get: function () { return types_1.MAX_JOINS; } });
|
|
9
|
+
Object.defineProperty(exports, "MAX_LIMIT", { enumerable: true, get: function () { return types_1.MAX_LIMIT; } });
|
|
10
|
+
Object.defineProperty(exports, "DEFAULT_LIMIT", { enumerable: true, get: function () { return types_1.DEFAULT_LIMIT; } });
|
|
11
|
+
Object.defineProperty(exports, "NUMERIC_TYPES", { enumerable: true, get: function () { return types_1.NUMERIC_TYPES; } });
|
|
12
|
+
var validator_1 = require("./validator");
|
|
13
|
+
Object.defineProperty(exports, "validateQuery", { enumerable: true, get: function () { return validator_1.validateQuery; } });
|
|
14
|
+
Object.defineProperty(exports, "injectTenantFilter", { enumerable: true, get: function () { return validator_1.injectTenantFilter; } });
|
|
15
|
+
Object.defineProperty(exports, "applyDefaults", { enumerable: true, get: function () { return validator_1.applyDefaults; } });
|
|
16
|
+
var postgres_adapter_1 = require("./postgres-adapter");
|
|
17
|
+
Object.defineProperty(exports, "PostgresAdapter", { enumerable: true, get: function () { return postgres_adapter_1.PostgresAdapter; } });
|
|
18
|
+
var mongo_adapter_1 = require("./mongo-adapter");
|
|
19
|
+
Object.defineProperty(exports, "MongoAdapter", { enumerable: true, get: function () { return mongo_adapter_1.MongoAdapter; } });
|
|
20
|
+
var formatter_1 = require("./formatter");
|
|
21
|
+
Object.defineProperty(exports, "formatResultForLLM", { enumerable: true, get: function () { return formatter_1.formatResultForLLM; } });
|
|
22
|
+
Object.defineProperty(exports, "formatResultForResponse", { enumerable: true, get: function () { return formatter_1.formatResultForResponse; } });
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,qEAAqE;AACrE,qDAAqD;;;AAErD,iCA6BiB;AALf,YAAY;AACZ,kGAAA,SAAS,OAAA;AACT,kGAAA,SAAS,OAAA;AACT,sGAAA,aAAa,OAAA;AACb,sGAAA,aAAa,OAAA;AAGf,yCAIqB;AAHnB,0GAAA,aAAa,OAAA;AACb,+GAAA,kBAAkB,OAAA;AAClB,0GAAA,aAAa,OAAA;AAGf,uDAAqD;AAA5C,mHAAA,eAAe,OAAA;AACxB,iDAA+C;AAAtC,6GAAA,YAAY,OAAA;AACrB,yCAA0E;AAAjE,+GAAA,kBAAkB,OAAA;AAAE,oHAAA,uBAAuB,OAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Db, Document } from "mongodb";
|
|
2
|
+
import { QueryDSL, QueryResult, DbAdapter } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* MongoDB adapter — builds aggregation pipeline from QueryDSL and executes it.
|
|
5
|
+
*/
|
|
6
|
+
export declare class MongoAdapter implements DbAdapter {
|
|
7
|
+
private db;
|
|
8
|
+
private client;
|
|
9
|
+
constructor(dbOrUri: Db | string, dbName?: string);
|
|
10
|
+
connect(): Promise<void>;
|
|
11
|
+
execute(query: QueryDSL): Promise<QueryResult>;
|
|
12
|
+
/**
|
|
13
|
+
* Builds a MongoDB aggregation pipeline from QueryDSL.
|
|
14
|
+
*/
|
|
15
|
+
buildPipeline(query: QueryDSL): Document[];
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=mongo-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mongo-adapter.d.ts","sourceRoot":"","sources":["../src/mongo-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,EAAE,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EACL,QAAQ,EACR,WAAW,EACX,SAAS,EAEV,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,qBAAa,YAAa,YAAW,SAAS;IAC5C,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,MAAM,CAAqB;gBAEvB,OAAO,EAAE,EAAE,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAU3C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMxB,OAAO,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC;IAgBpD;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,QAAQ,EAAE;IAmJpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MongoAdapter = void 0;
|
|
4
|
+
const mongodb_1 = require("mongodb");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
/**
|
|
7
|
+
* MongoDB adapter — builds aggregation pipeline from QueryDSL and executes it.
|
|
8
|
+
*/
|
|
9
|
+
class MongoAdapter {
|
|
10
|
+
db;
|
|
11
|
+
client;
|
|
12
|
+
constructor(dbOrUri, dbName) {
|
|
13
|
+
if (typeof dbOrUri === "string") {
|
|
14
|
+
this.client = new mongodb_1.MongoClient(dbOrUri);
|
|
15
|
+
this.db = this.client.db(dbName);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
this.client = null;
|
|
19
|
+
this.db = dbOrUri;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async connect() {
|
|
23
|
+
if (this.client) {
|
|
24
|
+
await this.client.connect();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async execute(query) {
|
|
28
|
+
const start = Date.now();
|
|
29
|
+
const pipeline = this.buildPipeline(query);
|
|
30
|
+
const collection = this.db.collection(query.source.name);
|
|
31
|
+
const cursor = collection.aggregate(pipeline);
|
|
32
|
+
const rows = await cursor.toArray();
|
|
33
|
+
const executionTimeMs = Date.now() - start;
|
|
34
|
+
return {
|
|
35
|
+
rows: rows,
|
|
36
|
+
rowCount: rows.length,
|
|
37
|
+
executionTimeMs,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Builds a MongoDB aggregation pipeline from QueryDSL.
|
|
42
|
+
*/
|
|
43
|
+
buildPipeline(query) {
|
|
44
|
+
const pipeline = [];
|
|
45
|
+
// ─── $match (filters) ────────────────────────────────
|
|
46
|
+
if (query.filters && query.filters.length > 0) {
|
|
47
|
+
const matchStage = {};
|
|
48
|
+
for (const filter of query.filters) {
|
|
49
|
+
switch (filter.operator) {
|
|
50
|
+
case "eq":
|
|
51
|
+
matchStage[filter.field] = filter.value;
|
|
52
|
+
break;
|
|
53
|
+
case "neq":
|
|
54
|
+
matchStage[filter.field] = { $ne: filter.value };
|
|
55
|
+
break;
|
|
56
|
+
case "gt":
|
|
57
|
+
matchStage[filter.field] = { $gt: filter.value };
|
|
58
|
+
break;
|
|
59
|
+
case "gte":
|
|
60
|
+
matchStage[filter.field] = { $gte: filter.value };
|
|
61
|
+
break;
|
|
62
|
+
case "lt":
|
|
63
|
+
matchStage[filter.field] = { $lt: filter.value };
|
|
64
|
+
break;
|
|
65
|
+
case "lte":
|
|
66
|
+
matchStage[filter.field] = { $lte: filter.value };
|
|
67
|
+
break;
|
|
68
|
+
case "in":
|
|
69
|
+
matchStage[filter.field] = { $in: filter.value };
|
|
70
|
+
break;
|
|
71
|
+
case "contains":
|
|
72
|
+
matchStage[filter.field] = {
|
|
73
|
+
$regex: filter.value,
|
|
74
|
+
$options: "i",
|
|
75
|
+
};
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
pipeline.push({ $match: matchStage });
|
|
80
|
+
}
|
|
81
|
+
// ─── $lookup (joins) ─────────────────────────────────
|
|
82
|
+
if (query.joins) {
|
|
83
|
+
for (const join of query.joins) {
|
|
84
|
+
pipeline.push({
|
|
85
|
+
$lookup: {
|
|
86
|
+
from: join.table,
|
|
87
|
+
localField: join.on.localField,
|
|
88
|
+
foreignField: join.on.foreignField,
|
|
89
|
+
as: join.table,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
// For inner join, filter out docs with no matches
|
|
93
|
+
if (join.type === "inner") {
|
|
94
|
+
pipeline.push({
|
|
95
|
+
$match: {
|
|
96
|
+
[join.table]: { $ne: [] },
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
// Unwind the joined array (one-to-one style)
|
|
101
|
+
pipeline.push({
|
|
102
|
+
$unwind: {
|
|
103
|
+
path: `$${join.table}`,
|
|
104
|
+
preserveNullAndEmptyArrays: join.type !== "inner",
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// ─── $group (aggregation) ────────────────────────────
|
|
110
|
+
if (query.aggregation) {
|
|
111
|
+
const agg = query.aggregation;
|
|
112
|
+
const groupStage = {
|
|
113
|
+
_id: agg.groupBy ? `$${agg.groupBy}` : null,
|
|
114
|
+
};
|
|
115
|
+
switch (agg.type) {
|
|
116
|
+
case "count":
|
|
117
|
+
groupStage["result"] = { $sum: 1 };
|
|
118
|
+
break;
|
|
119
|
+
case "sum":
|
|
120
|
+
groupStage["result"] = { $sum: `$${agg.field}` };
|
|
121
|
+
break;
|
|
122
|
+
case "avg":
|
|
123
|
+
groupStage["result"] = { $avg: `$${agg.field}` };
|
|
124
|
+
break;
|
|
125
|
+
case "min":
|
|
126
|
+
groupStage["result"] = { $min: `$${agg.field}` };
|
|
127
|
+
break;
|
|
128
|
+
case "max":
|
|
129
|
+
groupStage["result"] = { $max: `$${agg.field}` };
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
pipeline.push({ $group: groupStage });
|
|
133
|
+
// Rename _id to groupBy field name for cleaner output
|
|
134
|
+
if (agg.groupBy) {
|
|
135
|
+
pipeline.push({
|
|
136
|
+
$project: {
|
|
137
|
+
_id: 0,
|
|
138
|
+
[agg.groupBy]: "$_id",
|
|
139
|
+
result: 1,
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
pipeline.push({
|
|
145
|
+
$project: {
|
|
146
|
+
_id: 0,
|
|
147
|
+
result: 1,
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// ─── $project (select) ─────────────────────────────
|
|
154
|
+
if (query.select && query.select.length > 0) {
|
|
155
|
+
const projection = { _id: 0 };
|
|
156
|
+
for (const field of query.select) {
|
|
157
|
+
projection[field] = 1;
|
|
158
|
+
}
|
|
159
|
+
pipeline.push({ $project: projection });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// ─── $sort ───────────────────────────────────────────
|
|
163
|
+
if (query.sort) {
|
|
164
|
+
pipeline.push({
|
|
165
|
+
$sort: {
|
|
166
|
+
[query.sort.field]: query.sort.direction === "desc" ? -1 : 1,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// ─── $skip / $limit ──────────────────────────────────
|
|
171
|
+
const offset = query.pagination?.offset ?? 0;
|
|
172
|
+
if (offset > 0) {
|
|
173
|
+
pipeline.push({ $skip: offset });
|
|
174
|
+
}
|
|
175
|
+
const limit = query.pagination?.limit ?? types_1.DEFAULT_LIMIT;
|
|
176
|
+
pipeline.push({ $limit: limit });
|
|
177
|
+
return pipeline;
|
|
178
|
+
}
|
|
179
|
+
async close() {
|
|
180
|
+
if (this.client) {
|
|
181
|
+
await this.client.close();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
exports.MongoAdapter = MongoAdapter;
|
|
186
|
+
//# sourceMappingURL=mongo-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mongo-adapter.js","sourceRoot":"","sources":["../src/mongo-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Pool, PoolConfig } from "pg";
|
|
2
|
+
import { QueryDSL, QueryResult, DbAdapter } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Postgres adapter — builds parameterized SQL from QueryDSL and executes it.
|
|
5
|
+
*/
|
|
6
|
+
export declare class PostgresAdapter implements DbAdapter {
|
|
7
|
+
private pool;
|
|
8
|
+
constructor(config: PoolConfig | Pool);
|
|
9
|
+
execute(query: QueryDSL): Promise<QueryResult>;
|
|
10
|
+
/**
|
|
11
|
+
* Builds a parameterized SQL query from QueryDSL.
|
|
12
|
+
*/
|
|
13
|
+
buildSQL(query: QueryDSL): {
|
|
14
|
+
text: string;
|
|
15
|
+
values: any[];
|
|
16
|
+
};
|
|
17
|
+
private buildAggregationSelect;
|
|
18
|
+
private quote;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=postgres-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-adapter.d.ts","sourceRoot":"","sources":["../src/postgres-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACtC,OAAO,EACL,QAAQ,EACR,WAAW,EACX,SAAS,EAEV,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAC/C,OAAO,CAAC,IAAI,CAAO;gBAEP,MAAM,EAAE,UAAU,GAAG,IAAI;IAQ/B,OAAO,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC;IAcpD;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,GAAG,EAAE,CAAA;KAAE;IA0H1D,OAAO,CAAC,sBAAsB;IAiC9B,OAAO,CAAC,KAAK;IAMP,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PostgresAdapter = void 0;
|
|
4
|
+
const pg_1 = require("pg");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
/**
|
|
7
|
+
* Postgres adapter — builds parameterized SQL from QueryDSL and executes it.
|
|
8
|
+
*/
|
|
9
|
+
class PostgresAdapter {
|
|
10
|
+
pool;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
if (config instanceof pg_1.Pool) {
|
|
13
|
+
this.pool = config;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
this.pool = new pg_1.Pool(config);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async execute(query) {
|
|
20
|
+
const start = Date.now();
|
|
21
|
+
const { text, values } = this.buildSQL(query);
|
|
22
|
+
const result = await this.pool.query(text, values);
|
|
23
|
+
const executionTimeMs = Date.now() - start;
|
|
24
|
+
return {
|
|
25
|
+
rows: result.rows,
|
|
26
|
+
rowCount: result.rowCount ?? result.rows.length,
|
|
27
|
+
executionTimeMs,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Builds a parameterized SQL query from QueryDSL.
|
|
32
|
+
*/
|
|
33
|
+
buildSQL(query) {
|
|
34
|
+
const values = [];
|
|
35
|
+
let paramIdx = 1;
|
|
36
|
+
const source = this.quote(query.source.name);
|
|
37
|
+
// ─── SELECT / Aggregation ─────────────────────────────
|
|
38
|
+
let selectClause;
|
|
39
|
+
if (query.aggregation) {
|
|
40
|
+
selectClause = this.buildAggregationSelect(query);
|
|
41
|
+
}
|
|
42
|
+
else if (query.select && query.select.length > 0) {
|
|
43
|
+
selectClause = query.select
|
|
44
|
+
.map((f) => {
|
|
45
|
+
if (f.includes(".")) {
|
|
46
|
+
const [table, field] = f.split(".");
|
|
47
|
+
return `${this.quote(table)}.${this.quote(field)}`;
|
|
48
|
+
}
|
|
49
|
+
return `${source}.${this.quote(f)}`;
|
|
50
|
+
})
|
|
51
|
+
.join(", ");
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
selectClause = `${source}.*`;
|
|
55
|
+
}
|
|
56
|
+
// ─── FROM ─────────────────────────────────────────────
|
|
57
|
+
let fromClause = source;
|
|
58
|
+
// ─── JOINS ────────────────────────────────────────────
|
|
59
|
+
const joinClauses = [];
|
|
60
|
+
if (query.joins) {
|
|
61
|
+
for (const join of query.joins) {
|
|
62
|
+
const joinType = join.type === "inner" ? "INNER JOIN" : "LEFT JOIN";
|
|
63
|
+
const joinTable = this.quote(join.table);
|
|
64
|
+
joinClauses.push(`${joinType} ${joinTable} ON ${source}.${this.quote(join.on.localField)} = ${joinTable}.${this.quote(join.on.foreignField)}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// ─── WHERE ────────────────────────────────────────────
|
|
68
|
+
const whereParts = [];
|
|
69
|
+
if (query.filters) {
|
|
70
|
+
for (const filter of query.filters) {
|
|
71
|
+
const col = `${source}.${this.quote(filter.field)}`;
|
|
72
|
+
switch (filter.operator) {
|
|
73
|
+
case "eq":
|
|
74
|
+
whereParts.push(`${col} = $${paramIdx++}`);
|
|
75
|
+
values.push(filter.value);
|
|
76
|
+
break;
|
|
77
|
+
case "neq":
|
|
78
|
+
whereParts.push(`${col} != $${paramIdx++}`);
|
|
79
|
+
values.push(filter.value);
|
|
80
|
+
break;
|
|
81
|
+
case "gt":
|
|
82
|
+
whereParts.push(`${col} > $${paramIdx++}`);
|
|
83
|
+
values.push(filter.value);
|
|
84
|
+
break;
|
|
85
|
+
case "gte":
|
|
86
|
+
whereParts.push(`${col} >= $${paramIdx++}`);
|
|
87
|
+
values.push(filter.value);
|
|
88
|
+
break;
|
|
89
|
+
case "lt":
|
|
90
|
+
whereParts.push(`${col} < $${paramIdx++}`);
|
|
91
|
+
values.push(filter.value);
|
|
92
|
+
break;
|
|
93
|
+
case "lte":
|
|
94
|
+
whereParts.push(`${col} <= $${paramIdx++}`);
|
|
95
|
+
values.push(filter.value);
|
|
96
|
+
break;
|
|
97
|
+
case "in":
|
|
98
|
+
whereParts.push(`${col} = ANY($${paramIdx++})`);
|
|
99
|
+
values.push(filter.value);
|
|
100
|
+
break;
|
|
101
|
+
case "contains":
|
|
102
|
+
whereParts.push(`${col} ILIKE $${paramIdx++}`);
|
|
103
|
+
values.push(`%${filter.value}%`);
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// ─── GROUP BY ─────────────────────────────────────────
|
|
109
|
+
let groupByClause = "";
|
|
110
|
+
if (query.aggregation?.groupBy) {
|
|
111
|
+
groupByClause = `GROUP BY ${source}.${this.quote(query.aggregation.groupBy)}`;
|
|
112
|
+
}
|
|
113
|
+
// ─── ORDER BY ─────────────────────────────────────────
|
|
114
|
+
let orderByClause = "";
|
|
115
|
+
if (query.sort) {
|
|
116
|
+
const dir = query.sort.direction === "desc" ? "DESC" : "ASC";
|
|
117
|
+
orderByClause = `ORDER BY ${source}.${this.quote(query.sort.field)} ${dir}`;
|
|
118
|
+
}
|
|
119
|
+
// ─── LIMIT / OFFSET ──────────────────────────────────
|
|
120
|
+
const limit = query.pagination?.limit ?? types_1.DEFAULT_LIMIT;
|
|
121
|
+
const offset = query.pagination?.offset ?? 0;
|
|
122
|
+
// ─── Assemble ─────────────────────────────────────────
|
|
123
|
+
const parts = [
|
|
124
|
+
`SELECT ${selectClause}`,
|
|
125
|
+
`FROM ${fromClause}`,
|
|
126
|
+
...joinClauses,
|
|
127
|
+
whereParts.length > 0
|
|
128
|
+
? `WHERE ${whereParts.join(" AND ")}`
|
|
129
|
+
: "",
|
|
130
|
+
groupByClause,
|
|
131
|
+
orderByClause,
|
|
132
|
+
`LIMIT ${limit}`,
|
|
133
|
+
offset > 0 ? `OFFSET ${offset}` : "",
|
|
134
|
+
].filter(Boolean);
|
|
135
|
+
return { text: parts.join(" "), values };
|
|
136
|
+
}
|
|
137
|
+
buildAggregationSelect(query) {
|
|
138
|
+
const agg = query.aggregation;
|
|
139
|
+
const source = this.quote(query.source.name);
|
|
140
|
+
let aggExpr;
|
|
141
|
+
switch (agg.type) {
|
|
142
|
+
case "count":
|
|
143
|
+
aggExpr = agg.field
|
|
144
|
+
? `COUNT(${source}.${this.quote(agg.field)})`
|
|
145
|
+
: `COUNT(*)`;
|
|
146
|
+
break;
|
|
147
|
+
case "sum":
|
|
148
|
+
aggExpr = `SUM(${source}.${this.quote(agg.field)})`;
|
|
149
|
+
break;
|
|
150
|
+
case "avg":
|
|
151
|
+
aggExpr = `AVG(${source}.${this.quote(agg.field)})`;
|
|
152
|
+
break;
|
|
153
|
+
case "min":
|
|
154
|
+
aggExpr = `MIN(${source}.${this.quote(agg.field)})`;
|
|
155
|
+
break;
|
|
156
|
+
case "max":
|
|
157
|
+
aggExpr = `MAX(${source}.${this.quote(agg.field)})`;
|
|
158
|
+
break;
|
|
159
|
+
default:
|
|
160
|
+
aggExpr = `COUNT(*)`;
|
|
161
|
+
}
|
|
162
|
+
if (agg.groupBy) {
|
|
163
|
+
return `${source}.${this.quote(agg.groupBy)}, ${aggExpr} AS result`;
|
|
164
|
+
}
|
|
165
|
+
return `${aggExpr} AS result`;
|
|
166
|
+
}
|
|
167
|
+
quote(identifier) {
|
|
168
|
+
// Prevent SQL injection in identifiers
|
|
169
|
+
const safe = identifier.replace(/[^a-zA-Z0-9_]/g, "");
|
|
170
|
+
return `"${safe}"`;
|
|
171
|
+
}
|
|
172
|
+
async close() {
|
|
173
|
+
await this.pool.end();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
exports.PostgresAdapter = PostgresAdapter;
|
|
177
|
+
//# sourceMappingURL=postgres-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-adapter.js","sourceRoot":"","sources":["../src/postgres-adapter.ts"],"names":[],"mappings":";;;AAAA,2BAAsC;AACtC,mCAKiB;AAEjB;;GAEG;AACH,MAAa,eAAe;IAClB,IAAI,CAAO;IAEnB,YAAY,MAAyB;QACnC,IAAI,MAAM,YAAY,SAAI,EAAE,CAAC;YAC3B,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,GAAG,IAAI,SAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAAe;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAE9C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACnD,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QAE3C,OAAO;YACL,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM;YAC/C,eAAe;SAChB,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,KAAe;QACtB,MAAM,MAAM,GAAU,EAAE,CAAC;QACzB,IAAI,QAAQ,GAAG,CAAC,CAAC;QAEjB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAE7C,yDAAyD;QACzD,IAAI,YAAoB,CAAC;QACzB,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YACtB,YAAY,GAAG,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC;QACpD,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnD,YAAY,GAAG,KAAK,CAAC,MAAM;iBACxB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACT,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;oBACpB,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBACpC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrD,CAAC;gBACD,OAAO,GAAG,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,CAAC,CAAC;iBACD,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,YAAY,GAAG,GAAG,MAAM,IAAI,CAAC;QAC/B,CAAC;QAED,yDAAyD;QACzD,IAAI,UAAU,GAAG,MAAM,CAAC;QAExB,yDAAyD;QACzD,MAAM,WAAW,GAAa,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBAC/B,MAAM,QAAQ,GACZ,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC;gBACrD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACzC,WAAW,CAAC,IAAI,CACd,GAAG,QAAQ,IAAI,SAAS,OAAO,MAAM,IAAI,IAAI,CAAC,KAAK,CACjD,IAAI,CAAC,EAAE,CAAC,UAAU,CACnB,MAAM,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CACvD,CAAC;YACJ,CAAC;QACH,CAAC;QAED,yDAAyD;QACzD,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YAClB,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBACnC,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpD,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;oBACxB,KAAK,IAAI;wBACP,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,OAAO,QAAQ,EAAE,EAAE,CAAC,CAAC;wBAC3C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;wBAC1B,MAAM;oBACR,KAAK,KAAK;wBACR,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,QAAQ,QAAQ,EAAE,EAAE,CAAC,CAAC;wBAC5C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;wBAC1B,MAAM;oBACR,KAAK,IAAI;wBACP,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,OAAO,QAAQ,EAAE,EAAE,CAAC,CAAC;wBAC3C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;wBAC1B,MAAM;oBACR,KAAK,KAAK;wBACR,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,QAAQ,QAAQ,EAAE,EAAE,CAAC,CAAC;wBAC5C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;wBAC1B,MAAM;oBACR,KAAK,IAAI;wBACP,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,OAAO,QAAQ,EAAE,EAAE,CAAC,CAAC;wBAC3C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;wBAC1B,MAAM;oBACR,KAAK,KAAK;wBACR,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,QAAQ,QAAQ,EAAE,EAAE,CAAC,CAAC;wBAC5C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;wBAC1B,MAAM;oBACR,KAAK,IAAI;wBACP,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,WAAW,QAAQ,EAAE,GAAG,CAAC,CAAC;wBAChD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;wBAC1B,MAAM;oBACR,KAAK,UAAU;wBACb,UAAU,CAAC,IAAI,CAAC,GAAG,GAAG,WAAW,QAAQ,EAAE,EAAE,CAAC,CAAC;wBAC/C,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;wBACjC,MAAM;gBACV,CAAC;YACH,CAAC;QACH,CAAC;QAED,yDAAyD;QACzD,IAAI,aAAa,GAAG,EAAE,CAAC;QACvB,IAAI,KAAK,CAAC,WAAW,EAAE,OAAO,EAAE,CAAC;YAC/B,aAAa,GAAG,YAAY,MAAM,IAAI,IAAI,CAAC,KAAK,CAC9C,KAAK,CAAC,WAAW,CAAC,OAAO,CAC1B,EAAE,CAAC;QACN,CAAC;QAED,yDAAyD;QACzD,IAAI,aAAa,GAAG,EAAE,CAAC;QACvB,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;YAC7D,aAAa,GAAG,YAAY,MAAM,IAAI,IAAI,CAAC,KAAK,CAC9C,KAAK,CAAC,IAAI,CAAC,KAAK,CACjB,IAAI,GAAG,EAAE,CAAC;QACb,CAAC;QAED,wDAAwD;QACxD,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,EAAE,KAAK,IAAI,qBAAa,CAAC;QACvD,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC,CAAC;QAE7C,yDAAyD;QACzD,MAAM,KAAK,GAAG;YACZ,UAAU,YAAY,EAAE;YACxB,QAAQ,UAAU,EAAE;YACpB,GAAG,WAAW;YACd,UAAU,CAAC,MAAM,GAAG,CAAC;gBACnB,CAAC,CAAC,SAAS,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;gBACrC,CAAC,CAAC,EAAE;YACN,aAAa;YACb,aAAa;YACb,SAAS,KAAK,EAAE;YAChB,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE;SACrC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAElB,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3C,CAAC;IAEO,sBAAsB,CAAC,KAAe;QAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,WAAY,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,OAAe,CAAC;QAEpB,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,OAAO;gBACV,OAAO,GAAG,GAAG,CAAC,KAAK;oBACjB,CAAC,CAAC,SAAS,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG;oBAC7C,CAAC,CAAC,UAAU,CAAC;gBACf,MAAM;YACR,KAAK,KAAK;gBACR,OAAO,GAAG,OAAO,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAM,CAAC,GAAG,CAAC;gBACrD,MAAM;YACR,KAAK,KAAK;gBACR,OAAO,GAAG,OAAO,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAM,CAAC,GAAG,CAAC;gBACrD,MAAM;YACR,KAAK,KAAK;gBACR,OAAO,GAAG,OAAO,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAM,CAAC,GAAG,CAAC;gBACrD,MAAM;YACR,KAAK,KAAK;gBACR,OAAO,GAAG,OAAO,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAM,CAAC,GAAG,CAAC;gBACrD,MAAM;YACR;gBACE,OAAO,GAAG,UAAU,CAAC;QACzB,CAAC;QAED,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YAChB,OAAO,GAAG,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,OAAO,YAAY,CAAC;QACtE,CAAC;QACD,OAAO,GAAG,OAAO,YAAY,CAAC;IAChC,CAAC;IAEO,KAAK,CAAC,UAAkB;QAC9B,uCAAuC;QACvC,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;QACtD,OAAO,IAAI,IAAI,GAAG,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;IACxB,CAAC;CACF;AAhMD,0CAgMC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
export type FilterOperator = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "contains";
|
|
2
|
+
export type JoinType = "inner" | "left";
|
|
3
|
+
export type AggregationType = "count" | "sum" | "avg" | "min" | "max";
|
|
4
|
+
export type SortDirection = "asc" | "desc";
|
|
5
|
+
export interface QueryFilter {
|
|
6
|
+
field: string;
|
|
7
|
+
operator: FilterOperator;
|
|
8
|
+
value: any;
|
|
9
|
+
}
|
|
10
|
+
export interface QuerySort {
|
|
11
|
+
field: string;
|
|
12
|
+
direction: SortDirection;
|
|
13
|
+
}
|
|
14
|
+
export interface QueryPagination {
|
|
15
|
+
limit: number;
|
|
16
|
+
offset?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface QueryJoin {
|
|
19
|
+
table: string;
|
|
20
|
+
on: {
|
|
21
|
+
localField: string;
|
|
22
|
+
foreignField: string;
|
|
23
|
+
};
|
|
24
|
+
type?: JoinType;
|
|
25
|
+
}
|
|
26
|
+
export interface QueryAggregation {
|
|
27
|
+
type: AggregationType;
|
|
28
|
+
field?: string;
|
|
29
|
+
groupBy?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface QueryDSL {
|
|
32
|
+
source: {
|
|
33
|
+
name: string;
|
|
34
|
+
};
|
|
35
|
+
select?: string[];
|
|
36
|
+
filters?: QueryFilter[];
|
|
37
|
+
sort?: QuerySort;
|
|
38
|
+
pagination?: QueryPagination;
|
|
39
|
+
joins?: QueryJoin[];
|
|
40
|
+
aggregation?: QueryAggregation;
|
|
41
|
+
}
|
|
42
|
+
export interface FieldMetadata {
|
|
43
|
+
name: string;
|
|
44
|
+
type: string;
|
|
45
|
+
}
|
|
46
|
+
export interface RelationMetadata {
|
|
47
|
+
table: string;
|
|
48
|
+
localField: string;
|
|
49
|
+
foreignField: string;
|
|
50
|
+
}
|
|
51
|
+
export interface TableMetadata {
|
|
52
|
+
name: string;
|
|
53
|
+
fields: FieldMetadata[];
|
|
54
|
+
relations?: RelationMetadata[];
|
|
55
|
+
}
|
|
56
|
+
export interface SchemaMetadata {
|
|
57
|
+
tables: TableMetadata[];
|
|
58
|
+
}
|
|
59
|
+
export interface UserContext {
|
|
60
|
+
userId: string;
|
|
61
|
+
orgId: string;
|
|
62
|
+
role: string;
|
|
63
|
+
}
|
|
64
|
+
export interface ChatRequest {
|
|
65
|
+
projectId: string;
|
|
66
|
+
message: string;
|
|
67
|
+
userContext: UserContext;
|
|
68
|
+
}
|
|
69
|
+
export interface ChatResponse {
|
|
70
|
+
message: string;
|
|
71
|
+
data?: any;
|
|
72
|
+
tokensUsed?: number;
|
|
73
|
+
visualization?: any;
|
|
74
|
+
}
|
|
75
|
+
export interface QueryResult {
|
|
76
|
+
rows: Record<string, any>[];
|
|
77
|
+
rowCount: number;
|
|
78
|
+
executionTimeMs: number;
|
|
79
|
+
}
|
|
80
|
+
export interface ValidationError {
|
|
81
|
+
code: string;
|
|
82
|
+
message: string;
|
|
83
|
+
path?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface ProjectRegistration {
|
|
86
|
+
projectId: string;
|
|
87
|
+
apiKey: string;
|
|
88
|
+
dbType: "postgres" | "mongo";
|
|
89
|
+
schema: SchemaMetadata;
|
|
90
|
+
tenantField?: string;
|
|
91
|
+
}
|
|
92
|
+
export interface UsageLogEntry {
|
|
93
|
+
projectId: string;
|
|
94
|
+
tokensUsed: number;
|
|
95
|
+
queryExecutionTimeMs: number;
|
|
96
|
+
rowCount: number;
|
|
97
|
+
timestamp: Date;
|
|
98
|
+
}
|
|
99
|
+
export interface DbAdapter {
|
|
100
|
+
execute(query: QueryDSL): Promise<QueryResult>;
|
|
101
|
+
close(): Promise<void>;
|
|
102
|
+
}
|
|
103
|
+
export declare const MAX_JOINS = 2;
|
|
104
|
+
export declare const MAX_LIMIT = 200;
|
|
105
|
+
export declare const DEFAULT_LIMIT = 50;
|
|
106
|
+
export declare const NUMERIC_TYPES: Set<string>;
|
|
107
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─── QueryDSL ────────────────────────────────────────────────
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.NUMERIC_TYPES = exports.DEFAULT_LIMIT = exports.MAX_LIMIT = exports.MAX_JOINS = void 0;
|
|
5
|
+
// ─── Constants ───────────────────────────────────────────────
|
|
6
|
+
exports.MAX_JOINS = 2;
|
|
7
|
+
exports.MAX_LIMIT = 200;
|
|
8
|
+
exports.DEFAULT_LIMIT = 50;
|
|
9
|
+
// ─── Numeric field types ─────────────────────────────────────
|
|
10
|
+
exports.NUMERIC_TYPES = new Set([
|
|
11
|
+
"integer",
|
|
12
|
+
"int",
|
|
13
|
+
"int4",
|
|
14
|
+
"int8",
|
|
15
|
+
"bigint",
|
|
16
|
+
"smallint",
|
|
17
|
+
"serial",
|
|
18
|
+
"bigserial",
|
|
19
|
+
"float",
|
|
20
|
+
"float4",
|
|
21
|
+
"float8",
|
|
22
|
+
"double",
|
|
23
|
+
"double precision",
|
|
24
|
+
"real",
|
|
25
|
+
"decimal",
|
|
26
|
+
"numeric",
|
|
27
|
+
"number",
|
|
28
|
+
"money",
|
|
29
|
+
]);
|
|
30
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,gEAAgE;;;AAsJhE,gEAAgE;AAEnD,QAAA,SAAS,GAAG,CAAC,CAAC;AACd,QAAA,SAAS,GAAG,GAAG,CAAC;AAChB,QAAA,aAAa,GAAG,EAAE,CAAC;AAEhC,gEAAgE;AAEnD,QAAA,aAAa,GAAG,IAAI,GAAG,CAAC;IACnC,SAAS;IACT,KAAK;IACL,MAAM;IACN,MAAM;IACN,QAAQ;IACR,UAAU;IACV,QAAQ;IACR,WAAW;IACX,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,kBAAkB;IAClB,MAAM;IACN,SAAS;IACT,SAAS;IACT,QAAQ;IACR,OAAO;CACR,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { QueryDSL, SchemaMetadata, ValidationError, UserContext } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Validates a QueryDSL object against the project schema and hard limits.
|
|
4
|
+
* Returns an array of validation errors (empty = valid).
|
|
5
|
+
*/
|
|
6
|
+
export declare function validateQuery(query: QueryDSL, schema: SchemaMetadata): ValidationError[];
|
|
7
|
+
/**
|
|
8
|
+
* Injects a mandatory tenant filter into the query.
|
|
9
|
+
* This is NOT exposed to the LLM — it's appended server-side.
|
|
10
|
+
*/
|
|
11
|
+
export declare function injectTenantFilter(query: QueryDSL, tenantField: string, userContext: UserContext): QueryDSL;
|
|
12
|
+
/**
|
|
13
|
+
* Applies default pagination if not specified.
|
|
14
|
+
*/
|
|
15
|
+
export declare function applyDefaults(query: QueryDSL): QueryDSL;
|
|
16
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,cAAc,EACd,eAAe,EAKf,WAAW,EACZ,MAAM,SAAS,CAAC;AAEjB;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,cAAc,GACrB,eAAe,EAAE,CA4PnB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,QAAQ,EACf,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,WAAW,GACvB,QAAQ,CAWV;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,QAAQ,CAQvD"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateQuery = validateQuery;
|
|
4
|
+
exports.injectTenantFilter = injectTenantFilter;
|
|
5
|
+
exports.applyDefaults = applyDefaults;
|
|
6
|
+
const types_1 = require("./types");
|
|
7
|
+
/**
|
|
8
|
+
* Validates a QueryDSL object against the project schema and hard limits.
|
|
9
|
+
* Returns an array of validation errors (empty = valid).
|
|
10
|
+
*/
|
|
11
|
+
function validateQuery(query, schema) {
|
|
12
|
+
const errors = [];
|
|
13
|
+
// ─── Source validation ───────────────────────────────────
|
|
14
|
+
const sourceTable = schema.tables.find((t) => t.name === query.source?.name);
|
|
15
|
+
if (!query.source?.name) {
|
|
16
|
+
errors.push({
|
|
17
|
+
code: "MISSING_SOURCE",
|
|
18
|
+
message: "Query must specify a source table/collection.",
|
|
19
|
+
path: "source.name",
|
|
20
|
+
});
|
|
21
|
+
return errors; // Can't validate further without source
|
|
22
|
+
}
|
|
23
|
+
if (!sourceTable) {
|
|
24
|
+
errors.push({
|
|
25
|
+
code: "INVALID_SOURCE",
|
|
26
|
+
message: `Table "${query.source.name}" does not exist in the schema.`,
|
|
27
|
+
path: "source.name",
|
|
28
|
+
});
|
|
29
|
+
return errors;
|
|
30
|
+
}
|
|
31
|
+
const allFieldNames = new Set(sourceTable.fields.map((f) => f.name));
|
|
32
|
+
// ─── Select validation ──────────────────────────────────
|
|
33
|
+
if (query.select) {
|
|
34
|
+
for (const field of query.select) {
|
|
35
|
+
// Allow "table.field" for joined fields
|
|
36
|
+
const bareField = field.includes(".") ? field.split(".")[1] : field;
|
|
37
|
+
const fieldTable = field.includes(".") ? field.split(".")[0] : null;
|
|
38
|
+
if (fieldTable) {
|
|
39
|
+
// Joined field — check that the joined table exists in schema
|
|
40
|
+
const joinedTable = schema.tables.find((t) => t.name === fieldTable);
|
|
41
|
+
if (!joinedTable) {
|
|
42
|
+
errors.push({
|
|
43
|
+
code: "INVALID_SELECT_FIELD",
|
|
44
|
+
message: `Table "${fieldTable}" referenced in select field "${field}" is not in schema.`,
|
|
45
|
+
path: `select`,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else if (!joinedTable.fields.find((f) => f.name === bareField)) {
|
|
49
|
+
errors.push({
|
|
50
|
+
code: "INVALID_SELECT_FIELD",
|
|
51
|
+
message: `Field "${bareField}" does not exist in table "${fieldTable}".`,
|
|
52
|
+
path: `select`,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else if (!allFieldNames.has(field)) {
|
|
57
|
+
errors.push({
|
|
58
|
+
code: "INVALID_SELECT_FIELD",
|
|
59
|
+
message: `Field "${field}" does not exist in table "${query.source.name}".`,
|
|
60
|
+
path: `select`,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// ─── Filters validation ─────────────────────────────────
|
|
66
|
+
if (query.filters) {
|
|
67
|
+
const validOps = new Set([
|
|
68
|
+
"eq",
|
|
69
|
+
"neq",
|
|
70
|
+
"gt",
|
|
71
|
+
"gte",
|
|
72
|
+
"lt",
|
|
73
|
+
"lte",
|
|
74
|
+
"in",
|
|
75
|
+
"contains",
|
|
76
|
+
]);
|
|
77
|
+
for (let i = 0; i < query.filters.length; i++) {
|
|
78
|
+
const f = query.filters[i];
|
|
79
|
+
if (!allFieldNames.has(f.field)) {
|
|
80
|
+
errors.push({
|
|
81
|
+
code: "INVALID_FILTER_FIELD",
|
|
82
|
+
message: `Filter field "${f.field}" does not exist in table "${query.source.name}".`,
|
|
83
|
+
path: `filters[${i}].field`,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (!validOps.has(f.operator)) {
|
|
87
|
+
errors.push({
|
|
88
|
+
code: "INVALID_FILTER_OPERATOR",
|
|
89
|
+
message: `Invalid operator "${f.operator}".`,
|
|
90
|
+
path: `filters[${i}].operator`,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (f.value === undefined || f.value === null) {
|
|
94
|
+
errors.push({
|
|
95
|
+
code: "MISSING_FILTER_VALUE",
|
|
96
|
+
message: `Filter on "${f.field}" must have a value.`,
|
|
97
|
+
path: `filters[${i}].value`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (f.operator === "in" && !Array.isArray(f.value)) {
|
|
101
|
+
errors.push({
|
|
102
|
+
code: "INVALID_FILTER_VALUE",
|
|
103
|
+
message: `Filter with "in" operator must have an array value.`,
|
|
104
|
+
path: `filters[${i}].value`,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// ─── Sort validation ────────────────────────────────────
|
|
110
|
+
if (query.sort) {
|
|
111
|
+
if (!allFieldNames.has(query.sort.field)) {
|
|
112
|
+
errors.push({
|
|
113
|
+
code: "INVALID_SORT_FIELD",
|
|
114
|
+
message: `Sort field "${query.sort.field}" does not exist in table "${query.source.name}".`,
|
|
115
|
+
path: "sort.field",
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
if (!["asc", "desc"].includes(query.sort.direction)) {
|
|
119
|
+
errors.push({
|
|
120
|
+
code: "INVALID_SORT_DIRECTION",
|
|
121
|
+
message: `Sort direction must be "asc" or "desc".`,
|
|
122
|
+
path: "sort.direction",
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// ─── Pagination validation ──────────────────────────────
|
|
127
|
+
if (query.pagination) {
|
|
128
|
+
if (typeof query.pagination.limit !== "number" ||
|
|
129
|
+
query.pagination.limit < 1) {
|
|
130
|
+
errors.push({
|
|
131
|
+
code: "INVALID_LIMIT",
|
|
132
|
+
message: `Pagination limit must be a positive number.`,
|
|
133
|
+
path: "pagination.limit",
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
else if (query.pagination.limit > types_1.MAX_LIMIT) {
|
|
137
|
+
errors.push({
|
|
138
|
+
code: "LIMIT_EXCEEDED",
|
|
139
|
+
message: `Pagination limit cannot exceed ${types_1.MAX_LIMIT}. Got ${query.pagination.limit}.`,
|
|
140
|
+
path: "pagination.limit",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (query.pagination.offset !== undefined &&
|
|
144
|
+
(typeof query.pagination.offset !== "number" ||
|
|
145
|
+
query.pagination.offset < 0)) {
|
|
146
|
+
errors.push({
|
|
147
|
+
code: "INVALID_OFFSET",
|
|
148
|
+
message: `Pagination offset must be a non-negative number.`,
|
|
149
|
+
path: "pagination.offset",
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// ─── Joins validation ───────────────────────────────────
|
|
154
|
+
if (query.joins) {
|
|
155
|
+
if (query.joins.length > types_1.MAX_JOINS) {
|
|
156
|
+
errors.push({
|
|
157
|
+
code: "MAX_JOINS_EXCEEDED",
|
|
158
|
+
message: `Maximum ${types_1.MAX_JOINS} joins allowed. Got ${query.joins.length}.`,
|
|
159
|
+
path: "joins",
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
const validRelations = sourceTable.relations || [];
|
|
163
|
+
for (let i = 0; i < query.joins.length; i++) {
|
|
164
|
+
const join = query.joins[i];
|
|
165
|
+
const joinTable = schema.tables.find((t) => t.name === join.table);
|
|
166
|
+
if (!joinTable) {
|
|
167
|
+
errors.push({
|
|
168
|
+
code: "INVALID_JOIN_TABLE",
|
|
169
|
+
message: `Join table "${join.table}" does not exist in schema.`,
|
|
170
|
+
path: `joins[${i}].table`,
|
|
171
|
+
});
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
// Check that join relationship is pre-defined
|
|
175
|
+
const relationExists = validRelations.some((r) => r.table === join.table &&
|
|
176
|
+
r.localField === join.on.localField &&
|
|
177
|
+
r.foreignField === join.on.foreignField);
|
|
178
|
+
if (!relationExists) {
|
|
179
|
+
errors.push({
|
|
180
|
+
code: "UNDEFINED_JOIN_RELATION",
|
|
181
|
+
message: `Join relation from "${query.source.name}" to "${join.table}" (${join.on.localField} → ${join.on.foreignField}) is not defined in schema.`,
|
|
182
|
+
path: `joins[${i}]`,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
if (join.type && !["inner", "left"].includes(join.type)) {
|
|
186
|
+
errors.push({
|
|
187
|
+
code: "INVALID_JOIN_TYPE",
|
|
188
|
+
message: `Join type must be "inner" or "left".`,
|
|
189
|
+
path: `joins[${i}].type`,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// ─── Aggregation validation ─────────────────────────────
|
|
195
|
+
if (query.aggregation) {
|
|
196
|
+
const validAggs = new Set(["count", "sum", "avg", "min", "max"]);
|
|
197
|
+
if (!validAggs.has(query.aggregation.type)) {
|
|
198
|
+
errors.push({
|
|
199
|
+
code: "INVALID_AGGREGATION_TYPE",
|
|
200
|
+
message: `Invalid aggregation type "${query.aggregation.type}".`,
|
|
201
|
+
path: "aggregation.type",
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
// For sum, avg, min, max — field is required and must be numeric
|
|
205
|
+
if (query.aggregation.type !== "count") {
|
|
206
|
+
if (!query.aggregation.field) {
|
|
207
|
+
errors.push({
|
|
208
|
+
code: "MISSING_AGGREGATION_FIELD",
|
|
209
|
+
message: `Aggregation type "${query.aggregation.type}" requires a field.`,
|
|
210
|
+
path: "aggregation.field",
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
const aggFieldMeta = sourceTable.fields.find((f) => f.name === query.aggregation.field);
|
|
215
|
+
if (!aggFieldMeta) {
|
|
216
|
+
errors.push({
|
|
217
|
+
code: "INVALID_AGGREGATION_FIELD",
|
|
218
|
+
message: `Aggregation field "${query.aggregation.field}" does not exist in table "${query.source.name}".`,
|
|
219
|
+
path: "aggregation.field",
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
else if (!types_1.NUMERIC_TYPES.has(aggFieldMeta.type.toLowerCase())) {
|
|
223
|
+
errors.push({
|
|
224
|
+
code: "NON_NUMERIC_AGGREGATION",
|
|
225
|
+
message: `Aggregation "${query.aggregation.type}" is only allowed on numeric fields. "${query.aggregation.field}" is of type "${aggFieldMeta.type}".`,
|
|
226
|
+
path: "aggregation.field",
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (query.aggregation.groupBy) {
|
|
232
|
+
if (!allFieldNames.has(query.aggregation.groupBy)) {
|
|
233
|
+
errors.push({
|
|
234
|
+
code: "INVALID_GROUPBY_FIELD",
|
|
235
|
+
message: `GroupBy field "${query.aggregation.groupBy}" does not exist in table "${query.source.name}".`,
|
|
236
|
+
path: "aggregation.groupBy",
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return errors;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Injects a mandatory tenant filter into the query.
|
|
245
|
+
* This is NOT exposed to the LLM — it's appended server-side.
|
|
246
|
+
*/
|
|
247
|
+
function injectTenantFilter(query, tenantField, userContext) {
|
|
248
|
+
const tenantFilter = {
|
|
249
|
+
field: tenantField,
|
|
250
|
+
operator: "eq",
|
|
251
|
+
value: userContext.orgId,
|
|
252
|
+
};
|
|
253
|
+
return {
|
|
254
|
+
...query,
|
|
255
|
+
filters: [...(query.filters || []), tenantFilter],
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Applies default pagination if not specified.
|
|
260
|
+
*/
|
|
261
|
+
function applyDefaults(query) {
|
|
262
|
+
return {
|
|
263
|
+
...query,
|
|
264
|
+
pagination: query.pagination || {
|
|
265
|
+
limit: types_1.DEFAULT_LIMIT,
|
|
266
|
+
offset: 0,
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@databridgeai/core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Core types, validators, and database adapters for DataBridge AI",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc -p tsconfig.json",
|
|
9
|
+
"dev": "tsc -p tsconfig.json --watch"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"pg": "^8.11.3",
|
|
13
|
+
"mongodb": "^6.3.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/pg": "^8.10.9",
|
|
17
|
+
"typescript": "^5.3.3"
|
|
18
|
+
},
|
|
19
|
+
"files": ["dist", "README.md"],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/rishabhAgg/DataBridgeAI.git",
|
|
26
|
+
"directory": "packages/core"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/rishabhAgg/DataBridgeAI#readme",
|
|
29
|
+
"keywords": ["databridgeai", "ai", "database", "query", "types", "validators"],
|
|
30
|
+
"license": "MIT"
|
|
31
|
+
}
|