orange-orm
Version:
Object Relational Mapper
1,706 lines (1,500 loc) • 463 kB
JavaScript
void !function() {
typeof self === 'undefined' && typeof global === 'object'
? global.self = global : null;
}();import * as fastJsonPatch from 'fast-json-patch';
import * as uuid from 'uuid';
import * as axios from 'axios';
import * as _default from 'rfdc/default';
import * as ajv from 'ajv';
import * as onChange from '@lroal/on-change';
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
function getDefaultExportFromNamespaceIfPresent (n) {
return n && Object.prototype.hasOwnProperty.call(n, 'default') ? n['default'] : n;
}
var getTSDefinition_1;
var hasRequiredGetTSDefinition;
function requireGetTSDefinition () {
if (hasRequiredGetTSDefinition) return getTSDefinition_1;
hasRequiredGetTSDefinition = 1;
const typeMap = {
StringColumn: 'string',
BooleanColumn: 'boolean',
UUIDColumn: 'string',
BinaryColumn: 'string',
JSONColumn: 'object',
DateColumn: 'Date | string',
NumberColumn: 'number',
};
function getTSDefinition(tableConfigs, {isNamespace = false, isHttp = false} = {}) {
const rootTablesAdded = new Map();
const tableNames = new Set();
const tablesAdded = new Map();
let src = '';
const defs = tableConfigs.map(getTSDefinitionTable).join('');
const tables = tableConfigs.reduce((tables, x) => {
tables[x.name] = x.table;
return tables;
}, {});
src += getPrefixTs(isNamespace);
if (isNamespace)
src += startNamespace(tables, isHttp);
src += defs;
src += getRdbClientTs(tables, isHttp);
if (isNamespace)
src += '}';
return src;
function getTSDefinitionTable({table, customFilters, name}) {
let Name = name.substr(0, 1).toUpperCase() + name.substr(1);
name = name.substr(0, 1).toLowerCase() + name.substr(1);
let result = '' + getTable(table, Name, name, customFilters);
return result;
}
function getTable(table, Name, name, customFilters) {
const _columns = columns(table);
const _tableRelations = tableRelations(table);
return `
export interface ${Name}Table {
count(filter?: RawFilter): Promise<number>;
getAll(): Promise<${Name}Array>;
getAll(fetchingStrategy: ${Name}Strategy): Promise<${Name}Array>;
getMany(filter?: RawFilter): Promise<${Name}Array>;
getMany(filter: RawFilter, fetchingStrategy: ${Name}Strategy): Promise<${Name}Array>;
getMany(${name}s: Array<${Name}>): Promise<${Name}Array>;
getMany(${name}s: Array<${Name}>, fetchingStrategy: ${Name}Strategy): Promise<${Name}Array>;
getOne(filter?: RawFilter): Promise<${Name}Row>;
getOne(filter?: RawFilter, fetchingStrategy?: ${Name}Strategy): Promise<${Name}Row>;
getOne(${name}: ${Name}): Promise<${Name}Row>;
getOne(${name}: ${Name}, fetchingStrategy: ${Name}Strategy): Promise<${Name}Row>;
getById(${getIdArgs(table)}): Promise<${Name}Row>;
getById(${getIdArgs(table)}, fetchingStrategy: ${Name}Strategy): Promise<${Name}Row>;
replace(${name}s: ${Name}[] | ${Name}): Promise<void>;
replace(${name}s: ${Name}[], fetchingStrategy: ${Name}Strategy): Promise<${Name}Array>;
replace(${name}: ${Name}, fetchingStrategy: ${Name}Strategy): Promise<${Name}Row>;
update(${name}: ${Name}): Promise<void>;
update(${name}: ${Name}, whereStrategy: ${Name}Strategy): Promise<void>;
update(${name}: ${Name}, whereStrategy: ${Name}Strategy): Promise<void>;
update(${name}: ${Name}, whereStrategy: ${Name}Strategy, fetchingStrategy: ${Name}Strategy): Promise<${Name}Row[]>;
updateChanges(${name}s: ${Name}[], old${name}s: ${Name}[]): Promise<${Name}Array>;
updateChanges(${name}s: ${Name}[],old${name}s: ${Name}[], fetchingStrategy: ${Name}Strategy): Promise<${Name}Array>;
updateChanges(${name}: ${Name}, old${name}: ${Name}): Promise<${Name}Row>;
updateChanges(${name}: ${Name},old${name}: ${Name}, fetchingStrategy: ${Name}Strategy): Promise<${Name}Row>;
insert(${name}s: ${Name}[]): Promise<${Name}Array>;
insert(${name}s: ${Name}[], fetchingStrategy: ${Name}Strategy): Promise<${Name}Array>;
insert(${name}: ${Name}): Promise<${Name}Row>;
insert(${name}: ${Name}, fetchingStrategy: ${Name}Strategy): Promise<${Name}Row>;
insertAndForget(${name}s: ${Name}[]): Promise<void>;
insertAndForget(${name}: ${Name}): Promise<void>;
delete(filter?: RawFilter): Promise<void>;
delete(${name}s: Array<${Name}>): Promise<void>;
deleteCascade(filter?: RawFilter): Promise<void>;
deleteCascade(${name}s: Array<${Name}>): Promise<void>;
proxify(${name}s: ${Name}[]): ${Name}Array;
proxify(${name}s: ${Name}[], fetchingStrategy: ${Name}Strategy): ${Name}Array;
proxify(${name}: ${Name}): ${Name}Row;
proxify(${name}: ${Name}, fetchingStrategy: ${Name}Strategy): ${Name}Row;
patch(patch: JsonPatch): Promise<void>;
patch(patch: JsonPatch, concurrency: ${Name}Concurrency, fetchingStrategy?: ${Name}Strategy): Promise<void>;
customFilters: ${Name}CustomFilters;
${_columns}
${_tableRelations}
}
export interface ${Name}ExpressConfig {
baseFilter?: RawFilter | ((context: ExpressContext) => RawFilter | Promise<RawFilter>);
customFilters?: Record<string, (context: ExpressContext,...args: any[]) => RawFilter | Promise<RawFilter>>;
concurrency?: ${Name}Concurrency;
readonly?: boolean;
disableBulkDeletes?: boolean;
}
export interface ${Name}HonoConfig {
baseFilter?: RawFilter | ((context: HonoContext) => RawFilter | Promise<RawFilter>);
customFilters?: Record<string, (context: HonoContext,...args: any[]) => RawFilter | Promise<RawFilter>>;
concurrency?: ${Name}Concurrency;
readonly?: boolean;
disableBulkDeletes?: boolean;
}
export interface ${Name}CustomFilters {
${getCustomFilters(customFilters)}
}
export interface ${Name}Array extends Array<${Name}> {
saveChanges(): Promise<void>;
saveChanges(concurrency: ${Name}Concurrency, fetchingStrategy?: ${Name}Strategy): Promise<void>;
acceptChanges(): void;
clearChanges(): void;
refresh(): Promise<void>;
refresh(fetchingStrategy: ${Name}Strategy): Promise<void>;
delete(): Promise<void>;
delete(options: ${Name}Concurrency): Promise<void>;
}
export interface ${Name}Row extends ${Name} {
saveChanges(): Promise<void>;
saveChanges(concurrency: ${Name}Concurrency, fetchingStrategy?: ${Name}Strategy): Promise<void>;
acceptChanges(): void;
clearChanges(): void;
refresh(): Promise<void>;
refresh(fetchingStrategy: ${Name}Strategy): Promise<void>;
delete(): Promise<void>;
delete(options: ${Name}Concurrency): Promise<void>;
}
${Concurrency(table, Name, true)}
`;
}
function getIdArgs(table) {
let result = [];
for (let i = 0; i < table._primaryColumns.length; i++) {
let column = table._primaryColumns[i];
result.push(`${column.alias}: ${typeMap[column.tsType]}`);
}
return result.join(', ');
}
function tableRelations(table) {
let relations = table._relations;
let result = '';
for (let relationName in relations) {
const tableName = getTableName(relations[relationName], relationName);
result += `${relationName}: ${tableName}RelatedTable;`;
}
return result;
}
function columns(table) {
let result = '';
let separator = '';
for (let i = 0; i < table._columns.length; i++) {
let column = table._columns[i];
result += `${separator}${column.alias} : ${column.tsType};`;
separator = `
`;
}
return result;
}
function Concurrency(table, name, isRoot) {
name = pascalCase(name);
if (!isRoot) {
if (tablesAdded.has(table))
return '';
else {
tablesAdded.set(table, name);
}
}
let otherConcurrency = '';
let concurrencyRelations = '';
let strategyRelations = '';
let regularRelations = '';
let relations = table._relations;
let relationName;
let separator = `
`;
let visitor = {};
visitor.visitJoin = function(relation) {
const tableTypeName = getTableName(relation, relationName);
otherConcurrency += `${Concurrency(relation.childTable, tableTypeName)}`;
concurrencyRelations += `${relationName}?: ${tableTypeName}Concurrency;${separator}`;
strategyRelations += `${relationName}?: ${tableTypeName}Strategy | boolean;${separator}`;
regularRelations += `${relationName}?: ${tableTypeName} | null;${separator}`;
};
visitor.visitOne = visitor.visitJoin;
visitor.visitMany = function(relation) {
const tableTypeName = getTableName(relation, relationName);
otherConcurrency += `${Concurrency(relation.childTable, tableTypeName)}`;
concurrencyRelations += `${relationName}?: ${tableTypeName}Concurrency;${separator}`;
strategyRelations += `${relationName}?: ${tableTypeName}Strategy | boolean;${separator}`;
regularRelations += `${relationName}?: ${tableTypeName}[] | null;${separator}`;
};
for (relationName in relations) {
var relation = relations[relationName];
relation.accept(visitor);
}
let row = '';
if (!isRoot) {
row = `export interface ${name}RelatedTable {
${columns(table)}
${tableRelations(table)}
all: (selector: (table: ${name}RelatedTable) => RawFilter) => Filter;
any: (selector: (table: ${name}RelatedTable) => RawFilter) => Filter;
none: (selector: (table: ${name}RelatedTable) => RawFilter) => Filter;
exists: () => Filter;
}`;
}
return `
export interface ${name}Concurrency {
readonly?: boolean;
concurrency?: Concurrency;
${concurrencyColumns(table)}
${concurrencyRelations}
}
export interface ${name} {
${regularColumns(table)}
${regularRelations}
}
export interface ${name}TableBase {
${columns(table)}
${tableRelations(table)}
}
export interface ${name}Strategy {
${strategyColumns(table)}
${strategyRelations}
limit?: number;
offset?: number;
orderBy?: Array<${orderByColumns(table)}> | ${orderByColumns(table)};
where?: (table: ${name}TableBase) => RawFilter;
}
${otherConcurrency}
${row}`;
}
function getTableName(relation, relationName) {
let name = rootTablesAdded.get(relation.childTable);
if (name)
return name;
else {
let name = pascalCase(relationName);
let count = 2;
while (tableNames.has(name)) {
name = name + 'x' + count;
count++;
}
rootTablesAdded.set(relation.childTable, name);
tableNames.add(name);
return name;
}
}
}
function regularColumns(table) {
let result = '';
let separator = '';
for (let i = 0; i < table._columns.length; i++) {
let column = table._columns[i];
if (column._notNull)
result += `${separator}${column.alias} : ${typeMap[column.tsType]};`;
else
result += `${separator}${column.alias}? : ${typeMap[column.tsType]} | null;`;
separator = `
`;
}
return result;
}
function orderByColumns(table) {
let result = '';
let separator = '';
for (let i = 0; i < table._columns.length; i++) {
let column = table._columns[i];
result += `${separator}'${column.alias}' | '${column.alias} desc'`;
separator = '| ';
}
return result;
}
function pascalCase(name) {
return name[0].toUpperCase() + name.substr(1);
}
function concurrencyColumns(table) {
let result = '';
let separator = '';
for (let i = 0; i < table._columns.length; i++) {
let column = table._columns[i];
result += `${separator}${column.alias}? : ColumnConcurrency;`;
separator = `
`;
}
return result;
}
function strategyColumns(table) {
let primarySet = new Set(table._primaryColumns);
let result = '';
let separator = '';
for (let i = 0; i < table._columns.length; i++) {
let column = table._columns[i];
if (primarySet.has(column))
continue;
result += `${separator}${column.alias}? : boolean;`;
separator = `
`;
}
return result;
}
function getCustomFilters(filters) {
return getLeafNames(filters);
function getLeafNames(obj, tabs = '\t\t\t\t\t') {
let result = '';
for (let p in obj) {
if (typeof obj[p] === 'object' && obj[p] !== null) {
result += '\n' + tabs + p + ': {' + tabs + getLeafNames(obj[p], tabs + '\t');
result += '\n' + tabs + '}';
}
else if (typeof obj[p] === 'function')
result += '\n' + tabs + p + ': (' + getParamNames(obj[p]) + ') => import(\'orange-orm\').Filter;';
}
return result;
}
}
function getParamNames(func) {
let STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
let ARGUMENT_NAMES = /([^\s,]+)/g;
let fnStr = func.toString().replace(STRIP_COMMENTS, '');
let result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
if (result === null)
return '';
return result.slice(1).join(': unknown, ') + ': unknown';
}
function getPrefixTs(isNamespace) {
if (isNamespace)
return `
/* eslint-disable @typescript-eslint/no-empty-interface */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { AxiosInterceptorManager, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
import type { BooleanColumn, JSONColumn, UUIDColumn, DateColumn, NumberColumn, BinaryColumn, StringColumn, Concurrency, Filter, RawFilter, TransactionOptions, Pool, Express, Hono, Url, ColumnConcurrency, JsonPatch } from 'orange-orm';
export { RequestHandler } from 'express';
export { Concurrency, Filter, RawFilter, Config, TransactionOptions, Pool } from 'orange-orm';
export = r;
declare function r(config: Config): r.RdbClient;
`;
return `
/* eslint-disable @typescript-eslint/no-empty-interface */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-explicit-any */
import schema from './schema';
import type { AxiosInterceptorManager, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
import type { BooleanColumn, JSONColumn, UUIDColumn, DateColumn, NumberColumn, BinaryColumn, StringColumn, Concurrency, Filter, RawFilter, TransactionOptions, Pool, Express, Hono, Url, ColumnConcurrency, JsonPatch } from 'orange-orm';
export default schema as RdbClient;`;
}
function startNamespace(tables, isHttp) {
return `
declare namespace r {${getTables(isHttp)}
`;
function getTables(isHttp) {
let result = '';
for (let name in tables) {
let Name = name.substring(0, 1).toUpperCase() + name.substring(1);
result +=
`
const ${name}: ${Name}Table;`;
}
if (!isHttp)
result += `
function and(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter;
function or(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter;
function not(): Filter;
function transaction(fn: (transaction: RdbClient) => Promise<unknown>, options?: TransactionOptions): Promise<void>;
function query(filter: RawFilter | string): Promise<unknown[]>;
function query<T>(filter: RawFilter | string): Promise<T[]>;
function transaction(fn: (transaction: RdbClient) => Promise<unknown>, options?: TransactionOptions): Promise<void>;
const filter: Filter;
function express(): Express;
function express(config: ExpressConfig): Express;
function hono(): Hono;
function hono(config: HonoConfig): Hono;
`;
else
result += `
const interceptors: {
request: AxiosInterceptorManager<InternalAxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
};
function reactive(proxyMethod: (obj: unknown) => unknown): void;
function and(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter;
function or(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter;
function not(): Filter;
const filter: Filter;
`;
return result;
}
}
function getRdbClientTs(tables, isHttp) {
return `
export interface RdbClient {${getTables(isHttp)}
}
export interface RdbConfig {
db?: Pool | (() => Pool);
readonly?: boolean;
concurrency?: Concurrency;${getConcurrencyTables()}
}
export interface MetaData {
readonly?: boolean;
concurrency?: Concurrency;${getConcurrencyTables()}
}
export interface ExpressConfig {
db?: Pool | (() => Pool);
tables?: ExpressTables;
concurrency?: Concurrency;
readonly?: boolean;
disableBulkDeletes?: boolean;
hooks?: ExpressHooks;
}
export interface HonoConfig {
db?: Pool | (() => Pool);
tables?: HonoTables;
concurrency?: Concurrency;
readonly?: boolean;
disableBulkDeletes?: boolean;
hooks?: HonoHooks;
}
export interface ExpressContext {
request: import('express').Request;
response: import('express').Response;
client: RdbClient;
}
export interface HonoRequest {
method: string;
query: Record<string, string>;
headers: Record<string, string>;
json(): Promise<unknown>;
}
export interface HonoResponse {
status(code: number): HonoResponse;
setHeader(name: string, value: string): HonoResponse;
json(value: unknown): unknown;
send(value: unknown): unknown;
}
export interface HonoContext {
request: HonoRequest;
response: HonoResponse;
client: RdbClient;
}
export interface ExpressTransactionHooks {
beforeBegin?: (db: Pool, request: import('express').Request, response: import('express').Response) => void | Promise<void>;
afterBegin?: (db: Pool, request: import('express').Request, response: import('express').Response) => void | Promise<void>;
beforeCommit?: (db: Pool, request: import('express').Request, response: import('express').Response) => void | Promise<void>;
afterCommit?: (db: Pool, request: import('express').Request, response: import('express').Response) => void | Promise<void>;
afterRollback?: (db: Pool, request: import('express').Request, response: import('express').Response, error?: unknown) => void | Promise<void>;
}
export interface ExpressHooks extends ExpressTransactionHooks {
transaction?: ExpressTransactionHooks;
}
export interface HonoTransactionHooks {
beforeBegin?: (db: Pool, request: HonoRequest, response: HonoResponse) => void | Promise<void>;
afterBegin?: (db: Pool, request: HonoRequest, response: HonoResponse) => void | Promise<void>;
beforeCommit?: (db: Pool, request: HonoRequest, response: HonoResponse) => void | Promise<void>;
afterCommit?: (db: Pool, request: HonoRequest, response: HonoResponse) => void | Promise<void>;
afterRollback?: (db: Pool, request: HonoRequest, response: HonoResponse, error?: unknown) => void | Promise<void>;
}
export interface HonoHooks extends HonoTransactionHooks {
transaction?: HonoTransactionHooks;
}
export interface ExpressTables {${getExpressTables()}
}
export interface HonoTables {${getHonoTables()}
}
`;
function getConcurrencyTables() {
let result = '';
for (let name in tables) {
let Name = name.substring(0, 1).toUpperCase() + name.substring(1);
result +=
`
${name}?: ${Name}Concurrency;`;
}
return result;
}
function getTables(isHttp) {
let result = '';
for (let name in tables) {
let Name = name.substring(0, 1).toUpperCase() + name.substring(1);
result +=
`
${name}: ${Name}Table;`;
}
if (isHttp)
result += `
(config: {db: Url}): RdbClient;
interceptors: {
request: AxiosInterceptorManager<InternalAxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
};
reactive(proxyMethod: (obj: unknown) => unknown): void;
and(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter;
or(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter;
not(): Filter;
transaction(fn: (transaction: RdbClient) => Promise<unknown>, options?: TransactionOptions): Promise<void>;
filter: Filter;
createPatch(original: any[], modified: any[]): JsonPatch;
createPatch(original: any, modified: any): JsonPatch;`;
else
result += `
(config: RdbConfig): RdbClient;
and(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter;
or(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter;
not(): Filter;
query(filter: RawFilter | string): Promise<unknown[]>;
query<T>(filter: RawFilter | string): Promise<T[]>;
transaction(fn: (transaction: RdbClient) => Promise<unknown>, options?: TransactionOptions): Promise<void>;
filter: Filter;
createPatch(original: any[], modified: any[]): JsonPatch;
createPatch(original: any, modified: any): JsonPatch;
express(): Express;
express(config: ExpressConfig): Express;
hono(): Hono;
hono(config: HonoConfig): Hono;
readonly metaData: MetaData;`;
return result;
}
function getExpressTables() {
let result = '';
for (let name in tables) {
let Name = name.substring(0, 1).toUpperCase() + name.substring(1);
result +=
`
${name}?: boolean | ${Name}ExpressConfig;`;
}
return result;
}
function getHonoTables() {
let result = '';
for (let name in tables) {
let Name = name.substring(0, 1).toUpperCase() + name.substring(1);
result +=
`
${name}?: boolean | ${Name}HonoConfig;`;
}
return result;
}
}
getTSDefinition_1 = getTSDefinition;
return getTSDefinition_1;
}
var getMeta_1;
var hasRequiredGetMeta;
function requireGetMeta () {
if (hasRequiredGetMeta) return getMeta_1;
hasRequiredGetMeta = 1;
function getMeta(table, map = new Map()) {
if (map.has(table))
return map.get(table).id;
let strategy = {
keys: table._primaryColumns.map(x => ({name: x.alias, type: x.tsType})),
columns: {},
relations: {},
id: map.size
};
map.set(table, strategy);
for (let i = 0; i < table._columns.length; i++) {
const column = table._columns[i];
strategy.columns[column.alias] = {};
if ('serializable' in column && !column.serializable)
strategy.columns[column.alias].serializable = false;
else
strategy.columns[column.alias].serializable = true;
}
let relations = table._relations;
let relationName;
let visitor = {};
visitor.visitJoin = function(relation) {
strategy.relations[relationName] = getMeta(relation.childTable, map);
};
visitor.visitMany = function(relation) {
strategy.relations[relationName] = getMeta(relation.childTable, map);
};
visitor.visitOne = visitor.visitMany;
for (relationName in relations) {
let relation = relations[relationName];
relation.accept(visitor);
}
return strategy;
}
getMeta_1 = getMeta;
return getMeta_1;
}
var hostExpress_1;
var hasRequiredHostExpress;
function requireHostExpress () {
if (hasRequiredHostExpress) return hostExpress_1;
hasRequiredHostExpress = 1;
const getTSDefinition = requireGetTSDefinition();
// let hostLocal = _hostLocal;
const getMeta = requireGetMeta();
function hostExpress(hostLocal, client, options = {}) {
if ('db' in options && (options.db ?? undefined) === undefined || !client.db)
throw new Error('No db specified');
const dbOptions = { db: options.db || client.db };
let c = {};
const readonly = { readonly: options.readonly};
const sharedHooks = options.hooks;
for (let tableName in client.tables) {
const tableOptions = options[tableName] || {};
const hooks = tableOptions.hooks || sharedHooks;
c[tableName] = hostLocal({
...dbOptions,
...readonly,
...tableOptions,
table: client.tables[tableName],
isHttp: true,
client,
hooks
});
}
async function handler(req, res) {
if (req.method === 'POST')
return post.apply(null, arguments);
if (req.method === 'PATCH')
return patch.apply(null, arguments);
if (req.method === 'GET')
return get.apply(null, arguments);
if (req.method === 'OPTIONS')
return handleOptions(req, res); // assuming the second argument is `response`
else
res.status(405).set('Allow', 'GET, POST, PATCH, OPTIONS').send('Method Not Allowed');
}
handler.db = handler;
handler.dts = get;
function get(request, response) {
try {
if (request.query.table) {
if (!(request.query.table in c)) {
let e = new Error('Table is not exposed or does not exist');
// @ts-ignore
e.status = 400;
throw e;
}
const result = getMeta(client.tables[request.query.table]);
response.setHeader('content-type', 'text/plain');
response.status(200).send(result);
}
else {
const isNamespace = request.query.isNamespace === 'true';
let tsArg = Object.keys(c).map(x => {
return { table: client.tables[x], customFilters: options?.tables?.[x].customFilters, name: x };
});
response.setHeader('content-type', 'text/plain');
response.status(200).send(getTSDefinition(tsArg, { isNamespace, isHttp: true }));
}
}
catch (e) {
if (e.status === undefined)
response.status(500).send(e.message || e);
else
response.status(e.status).send(e.message);
}
}
async function patch(request, response) {
try {
response.json(await c[request.query.table].patch(request.body, request, response));
}
catch (e) {
if (e.status === undefined)
response.status(500).send(e.message || e);
else
response.status(e.status).send(e.message);
}
}
async function post(request, response) {
try {
if (!request.query.table) {
let e = new Error('Table not defined');
// @ts-ignore
e.status = 400;
throw e;
}
else if (!(request.query.table in c)) {
let e = new Error('Table is not exposed or does not exist');
// @ts-ignore
e.status = 400;
throw e;
}
response.json(await c[request.query.table].post(request.body, request, response));
}
catch (e) {
if (e.status === undefined)
response.status(500).send(e.message || e);
else
response.status(e.status).send(e.message);
}
}
function handleOptions(req, response) {
response.setHeader('Access-Control-Allow-Origin', '*'); // Adjust this as per your CORS needs
response.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, OPTIONS'); // And any other methods you support
response.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // And any other headers you expect in requests
response.setHeader('Access-Control-Max-Age', '86400'); // Cache preflight request for a day. Adjust as you see fit
response.status(204).send(); // 204 No Content response for successful OPTIONS requests
}
return handler;
}
hostExpress_1 = hostExpress;
return hostExpress_1;
}
var hostHono_1;
var hasRequiredHostHono;
function requireHostHono () {
if (hasRequiredHostHono) return hostHono_1;
hasRequiredHostHono = 1;
const getTSDefinition = requireGetTSDefinition();
const getMeta = requireGetMeta();
function hostHono(hostLocal, client, options = {}) {
if ('db' in options && (options.db ?? undefined) === undefined || !client.db)
throw new Error('No db specified');
const dbOptions = { db: options.db || client.db };
let c = {};
const readonly = { readonly: options.readonly };
const sharedHooks = options.hooks;
for (let tableName in client.tables) {
const tableOptions = options[tableName] || {};
const hooks = tableOptions.hooks || sharedHooks;
c[tableName] = hostLocal({
...dbOptions,
...readonly,
...tableOptions,
table: client.tables[tableName],
isHttp: true,
client,
hooks
});
}
async function handler(ctx) {
const request = createRequest(ctx);
const response = createResponse();
try {
if (request.method === 'POST')
return await post(request, response);
if (request.method === 'PATCH')
return await patch(request, response);
if (request.method === 'GET')
return get(request, response);
if (request.method === 'OPTIONS')
return handleOptions(response);
return response
.status(405)
.setHeader('Allow', 'GET, POST, PATCH, OPTIONS')
.send('Method Not Allowed');
}
catch (e) {
if (e.status === undefined)
return response.status(500).send(e.message || e);
return response.status(e.status).send(e.message);
}
}
handler.db = handler;
handler.dts = get;
function get(request, response) {
if (request.query.table) {
if (!(request.query.table in c)) {
let e = new Error('Table is not exposed or does not exist');
// @ts-ignore
e.status = 400;
throw e;
}
const result = getMeta(client.tables[request.query.table]);
response.setHeader('content-type', 'text/plain');
return response.status(200).send(result);
}
const isNamespace = request.query.isNamespace === 'true';
let tsArg = Object.keys(c).map(x => {
return { table: client.tables[x], customFilters: options?.tables?.[x].customFilters, name: x };
});
response.setHeader('content-type', 'text/plain');
return response.status(200).send(getTSDefinition(tsArg, { isNamespace, isHttp: true }));
}
async function patch(request, response) {
const table = request.query.table;
const body = await request.json();
return response.json(await c[table].patch(body, request, response));
}
async function post(request, response) {
if (!request.query.table) {
let e = new Error('Table not defined');
// @ts-ignore
e.status = 400;
throw e;
}
if (!(request.query.table in c)) {
let e = new Error('Table is not exposed or does not exist');
// @ts-ignore
e.status = 400;
throw e;
}
const body = await request.json();
return response.json(await c[request.query.table].post(body, request, response));
}
function handleOptions(response) {
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, OPTIONS');
response.setHeader('Access-Control-Allow-Headers', 'Content-Type');
response.setHeader('Access-Control-Max-Age', '86400');
return response.status(204).send('');
}
function createRequest(ctx) {
let bodyPromise;
const query = Object.fromEntries(new URL(ctx.req.url).searchParams.entries());
const headers = {};
for (const [name, value] of ctx.req.raw.headers.entries())
headers[name] = value;
return {
method: ctx.req.method,
query,
headers,
json: async () => {
if (!bodyPromise)
bodyPromise = ctx.req.json();
return bodyPromise;
}
};
}
function createResponse() {
let statusCode = 200;
const headers = new Headers();
return {
status(code) {
statusCode = code;
return this;
},
setHeader(name, value) {
headers.set(name, value);
return this;
},
json(value) {
if (!headers.has('content-type'))
headers.set('content-type', 'application/json');
return new Response(JSON.stringify(value), { status: statusCode, headers });
},
send(value) {
if (typeof value === 'string') {
if (!headers.has('content-type'))
headers.set('content-type', 'text/plain');
return new Response(value, { status: statusCode, headers });
}
if (!headers.has('content-type'))
headers.set('content-type', 'application/json');
return new Response(JSON.stringify(value), { status: statusCode, headers });
}
};
}
return handler;
}
hostHono_1 = hostHono;
return hostHono_1;
}
var require$$0$3 = /*@__PURE__*/getDefaultExportFromNamespaceIfPresent(fastJsonPatch);
var dateToISOString_1;
var hasRequiredDateToISOString;
function requireDateToISOString () {
if (hasRequiredDateToISOString) return dateToISOString_1;
hasRequiredDateToISOString = 1;
function dateToISOString(date) {
let tzo = -date.getTimezoneOffset();
let dif = tzo >= 0 ? '+' : '-';
function pad(num) {
let norm = Math.floor(Math.abs(num));
return (norm < 10 ? '0' : '') + norm;
}
function padMilli(d) {
return (d.getMilliseconds() + '').padStart(3, '0');
}
return date.getFullYear() +
'-' + pad(date.getMonth() + 1) +
'-' + pad(date.getDate()) +
'T' + pad(date.getHours()) +
':' + pad(date.getMinutes()) +
':' + pad(date.getSeconds()) +
'.' + padMilli(date) +
dif + pad(tzo / 60) +
':' + pad(tzo % 60);
}
dateToISOString_1 = dateToISOString;
return dateToISOString_1;
}
var stringify_1;
var hasRequiredStringify;
function requireStringify () {
if (hasRequiredStringify) return stringify_1;
hasRequiredStringify = 1;
let dateToISOString = requireDateToISOString();
function stringify(value) {
return JSON.stringify(value, replacer);
}
function replacer(key, value) {
// @ts-ignore
if (typeof value === 'bigint')
return value.toString();
else if (value instanceof Date && !isNaN(value))
return dateToISOString(value);
else
return value;
}
stringify_1 = stringify;
return stringify_1;
}
var require$$0$2 = /*@__PURE__*/getDefaultExportFromNamespaceIfPresent(uuid);
var createPatch;
var hasRequiredCreatePatch;
function requireCreatePatch () {
if (hasRequiredCreatePatch) return createPatch;
hasRequiredCreatePatch = 1;
const jsonpatch = require$$0$3;
let dateToIsoString = requireDateToISOString();
let stringify = requireStringify();
let { v4: uuid } = require$$0$2;
createPatch = function createPatch(original, dto, options) {
let subject = toCompareObject({ d: original }, options, true);
let clonedDto = toCompareObject({ d: dto }, options, true);
let keyPositionMap = toKeyPositionMap(dto);
let observer = jsonpatch.observe(subject);
subject.d = clonedDto.d;
let changes = jsonpatch.generate(observer);
let clonedOriginal = toCompareObject(original, options);
let {inserted, deleted, updated} = splitChanges(changes);
updated.sort(comparePatch);
return [...inserted, ...updated, ...deleted];
function splitChanges(changes) {
let inserted = [];
let deleted = [];
let updated = [];
for (let change of changes) {
change.path = change.path.substring(2);
if (change.op === 'add' && change.path.split('/').length === 2) {
inserted.push(change);
}
else if (change.op === 'remove' && change.path.split('/').length === 2) {
addOldValue(change);
deleted.push(change);
} else {
addOldValue(change);
updated.push(change);
}
}
return { inserted, updated, deleted};
}
function addOldValue(change) {
if (change.op === 'remove' || change.op === 'replace') {
let splitPath = change.path.split('/');
splitPath.shift();
change.oldValue = splitPath.reduce(extract, clonedOriginal);
}
else
return change;
function extract(obj, element) {
return obj[element];
}
return change;
}
function toKeyPositionMap(rows) {
return rows.reduce((map, element, i) => {
if (options && options.keys && element === Object(element)) {
let key = [];
for (let i = 0; i < options.keys.length; i++) {
let keyName = options.keys[i].name;
key.push(negotiateTempKey(element[keyName]));
}
map[stringify(key)] = i;
}
else if ('id' in element)
map[stringify([element.id])] = i;
else
map[i] = i;
return map;
}, {});
}
function toCompareObject(object, options, isRoot) {
if (Array.isArray(object)) {
let copy = { __patchType: 'Array' };
for (let i = 0; i < object.length; i++) {
let element = toCompareObject(object[i], options);
if (options && options.keys && element === Object(element)) {
let key = [];
for (let i = 0; i < options.keys.length; i++) {
let keyName = options.keys[i].name;
key.push(negotiateTempKey(element[keyName]));
}
copy[stringify(key)] = element;
}
else if (element === Object(element) && 'id' in element)
copy[stringify([element.id])] = element;
else
copy[i] = element;
}
return copy;
}
else if (typeof object === 'bigint')
return object.toString();
else if (isValidDate(object))
return dateToIsoString(object);
else if (object === Object(object)) {
let copy = {};
for (let name in object) {
copy[name] = toCompareObject(object[name], isRoot ? options : options && options.relations && options.relations[name]);
}
return copy;
}
return object;
}
function isValidDate(d) {
return d instanceof Date && !isNaN(d);
}
function negotiateTempKey(value) {
if (value === undefined)
return `~${uuid()}`;
else
return value;
}
function comparePatch(a, b) {
const aPathArray = a.path.split('/');
const bPathArray = b.path.split('/');
return (aPathArray.length - bPathArray.length) || (keyPositionMap[aPathArray[1]] ?? Infinity - keyPositionMap[bPathArray[1]] ?? Infinity) || a.path.localeCompare(b.path);
}
};
return createPatch;
}
var extractSql;
var hasRequiredExtractSql;
function requireExtractSql () {
if (hasRequiredExtractSql) return extractSql;
hasRequiredExtractSql = 1;
function extract(sql) {
if (sql && typeof(sql) === 'function')
return sql();
else if (sql === undefined)
return '';
else
return sql;
}
extractSql = extract;
return extractSql;
}
var extractParameters;
var hasRequiredExtractParameters;
function requireExtractParameters () {
if (hasRequiredExtractParameters) return extractParameters;
hasRequiredExtractParameters = 1;
function extract(parameters) {
if (parameters) {
return parameters.slice(0);
}
return [];
}
extractParameters = extract;
return extractParameters;
}
var newParameterized_1;
var hasRequiredNewParameterized;
function requireNewParameterized () {
if (hasRequiredNewParameterized) return newParameterized_1;
hasRequiredNewParameterized = 1;
var extractSql = requireExtractSql();
var extractParameters = requireExtractParameters();
function Parameterized(text, parameters) {
this._text = text;
this.parameters = parameters;
}
Parameterized.prototype.sql = function() {
return this._text;
};
Parameterized.prototype.prepend = function(other) {
if (other.sql) {
var params = other.parameters.concat(this.parameters);
return newParameterized(other.sql() + this._text, params);
} else
return newParameterized(other + this._text, this.parameters);
};
Parameterized.prototype.append = function(other) {
if (other.sql) {
var params = this.parameters.concat(other.parameters);
return newParameterized(this._text + other.sql(), params);
} else
return newParameterized(this._text + other, this.parameters);
};
function newParameterized(text, parameters) {
text = extractSql(text);
parameters = extractParameters(parameters);
return new Parameterized(text, parameters);
}
newParameterized_1 = newParameterized;
return newParameterized_1;
}
var negotiateNextAndFilter_1;
var hasRequiredNegotiateNextAndFilter;
function requireNegotiateNextAndFilter () {
if (hasRequiredNegotiateNextAndFilter) return negotiateNextAndFilter_1;
hasRequiredNegotiateNextAndFilter = 1;
function negotiateNextAndFilter(filter, other) {
if (!other.sql())
return filter;
return filter.append(' AND ').append(other);
}
negotiateNextAndFilter_1 = negotiateNextAndFilter;
return negotiateNextAndFilter_1;
}
var negotiateNextOrFilter_1;
var hasRequiredNegotiateNextOrFilter;
function requireNegotiateNextOrFilter () {
if (hasRequiredNegotiateNextOrFilter) return negotiateNextOrFilter_1;
hasRequiredNegotiateNextOrFilter = 1;
function negotiateNextOrFilter(filter, other) {
if (!other.sql())
return filter;
return filter.prepend('(').append(' OR ').append(other).append(')');
}
negotiateNextOrFilter_1 = negotiateNextOrFilter;
return negotiateNextOrFilter_1;
}
var utils;
var hasRequiredUtils;
function requireUtils () {
if (hasRequiredUtils) return utils;
hasRequiredUtils = 1;
const newParameterized = requireNewParameterized();
const negotiateNextAndFilter = requireNegotiateNextAndFilter();
const negotiateNextOrFilter = requireNegotiateNextOrFilter();
function newBoolean(filter) {
var c = {};
c.sql = filter.sql.bind(filter);
c.parameters = filter.parameters;
c.append = function(other) {
var nextFilter = filter.append(other);
return newBoolean(nextFilter);
};
c.prepend = function(other) {
var nextFilter = filter.prepend(other);
return newBoolean(nextFilter);
};
c.and = function(context, other) {
if (other === undefined) {
other = context;
context = null;
}
other = negotiateRawSqlFilter(context, other);
var nextFilter = negotiateNextAndFilter(filter, other);
var next = newBoolean(nextFilter);
for (var i = 2; i < arguments.length; i++) {
next = next.and(context, arguments[i]);
}
return next;
};
c.or = function(context, other) {
if (other === undefined) {
other = context;
context = null;
}
other = negotiateRawSqlFilter(context, other);
var nextFilter = negotiateNextOrFilter(filter, other);
var next = newBoolean(nextFilter);
for (var i = 2; i < arguments.length; i++) {
next = next.or(context, arguments[i]);
}
return next;
};
c.not = function(_context) {
var nextFilter = filter.prepend('NOT (').append(')');
return newBoolean(nextFilter);
};
return c;
}
function negotiateRawSqlFilter(context, filter, optionalTable, emptyArrayMeansFalse) {
if (Array.isArray(filter) && filter.length === 0) {
const sql = emptyArrayMeansFalse ? '1 = 2' : '1 = 1';
return newBoolean(newParameterized(sql));
}
else if (Array.isArray(filter)) {
let curFilter;
let curObjectFilter;
for (let i = 0; i < filter.length; i++) {
let nextFilter = negotiateRawSqlFilter(context,filter[i], optionalTable);
if (nextFilter.isObjectFilter)
curObjectFilter = curObjectFilter ? curObjectFilter.or(context, nextFilter) : nextFilter;
else
curFilter = curFilter ? curFilter.and(context, nextFilter) : nextFilter;
}
if (curFilter && curObjectFilter)
return curFilter.and(context, curObjectFilter);
else if (curFilter)
return curFilter;
else
return curObjectFilter;
}
else {
let params = [];
if (filter) {
if (filter.and)
return filter;
if (filter.sql) {
let sql = filter.sql;
if (typeof filter.sql === 'function') {
sql = filter.sql();
}
params.push(sql, filter.parameters);
}
else if (isObjectFilter(filter, optionalTable)) {
return newObjectFilter(context, filter, optionalTable);
}
else
params = [filter];
} else {
params = [filter];
}
let parameterized = newParameterized.apply(null, params);
return newBoolean(parameterized);
}
}
function isObjectFilter(object, optionalTable) {
return optionalTable && object;
}
function newObjectFilter(context, object, table) {
let primaryColumns = table._primaryColumns;
let filter;
for (let i = 0; i < primaryColumns.length; i++) {
let column = primaryColumns[i];
let colFilter = column.equal(context, object[column.alias]);
filter = filter ? filter.and(context, colFilter) : colFilter ;
}
filter.isObjectFilter = true;
return filter;
}
utils = { negotiateRawSqlFilter, newBoolean};
return utils;
}
var negotiateRawSqlFilter_1;
var hasRequiredNegotiateRawSqlFilter;
function requireNegotiateRawSqlFilter () {
if (hasRequiredNegotiateRawSqlFilter) return negotiateRawSqlFilter_1;
hasRequiredNegotiateRawSqlFilter = 1;
const { negotiateRawSqlFilter } = requireUtils();
negotiateRawSqlFilter_1 = negotiateRawSqlFilter;
return negotiateRawSqlFilter_1;
}
var emptyFilter_1;
var hasRequiredEmptyFilter;
function requireEmptyFilter () {
if (hasRequiredEmptyFilter) return emptyFilter_1;
hasRequiredEmptyFilter = 1;
var negotiateRawSqlFilter = requireNegotiateRawSqlFilter();
var parameterized = requireNewParameterized()('');
function emptyFilter() {
return emptyFilter.and.apply(null, arguments);
}
emptyFilter.sql = parameterized.sql.bind(parameterized);
emptyFilter.parameters = parameterized.parameters;
emptyFilter.and = function(context, other) {
if (other === undefined) {
other = context;
context = null;
}
other = negotiateRawSqlFilter(context, other);
for (var i = 2; i < arguments.length; i++) {
other = other.and(context, arguments[i]);
}
return other;
};
emptyFilter.or = function(context, other) {
if (other === undefined) {
other = context;
context = null;
}
other = negotiateRawSqlFilter(context, other);
for (var i = 2; i < arguments.length; i++) {
other = other.or(context, arguments[i]);
}
return other;
};
emptyFilter.not = function(context, other) {
if (other === undefined) {
other = context;
context = null;
}
other = negotiateRawSqlFilter(context, other).not(context);
for (var i = 2; i < arguments.length; i++) {
other = other.and(context, arguments[i]);
}
return other;
};
emptyFilter_1 = emptyFilter;
return emptyFilter_1;
}
var executePath;
var hasRequiredExecutePath;
function requireExecutePath () {
if (hasRequiredExecutePath) return executePath;
hasRequiredExecutePath = 1;
const createPatch = requireCreatePatch();
const emptyFilter = requireEmptyFilter();
const negotiateRawSqlFilter = requireNegotiateRawSqlFilter();
let getMeta = requireGetMeta();
let isSafe = Symbol();
let _allowedOps = {
and: true,
or: true,
not: true,
AND: true,
OR: true,
NOT: true,
equal: true,
eq: true,
EQ: true,
notEqual: true,
ne: true,
NE: true,
lessThan: true,
lt: true,
LT: true,
lessThanOrEqual: true,
le: true,
LE: true,
greaterThan: true,
gt: true,
GT: true,
greaterThanOrEqual: true,
ge: true,
GE: true,
between: true,
in: true,
IN: true,
startsWith: true,
iStartsWith: true,
endsWith: true,
iEndsWith: true,
contains: true,
iContains: true,
iEqual: true,
iEq: true,
ieq: true,
IEQ: true,
exists: true,
all: true,
any: true,
none: true,
where: true,
sum: true,
avg: true,
max: true,
min: true,
count: true,
groupSum: true,
groupAvg: true,
groupMax: true,
groupMin: true,
groupCount: true,
_aggregate: true,
self: true,
};
function _executePath(context, ...rest) {
const _ops = {
and: emptyFilter.and.bind(null, context),
or: emptyFilter.or.bind(null, context),
not: emptyFilter.not.bind(null, context),
AND: emptyFilter.and.bind(null, context),
OR: emptyFilter.or.bind(null, context),
NOT: emptyFilter.not.bind(null, context),
};
return executePath(...rest);
async function executePath({ table, JSONFilter, baseFilter, customFilters = {}, request, response, readonly, disableBulkDeletes, isHttp, client }) {
let allowedOps = { ..._allowedOps, insert: !readonly, ...extractRelations(getMeta(table)) };
let ops = { ..._ops, ...getCustomFilterPaths(customFilters), getManyDto, getMany, aggregate, distinct, count, delete: _delete, cascadeDelete, update, replace };
let res = await parseFilter(JSONFilter, table);
if (res === undefined)
return {};
else
return res;
function parseFilter(json, table) {
if (isFilter(json)) {
let subFilters = [];
let anyAllNone = tryGetAnyAllNone(json.path, table);
if (anyAllNone) {
const arg0 = json.args[0];
if (isHttp && arg0 !== undefined)
validateArgs(arg0);
const f = arg0 === undefined
? anyAllNone(context)
: anyAllNone(context, x => parseFilter(arg0, x));
if(!('isSafe' in f))
f.isSafe = isSafe;
return f;
}
else {
for (let i = 0; i < json.args.length; i++) {
subFilters.push(parseFilter(json.args[i], nextTable(json.path, table)));
}
}
return executePath(json.path, subFilters);
}
else if (Array.isArray(json)) {
const result = [];
for (let i = 0; i < json.length; i++) {
result.push(parseFilter(json[i], table));
}
return result;
}
else if (isColumnRef(json)) {
return resolveColumnRef(table, json.__columnRef);
}
return json;
function tryGetAnyAllNone(path, table) {
const parts = path.split('.');
for (let i = 0; i < parts.length; i++) {
table = table[parts[i]];
}
let ops = new Set(['all', 'any', 'none', 'where', '_aggregate']);
// let ops = new Set(['all', 'any', 'none', 'where']);
let last = parts[parts.length - 1];
if (last === 'count' && parts.length > 1)
ops.add('count');
if (ops.has(last) || (table && (table._primaryColumns || (table.any && table.all))))
return table;
}
function executePath(path, args) {
if (path in ops) {
if (isHttp)
validateArgs(args);
let op = ops[path].apply(null, args);
if (op.then)
return op.then((o) => {
setSafe(o);
return o;
});
setSafe(op);
return op;
}
let pathArray = path.split('.');
let target = table;
let op = pathArray[pathArray.length - 1];
if (!allowedOps[op] && isHttp) {
let e = new Error('Disallowed operator ' + op);
// @ts-ignore
e.status = 403;
throw e;
}
for (let i = 0; i < pathArray.length; i++) {
target = target[pathArray[i]];
}
if (!target) {
const left = args && args[0];
if (left) {
target = left;
for (let i = 0; i < pathArray.length; i++) {
target = target[pathArray[i]];
}
if (target) {
let res = target.apply(null, [context].concat(args.slice(1)));
setSafe(res);
return res;
}
}
throw new Error(`Method '${path}' does not exist`);
}
let res = target.apply(null, [context, ...args]);
setSafe(res);
return res;
}
}
async function invokeBaseFilter() {
if (typeof baseFilter === 'function') {
const res = await baseFilter.apply(null, [bindDb(client), request, response]);
if (!res)
return;
const JSONFilter = JSON.parse(JSON.stringify(res));
//@ts-ignore
return executePath({ table, JSONFilter, request, response });
}
else
return;
}
function getCustomFilterPaths(customFilters) {
return getLeafNames(customFilters);
function getLeafNames(obj, result = {}, current = 'customFilters.') {
for (let p in obj) {
if (typeof obj[p] === 'object' && obj[p] !== null)
getLeafNames(obj[p], result, current + p + '.');
else
result[current + p] = resolveFilter.bind(null, obj[p]);
}
return result;
}
async function resolveFilter(fn, ...args) {
const context = { db: bindDb(client), request, response };
let res = fn.apply(null, [context, ...args]);
if (res.then)
res = await res;
const JSONFilter = JSON.parse(JSON.str