shokupan 0.13.1 → 0.14.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/dist/{analyzer-BOtveWL-.cjs → analyzer-BZSVGTmP.cjs} +5 -4
- package/dist/analyzer-BZSVGTmP.cjs.map +1 -0
- package/dist/{analyzer-B0fMzeIo.js → analyzer-Faojwm7c.js} +5 -4
- package/dist/analyzer-Faojwm7c.js.map +1 -0
- package/dist/{analyzer.impl-CUDO6vpn.cjs → analyzer.impl-5aCqtook.cjs} +28 -11
- package/dist/analyzer.impl-5aCqtook.cjs.map +1 -0
- package/dist/{analyzer.impl-DmHe92Oi.js → analyzer.impl-COdN69gL.js} +28 -11
- package/dist/analyzer.impl-COdN69gL.js.map +1 -0
- package/dist/ast-analyzer-worker-C3jrQ8VR.js +184 -0
- package/dist/ast-analyzer-worker-C3jrQ8VR.js.map +1 -0
- package/dist/ast-analyzer-worker-D_uYkqmY.cjs +184 -0
- package/dist/ast-analyzer-worker-D_uYkqmY.cjs.map +1 -0
- package/dist/cli.cjs +1 -1
- package/dist/cli.js +1 -1
- package/dist/context.d.ts +39 -4
- package/dist/decorators/di.d.ts +31 -0
- package/dist/decorators/hooks.d.ts +28 -0
- package/dist/decorators/http.d.ts +60 -0
- package/dist/decorators/index.d.ts +8 -0
- package/dist/decorators/mcp.d.ts +48 -0
- package/dist/decorators/util/container.d.ts +36 -0
- package/dist/decorators/websocket.d.ts +172 -0
- package/dist/index-BP7v0Hiv.cjs +12216 -0
- package/dist/index-BP7v0Hiv.cjs.map +1 -0
- package/dist/index-CUNBeZKj.js +12176 -0
- package/dist/index-CUNBeZKj.js.map +1 -0
- package/dist/index.cjs +137 -10518
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +137 -10477
- package/dist/index.js.map +1 -1
- package/dist/{json-parser-COdZ0fqY.cjs → json-parser-BA0mUgMF.cjs} +3 -3
- package/dist/json-parser-BA0mUgMF.cjs.map +1 -0
- package/dist/{json-parser-B3dnQmCC.js → json-parser-BFM-SnBR.js} +3 -3
- package/dist/json-parser-BFM-SnBR.js.map +1 -0
- package/dist/knex-DDPXR-sQ.js +218 -0
- package/dist/knex-DDPXR-sQ.js.map +1 -0
- package/dist/knex-DghF-jjm.cjs +240 -0
- package/dist/knex-DghF-jjm.cjs.map +1 -0
- package/dist/level-BU87Jbus.js +184 -0
- package/dist/level-BU87Jbus.js.map +1 -0
- package/dist/level-DNFl2n-m.cjs +184 -0
- package/dist/level-DNFl2n-m.cjs.map +1 -0
- package/dist/plugins/application/api-explorer/static/explorer-client.mjs +54 -28
- package/dist/plugins/application/asyncapi/plugin.d.ts +1 -0
- package/dist/plugins/application/asyncapi/static/asyncapi-client.mjs +22 -11
- package/dist/plugins/application/dashboard/fetch-interceptor.d.ts +3 -1
- package/dist/plugins/application/dashboard/metrics-collector.d.ts +5 -3
- package/dist/plugins/application/dashboard/plugin.d.ts +36 -3
- package/dist/plugins/application/dashboard/static/requests.js +517 -53
- package/dist/plugins/application/dashboard/static/tabs.js +2 -2
- package/dist/plugins/application/error-view/index.d.ts +25 -0
- package/dist/plugins/application/error-view/reason-phrases.d.ts +1 -0
- package/dist/plugins/application/openapi/analyzer.d.ts +3 -1
- package/dist/plugins/application/openapi/analyzer.impl.d.ts +4 -2
- package/dist/router.d.ts +52 -21
- package/dist/shokupan.d.ts +25 -11
- package/dist/sqlite-CLrcTkti.js +180 -0
- package/dist/sqlite-CLrcTkti.js.map +1 -0
- package/dist/sqlite-n7FQ6Ja6.cjs +180 -0
- package/dist/sqlite-n7FQ6Ja6.cjs.map +1 -0
- package/dist/surreal-6QONU6xa.cjs +210 -0
- package/dist/surreal-6QONU6xa.cjs.map +1 -0
- package/dist/surreal-w7DeGVI-.js +188 -0
- package/dist/surreal-w7DeGVI-.js.map +1 -0
- package/dist/util/adapter/datastore/knex.d.ts +29 -0
- package/dist/util/adapter/datastore/level.d.ts +26 -0
- package/dist/util/adapter/datastore/sqlite.d.ts +24 -0
- package/dist/util/adapter/datastore/surreal.d.ts +29 -0
- package/dist/util/adapter/datastore.d.ts +59 -0
- package/dist/util/adapter/h3.d.ts +8 -0
- package/dist/util/adapter/index.d.ts +1 -0
- package/dist/util/ast-analyzer-worker.d.ts +77 -0
- package/dist/util/ast-worker-thread.d.ts +1 -0
- package/dist/util/cookie-parser.d.ts +6 -0
- package/dist/util/env-loader.d.ts +7 -0
- package/dist/util/html.d.ts +15 -0
- package/dist/util/ide.d.ts +9 -0
- package/dist/util/logger.d.ts +25 -0
- package/dist/util/query-string.d.ts +8 -0
- package/dist/util/response-transformer.d.ts +87 -0
- package/dist/util/symbol.d.ts +1 -0
- package/dist/util/types.d.ts +116 -42
- package/dist/websocket.d.ts +163 -0
- package/package.json +27 -1
- package/dist/analyzer-B0fMzeIo.js.map +0 -1
- package/dist/analyzer-BOtveWL-.cjs.map +0 -1
- package/dist/analyzer.impl-CUDO6vpn.cjs.map +0 -1
- package/dist/analyzer.impl-DmHe92Oi.js.map +0 -1
- package/dist/json-parser-B3dnQmCC.js.map +0 -1
- package/dist/json-parser-COdZ0fqY.cjs.map +0 -1
- package/dist/plugins/application/error-view/views/error.d.ts +0 -2
- package/dist/plugins/application/error-view/views/status.d.ts +0 -2
- package/dist/util/decorators.d.ts +0 -134
- package/dist/util/di.d.ts +0 -13
- /package/dist/{util → decorators/util}/metadata.d.ts +0 -0
- /package/dist/{util → decorators/util}/stack.d.ts +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-n7FQ6Ja6.cjs","sources":["../src/util/adapter/datastore/sqlite.ts"],"sourcesContent":["import { Database } from 'bun:sqlite';\nimport { createLogger } from '../../logger';\nimport type { DatastoreAdapter, QueryOptions } from '../datastore';\n\nexport class SqliteAdapter implements DatastoreAdapter {\n name = 'sqlite';\n private db: Database;\n private logger = createLogger('sqlite-adapter');\n private tables = new Set<string>();\n\n constructor(\n private options: { filename?: string; } = {}\n ) {\n this.db = new Database(options.filename || ':memory:');\n process.on(\"exit\", async () => {\n this.db.close();\n });\n }\n\n async connect(): Promise<void> {\n // Bun SQLite is synchronous/immediate open\n return;\n }\n\n async disconnect(): Promise<void> {\n this.db.close();\n }\n\n async setupSchema(): Promise<void> {\n // In SQLite we need to create tables eagerly or lazily. \n // We'll pre-create standard tables but also ensureTable in methods.\n // For 'schemaless' behavior, we use a single 'data' JSON column.\n // Also 'id' as primary key.\n // We might want created_at/updated_at.\n\n const tables = [\n 'failed_requests', 'sessions', 'users', 'idempotency_keys',\n 'middleware_tracking', 'requests', 'metrics', 'idempotency' // 'idempotency' used in plugin.ts but 'idempotency_keys' used elsewhere? Check code. \n // The plugin code used `new RecordId('idempotency', key)`, so table name is 'idempotency'.\n // The shokupan.ts defined 'idempotency_keys'. \n // We'll create both or just handle lazily.\n ];\n\n for (const table of tables) {\n await this.ensureTable(table);\n }\n }\n\n private ensureTable(table: string) {\n if (this.tables.has(table)) return;\n\n this.db.run(`CREATE TABLE IF NOT EXISTS \"${table}\" (\n id TEXT PRIMARY KEY,\n data JSON,\n created_at INTEGER,\n updated_at INTEGER\n )`);\n\n this.tables.add(table);\n }\n\n async get<T>(table: string, id: string): Promise<T | null> {\n this.ensureTable(table);\n const stmt = this.db.prepare(`SELECT data FROM \"${table}\" WHERE id = ?`);\n const res = stmt.get(id) as { data: string; } | null;\n if (!res || !res.data) return null;\n\n try {\n return JSON.parse(res.data) as T;\n } catch (e) {\n return null;\n }\n }\n\n async create<T>(table: string, id: string, data: T): Promise<T> {\n this.ensureTable(table);\n const now = Date.now();\n // data usually includes id in Shokupan logic? Or maybe not.\n // We store full object in data, including id if present.\n const serialized = JSON.stringify(data);\n\n try {\n this.db.run(\n `INSERT INTO \"${table}\" (id, data, created_at, updated_at) VALUES (?, ?, ?, ?)`,\n [id, serialized, now, now]\n );\n return data;\n } catch (err: any) {\n if (err.message.includes('constraint failed')) {\n // Duplicate\n throw new Error(`Record ${id} already exists`);\n }\n throw err;\n }\n }\n\n async update<T>(table: string, id: string, data: Partial<T>): Promise<T> {\n this.ensureTable(table);\n\n // SQLite JSON patch is tricky without json_patch() extension or complex queries.\n // Simplest is Read-Modify-Write for now, as concurrency is single-process-ish with Bun (mostly).\n // Or usage of json_patch in newer SQLite versions (Bun uses recent sqlite).\n\n // Let's try Read-Modify-Write for safety/simplicity first.\n const current = await this.get<T>(table, id);\n if (!current) throw new Error(`Record ${id} does not exist`);\n\n const updated = { ...current, ...data };\n const serialized = JSON.stringify(updated);\n const now = Date.now();\n\n this.db.run(\n `UPDATE \"${table}\" SET data = ?, updated_at = ? WHERE id = ?`,\n [serialized, now, id]\n );\n\n return updated;\n }\n\n async upsert<T>(table: string, id: string, data: T): Promise<T> {\n this.ensureTable(table);\n const now = Date.now();\n const serialized = JSON.stringify(data);\n\n // SQLite UPSERT syntax\n this.db.run(\n `INSERT INTO \"${table}\" (id, data, created_at, updated_at) VALUES (?, ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET data = excluded.data, updated_at = excluded.updated_at`,\n [id, serialized, now, now]\n );\n\n return data;\n }\n\n async delete(table: string, id: string): Promise<void> {\n this.ensureTable(table);\n this.db.run(`DELETE FROM \"${table}\" WHERE id = ?`, [id]);\n }\n\n async count(table: string, query?: QueryOptions): Promise<number> {\n this.ensureTable(table);\n const { sql, params } = this.buildWhere(query);\n const res = this.db.prepare(`SELECT COUNT(*) as count FROM \"${table}\" ${sql}`).get(...params) as { count: number; };\n return res.count;\n }\n\n async deleteMany(table: string, query?: QueryOptions): Promise<void> {\n this.ensureTable(table);\n const { sql, params } = this.buildWhere(query);\n // SQLite DELETE with LIMIT/ORDER is a compile-time option `SQLITE_ENABLE_UPDATE_DELETE_LIMIT`.\n // Bun ships with it? Assuming yes, or standard DELETE WHERE works. \n // If query has LIMIT/ORDER, we have to check support.\n // Safest: SELECT ids -> DELETE by ids if LIMIT/ORDER used?\n\n if (query?.limit || query?.sort) {\n // Complex delete\n const selectQ = this.buildWhere(query);\n // We need to order/limit the selection of IDs\n let orderSql = '';\n if (query.sort) {\n const parts = Object.entries(query.sort).map(([k, v]) => {\n return `json_extract(data, '$.${k}') ${v.toUpperCase()}`;\n });\n if (parts.length) orderSql = ' ORDER BY ' + parts.join(', ');\n }\n let limitSql = '';\n if (query.limit) limitSql = ` LIMIT ${query.limit}`;\n\n const rows = this.db.prepare(`SELECT id FROM \"${table}\" ${selectQ.sql} ${orderSql} ${limitSql}`).all(...selectQ.params) as { id: string; }[];\n\n if (rows.length === 0) return;\n\n const ids = rows.map(r => r.id);\n // Batch delete\n const placeholders = ids.map(() => '?').join(',');\n this.db.run(`DELETE FROM \"${table}\" WHERE id IN (${placeholders})`, ids);\n } else {\n this.db.run(`DELETE FROM \"${table}\" ${sql}`, params);\n }\n }\n\n async findMany<T>(table: string, query?: QueryOptions): Promise<T[]> {\n this.ensureTable(table);\n const { sql, params } = this.buildWhere(query);\n\n let orderSql = '';\n if (query?.sort) {\n const parts = Object.entries(query.sort).map(([k, v]) => {\n // Extract from JSON\n return `json_extract(data, '$.${k}') ${v.toUpperCase()}`;\n });\n if (parts.length) orderSql = ' ORDER BY ' + parts.join(', ');\n }\n\n let limitSql = '';\n if (query?.limit) limitSql = ` LIMIT ${query.limit}`;\n if (query?.offset) limitSql += ` OFFSET ${query.offset}`;\n\n const rows = this.db.prepare(`SELECT data FROM \"${table}\" ${sql} ${orderSql} ${limitSql}`).all(...params) as { data: string; }[];\n return rows.map(r => JSON.parse(r.data));\n }\n\n private buildWhere(query?: QueryOptions): { sql: string, params: any[]; } {\n if (!query) return { sql: '', params: [] };\n\n let clauses: string[] = [];\n let params: any[] = [];\n\n if (query.where) {\n Object.entries(query.where).forEach(([k, v]) => {\n clauses.push(`json_extract(data, '$.${k}') = ?`);\n params.push(v);\n });\n }\n\n if (query.gt) {\n Object.entries(query.gt).forEach(([k, v]) => {\n clauses.push(`json_extract(data, '$.${k}') > ?`);\n params.push(v);\n });\n }\n\n if (query.lt) {\n Object.entries(query.lt).forEach(([k, v]) => {\n clauses.push(`json_extract(data, '$.${k}') < ?`);\n params.push(v);\n });\n }\n\n if (clauses.length === 0) return { sql: '', params: [] };\n return { sql: 'WHERE ' + clauses.join(' AND '), params };\n }\n}\n"],"names":["Database","createLogger"],"mappings":"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"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
25
|
+
const surrealdb = require("surrealdb");
|
|
26
|
+
const index = require("./index-BP7v0Hiv.cjs");
|
|
27
|
+
class SurrealAdapter {
|
|
28
|
+
name = "surrealdb";
|
|
29
|
+
db;
|
|
30
|
+
logger = index.createLogger("surreal-adapter");
|
|
31
|
+
options;
|
|
32
|
+
constructor(options = {}) {
|
|
33
|
+
this.options = options;
|
|
34
|
+
if (options.engines) {
|
|
35
|
+
this.db = new surrealdb.Surreal({ engines: options.engines });
|
|
36
|
+
} else {
|
|
37
|
+
this.db = new surrealdb.Surreal();
|
|
38
|
+
}
|
|
39
|
+
process.on("exit", async () => {
|
|
40
|
+
await this.disconnect();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async connect() {
|
|
44
|
+
let url = this.options.url;
|
|
45
|
+
if (!url) {
|
|
46
|
+
if (process.env.NODE_ENV === "test") {
|
|
47
|
+
url = "mem://";
|
|
48
|
+
} else {
|
|
49
|
+
url = "surrealkv://database";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (!this.options.engines && !url.match(/^(?:wss?|https?):\/\//)) {
|
|
53
|
+
try {
|
|
54
|
+
const mod = await import("@surrealdb/node");
|
|
55
|
+
this.db = new surrealdb.Surreal({ engines: mod.createNodeEngines() });
|
|
56
|
+
} catch (e) {
|
|
57
|
+
this.logger.warn("SurrealAdapter", "Could not load @surrealdb/node engines. Embedded protocols might fail.", { error: e });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
await this.db.connect(url, this.options.connectOptions);
|
|
61
|
+
await this.db.use({
|
|
62
|
+
namespace: this.options.namespace ?? "vendor",
|
|
63
|
+
database: this.options.database ?? "shokupan"
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async disconnect() {
|
|
67
|
+
await this.db.close();
|
|
68
|
+
}
|
|
69
|
+
async setupSchema() {
|
|
70
|
+
await this.db.query(`
|
|
71
|
+
DEFINE TABLE OVERWRITE failed_requests SCHEMALESS COMMENT "Created by Shokupan";
|
|
72
|
+
DEFINE TABLE OVERWRITE sessions SCHEMALESS COMMENT "Created by Shokupan";
|
|
73
|
+
DEFINE TABLE OVERWRITE users SCHEMALESS COMMENT "Created by Shokupan";
|
|
74
|
+
DEFINE TABLE OVERWRITE idempotency_keys SCHEMALESS COMMENT "Created by Shokupan";
|
|
75
|
+
DEFINE TABLE OVERWRITE middleware_tracking SCHEMALESS COMMENT "Created by Shokupan";
|
|
76
|
+
DEFINE TABLE OVERWRITE requests SCHEMALESS COMMENT "Created by Shokupan";
|
|
77
|
+
DEFINE TABLE OVERWRITE metrics SCHEMALESS COMMENT "Created by Shokupan";
|
|
78
|
+
`);
|
|
79
|
+
}
|
|
80
|
+
retry(fn) {
|
|
81
|
+
return fn().catch((err) => {
|
|
82
|
+
if (err?.message?.includes("This transaction can be retried")) {
|
|
83
|
+
return fn();
|
|
84
|
+
}
|
|
85
|
+
throw err;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async get(table, id) {
|
|
89
|
+
try {
|
|
90
|
+
const result = await this.db.select(new surrealdb.RecordId(table, id));
|
|
91
|
+
if (Array.isArray(result)) return result[0] || null;
|
|
92
|
+
return result || null;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async create(table, id, data) {
|
|
98
|
+
return this.retry(() => this.db.create(new surrealdb.RecordId(table, id)).content(data));
|
|
99
|
+
}
|
|
100
|
+
async update(table, id, data) {
|
|
101
|
+
return this.retry(() => this.db.update(new surrealdb.RecordId(table, id)).merge(data));
|
|
102
|
+
}
|
|
103
|
+
async upsert(table, id, data) {
|
|
104
|
+
return this.retry(() => this.db.upsert(new surrealdb.RecordId(table, id)).content(data));
|
|
105
|
+
}
|
|
106
|
+
async delete(table, id) {
|
|
107
|
+
await this.retry(() => this.db.delete(new surrealdb.RecordId(table, id)));
|
|
108
|
+
}
|
|
109
|
+
async count(table, query) {
|
|
110
|
+
const q = this.buildQuery(table, query, true);
|
|
111
|
+
const res = await this.db.query(q.statement, q.vars);
|
|
112
|
+
const result = res;
|
|
113
|
+
this.logger.debug("SurrealAdapter", "Count Result", { result });
|
|
114
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
115
|
+
const first = result[0];
|
|
116
|
+
if (Array.isArray(first)) {
|
|
117
|
+
if (first[0]?.count !== void 0) return first[0].count;
|
|
118
|
+
}
|
|
119
|
+
if (first?.count !== void 0) return first.count;
|
|
120
|
+
if (first?.result && Array.isArray(first.result)) {
|
|
121
|
+
const inner = first.result[0];
|
|
122
|
+
if (inner?.count !== void 0) return inner.count;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
async deleteMany(table, query) {
|
|
128
|
+
const q = this.buildQuery(table, query, false, true);
|
|
129
|
+
await this.db.query(q.statement, q.vars);
|
|
130
|
+
}
|
|
131
|
+
async findMany(table, query) {
|
|
132
|
+
const q = this.buildQuery(table, query);
|
|
133
|
+
try {
|
|
134
|
+
const res = await this.db.query(q.statement, q.vars);
|
|
135
|
+
let result = res;
|
|
136
|
+
if (Array.isArray(res) && res.length > 0) {
|
|
137
|
+
if (Array.isArray(res[0])) result = res[0];
|
|
138
|
+
else if (res[0].result && Array.isArray(res[0].result)) result = res[0].result;
|
|
139
|
+
else result = res[0] || [];
|
|
140
|
+
}
|
|
141
|
+
return Array.isArray(result) ? result : [];
|
|
142
|
+
} catch (e) {
|
|
143
|
+
this.logger.error("SurrealAdapter", `findMany ${table} failed`, e);
|
|
144
|
+
throw e;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
buildQuery(table, options, isCount = false, isDelete = false) {
|
|
148
|
+
let fields = isDelete ? "" : isCount ? "count()" : "*";
|
|
149
|
+
let from = `FROM type::table($table)`;
|
|
150
|
+
let vars = { table };
|
|
151
|
+
let clauses = [];
|
|
152
|
+
if (options?.where) {
|
|
153
|
+
Object.entries(options.where).forEach(([k, v], i) => {
|
|
154
|
+
const varName = `where_${i}`;
|
|
155
|
+
clauses.push(`${k} = $${varName}`);
|
|
156
|
+
vars[varName] = v;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (options?.gt) {
|
|
160
|
+
Object.entries(options.gt).forEach(([k, v], i) => {
|
|
161
|
+
const varName = `gt_${i}`;
|
|
162
|
+
clauses.push(`${k} > $${varName}`);
|
|
163
|
+
vars[varName] = v;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
if (options?.lt) {
|
|
167
|
+
Object.entries(options.lt).forEach(([k, v], i) => {
|
|
168
|
+
const varName = `lt_${i}`;
|
|
169
|
+
clauses.push(`${k} < $${varName}`);
|
|
170
|
+
vars[varName] = v;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
let whereStr = clauses.length ? "WHERE " + clauses.join(" AND ") : "";
|
|
174
|
+
let suffix = "";
|
|
175
|
+
if (!isCount && !isDelete) {
|
|
176
|
+
if (options?.sort) {
|
|
177
|
+
const sorts = Object.entries(options.sort).map(([k, v]) => `${k} ${v.toUpperCase()}`);
|
|
178
|
+
if (sorts.length) suffix += ` ORDER BY ${sorts.join(", ")}`;
|
|
179
|
+
}
|
|
180
|
+
if (options?.limit) {
|
|
181
|
+
suffix += ` LIMIT ${options.limit}`;
|
|
182
|
+
}
|
|
183
|
+
if (options?.offset) {
|
|
184
|
+
suffix += ` START ${options.offset}`;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (isDelete) {
|
|
188
|
+
if (options?.sort) {
|
|
189
|
+
const sorts = Object.entries(options.sort).map(([k, v]) => `${k} ${v.toUpperCase()}`);
|
|
190
|
+
if (sorts.length) suffix += ` ORDER BY ${sorts.join(", ")}`;
|
|
191
|
+
}
|
|
192
|
+
if (options?.limit) {
|
|
193
|
+
suffix += ` LIMIT ${options.limit}`;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (isDelete) {
|
|
197
|
+
return {
|
|
198
|
+
statement: `DELETE type::table($table) ${whereStr}${suffix};`,
|
|
199
|
+
vars
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
const groupAll = isCount ? "GROUP ALL" : "";
|
|
203
|
+
return {
|
|
204
|
+
statement: `SELECT ${fields} ${from} ${whereStr} ${groupAll} ${suffix};`,
|
|
205
|
+
vars
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
exports.SurrealAdapter = SurrealAdapter;
|
|
210
|
+
//# sourceMappingURL=surreal-6QONU6xa.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surreal-6QONU6xa.cjs","sources":["../src/util/adapter/datastore/surreal.ts"],"sourcesContent":["import { RecordId, Surreal } from 'surrealdb';\nimport { createLogger } from '../../logger';\nimport type { DatastoreAdapter, QueryOptions } from '../datastore';\n\nexport interface SurrealAdapterOptions {\n url?: string;\n namespace?: string;\n database?: string;\n auth?: any;\n engines?: any;\n connectOptions?: any;\n}\n\nexport class SurrealAdapter implements DatastoreAdapter {\n name = 'surrealdb';\n private db: Surreal;\n private logger = createLogger('surreal-adapter');\n private options: SurrealAdapterOptions;\n\n constructor(options: SurrealAdapterOptions = {}) {\n this.options = options;\n if (options.engines) {\n this.db = new Surreal({ engines: options.engines });\n } else {\n this.db = new Surreal();\n }\n\n process.on(\"exit\", async () => {\n await this.disconnect();\n });\n }\n\n async connect(): Promise<void> {\n let url = this.options.url;\n if (!url) {\n // Default behavior equivalent to old initDatastore\n if (process.env.NODE_ENV === 'test') {\n url = 'mem://';\n } else {\n url = 'surrealkv://database';\n }\n }\n\n if (!this.options.engines && !url.match(/^(?:wss?|https?):\\/\\//)) {\n try {\n const mod = await import('@surrealdb/node');\n this.db = new Surreal({ engines: mod.createNodeEngines() });\n } catch (e) {\n this.logger.warn('SurrealAdapter', \"Could not load @surrealdb/node engines. Embedded protocols might fail.\", { error: e });\n }\n }\n\n await this.db.connect(url, this.options.connectOptions);\n\n await this.db.use({\n namespace: this.options.namespace ?? \"vendor\",\n database: this.options.database ?? \"shokupan\"\n });\n }\n\n async disconnect(): Promise<void> {\n await this.db.close();\n }\n\n async setupSchema(): Promise<void> {\n // Equivalent to old createSchema but generic tables if dynamic?\n // Old code had hardcoded table defines. We should keep them for now or rely on \"SCHEMALESS\" \n // SurrealDB is schemaless by default but defines help with performance/structure.\n // We'll reimplement the base defines.\n\n await this.db.query(`\n DEFINE TABLE OVERWRITE failed_requests SCHEMALESS COMMENT \"Created by Shokupan\";\n DEFINE TABLE OVERWRITE sessions SCHEMALESS COMMENT \"Created by Shokupan\";\n DEFINE TABLE OVERWRITE users SCHEMALESS COMMENT \"Created by Shokupan\";\n DEFINE TABLE OVERWRITE idempotency_keys SCHEMALESS COMMENT \"Created by Shokupan\";\n DEFINE TABLE OVERWRITE middleware_tracking SCHEMALESS COMMENT \"Created by Shokupan\";\n DEFINE TABLE OVERWRITE requests SCHEMALESS COMMENT \"Created by Shokupan\";\n DEFINE TABLE OVERWRITE metrics SCHEMALESS COMMENT \"Created by Shokupan\";\n `);\n }\n\n private retry<T>(fn: () => Promise<T>): Promise<T> {\n return fn().catch(err => {\n if (err?.message?.includes('This transaction can be retried')) {\n return fn();\n }\n throw err;\n });\n }\n\n async get<T>(table: string, id: string): Promise<T | null> {\n try {\n const result = await this.db.select<T>(new RecordId(table, id));\n // SurrealDB select typically returns the object, or throws if connection fails.\n // If ID not found, it might return undefined or null or error depending on version.\n // Recent JS SDK: select returns T (single) or T[] (if variable).\n // But if it returns undefined/null, we return null.\n if (Array.isArray(result)) return result[0] || null;\n return result as T || null;\n } catch (error) {\n // If it throws because of not found (some older versions), return null.\n // Or log real error? generic get should probably return null if not found.\n return null;\n }\n }\n\n async create<T>(table: string, id: string, data: T): Promise<T> {\n return this.retry(() => this.db.create(new RecordId(table, id)).content(data as any)) as any;\n }\n\n async update<T>(table: string, id: string, data: Partial<T>): Promise<T> {\n return this.retry(() => this.db.update(new RecordId(table, id)).merge(data as any)) as any;\n }\n\n async upsert<T>(table: string, id: string, data: T): Promise<T> {\n // SurrealDB .upsert() replaces content. If we want merge-like upsert behavior we might need logic,\n // but typically upsert means \"insert or replace\".\n return this.retry(() => this.db.upsert(new RecordId(table, id)).content(data as any)) as any;\n }\n\n async delete(table: string, id: string): Promise<void> {\n await this.retry(() => this.db.delete(new RecordId(table, id)));\n }\n\n async count(table: string, query?: QueryOptions): Promise<number> {\n const q = this.buildQuery(table, query, true);\n const res = await this.db.query<[{ count: number; }]>(q.statement, q.vars);\n\n const result = res as any; // Cast to inspect\n this.logger.debug('SurrealAdapter', \"Count Result\", { result });\n\n // Defensive coding:\n if (Array.isArray(result) && result.length > 0) {\n const first = result[0];\n\n // 1. Nested array result (common in query()): [[{ count: N }]]\n if (Array.isArray(first)) {\n if (first[0]?.count !== undefined) return first[0].count;\n }\n\n // 2. Direct result: [{ count: N }]\n if (first?.count !== undefined) return first.count;\n\n // 3. Result wrapper: [{ result: [{ count: N }], status: \"OK\" }]\n if (first?.result && Array.isArray(first.result)) {\n const inner = first.result[0];\n if (inner?.count !== undefined) return inner.count;\n }\n }\n\n return 0;\n }\n\n async deleteMany(table: string, query?: QueryOptions): Promise<void> {\n const q = this.buildQuery(table, query, false, true);\n await this.db.query(q.statement, q.vars);\n }\n\n async findMany<T>(table: string, query?: QueryOptions): Promise<T[]> {\n const q = this.buildQuery(table, query);\n try {\n const res = await this.db.query<T[]>(q.statement, q.vars);\n\n // Robust result extraction\n let result: any = res;\n if (Array.isArray(res) && res.length > 0) {\n if (Array.isArray(res[0])) result = res[0];\n else if ((res[0] as any).result && Array.isArray((res[0] as any).result)) result = (res[0] as any).result;\n else result = res[0] || [];\n }\n\n return (Array.isArray(result) ? result : []) as T[];\n } catch (e) {\n this.logger.error('SurrealAdapter', `findMany ${table} failed`, e);\n throw e;\n }\n }\n\n private buildQuery(table: string, options?: QueryOptions, isCount = false, isDelete = false): { statement: string, vars: any; } {\n // Basic query builder\n let type = isDelete ? 'DELETE' : 'SELECT';\n let fields = isDelete ? '' : (isCount ? 'count()' : '*');\n let from = `FROM type::table($table)`;\n let vars: any = { table };\n let clauses: string[] = [];\n\n if (options?.where) {\n Object.entries(options.where).forEach(([k, v], i) => {\n const varName = `where_${i}`;\n clauses.push(`${k} = $${varName}`);\n vars[varName] = v;\n });\n }\n\n if (options?.gt) {\n Object.entries(options.gt).forEach(([k, v], i) => {\n const varName = `gt_${i}`;\n clauses.push(`${k} > $${varName}`);\n vars[varName] = v;\n });\n }\n\n if (options?.lt) {\n Object.entries(options.lt).forEach(([k, v], i) => {\n const varName = `lt_${i}`;\n clauses.push(`${k} < $${varName}`);\n vars[varName] = v;\n });\n }\n\n let whereStr = clauses.length ? 'WHERE ' + clauses.join(' AND ') : '';\n\n let suffix = '';\n if (!isCount && !isDelete) {\n if (options?.sort) {\n const sorts = Object.entries(options.sort).map(([k, v]) => `${k} ${v.toUpperCase()}`);\n if (sorts.length) suffix += ` ORDER BY ${sorts.join(', ')}`;\n }\n if (options?.limit) {\n suffix += ` LIMIT ${options.limit}`;\n }\n if (options?.offset) {\n suffix += ` START ${options.offset}`;\n }\n }\n\n // Handle Delete LIMIT separately because DELETE statements support LIMIT\n if (isDelete) {\n // Surreal DELETE supports WHERE ... \n // Does it support LIMIT? Yes: DELETE user WHERE ... LIMIT 10\n // Does it support ORDER BY? Yes.\n if (options?.sort) {\n const sorts = Object.entries(options.sort).map(([k, v]) => `${k} ${v.toUpperCase()}`);\n if (sorts.length) suffix += ` ORDER BY ${sorts.join(', ')}`;\n }\n if (options?.limit) {\n suffix += ` LIMIT ${options.limit}`;\n }\n }\n\n // isDelete format: DELETE [FROM] table WHERE ...\n // SurrealQL: DELETE table WHERE ...\n if (isDelete) {\n return {\n statement: `DELETE type::table($table) ${whereStr}${suffix};`,\n vars\n };\n }\n\n const groupAll = isCount ? 'GROUP ALL' : '';\n\n return {\n statement: `SELECT ${fields} ${from} ${whereStr} ${groupAll} ${suffix};`,\n vars\n };\n }\n}\n"],"names":["createLogger","Surreal","RecordId"],"mappings":"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"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { Surreal, RecordId } from "surrealdb";
|
|
2
|
+
import { c as createLogger } from "./index-CUNBeZKj.js";
|
|
3
|
+
class SurrealAdapter {
|
|
4
|
+
name = "surrealdb";
|
|
5
|
+
db;
|
|
6
|
+
logger = createLogger("surreal-adapter");
|
|
7
|
+
options;
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
if (options.engines) {
|
|
11
|
+
this.db = new Surreal({ engines: options.engines });
|
|
12
|
+
} else {
|
|
13
|
+
this.db = new Surreal();
|
|
14
|
+
}
|
|
15
|
+
process.on("exit", async () => {
|
|
16
|
+
await this.disconnect();
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async connect() {
|
|
20
|
+
let url = this.options.url;
|
|
21
|
+
if (!url) {
|
|
22
|
+
if (process.env.NODE_ENV === "test") {
|
|
23
|
+
url = "mem://";
|
|
24
|
+
} else {
|
|
25
|
+
url = "surrealkv://database";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (!this.options.engines && !url.match(/^(?:wss?|https?):\/\//)) {
|
|
29
|
+
try {
|
|
30
|
+
const mod = await import("@surrealdb/node");
|
|
31
|
+
this.db = new Surreal({ engines: mod.createNodeEngines() });
|
|
32
|
+
} catch (e) {
|
|
33
|
+
this.logger.warn("SurrealAdapter", "Could not load @surrealdb/node engines. Embedded protocols might fail.", { error: e });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
await this.db.connect(url, this.options.connectOptions);
|
|
37
|
+
await this.db.use({
|
|
38
|
+
namespace: this.options.namespace ?? "vendor",
|
|
39
|
+
database: this.options.database ?? "shokupan"
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async disconnect() {
|
|
43
|
+
await this.db.close();
|
|
44
|
+
}
|
|
45
|
+
async setupSchema() {
|
|
46
|
+
await this.db.query(`
|
|
47
|
+
DEFINE TABLE OVERWRITE failed_requests SCHEMALESS COMMENT "Created by Shokupan";
|
|
48
|
+
DEFINE TABLE OVERWRITE sessions SCHEMALESS COMMENT "Created by Shokupan";
|
|
49
|
+
DEFINE TABLE OVERWRITE users SCHEMALESS COMMENT "Created by Shokupan";
|
|
50
|
+
DEFINE TABLE OVERWRITE idempotency_keys SCHEMALESS COMMENT "Created by Shokupan";
|
|
51
|
+
DEFINE TABLE OVERWRITE middleware_tracking SCHEMALESS COMMENT "Created by Shokupan";
|
|
52
|
+
DEFINE TABLE OVERWRITE requests SCHEMALESS COMMENT "Created by Shokupan";
|
|
53
|
+
DEFINE TABLE OVERWRITE metrics SCHEMALESS COMMENT "Created by Shokupan";
|
|
54
|
+
`);
|
|
55
|
+
}
|
|
56
|
+
retry(fn) {
|
|
57
|
+
return fn().catch((err) => {
|
|
58
|
+
if (err?.message?.includes("This transaction can be retried")) {
|
|
59
|
+
return fn();
|
|
60
|
+
}
|
|
61
|
+
throw err;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async get(table, id) {
|
|
65
|
+
try {
|
|
66
|
+
const result = await this.db.select(new RecordId(table, id));
|
|
67
|
+
if (Array.isArray(result)) return result[0] || null;
|
|
68
|
+
return result || null;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async create(table, id, data) {
|
|
74
|
+
return this.retry(() => this.db.create(new RecordId(table, id)).content(data));
|
|
75
|
+
}
|
|
76
|
+
async update(table, id, data) {
|
|
77
|
+
return this.retry(() => this.db.update(new RecordId(table, id)).merge(data));
|
|
78
|
+
}
|
|
79
|
+
async upsert(table, id, data) {
|
|
80
|
+
return this.retry(() => this.db.upsert(new RecordId(table, id)).content(data));
|
|
81
|
+
}
|
|
82
|
+
async delete(table, id) {
|
|
83
|
+
await this.retry(() => this.db.delete(new RecordId(table, id)));
|
|
84
|
+
}
|
|
85
|
+
async count(table, query) {
|
|
86
|
+
const q = this.buildQuery(table, query, true);
|
|
87
|
+
const res = await this.db.query(q.statement, q.vars);
|
|
88
|
+
const result = res;
|
|
89
|
+
this.logger.debug("SurrealAdapter", "Count Result", { result });
|
|
90
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
91
|
+
const first = result[0];
|
|
92
|
+
if (Array.isArray(first)) {
|
|
93
|
+
if (first[0]?.count !== void 0) return first[0].count;
|
|
94
|
+
}
|
|
95
|
+
if (first?.count !== void 0) return first.count;
|
|
96
|
+
if (first?.result && Array.isArray(first.result)) {
|
|
97
|
+
const inner = first.result[0];
|
|
98
|
+
if (inner?.count !== void 0) return inner.count;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
async deleteMany(table, query) {
|
|
104
|
+
const q = this.buildQuery(table, query, false, true);
|
|
105
|
+
await this.db.query(q.statement, q.vars);
|
|
106
|
+
}
|
|
107
|
+
async findMany(table, query) {
|
|
108
|
+
const q = this.buildQuery(table, query);
|
|
109
|
+
try {
|
|
110
|
+
const res = await this.db.query(q.statement, q.vars);
|
|
111
|
+
let result = res;
|
|
112
|
+
if (Array.isArray(res) && res.length > 0) {
|
|
113
|
+
if (Array.isArray(res[0])) result = res[0];
|
|
114
|
+
else if (res[0].result && Array.isArray(res[0].result)) result = res[0].result;
|
|
115
|
+
else result = res[0] || [];
|
|
116
|
+
}
|
|
117
|
+
return Array.isArray(result) ? result : [];
|
|
118
|
+
} catch (e) {
|
|
119
|
+
this.logger.error("SurrealAdapter", `findMany ${table} failed`, e);
|
|
120
|
+
throw e;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
buildQuery(table, options, isCount = false, isDelete = false) {
|
|
124
|
+
let fields = isDelete ? "" : isCount ? "count()" : "*";
|
|
125
|
+
let from = `FROM type::table($table)`;
|
|
126
|
+
let vars = { table };
|
|
127
|
+
let clauses = [];
|
|
128
|
+
if (options?.where) {
|
|
129
|
+
Object.entries(options.where).forEach(([k, v], i) => {
|
|
130
|
+
const varName = `where_${i}`;
|
|
131
|
+
clauses.push(`${k} = $${varName}`);
|
|
132
|
+
vars[varName] = v;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
if (options?.gt) {
|
|
136
|
+
Object.entries(options.gt).forEach(([k, v], i) => {
|
|
137
|
+
const varName = `gt_${i}`;
|
|
138
|
+
clauses.push(`${k} > $${varName}`);
|
|
139
|
+
vars[varName] = v;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (options?.lt) {
|
|
143
|
+
Object.entries(options.lt).forEach(([k, v], i) => {
|
|
144
|
+
const varName = `lt_${i}`;
|
|
145
|
+
clauses.push(`${k} < $${varName}`);
|
|
146
|
+
vars[varName] = v;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
let whereStr = clauses.length ? "WHERE " + clauses.join(" AND ") : "";
|
|
150
|
+
let suffix = "";
|
|
151
|
+
if (!isCount && !isDelete) {
|
|
152
|
+
if (options?.sort) {
|
|
153
|
+
const sorts = Object.entries(options.sort).map(([k, v]) => `${k} ${v.toUpperCase()}`);
|
|
154
|
+
if (sorts.length) suffix += ` ORDER BY ${sorts.join(", ")}`;
|
|
155
|
+
}
|
|
156
|
+
if (options?.limit) {
|
|
157
|
+
suffix += ` LIMIT ${options.limit}`;
|
|
158
|
+
}
|
|
159
|
+
if (options?.offset) {
|
|
160
|
+
suffix += ` START ${options.offset}`;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (isDelete) {
|
|
164
|
+
if (options?.sort) {
|
|
165
|
+
const sorts = Object.entries(options.sort).map(([k, v]) => `${k} ${v.toUpperCase()}`);
|
|
166
|
+
if (sorts.length) suffix += ` ORDER BY ${sorts.join(", ")}`;
|
|
167
|
+
}
|
|
168
|
+
if (options?.limit) {
|
|
169
|
+
suffix += ` LIMIT ${options.limit}`;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (isDelete) {
|
|
173
|
+
return {
|
|
174
|
+
statement: `DELETE type::table($table) ${whereStr}${suffix};`,
|
|
175
|
+
vars
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const groupAll = isCount ? "GROUP ALL" : "";
|
|
179
|
+
return {
|
|
180
|
+
statement: `SELECT ${fields} ${from} ${whereStr} ${groupAll} ${suffix};`,
|
|
181
|
+
vars
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
export {
|
|
186
|
+
SurrealAdapter
|
|
187
|
+
};
|
|
188
|
+
//# sourceMappingURL=surreal-w7DeGVI-.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surreal-w7DeGVI-.js","sources":["../src/util/adapter/datastore/surreal.ts"],"sourcesContent":["import { RecordId, Surreal } from 'surrealdb';\nimport { createLogger } from '../../logger';\nimport type { DatastoreAdapter, QueryOptions } from '../datastore';\n\nexport interface SurrealAdapterOptions {\n url?: string;\n namespace?: string;\n database?: string;\n auth?: any;\n engines?: any;\n connectOptions?: any;\n}\n\nexport class SurrealAdapter implements DatastoreAdapter {\n name = 'surrealdb';\n private db: Surreal;\n private logger = createLogger('surreal-adapter');\n private options: SurrealAdapterOptions;\n\n constructor(options: SurrealAdapterOptions = {}) {\n this.options = options;\n if (options.engines) {\n this.db = new Surreal({ engines: options.engines });\n } else {\n this.db = new Surreal();\n }\n\n process.on(\"exit\", async () => {\n await this.disconnect();\n });\n }\n\n async connect(): Promise<void> {\n let url = this.options.url;\n if (!url) {\n // Default behavior equivalent to old initDatastore\n if (process.env.NODE_ENV === 'test') {\n url = 'mem://';\n } else {\n url = 'surrealkv://database';\n }\n }\n\n if (!this.options.engines && !url.match(/^(?:wss?|https?):\\/\\//)) {\n try {\n const mod = await import('@surrealdb/node');\n this.db = new Surreal({ engines: mod.createNodeEngines() });\n } catch (e) {\n this.logger.warn('SurrealAdapter', \"Could not load @surrealdb/node engines. Embedded protocols might fail.\", { error: e });\n }\n }\n\n await this.db.connect(url, this.options.connectOptions);\n\n await this.db.use({\n namespace: this.options.namespace ?? \"vendor\",\n database: this.options.database ?? \"shokupan\"\n });\n }\n\n async disconnect(): Promise<void> {\n await this.db.close();\n }\n\n async setupSchema(): Promise<void> {\n // Equivalent to old createSchema but generic tables if dynamic?\n // Old code had hardcoded table defines. We should keep them for now or rely on \"SCHEMALESS\" \n // SurrealDB is schemaless by default but defines help with performance/structure.\n // We'll reimplement the base defines.\n\n await this.db.query(`\n DEFINE TABLE OVERWRITE failed_requests SCHEMALESS COMMENT \"Created by Shokupan\";\n DEFINE TABLE OVERWRITE sessions SCHEMALESS COMMENT \"Created by Shokupan\";\n DEFINE TABLE OVERWRITE users SCHEMALESS COMMENT \"Created by Shokupan\";\n DEFINE TABLE OVERWRITE idempotency_keys SCHEMALESS COMMENT \"Created by Shokupan\";\n DEFINE TABLE OVERWRITE middleware_tracking SCHEMALESS COMMENT \"Created by Shokupan\";\n DEFINE TABLE OVERWRITE requests SCHEMALESS COMMENT \"Created by Shokupan\";\n DEFINE TABLE OVERWRITE metrics SCHEMALESS COMMENT \"Created by Shokupan\";\n `);\n }\n\n private retry<T>(fn: () => Promise<T>): Promise<T> {\n return fn().catch(err => {\n if (err?.message?.includes('This transaction can be retried')) {\n return fn();\n }\n throw err;\n });\n }\n\n async get<T>(table: string, id: string): Promise<T | null> {\n try {\n const result = await this.db.select<T>(new RecordId(table, id));\n // SurrealDB select typically returns the object, or throws if connection fails.\n // If ID not found, it might return undefined or null or error depending on version.\n // Recent JS SDK: select returns T (single) or T[] (if variable).\n // But if it returns undefined/null, we return null.\n if (Array.isArray(result)) return result[0] || null;\n return result as T || null;\n } catch (error) {\n // If it throws because of not found (some older versions), return null.\n // Or log real error? generic get should probably return null if not found.\n return null;\n }\n }\n\n async create<T>(table: string, id: string, data: T): Promise<T> {\n return this.retry(() => this.db.create(new RecordId(table, id)).content(data as any)) as any;\n }\n\n async update<T>(table: string, id: string, data: Partial<T>): Promise<T> {\n return this.retry(() => this.db.update(new RecordId(table, id)).merge(data as any)) as any;\n }\n\n async upsert<T>(table: string, id: string, data: T): Promise<T> {\n // SurrealDB .upsert() replaces content. If we want merge-like upsert behavior we might need logic,\n // but typically upsert means \"insert or replace\".\n return this.retry(() => this.db.upsert(new RecordId(table, id)).content(data as any)) as any;\n }\n\n async delete(table: string, id: string): Promise<void> {\n await this.retry(() => this.db.delete(new RecordId(table, id)));\n }\n\n async count(table: string, query?: QueryOptions): Promise<number> {\n const q = this.buildQuery(table, query, true);\n const res = await this.db.query<[{ count: number; }]>(q.statement, q.vars);\n\n const result = res as any; // Cast to inspect\n this.logger.debug('SurrealAdapter', \"Count Result\", { result });\n\n // Defensive coding:\n if (Array.isArray(result) && result.length > 0) {\n const first = result[0];\n\n // 1. Nested array result (common in query()): [[{ count: N }]]\n if (Array.isArray(first)) {\n if (first[0]?.count !== undefined) return first[0].count;\n }\n\n // 2. Direct result: [{ count: N }]\n if (first?.count !== undefined) return first.count;\n\n // 3. Result wrapper: [{ result: [{ count: N }], status: \"OK\" }]\n if (first?.result && Array.isArray(first.result)) {\n const inner = first.result[0];\n if (inner?.count !== undefined) return inner.count;\n }\n }\n\n return 0;\n }\n\n async deleteMany(table: string, query?: QueryOptions): Promise<void> {\n const q = this.buildQuery(table, query, false, true);\n await this.db.query(q.statement, q.vars);\n }\n\n async findMany<T>(table: string, query?: QueryOptions): Promise<T[]> {\n const q = this.buildQuery(table, query);\n try {\n const res = await this.db.query<T[]>(q.statement, q.vars);\n\n // Robust result extraction\n let result: any = res;\n if (Array.isArray(res) && res.length > 0) {\n if (Array.isArray(res[0])) result = res[0];\n else if ((res[0] as any).result && Array.isArray((res[0] as any).result)) result = (res[0] as any).result;\n else result = res[0] || [];\n }\n\n return (Array.isArray(result) ? result : []) as T[];\n } catch (e) {\n this.logger.error('SurrealAdapter', `findMany ${table} failed`, e);\n throw e;\n }\n }\n\n private buildQuery(table: string, options?: QueryOptions, isCount = false, isDelete = false): { statement: string, vars: any; } {\n // Basic query builder\n let type = isDelete ? 'DELETE' : 'SELECT';\n let fields = isDelete ? '' : (isCount ? 'count()' : '*');\n let from = `FROM type::table($table)`;\n let vars: any = { table };\n let clauses: string[] = [];\n\n if (options?.where) {\n Object.entries(options.where).forEach(([k, v], i) => {\n const varName = `where_${i}`;\n clauses.push(`${k} = $${varName}`);\n vars[varName] = v;\n });\n }\n\n if (options?.gt) {\n Object.entries(options.gt).forEach(([k, v], i) => {\n const varName = `gt_${i}`;\n clauses.push(`${k} > $${varName}`);\n vars[varName] = v;\n });\n }\n\n if (options?.lt) {\n Object.entries(options.lt).forEach(([k, v], i) => {\n const varName = `lt_${i}`;\n clauses.push(`${k} < $${varName}`);\n vars[varName] = v;\n });\n }\n\n let whereStr = clauses.length ? 'WHERE ' + clauses.join(' AND ') : '';\n\n let suffix = '';\n if (!isCount && !isDelete) {\n if (options?.sort) {\n const sorts = Object.entries(options.sort).map(([k, v]) => `${k} ${v.toUpperCase()}`);\n if (sorts.length) suffix += ` ORDER BY ${sorts.join(', ')}`;\n }\n if (options?.limit) {\n suffix += ` LIMIT ${options.limit}`;\n }\n if (options?.offset) {\n suffix += ` START ${options.offset}`;\n }\n }\n\n // Handle Delete LIMIT separately because DELETE statements support LIMIT\n if (isDelete) {\n // Surreal DELETE supports WHERE ... \n // Does it support LIMIT? Yes: DELETE user WHERE ... LIMIT 10\n // Does it support ORDER BY? Yes.\n if (options?.sort) {\n const sorts = Object.entries(options.sort).map(([k, v]) => `${k} ${v.toUpperCase()}`);\n if (sorts.length) suffix += ` ORDER BY ${sorts.join(', ')}`;\n }\n if (options?.limit) {\n suffix += ` LIMIT ${options.limit}`;\n }\n }\n\n // isDelete format: DELETE [FROM] table WHERE ...\n // SurrealQL: DELETE table WHERE ...\n if (isDelete) {\n return {\n statement: `DELETE type::table($table) ${whereStr}${suffix};`,\n vars\n };\n }\n\n const groupAll = isCount ? 'GROUP ALL' : '';\n\n return {\n statement: `SELECT ${fields} ${from} ${whereStr} ${groupAll} ${suffix};`,\n vars\n };\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Knex } from 'knex';
|
|
2
|
+
import { DatastoreAdapter, QueryOptions } from '../datastore';
|
|
3
|
+
export interface KnexAdapterOptions extends Knex.Config {
|
|
4
|
+
}
|
|
5
|
+
export declare class KnexAdapter implements DatastoreAdapter {
|
|
6
|
+
private options;
|
|
7
|
+
name: string;
|
|
8
|
+
private db;
|
|
9
|
+
private logger;
|
|
10
|
+
private jsonColumnType;
|
|
11
|
+
constructor(options: KnexAdapterOptions);
|
|
12
|
+
connect(): Promise<void>;
|
|
13
|
+
private detectDialectFeatures;
|
|
14
|
+
disconnect(): Promise<void>;
|
|
15
|
+
setupSchema(): Promise<void>;
|
|
16
|
+
private ensureTable;
|
|
17
|
+
private jsonRef;
|
|
18
|
+
get<T>(table: string, id: string): Promise<T | null>;
|
|
19
|
+
create<T>(table: string, id: string, data: T): Promise<T>;
|
|
20
|
+
update<T>(table: string, id: string, data: Partial<T>): Promise<T>;
|
|
21
|
+
upsert<T>(table: string, id: string, data: T): Promise<T>;
|
|
22
|
+
delete(table: string, id: string): Promise<void>;
|
|
23
|
+
count(table: string, query?: QueryOptions): Promise<number>;
|
|
24
|
+
deleteMany(table: string, query?: QueryOptions): Promise<void>;
|
|
25
|
+
private findManyIDs;
|
|
26
|
+
findMany<T>(table: string, query?: QueryOptions): Promise<T[]>;
|
|
27
|
+
private applyFilters;
|
|
28
|
+
private applyQuery;
|
|
29
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { DatastoreAdapter, QueryOptions } from '../datastore';
|
|
2
|
+
export declare class LevelAdapter implements DatastoreAdapter {
|
|
3
|
+
private options;
|
|
4
|
+
name: string;
|
|
5
|
+
private db;
|
|
6
|
+
private logger;
|
|
7
|
+
constructor(options?: {
|
|
8
|
+
location?: string;
|
|
9
|
+
db?: any;
|
|
10
|
+
});
|
|
11
|
+
connect(): Promise<void>;
|
|
12
|
+
disconnect(): Promise<void>;
|
|
13
|
+
setupSchema(): Promise<void>;
|
|
14
|
+
private getKey;
|
|
15
|
+
get<T>(table: string, id: string): Promise<T | null>;
|
|
16
|
+
create<T>(table: string, id: string, data: T): Promise<T>;
|
|
17
|
+
update<T>(table: string, id: string, data: Partial<T>): Promise<T>;
|
|
18
|
+
upsert<T>(table: string, id: string, data: T): Promise<T>;
|
|
19
|
+
delete(table: string, id: string): Promise<void>;
|
|
20
|
+
count(table: string, query?: QueryOptions): Promise<number>;
|
|
21
|
+
deleteMany(table: string, query?: QueryOptions): Promise<void>;
|
|
22
|
+
findMany<T>(table: string, query?: QueryOptions): Promise<T[]>;
|
|
23
|
+
private scan;
|
|
24
|
+
private matches;
|
|
25
|
+
private applySortLimit;
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { DatastoreAdapter, QueryOptions } from '../datastore';
|
|
2
|
+
export declare class SqliteAdapter implements DatastoreAdapter {
|
|
3
|
+
private options;
|
|
4
|
+
name: string;
|
|
5
|
+
private db;
|
|
6
|
+
private logger;
|
|
7
|
+
private tables;
|
|
8
|
+
constructor(options?: {
|
|
9
|
+
filename?: string;
|
|
10
|
+
});
|
|
11
|
+
connect(): Promise<void>;
|
|
12
|
+
disconnect(): Promise<void>;
|
|
13
|
+
setupSchema(): Promise<void>;
|
|
14
|
+
private ensureTable;
|
|
15
|
+
get<T>(table: string, id: string): Promise<T | null>;
|
|
16
|
+
create<T>(table: string, id: string, data: T): Promise<T>;
|
|
17
|
+
update<T>(table: string, id: string, data: Partial<T>): Promise<T>;
|
|
18
|
+
upsert<T>(table: string, id: string, data: T): Promise<T>;
|
|
19
|
+
delete(table: string, id: string): Promise<void>;
|
|
20
|
+
count(table: string, query?: QueryOptions): Promise<number>;
|
|
21
|
+
deleteMany(table: string, query?: QueryOptions): Promise<void>;
|
|
22
|
+
findMany<T>(table: string, query?: QueryOptions): Promise<T[]>;
|
|
23
|
+
private buildWhere;
|
|
24
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { DatastoreAdapter, QueryOptions } from '../datastore';
|
|
2
|
+
export interface SurrealAdapterOptions {
|
|
3
|
+
url?: string;
|
|
4
|
+
namespace?: string;
|
|
5
|
+
database?: string;
|
|
6
|
+
auth?: any;
|
|
7
|
+
engines?: any;
|
|
8
|
+
connectOptions?: any;
|
|
9
|
+
}
|
|
10
|
+
export declare class SurrealAdapter implements DatastoreAdapter {
|
|
11
|
+
name: string;
|
|
12
|
+
private db;
|
|
13
|
+
private logger;
|
|
14
|
+
private options;
|
|
15
|
+
constructor(options?: SurrealAdapterOptions);
|
|
16
|
+
connect(): Promise<void>;
|
|
17
|
+
disconnect(): Promise<void>;
|
|
18
|
+
setupSchema(): Promise<void>;
|
|
19
|
+
private retry;
|
|
20
|
+
get<T>(table: string, id: string): Promise<T | null>;
|
|
21
|
+
create<T>(table: string, id: string, data: T): Promise<T>;
|
|
22
|
+
update<T>(table: string, id: string, data: Partial<T>): Promise<T>;
|
|
23
|
+
upsert<T>(table: string, id: string, data: T): Promise<T>;
|
|
24
|
+
delete(table: string, id: string): Promise<void>;
|
|
25
|
+
count(table: string, query?: QueryOptions): Promise<number>;
|
|
26
|
+
deleteMany(table: string, query?: QueryOptions): Promise<void>;
|
|
27
|
+
findMany<T>(table: string, query?: QueryOptions): Promise<T[]>;
|
|
28
|
+
private buildQuery;
|
|
29
|
+
}
|