Comparing version 30.0.0 to 31.0.0
@@ -8,2 +8,3 @@ import { postProcessResponse, wrapIdentifier } from './helper.js'; | ||
export const initKmoreEvent = { | ||
dbId: '', | ||
type: 'unknown', | ||
@@ -20,2 +21,3 @@ identifier: void 0, | ||
exError: void 0, | ||
queryBuilder: void 0, | ||
timestamp: Date.now(), | ||
@@ -22,0 +24,0 @@ }; |
@@ -1,8 +0,8 @@ | ||
import { Observable, Subject } from 'rxjs'; | ||
import { KmoreEvent, OnQueryData, OnQueryErrorData, OnQueryErrorErr, OnQueryRespRaw, QueryResponse } from './types.js'; | ||
export declare const globalSubject: Subject<KmoreEvent>; | ||
export declare const globalEvent: Observable<KmoreEvent>; | ||
export declare function bindOnQuery(subject: Subject<KmoreEvent>, identifier: unknown, data: OnQueryData): void; | ||
export declare function bindOnQueryResp(subject: Subject<KmoreEvent>, identifier: unknown, _: QueryResponse, respRaw: OnQueryRespRaw): void; | ||
export declare function bindOnQueryError(subject: Subject<KmoreEvent>, identifier: unknown, err: OnQueryErrorErr, data: OnQueryErrorData): void; | ||
import type { Knex } from 'knex'; | ||
import { EventCallbacks, OnQueryData, OnQueryErrorData, OnQueryErrorErr, OnQueryRespRaw, QueryResponse } from './types.js'; | ||
export declare function callCbOnStart<Ctx = unknown>(ctx: Ctx | undefined, dbId: string, cbs: EventCallbacks<Ctx> | undefined, identifier: unknown, builder: Knex.QueryBuilder): Promise<void>; | ||
export declare function callCbOnQuery<Ctx = unknown>(ctx: Ctx | undefined, dbId: string, cbs: EventCallbacks<Ctx> | undefined, identifier: unknown, data: OnQueryData): Promise<void>; | ||
export declare function callCbOnQueryResp<Ctx = unknown>(ctx: Ctx | undefined, dbId: string, cbs: EventCallbacks<Ctx> | undefined, identifier: unknown, _resp: QueryResponse, // not used | ||
respRaw: OnQueryRespRaw): Promise<void>; | ||
export declare function callCbOnQueryError<Ctx = unknown>(ctx: Ctx | undefined, dbId: string, cbs: EventCallbacks<Ctx> | undefined, identifier: unknown, err: OnQueryErrorErr, data: OnQueryErrorData): Promise<void>; | ||
//# sourceMappingURL=event.d.ts.map |
@@ -1,45 +0,64 @@ | ||
import { Subject } from 'rxjs'; | ||
import { initKmoreEvent } from './config.js'; | ||
export const globalSubject = new Subject(); | ||
export const globalEvent = globalSubject.asObservable(); | ||
export function bindOnQuery(subject, identifier, data) { | ||
const queryUid = pickQueryUidFrom(data); | ||
processKnexOnEvent(subject, { | ||
type: 'query', | ||
identifier, | ||
data, | ||
queryUid, | ||
}); | ||
export async function callCbOnStart(ctx, dbId, cbs, identifier, builder) { | ||
const cb = cbs?.start; | ||
if (typeof cb === 'function') { | ||
const event = processKnexOnEvent({ | ||
type: 'start', | ||
identifier, | ||
data: void 0, | ||
queryUid: '', | ||
queryBuilder: builder, | ||
}); | ||
event.dbId = dbId; | ||
await cb(event, ctx); | ||
} | ||
} | ||
export function bindOnQueryResp(subject, identifier, _, respRaw) { | ||
const queryUid = pickQueryUidFrom(respRaw); | ||
processKnexOnEvent(subject, { | ||
type: 'queryResponse', | ||
identifier, | ||
respRaw, | ||
queryUid, | ||
}); | ||
export async function callCbOnQuery(ctx, dbId, cbs, identifier, data) { | ||
const cb = cbs?.query; | ||
if (typeof cb === 'function') { | ||
const queryUid = pickQueryUidFrom(data); | ||
const event = processKnexOnEvent({ | ||
type: 'query', | ||
identifier, | ||
data, | ||
queryUid, | ||
queryBuilder: void 0, | ||
}); | ||
event.dbId = dbId; | ||
await cb(event, ctx); | ||
} | ||
} | ||
export function bindOnQueryError(subject, identifier, err, data) { | ||
const queryUid = pickQueryUidFrom(data); | ||
processKnexOnEvent(subject, { | ||
type: 'queryError', | ||
identifier, | ||
exError: err, | ||
exData: data, | ||
queryUid, | ||
}); | ||
export async function callCbOnQueryResp(ctx, dbId, cbs, identifier, _resp, // not used | ||
respRaw) { | ||
const cb = cbs?.queryResponse; | ||
if (typeof cb === 'function') { | ||
const queryUid = pickQueryUidFrom(respRaw); | ||
const event = processKnexOnEvent({ | ||
type: 'queryResponse', | ||
identifier, | ||
respRaw, | ||
queryUid, | ||
queryBuilder: void 0, | ||
}); | ||
event.dbId = dbId; | ||
await cb(event, ctx); | ||
} | ||
} | ||
function processKnexOnEvent(subject, input) { | ||
if (!subject || typeof subject.next !== 'function') { | ||
throw new TypeError('Subject invalid'); | ||
} | ||
if (subject.closed) { | ||
// throw new Error('Kmore:subject already closed') | ||
console.warn({ | ||
msg: 'Kmore event:subject already closed. skip tracing.', | ||
input, | ||
export async function callCbOnQueryError(ctx, dbId, cbs, identifier, err, data) { | ||
const cb = cbs?.queryError; | ||
if (typeof cb === 'function') { | ||
const queryUid = pickQueryUidFrom(data); | ||
const event = processKnexOnEvent({ | ||
type: 'queryError', | ||
identifier, | ||
exError: err, | ||
exData: data, | ||
queryUid, | ||
queryBuilder: void 0, | ||
}); | ||
return; | ||
event.dbId = dbId; | ||
await cb(event, ctx); | ||
} | ||
} | ||
function processKnexOnEvent(input) { | ||
const ev = { | ||
@@ -50,22 +69,32 @@ ...initKmoreEvent, | ||
}; | ||
if (ev.type === 'query') { | ||
const data = input.data; | ||
ev.method = data.method ? data.method : ''; | ||
ev.kUid = data.__knexUid; | ||
ev.trxId = data.__knexTxId ? data.__knexTxId : void 0; | ||
switch (ev.type) { | ||
case 'start': { | ||
break; | ||
} | ||
case 'query': { | ||
const data = input.data; | ||
ev.method = data.method ? data.method : ''; | ||
ev.kUid = data.__knexUid; | ||
ev.trxId = data.__knexTxId ? data.__knexTxId : void 0; | ||
break; | ||
} | ||
case 'queryResponse': { | ||
const data = input.respRaw; | ||
ev.method = data.method ? data.method : ''; | ||
ev.command = data.response?.command; | ||
ev.kUid = data.__knexUid; | ||
ev.trxId = data.__knexTxId ? data.__knexTxId : void 0; | ||
break; | ||
} | ||
case 'queryError': { | ||
const data = input.exData; | ||
ev.method = data.method; | ||
ev.kUid = data.__knexUid; | ||
ev.trxId = data.__knexTxId ? data.__knexTxId : void 0; | ||
break; | ||
} | ||
default: | ||
break; | ||
} | ||
else if (ev.type === 'queryResponse') { | ||
const data = input.respRaw; | ||
ev.method = data.method ? data.method : ''; | ||
ev.command = data.response?.command; | ||
ev.kUid = data.__knexUid; | ||
ev.trxId = data.__knexTxId ? data.__knexTxId : void 0; | ||
} | ||
else if (ev.type === 'queryError') { | ||
const data = input.exData; | ||
ev.method = data.method; | ||
ev.kUid = data.__knexUid; | ||
ev.trxId = data.__knexTxId ? data.__knexTxId : void 0; | ||
} | ||
subject.next(ev); | ||
return ev; | ||
} | ||
@@ -72,0 +101,0 @@ function pickQueryUidFrom(input) { |
@@ -1,5 +0,2 @@ | ||
import { camelToSnake, camelKeys, | ||
// pascalCase, | ||
snakeKeys, } from '@waiting/shared-core'; | ||
// import keysDto2DoSnake from 'snakecase-keys' | ||
import { camelToSnake, camelKeys, snakeKeys, } from '@waiting/shared-core'; | ||
import { CaseType, EnumClient } from './types.js'; | ||
@@ -6,0 +3,0 @@ export async function getCurrentTime(dbh, clientType) { |
@@ -5,3 +5,2 @@ export * from './config.js'; | ||
export * from './types.js'; | ||
export { globalEvent, globalSubject, } from './event.js'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -5,3 +5,2 @@ export * from './config.js'; | ||
export * from './types.js'; | ||
export { globalEvent, globalSubject, } from './event.js'; | ||
//# sourceMappingURL=index.js.map |
import type { DbDict } from 'kmore-types'; | ||
import type { Knex } from 'knex'; | ||
import { CaseType, DbQueryBuilder, KmoreEvent, KnexConfig, QuerySpanInfo } from './types.js'; | ||
export declare class Kmore<D = unknown> { | ||
readonly config: KnexConfig; | ||
readonly dict: DbDict<D>; | ||
dbh: Knex; | ||
instanceId: string | symbol; | ||
readonly refTables: DbQueryBuilder<D, 'ref_', CaseType.none>; | ||
readonly camelTables: DbQueryBuilder<D, 'ref_', CaseType.camel>; | ||
readonly snakeTables: DbQueryBuilder<D, 'ref_', CaseType.snake>; | ||
import { CaseType, DbQueryBuilder, EventCallbacks, KnexConfig, QuerySpanInfo } from './types.js'; | ||
export declare class Kmore<D = any, Context = any> { | ||
readonly refTables: DbQueryBuilder<Context, D, 'ref_', CaseType.none>; | ||
readonly camelTables: DbQueryBuilder<Context, D, 'ref_', CaseType.camel>; | ||
readonly snakeTables: DbQueryBuilder<Context, D, 'ref_', CaseType.snake>; | ||
/** | ||
@@ -36,8 +32,13 @@ * Generics parameter, do NOT access as variable! | ||
protected listenEvent: boolean; | ||
constructor(config: KnexConfig, dict: DbDict<D>, dbh: Knex, instanceId: string | symbol); | ||
unsubscribe(): void; | ||
protected createRefTables<P extends string>(dbh: Knex, prefix: P, caseConvert: CaseType): DbQueryBuilder<D, P, CaseType>; | ||
protected extRefTableFnProperty(dbh: Knex, refName: string, caseConvert: CaseType): Knex.QueryBuilder; | ||
readonly config: KnexConfig; | ||
readonly dict: DbDict<D>; | ||
readonly dbId: string; | ||
readonly dbh: Knex; | ||
readonly instanceId: string | symbol; | ||
readonly eventCallbacks: EventCallbacks<Context> | undefined; | ||
constructor(options: KmoreFactoryOpts<D, Context>); | ||
protected createRefTables<P extends string>(prefix: P, caseConvert: CaseType): DbQueryBuilder<Context, D, P, CaseType>; | ||
protected extRefTableFnProperty(refName: string, caseConvert: CaseType, ctx: Context | undefined): Knex.QueryBuilder; | ||
} | ||
export interface KmoreFactoryOpts<D> { | ||
export interface KmoreFactoryOpts<D, Ctx = unknown> { | ||
config: KnexConfig; | ||
@@ -48,6 +49,6 @@ dict: DbDict<D>; | ||
dbId?: string; | ||
eventCallbacks?: EventCallbacks<Ctx> | undefined; | ||
} | ||
export declare type EventCallback = (event: KmoreEvent) => void; | ||
export declare function kmoreFactory<D extends object>(options: KmoreFactoryOpts<D>, enableTracing?: boolean): Kmore<D>; | ||
export declare function createDbh(knexConfig: KnexConfig, enableTracing?: boolean): Knex; | ||
export declare function KmoreFactory<D, Ctx = unknown>(options: KmoreFactoryOpts<D, Ctx>): Kmore<D, Ctx>; | ||
export declare function createDbh(knexConfig: KnexConfig): Knex; | ||
//# sourceMappingURL=kmore.d.ts.map |
@@ -0,15 +1,10 @@ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
/* eslint-disable import/no-extraneous-dependencies */ | ||
import assert from 'assert'; | ||
import { TracerLog, TracerTag, } from '@mw-components/jaeger'; | ||
import { genISO8601String, humanMemoryUsage, } from '@waiting/shared-core'; | ||
// eslint-disable-next-line no-duplicate-imports, import/no-named-default | ||
import { default as _knex } from 'knex'; | ||
import { defaultPropDescriptor } from './config.js'; | ||
import { bindOnQuery, bindOnQueryError, bindOnQueryResp, globalSubject } from './event.js'; | ||
import { callCbOnQuery, callCbOnQueryError, callCbOnQueryResp, callCbOnStart } from './event.js'; | ||
import { CaseType, } from './types.js'; | ||
export class Kmore { | ||
config; | ||
dict; | ||
dbh; | ||
instanceId; | ||
refTables; | ||
@@ -44,31 +39,22 @@ camelTables; | ||
// protected readonly subject: Subject<KmoreEvent> | ||
constructor(config, dict, dbh, instanceId) { | ||
this.config = config; | ||
this.dict = dict; | ||
this.dbh = dbh; | ||
this.instanceId = instanceId; | ||
this.refTables = this.createRefTables(this.dbh, 'ref_', CaseType.none); | ||
this.camelTables = this.createRefTables(this.dbh, 'ref_', CaseType.camel); | ||
// this.pascalTables = this.createRefTables<'ref_'>(this.dbh, 'ref_', CaseType.pascal) | ||
this.snakeTables = this.createRefTables(this.dbh, 'ref_', CaseType.snake); | ||
config; | ||
dict; | ||
dbId; | ||
dbh; | ||
instanceId; | ||
eventCallbacks; | ||
constructor(options) { | ||
const dbId = options.dbId ? options.dbId : Date.now().toString(); | ||
this.dbId = dbId; | ||
this.dbh = options.dbh ? options.dbh : createDbh(options.config); | ||
this.instanceId = options.instanceId ? options.instanceId : Symbol(`${dbId}-` + Date.now().toString()); | ||
this.eventCallbacks = options.eventCallbacks; | ||
this.config = options.config; | ||
this.dict = options.dict; | ||
this.refTables = this.createRefTables('ref_', CaseType.none); | ||
this.camelTables = this.createRefTables('ref_', CaseType.camel); | ||
// this.pascalTables = this.createRefTables<'ref_'>('ref_', CaseType.pascal) | ||
this.snakeTables = this.createRefTables('ref_', CaseType.snake); | ||
} | ||
unsubscribe() { | ||
this.queryUidSpanMap.forEach((info) => { | ||
const { span } = info; | ||
if (span) { | ||
const input = { | ||
[TracerTag.logLevel]: 'warn', | ||
message: 'finish span on Kmore unsubscribe()', | ||
event: 'Kmore:unsubscribe', | ||
queryUidSpanMapSize: this.queryUidSpanMap.size, | ||
time: genISO8601String(), | ||
[TracerLog.svcMemoryUsage]: humanMemoryUsage(), | ||
}; | ||
span.log(input); | ||
span.finish(); | ||
} | ||
}); | ||
this.listenEvent = false; | ||
} | ||
createRefTables(dbh, prefix, caseConvert) { | ||
createRefTables(prefix, caseConvert) { | ||
const rb = {}; | ||
@@ -83,4 +69,4 @@ if (!this.dict || !this.dict.tables || !Object.keys(this.dict.tables).length) { | ||
...defaultPropDescriptor, | ||
value: () => { | ||
return this.extRefTableFnProperty(dbh, refName, caseConvert); | ||
value: (ctx) => { | ||
return this.extRefTableFnProperty(refName, caseConvert, ctx); | ||
}, // must dynamically!! | ||
@@ -95,3 +81,3 @@ }); | ||
} | ||
extRefTableFnProperty(dbh, refName, caseConvert) { | ||
extRefTableFnProperty(refName, caseConvert, ctx) { | ||
assert(caseConvert, 'caseConvert must be defined'); | ||
@@ -101,23 +87,19 @@ const opts = { | ||
}; | ||
const refTable = dbh(refName).queryContext(opts); | ||
const refTable = this.dbh(refName) | ||
.queryContext(opts) | ||
.on('start', async (builder) => callCbOnStart(ctx, this.dbId, this.eventCallbacks, this.instanceId, builder)) | ||
.on('query', async (data) => callCbOnQuery(ctx, this.dbId, this.eventCallbacks, this.instanceId, data)) | ||
.on('query-response', async (resp, respRaw) => callCbOnQueryResp(ctx, this.dbId, this.eventCallbacks, this.instanceId, resp, respRaw)) | ||
.on('query-error', async (err, data) => callCbOnQueryError(ctx, this.dbId, this.eventCallbacks, this.instanceId, err, data)); | ||
return refTable; | ||
} | ||
} | ||
export function kmoreFactory(options, enableTracing = false) { | ||
const dbId = options.dbId ? options.dbId : ''; | ||
const dbh = options.dbh ? options.dbh : createDbh(options.config, enableTracing); | ||
const instanceId = options.instanceId ? options.instanceId : Symbol(`${dbId}-` + Date.now().toString()); | ||
const km = new Kmore(options.config, options.dict, dbh, instanceId); | ||
export function KmoreFactory(options) { | ||
const km = new Kmore(options); | ||
return km; | ||
} | ||
export function createDbh(knexConfig, enableTracing = false) { | ||
let inst = _knex(knexConfig); | ||
if (enableTracing) { | ||
inst = inst | ||
.on('query', (data) => bindOnQuery(globalSubject, void 0, data)) | ||
.on('query-response', (_, respRaw) => bindOnQueryResp(globalSubject, void 0, _, respRaw)) | ||
.on('query-error', (err, data) => bindOnQueryError(globalSubject, void 0, err, data)); | ||
} | ||
export function createDbh(knexConfig) { | ||
const inst = _knex(knexConfig); | ||
return inst; | ||
} | ||
//# sourceMappingURL=kmore.js.map |
@@ -19,4 +19,4 @@ import { RecordCamelKeys, RecordPascalKeys, RecordSnakeKeys } from '@waiting/shared-types'; | ||
} | ||
export declare type DbQueryBuilder<D, Prefix extends string, CaseConvert extends CaseType> = { | ||
[tb in keyof D as `${Prefix}${tb & string}`]: CaseConvert extends CaseType.camel ? TbQueryBuilder<RecordCamelKeys<D[tb]>> : CaseConvert extends CaseType.snake ? TbQueryBuilder<RecordSnakeKeys<D[tb]>> : CaseConvert extends CaseType.pascal ? TbQueryBuilder<RecordPascalKeys<D[tb]>> : TbQueryBuilder<D[tb]>; | ||
export declare type DbQueryBuilder<Context, D, Prefix extends string, CaseConvert extends CaseType> = { | ||
[tb in keyof D as `${Prefix}${tb & string}`]: CaseConvert extends CaseType.camel ? TbQueryBuilder<RecordCamelKeys<D[tb]>, Context> : CaseConvert extends CaseType.snake ? TbQueryBuilder<RecordSnakeKeys<D[tb]>, Context> : CaseConvert extends CaseType.pascal ? TbQueryBuilder<RecordPascalKeys<D[tb]>, Context> : TbQueryBuilder<D[tb], Context>; | ||
}; | ||
@@ -27,5 +27,7 @@ export interface BuilderInput { | ||
} | ||
export declare type TbQueryBuilder<TRecord> = () => Knex.QueryBuilder<TRecord, TRecord[]>; | ||
export declare type TbQueryBuilder<TRecord, Context> = (ctx?: Context) => Knex.QueryBuilder<TRecord, TRecord[]>; | ||
export declare type EventType = 'query' | 'queryError' | 'queryResponse' | 'start' | 'unknown'; | ||
export interface KmoreEvent<T = unknown> { | ||
type: 'query' | 'queryError' | 'queryResponse' | 'unknown'; | ||
dbId: string; | ||
type: EventType; | ||
/** passed from external */ | ||
@@ -52,2 +54,3 @@ identifier: unknown; | ||
exError: OnQueryErrorErr | undefined; | ||
queryBuilder: Knex.QueryBuilder | undefined; | ||
timestamp: number; | ||
@@ -139,2 +142,18 @@ } | ||
} | ||
export interface EventCallbackOptions<Ctx = unknown, R = unknown> { | ||
ctx: Ctx; | ||
event?: KmoreEvent<R>; | ||
} | ||
/** | ||
* @docs https://knexjs.org/guide/interfaces.html#query-response | ||
*/ | ||
export declare type EventCallback<Ctx = any> = (event: KmoreEvent, ctx?: Ctx) => Promise<void>; | ||
/** | ||
* @docs https://knexjs.org/guide/interfaces.html#query-response | ||
*/ | ||
export declare type EventCallbackType = Exclude<EventType, 'unknown'>; | ||
/** | ||
* @docs https://knexjs.org/guide/interfaces.html#query-response | ||
*/ | ||
export declare type EventCallbacks<Ctx = any> = Partial<Record<EventCallbackType, EventCallback<Ctx>>>; | ||
//# sourceMappingURL=types.d.ts.map |
{ | ||
"name": "kmore", | ||
"author": "waiting", | ||
"version": "30.0.0", | ||
"version": "31.0.0", | ||
"description": "A SQL query builder based on knex with powerful TypeScript type support", | ||
@@ -22,3 +22,3 @@ "keywords": [ | ||
"bin": {}, | ||
"types": "./dist/index.d.ts", | ||
"types": "./src/index.ts", | ||
"exports": { | ||
@@ -42,11 +42,11 @@ ".": { | ||
"dependencies": { | ||
"@waiting/shared-core": "^20.3.0", | ||
"@waiting/shared-types": "^20.2.0", | ||
"rxjs": "^7.5.0" | ||
"@waiting/shared-core": "^20.3.0" | ||
}, | ||
"devDependencies": { | ||
"@waiting/shared-types": "^20.2.0", | ||
"cross-env": "7", | ||
"kmore-types": "^30.0.0", | ||
"kmore-types": "^31.0.0", | ||
"knex": "^2.1.0", | ||
"pg": "^8.7.3" | ||
"pg": "^8.7.3", | ||
"rxjs": "^7.5.0" | ||
}, | ||
@@ -80,3 +80,3 @@ "engines": { | ||
}, | ||
"gitHead": "ee1581dda7814045e634f79094d08c1bf9e74b13" | ||
"gitHead": "5981bf87480c548602c1f1382ccd23074babf37e" | ||
} |
104
README.md
@@ -23,3 +23,3 @@ # [kmore](https://waitingsong.github.io/kmore/) | ||
```sh | ||
npm install kmore kmore-cli knex | ||
npm install kmore kmore-cli | ||
@@ -41,3 +41,5 @@ # Then add one of the following: | ||
"script": { | ||
"db:gen": "kmore gen --path src/ test/" | ||
"build": "tsc -b && npm run db:gen", | ||
"db:gen": "kmore gen --path src/ test/", | ||
"db:gen-cjs": "kmore gen --path src/ test/ --format cjs" | ||
}, | ||
@@ -106,4 +108,6 @@ } | ||
### Inert rows via auto generated table accessor | ||
#### Snake style | ||
```ts | ||
// auto generated accessort tb_user() and tb_user_detail() on km.rb | ||
// auto generated accessort tb_user() and tb_user_detail() | ||
const { ref_tb_user, ref_tb_user_detail } = km.refTables | ||
@@ -113,4 +117,4 @@ | ||
.insert([ | ||
{ name: 'user1', ctime: new Date() }, // ms | ||
{ name: 'user2', ctime: 'now()' }, // μs | ||
{ user_name: 'user1', ctime: new Date() }, // ms | ||
{ user_name: 'user2', ctime: 'now()' }, // μs | ||
]) | ||
@@ -121,4 +125,4 @@ .then() | ||
.insert([ | ||
{ uid: 1, age: 10, address: 'address1' }, | ||
{ uid: 2, age: 10, address: 'address1' }, | ||
{ uid: 1, age: 10, user_address: 'address1' }, | ||
{ uid: 2, age: 10, user_address: 'address1' }, | ||
]) | ||
@@ -129,2 +133,24 @@ .returning('*') | ||
#### Camel style | ||
```ts | ||
import { RecordCamelKeys } from '@waiting/shared-types' | ||
// auto generated accessort tb_user() and tb_user_detail() | ||
const { ref_tb_user, ref_tb_user_detail } = km.camelTables | ||
interface UserDO { | ||
user_name: string | ||
ctime: date | string | ||
} | ||
type UserDTO = RecordCamelKeys<UserDO> | ||
const users: UserDTO[] = await ref_tb_user() | ||
.insert([ | ||
{ userName: 'user1', ctime: new Date() }, // ms | ||
{ userName: 'user2', ctime: 'now()' }, // μs | ||
]) | ||
.returning('*') | ||
.then() | ||
``` | ||
### Join tables | ||
@@ -180,3 +206,3 @@ ```ts | ||
More examples of join see [joint-table](https://github.com/waitingsong/kmore/blob/master/packages/kmore/test/join-table/71.advanced.test.ts) | ||
More examples of join see [joint-table](https://github.com/waitingsong/kmore/blob/main/packages/kmore/test/join-table/71.advanced.test.ts) | ||
@@ -193,5 +219,27 @@ | ||
## Midway.js component | ||
```ts | ||
@Provide() | ||
export class UserRepo { | ||
@Inject() readonly ctx: Context | ||
@Inject() dbManager: DbSourceManager<'master' | 'slave', Db> | ||
async getUser(uid: number): Promise<UserDTO[]> { | ||
const db = this.dbManager.getDataSource('master') | ||
assert(db) | ||
const { ref_tb_user } = db.camelTables | ||
const user = await ref_tb_user(this.ctx) | ||
.select('*') | ||
.where({ uid }) | ||
return user | ||
} | ||
} | ||
``` | ||
## Demo | ||
- [see test](https://github.com/waitingsong/kmore/blob/master/test/) | ||
- [see test](https://github.com/waitingsong/kmore/blob/main/test/) | ||
@@ -204,7 +252,8 @@ | ||
| Package | Version | | ||
| --------------- | ------------------------ | | ||
| [`kmore`] | [![kmore-svg]][kmore-ch] | | ||
| [`kmore-types`] | [![types-svg]][types-ch] | | ||
| [`kmore-cli`] | [![cli-svg]][cli-ch] | | ||
| Package | Version | | ||
| -------------------------- | ------------------------ | | ||
| [`kmore`] | [![kmore-svg]][kmore-ch] | | ||
| [`kmore-types`] | [![types-svg]][types-ch] | | ||
| [`kmore-cli`] | [![cli-svg]][cli-ch] | | ||
| [`midway-component-kmore`] | [![mw-svg]][mw-ch] | | ||
@@ -222,9 +271,9 @@ | ||
[`kmore`]: https://github.com/waitingsong/kmore/tree/master/packages/kmore | ||
[`kmore-types`]: https://github.com/waitingsong/kmore/tree/master/packages/kmore-types | ||
[`kmore-cli`]: https://github.com/waitingsong/kmore/tree/master/packages/kmore-cli | ||
[`egg-kmore`]: https://github.com/waitingsong/kmore/tree/master/packages/egg-kmore | ||
[`kmore`]: https://github.com/waitingsong/kmore/tree/main/packages/kmore | ||
[`kmore-types`]: https://github.com/waitingsong/kmore/tree/main/packages/kmore-types | ||
[`kmore-cli`]: https://github.com/waitingsong/kmore/tree/main/packages/kmore-cli | ||
[`midway-component-kmore`]: https://github.com/waitingsong/kmore/tree/main/packages/midway-component-kmore | ||
[kmore-svg]: https://img.shields.io/npm/v/kmore.svg?maxAge=7200 | ||
[kmore-ch]: https://github.com/waitingsong/kmore/tree/master/packages/kmore/CHANGELOG.md | ||
[kmore-ch]: https://github.com/waitingsong/kmore/tree/main/packages/kmore/CHANGELOG.md | ||
[kmore-d-svg]: https://david-dm.org/waitingsong/kmore.svg?path=packages/kmore | ||
@@ -236,3 +285,3 @@ [kmore-d-link]: https://david-dm.org/waitingsong/kmore.svg?path=packages/kmore | ||
[types-svg]: https://img.shields.io/npm/v/kmore-types.svg?maxAge=7200 | ||
[types-ch]: https://github.com/waitingsong/kmore/tree/master/packages/kmore-types/CHANGELOG.md | ||
[types-ch]: https://github.com/waitingsong/kmore/tree/main/packages/kmore-types/CHANGELOG.md | ||
[types-d-svg]: https://david-dm.org/waitingsong/kmore.svg?path=packages/kmore-types | ||
@@ -244,3 +293,3 @@ [types-d-link]: https://david-dm.org/waitingsong/kmore.svg?path=packages/kmore-types | ||
[cli-svg]: https://img.shields.io/npm/v/kmore-cli.svg?maxAge=7200 | ||
[cli-ch]: https://github.com/waitingsong/kmore/tree/master/packages/kmore-clie/CHANGELOG.md | ||
[cli-ch]: https://github.com/waitingsong/kmore/tree/main/packages/kmore-clie/CHANGELOG.md | ||
[cli-d-svg]: https://david-dm.org/waitingsong/kmore.svg?path=packages/kmore-cli | ||
@@ -252,7 +301,8 @@ [cli-d-link]: https://david-dm.org/waitingsong/kmore.svg?path=packages/kmore-cli | ||
[egg-svg]: https://img.shields.io/npm/v/egg-kmore.svg?maxAge=7200 | ||
[egg-ch]: https://github.com/waitingsong/kmore/tree/master/packages/egg-kmore/CHANGELOG.md | ||
[egg-d-svg]: https://david-dm.org/waitingsong/kmore.svg?path=packages/egg-kmore | ||
[egg-d-link]: https://david-dm.org/waitingsong/kmore.svg?path=packages/egg-kmore | ||
[egg-dd-svg]: https://david-dm.org/waitingsong/kmore/dev-status.svg?path=packages/egg-kmore | ||
[egg-dd-link]: https://david-dm.org/waitingsong/kmore?path=packages/egg-kmore#info=devDependencies | ||
[mw-svg]: https://img.shields.io/npm/v/@mw-components/kmore.svg?maxAge=7200 | ||
[mw-ch]: https://github.com/waitingsong/kmore/tree/main/packages/midway-component-kmore/CHANGELOG.md | ||
[mw-d-svg]: https://david-dm.org/waitingsong/kmore.svg?path=packages/midway-component-kmore | ||
[mw-d-link]: https://david-dm.org/waitingsong/kmore.svg?path=packages/midway-component-kmore | ||
[mw-dd-svg]: https://david-dm.org/waitingsong/kmore/dev-status.svg?path=packages/midway-component-kmore | ||
[mw-dd-link]: https://david-dm.org/waitingsong/kmore?path=packages/egg-kmore#info=midway-component-kmore | ||
@@ -40,3 +40,5 @@ # [kmore](https://waitingsong.github.io/kmore/) | ||
"script": { | ||
"db:gen": "kmore gen --path src/ test/" | ||
"build": "tsc -b && npm run db:gen", | ||
"db:gen": "kmore gen --path src/ test/", | ||
"db:gen-cjs": "kmore gen --path src/ test/ --format cjs" | ||
}, | ||
@@ -104,4 +106,6 @@ } | ||
### 插入数据 | ||
#### Snake style | ||
```ts | ||
// auto generated accessort tb_user() and tb_user_detail() on km.rb | ||
// auto generated accessort tb_user() and tb_user_detail() | ||
const { ref_tb_user, ref_tb_user_detail } = km.refTables | ||
@@ -111,4 +115,4 @@ | ||
.insert([ | ||
{ name: 'user1', ctime: new Date() }, // ms | ||
{ name: 'user2', ctime: 'now()' }, // μs | ||
{ user_name: 'user1', ctime: new Date() }, // ms | ||
{ user_name: 'user2', ctime: 'now()' }, // μs | ||
]) | ||
@@ -119,4 +123,4 @@ .then() | ||
.insert([ | ||
{ uid: 1, age: 10, address: 'address1' }, | ||
{ uid: 2, age: 10, address: 'address1' }, | ||
{ uid: 1, age: 10, user_address: 'address1' }, | ||
{ uid: 2, age: 10, user_address: 'address1' }, | ||
]) | ||
@@ -127,2 +131,24 @@ .returning('*') | ||
#### Camel style | ||
```ts | ||
import { RecordCamelKeys } from '@waiting/shared-types' | ||
// auto generated accessort tb_user() and tb_user_detail() | ||
const { ref_tb_user, ref_tb_user_detail } = km.camelTables | ||
interface UserDO { | ||
user_name: string | ||
ctime: date | string | ||
} | ||
type UserDTO = RecordCamelKeys<UserDO> | ||
const users: UserDTO[] = await ref_tb_user() | ||
.insert([ | ||
{ userName: 'user1', ctime: new Date() }, // ms | ||
{ userName: 'user2', ctime: 'now()' }, // μs | ||
]) | ||
.returning('*') | ||
.then() | ||
``` | ||
### 连表 | ||
@@ -178,3 +204,3 @@ ```ts | ||
More examples of join see [joint-table](https://github.com/waitingsong/kmore/blob/master/packages/kmore/test/join-table/71.advanced.test.ts) | ||
More examples of join see [joint-table](https://github.com/waitingsong/kmore/blob/main/packages/kmore/test/join-table/71.advanced.test.ts) | ||
@@ -191,5 +217,27 @@ | ||
## Midway.js component | ||
```ts | ||
@Provide() | ||
export class UserRepo { | ||
@Inject() readonly ctx: Context | ||
@Inject() dbManager: DbSourceManager<'master' | 'slave', Db> | ||
async getUser(uid: number): Promise<UserDTO[]> { | ||
const db = this.dbManager.getDataSource('master') | ||
assert(db) | ||
const { ref_tb_user } = db.camelTables | ||
const user = await ref_tb_user(this.ctx) | ||
.select('*') | ||
.where({ uid }) | ||
return user | ||
} | ||
} | ||
``` | ||
## Demo | ||
- [see test](https://github.com/waitingsong/kmore/blob/master/test/) | ||
- [see test](https://github.com/waitingsong/kmore/blob/main/test/) | ||
@@ -202,7 +250,8 @@ | ||
| Package | Version | | ||
| --------------- | ------------------------ | | ||
| [`kmore`] | [![kmore-svg]][kmore-ch] | | ||
| [`kmore-types`] | [![types-svg]][types-ch] | | ||
| [`kmore-cli`] | [![cli-svg]][cli-ch] | | ||
| Package | Version | | ||
| -------------------------- | ------------------------ | | ||
| [`kmore`] | [![kmore-svg]][kmore-ch] | | ||
| [`kmore-types`] | [![types-svg]][types-ch] | | ||
| [`kmore-cli`] | [![cli-svg]][cli-ch] | | ||
| [`midway-component-kmore`] | [![mw-svg]][mw-ch] | | ||
@@ -220,9 +269,9 @@ | ||
[`kmore`]: https://github.com/waitingsong/kmore/tree/master/packages/kmore | ||
[`kmore-types`]: https://github.com/waitingsong/kmore/tree/master/packages/kmore-types | ||
[`kmore-cli`]: https://github.com/waitingsong/kmore/tree/master/packages/kmore-cli | ||
[`egg-kmore`]: https://github.com/waitingsong/kmore/tree/master/packages/egg-kmore | ||
[`kmore`]: https://github.com/waitingsong/kmore/tree/main/packages/kmore | ||
[`kmore-types`]: https://github.com/waitingsong/kmore/tree/main/packages/kmore-types | ||
[`kmore-cli`]: https://github.com/waitingsong/kmore/tree/main/packages/kmore-cli | ||
[`midway-component-kmore`]: https://github.com/waitingsong/kmore/tree/main/packages/midway-component-kmore | ||
[kmore-svg]: https://img.shields.io/npm/v/kmore.svg?maxAge=7200 | ||
[kmore-ch]: https://github.com/waitingsong/kmore/tree/master/packages/kmore/CHANGELOG.md | ||
[kmore-ch]: https://github.com/waitingsong/kmore/tree/main/packages/kmore/CHANGELOG.md | ||
[kmore-d-svg]: https://david-dm.org/waitingsong/kmore.svg?path=packages/kmore | ||
@@ -234,3 +283,3 @@ [kmore-d-link]: https://david-dm.org/waitingsong/kmore.svg?path=packages/kmore | ||
[types-svg]: https://img.shields.io/npm/v/kmore-types.svg?maxAge=7200 | ||
[types-ch]: https://github.com/waitingsong/kmore/tree/master/packages/kmore-types/CHANGELOG.md | ||
[types-ch]: https://github.com/waitingsong/kmore/tree/main/packages/kmore-types/CHANGELOG.md | ||
[types-d-svg]: https://david-dm.org/waitingsong/kmore.svg?path=packages/kmore-types | ||
@@ -242,3 +291,3 @@ [types-d-link]: https://david-dm.org/waitingsong/kmore.svg?path=packages/kmore-types | ||
[cli-svg]: https://img.shields.io/npm/v/kmore-cli.svg?maxAge=7200 | ||
[cli-ch]: https://github.com/waitingsong/kmore/tree/master/packages/kmore-clie/CHANGELOG.md | ||
[cli-ch]: https://github.com/waitingsong/kmore/tree/main/packages/kmore-clie/CHANGELOG.md | ||
[cli-d-svg]: https://david-dm.org/waitingsong/kmore.svg?path=packages/kmore-cli | ||
@@ -250,7 +299,8 @@ [cli-d-link]: https://david-dm.org/waitingsong/kmore.svg?path=packages/kmore-cli | ||
[egg-svg]: https://img.shields.io/npm/v/egg-kmore.svg?maxAge=7200 | ||
[egg-ch]: https://github.com/waitingsong/kmore/tree/master/packages/egg-kmore/CHANGELOG.md | ||
[egg-d-svg]: https://david-dm.org/waitingsong/kmore.svg?path=packages/egg-kmore | ||
[egg-d-link]: https://david-dm.org/waitingsong/kmore.svg?path=packages/egg-kmore | ||
[egg-dd-svg]: https://david-dm.org/waitingsong/kmore/dev-status.svg?path=packages/egg-kmore | ||
[egg-dd-link]: https://david-dm.org/waitingsong/kmore?path=packages/egg-kmore#info=devDependencies | ||
[mw-svg]: https://img.shields.io/npm/v/@mw-components/kmore.svg?maxAge=7200 | ||
[mw-ch]: https://github.com/waitingsong/kmore/tree/main/packages/midway-component-kmore/CHANGELOG.md | ||
[mw-d-svg]: https://david-dm.org/waitingsong/kmore.svg?path=packages/midway-component-kmore | ||
[mw-d-link]: https://david-dm.org/waitingsong/kmore.svg?path=packages/midway-component-kmore | ||
[mw-dd-svg]: https://david-dm.org/waitingsong/kmore/dev-status.svg?path=packages/midway-component-kmore | ||
[mw-dd-link]: https://david-dm.org/waitingsong/kmore?path=packages/egg-kmore#info=midway-component-kmore | ||
@@ -13,2 +13,3 @@ import { postProcessResponse, wrapIdentifier } from './helper.js' | ||
export const initKmoreEvent: KmoreEvent = { | ||
dbId: '', | ||
type: 'unknown', | ||
@@ -25,2 +26,3 @@ identifier: void 0, | ||
exError: void 0, | ||
queryBuilder: void 0, | ||
timestamp: Date.now(), | ||
@@ -27,0 +29,0 @@ } |
@@ -1,5 +0,6 @@ | ||
import { Observable, Subject } from 'rxjs' | ||
import type { Knex } from 'knex' | ||
import { initKmoreEvent } from './config.js' | ||
import { | ||
EventCallbacks, | ||
KmoreEvent, | ||
@@ -14,15 +15,36 @@ OnQueryData, | ||
export const globalSubject: Subject<KmoreEvent> = new Subject() | ||
export const globalEvent: Observable<KmoreEvent> = globalSubject.asObservable() | ||
export async function callCbOnStart<Ctx = unknown>( | ||
ctx: Ctx | undefined, | ||
dbId: string, | ||
cbs: EventCallbacks<Ctx> | undefined, | ||
identifier: unknown, | ||
builder: Knex.QueryBuilder, | ||
): Promise<void> { | ||
export function bindOnQuery( | ||
subject: Subject<KmoreEvent>, | ||
const cb: EventCallbacks<Ctx>['start'] = cbs?.start | ||
if (typeof cb === 'function') { | ||
const event = processKnexOnEvent({ | ||
type: 'start', | ||
identifier, | ||
data: void 0, | ||
queryUid: '', | ||
queryBuilder: builder, | ||
}) | ||
event.dbId = dbId | ||
await cb(event, ctx) | ||
} | ||
} | ||
export async function callCbOnQuery<Ctx = unknown>( | ||
ctx: Ctx | undefined, | ||
dbId: string, | ||
cbs: EventCallbacks<Ctx> | undefined, | ||
identifier: unknown, | ||
data: OnQueryData, | ||
): void { | ||
): Promise<void> { | ||
const queryUid = pickQueryUidFrom(data) | ||
processKnexOnEvent( | ||
subject, | ||
{ | ||
const cb: EventCallbacks<Ctx>['query'] = cbs?.query | ||
if (typeof cb === 'function') { | ||
const queryUid = pickQueryUidFrom(data) | ||
const event = processKnexOnEvent({ | ||
type: 'query', | ||
@@ -32,18 +54,22 @@ identifier, | ||
queryUid, | ||
}, | ||
) | ||
queryBuilder: void 0, | ||
}) | ||
event.dbId = dbId | ||
await cb(event, ctx) | ||
} | ||
} | ||
export function bindOnQueryResp( | ||
subject: Subject<KmoreEvent>, | ||
export async function callCbOnQueryResp<Ctx = unknown>( | ||
ctx: Ctx | undefined, | ||
dbId: string, | ||
cbs: EventCallbacks<Ctx> | undefined, | ||
identifier: unknown, | ||
_: QueryResponse, | ||
respRaw: | ||
OnQueryRespRaw, | ||
): void { | ||
_resp: QueryResponse, // not used | ||
respRaw: OnQueryRespRaw, | ||
): Promise<void> { | ||
const queryUid = pickQueryUidFrom(respRaw) | ||
processKnexOnEvent( | ||
subject, | ||
{ | ||
const cb: EventCallbacks<Ctx>['queryResponse'] = cbs?.queryResponse | ||
if (typeof cb === 'function') { | ||
const queryUid = pickQueryUidFrom(respRaw) | ||
const event = processKnexOnEvent({ | ||
type: 'queryResponse', | ||
@@ -53,17 +79,22 @@ identifier, | ||
queryUid, | ||
}, | ||
) | ||
queryBuilder: void 0, | ||
}) | ||
event.dbId = dbId | ||
await cb(event, ctx) | ||
} | ||
} | ||
export function bindOnQueryError( | ||
subject: Subject<KmoreEvent>, | ||
export async function callCbOnQueryError<Ctx = unknown>( | ||
ctx: Ctx | undefined, | ||
dbId: string, | ||
cbs: EventCallbacks<Ctx> | undefined, | ||
identifier: unknown, | ||
err: OnQueryErrorErr, | ||
data: OnQueryErrorData, | ||
): void { | ||
): Promise<void> { | ||
const queryUid = pickQueryUidFrom(data) | ||
processKnexOnEvent( | ||
subject, | ||
{ | ||
const cb: EventCallbacks<Ctx>['queryError'] = cbs?.queryError | ||
if (typeof cb === 'function') { | ||
const queryUid = pickQueryUidFrom(data) | ||
const event = processKnexOnEvent({ | ||
type: 'queryError', | ||
@@ -74,24 +105,11 @@ identifier, | ||
queryUid, | ||
}, | ||
) | ||
queryBuilder: void 0, | ||
}) | ||
event.dbId = dbId | ||
await cb(event, ctx) | ||
} | ||
} | ||
function processKnexOnEvent( | ||
subject: Subject<KmoreEvent>, | ||
input: Partial<KmoreEvent>, | ||
): void { | ||
if (! subject || typeof subject.next !== 'function') { | ||
throw new TypeError('Subject invalid') | ||
} | ||
if (subject.closed) { | ||
// throw new Error('Kmore:subject already closed') | ||
console.warn({ | ||
msg: 'Kmore event:subject already closed. skip tracing.', | ||
input, | ||
}) | ||
return | ||
} | ||
function processKnexOnEvent(input: Partial<KmoreEvent>): KmoreEvent { | ||
const ev: KmoreEvent = { | ||
@@ -102,23 +120,38 @@ ...initKmoreEvent, | ||
} | ||
if (ev.type === 'query') { | ||
const data = input.data as OnQueryData | ||
ev.method = data.method ? data.method : '' | ||
ev.kUid = data.__knexUid | ||
ev.trxId = data.__knexTxId ? data.__knexTxId : void 0 | ||
switch (ev.type) { | ||
case 'start': { | ||
break | ||
} | ||
case 'query': { | ||
const data = input.data as OnQueryData | ||
ev.method = data.method ? data.method : '' | ||
ev.kUid = data.__knexUid | ||
ev.trxId = data.__knexTxId ? data.__knexTxId : void 0 | ||
break | ||
} | ||
case 'queryResponse': { | ||
const data = input.respRaw as OnQueryRespRaw | ||
ev.method = data.method ? data.method : '' | ||
ev.command = data.response?.command | ||
ev.kUid = data.__knexUid | ||
ev.trxId = data.__knexTxId ? data.__knexTxId : void 0 | ||
break | ||
} | ||
case 'queryError': { | ||
const data = input.exData as OnQueryErrorData | ||
ev.method = data.method | ||
ev.kUid = data.__knexUid | ||
ev.trxId = data.__knexTxId ? data.__knexTxId : void 0 | ||
break | ||
} | ||
default: | ||
break | ||
} | ||
else if (ev.type === 'queryResponse') { | ||
const data = input.respRaw as OnQueryRespRaw | ||
ev.method = data.method ? data.method : '' | ||
ev.command = data.response?.command | ||
ev.kUid = data.__knexUid | ||
ev.trxId = data.__knexTxId ? data.__knexTxId : void 0 | ||
} | ||
else if (ev.type === 'queryError') { | ||
const data = input.exData as OnQueryErrorData | ||
ev.method = data.method | ||
ev.kUid = data.__knexUid | ||
ev.trxId = data.__knexTxId ? data.__knexTxId : void 0 | ||
} | ||
subject.next(ev) | ||
return ev | ||
} | ||
@@ -125,0 +158,0 @@ |
import { | ||
camelToSnake, | ||
camelKeys, | ||
// pascalCase, | ||
snakeKeys, | ||
} from '@waiting/shared-core' | ||
import { RecordCamelKeys, RecordPascalKeys, RecordSnakeKeys } from '@waiting/shared-types' | ||
// import keysDoToDtoCamel from 'camelcase-keys' | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
import type { Knex } from 'knex' | ||
// import keysDto2DoSnake from 'snakecase-keys' | ||
@@ -13,0 +10,0 @@ import { CaseType, EnumClient, KnexConfig, QueryContext } from './types.js' |
@@ -6,6 +6,2 @@ | ||
export * from './types.js' | ||
export { | ||
globalEvent, | ||
globalSubject, | ||
} from './event.js' | ||
@@ -0,13 +1,5 @@ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
/* eslint-disable import/no-extraneous-dependencies */ | ||
import assert from 'assert' | ||
import { | ||
SpanLogInput, | ||
TracerLog, | ||
TracerTag, | ||
} from '@mw-components/jaeger' | ||
import { | ||
genISO8601String, | ||
humanMemoryUsage, | ||
} from '@waiting/shared-core' | ||
import type { DbDict } from 'kmore-types' | ||
@@ -19,7 +11,7 @@ import type { Knex } from 'knex' | ||
import { defaultPropDescriptor } from './config.js' | ||
import { bindOnQuery, bindOnQueryError, bindOnQueryResp, globalSubject } from './event.js' | ||
import { callCbOnQuery, callCbOnQueryError, callCbOnQueryResp, callCbOnStart } from './event.js' | ||
import { | ||
CaseType, | ||
DbQueryBuilder, | ||
KmoreEvent, | ||
EventCallbacks, | ||
KnexConfig, | ||
@@ -36,8 +28,8 @@ OnQueryData, | ||
export class Kmore<D = unknown> { | ||
export class Kmore<D = any, Context = any> { | ||
readonly refTables: DbQueryBuilder<D, 'ref_', CaseType.none> | ||
readonly camelTables: DbQueryBuilder<D, 'ref_', CaseType.camel> | ||
readonly refTables: DbQueryBuilder<Context, D, 'ref_', CaseType.none> | ||
readonly camelTables: DbQueryBuilder<Context, D, 'ref_', CaseType.camel> | ||
// readonly pascalTables: DbQueryBuilder<D, 'ref_', CaseType.pascal> | ||
readonly snakeTables: DbQueryBuilder<D, 'ref_', CaseType.snake> | ||
readonly snakeTables: DbQueryBuilder<Context, D, 'ref_', CaseType.snake> | ||
@@ -73,32 +65,27 @@ /** | ||
public readonly config: KnexConfig | ||
public readonly dict: DbDict<D> | ||
public readonly dbId: string | ||
public readonly dbh: Knex | ||
public readonly instanceId: string | symbol | ||
public readonly eventCallbacks: EventCallbacks<Context> | undefined | ||
constructor( | ||
public readonly config: KnexConfig, | ||
public readonly dict: DbDict<D>, | ||
public dbh: Knex, | ||
public instanceId: string | symbol, | ||
options: KmoreFactoryOpts<D, Context>, | ||
) { | ||
this.refTables = this.createRefTables<'ref_'>(this.dbh, 'ref_', CaseType.none) | ||
this.camelTables = this.createRefTables<'ref_'>(this.dbh, 'ref_', CaseType.camel) | ||
// this.pascalTables = this.createRefTables<'ref_'>(this.dbh, 'ref_', CaseType.pascal) | ||
this.snakeTables = this.createRefTables<'ref_'>(this.dbh, 'ref_', CaseType.snake) | ||
} | ||
const dbId = options.dbId ? options.dbId : Date.now().toString() | ||
this.dbId = dbId | ||
this.dbh = options.dbh ? options.dbh : createDbh(options.config) | ||
this.instanceId = options.instanceId ? options.instanceId : Symbol(`${dbId}-` + Date.now().toString()) | ||
this.eventCallbacks = options.eventCallbacks | ||
unsubscribe(): void { | ||
this.queryUidSpanMap.forEach((info) => { | ||
const { span } = info | ||
if (span) { | ||
const input: SpanLogInput = { | ||
[TracerTag.logLevel]: 'warn', | ||
message: 'finish span on Kmore unsubscribe()', | ||
event: 'Kmore:unsubscribe', | ||
queryUidSpanMapSize: this.queryUidSpanMap.size, | ||
time: genISO8601String(), | ||
[TracerLog.svcMemoryUsage]: humanMemoryUsage(), | ||
} | ||
span.log(input) | ||
span.finish() | ||
} | ||
}) | ||
this.listenEvent = false | ||
this.config = options.config | ||
this.dict = options.dict | ||
this.refTables = this.createRefTables<'ref_'>('ref_', CaseType.none) | ||
this.camelTables = this.createRefTables<'ref_'>('ref_', CaseType.camel) | ||
// this.pascalTables = this.createRefTables<'ref_'>('ref_', CaseType.pascal) | ||
this.snakeTables = this.createRefTables<'ref_'>('ref_', CaseType.snake) | ||
} | ||
@@ -108,8 +95,7 @@ | ||
protected createRefTables<P extends string>( | ||
dbh: Knex, | ||
prefix: P, | ||
caseConvert: CaseType, | ||
): DbQueryBuilder<D, P, CaseType> { | ||
): DbQueryBuilder<Context, D, P, CaseType> { | ||
const rb = {} as DbQueryBuilder<D, P, CaseType> | ||
const rb = {} as DbQueryBuilder<Context, D, P, CaseType> | ||
@@ -125,4 +111,4 @@ if (! this.dict || ! this.dict.tables || ! Object.keys(this.dict.tables).length) { | ||
...defaultPropDescriptor, | ||
value: () => { | ||
return this.extRefTableFnProperty(dbh, refName, caseConvert) | ||
value: (ctx?: Context) => { | ||
return this.extRefTableFnProperty(refName, caseConvert, ctx) | ||
}, // must dynamically!! | ||
@@ -142,5 +128,5 @@ }) | ||
protected extRefTableFnProperty( | ||
dbh: Knex, | ||
refName: string, | ||
caseConvert: CaseType, | ||
ctx: Context | undefined, | ||
): Knex.QueryBuilder { | ||
@@ -153,16 +139,46 @@ | ||
} | ||
const refTable = dbh(refName).queryContext(opts) | ||
const refTable = this.dbh(refName) | ||
.queryContext(opts) | ||
.on('start', async (builder: Knex.QueryBuilder) => callCbOnStart<Context>( | ||
ctx, | ||
this.dbId, | ||
this.eventCallbacks, | ||
this.instanceId, | ||
builder, | ||
)) | ||
.on('query', async (data: OnQueryData) => callCbOnQuery<Context>( | ||
ctx, | ||
this.dbId, | ||
this.eventCallbacks, | ||
this.instanceId, | ||
data, | ||
)) | ||
.on( | ||
'query-response', | ||
async (resp: QueryResponse, respRaw: OnQueryRespRaw) => callCbOnQueryResp<Context>( | ||
ctx, | ||
this.dbId, | ||
this.eventCallbacks, | ||
this.instanceId, | ||
resp, | ||
respRaw, | ||
), | ||
) | ||
.on( | ||
'query-error', | ||
async (err: OnQueryErrorErr, data: OnQueryErrorData) => callCbOnQueryError<Context>( | ||
ctx, | ||
this.dbId, | ||
this.eventCallbacks, | ||
this.instanceId, | ||
err, | ||
data, | ||
), | ||
) | ||
return refTable | ||
} | ||
// private triggerEvent(event: KmoreEvent): void { | ||
// if (this.eventCallback) { | ||
// this.eventCallback(event) | ||
// } | ||
// void 0 | ||
// } | ||
} | ||
export interface KmoreFactoryOpts<D> { | ||
export interface KmoreFactoryOpts<D, Ctx = unknown> { | ||
config: KnexConfig | ||
@@ -173,19 +189,10 @@ dict: DbDict<D> | ||
dbId?: string | ||
eventCallbacks?: EventCallbacks<Ctx> | undefined | ||
} | ||
export type EventCallback = (event: KmoreEvent) => void | ||
export function kmoreFactory<D extends object>( | ||
options: KmoreFactoryOpts<D>, | ||
enableTracing = false, | ||
): Kmore<D> { | ||
export function KmoreFactory<D, Ctx = unknown>( | ||
options: KmoreFactoryOpts<D, Ctx>, | ||
): Kmore<D, Ctx> { | ||
const dbId = options.dbId ? options.dbId : '' | ||
const dbh: Knex = options.dbh ? options.dbh : createDbh(options.config, enableTracing) | ||
const instanceId = options.instanceId ? options.instanceId : Symbol(`${dbId}-` + Date.now().toString()) | ||
const km = new Kmore<D>( | ||
options.config, | ||
options.dict, | ||
dbh, | ||
instanceId, | ||
) | ||
const km = new Kmore<D, Ctx>(options) | ||
return km | ||
@@ -196,23 +203,7 @@ } | ||
knexConfig: KnexConfig, | ||
enableTracing = false, | ||
): Knex { | ||
let inst = _knex(knexConfig) | ||
if (enableTracing) { | ||
inst = inst | ||
.on('query', (data: OnQueryData) => bindOnQuery(globalSubject, void 0, data)) | ||
.on( | ||
'query-response', | ||
(_: QueryResponse, respRaw: OnQueryRespRaw) => bindOnQueryResp(globalSubject, void 0, _, respRaw), | ||
) | ||
.on( | ||
'query-error', | ||
(err: OnQueryErrorErr, data: OnQueryErrorData) => bindOnQueryError(globalSubject, void 0, err, data), | ||
) | ||
} | ||
const inst = _knex(knexConfig) | ||
return inst | ||
} | ||
@@ -27,2 +27,3 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
export type DbQueryBuilder< | ||
Context, | ||
D, | ||
@@ -35,8 +36,8 @@ Prefix extends string, | ||
[tb in keyof D as `${Prefix}${tb & string}`]: CaseConvert extends CaseType.camel | ||
? TbQueryBuilder<RecordCamelKeys<D[tb]>> | ||
? TbQueryBuilder<RecordCamelKeys<D[tb]>, Context> | ||
: CaseConvert extends CaseType.snake | ||
? TbQueryBuilder<RecordSnakeKeys<D[tb]>> | ||
? TbQueryBuilder<RecordSnakeKeys<D[tb]>, Context> | ||
: CaseConvert extends CaseType.pascal | ||
? TbQueryBuilder<RecordPascalKeys<D[tb]>> | ||
: TbQueryBuilder<D[tb]> | ||
? TbQueryBuilder<RecordPascalKeys<D[tb]>, Context> | ||
: TbQueryBuilder<D[tb], Context> | ||
} | ||
@@ -49,3 +50,3 @@ | ||
export type TbQueryBuilder<TRecord> = () => Knex.QueryBuilder<TRecord, TRecord[]> | ||
export type TbQueryBuilder<TRecord, Context> = (ctx?: Context) => Knex.QueryBuilder<TRecord, TRecord[]> | ||
// export type TbQueryBuilder<TRecord> | ||
@@ -70,4 +71,7 @@ // = <CaseConvert extends CaseType = CaseType.none>(caseConvert?: CaseConvert) | ||
export type EventType = 'query' | 'queryError' | 'queryResponse' | 'start' | 'unknown' | ||
export interface KmoreEvent <T = unknown> { | ||
type: 'query' | 'queryError' | 'queryResponse' | 'unknown' | ||
dbId: string | ||
type: EventType | ||
/** passed from external */ | ||
@@ -94,2 +98,3 @@ identifier: unknown | ||
exError: OnQueryErrorErr | undefined | ||
queryBuilder: Knex.QueryBuilder | undefined // when event is 'start | ||
timestamp: number | ||
@@ -189,1 +194,18 @@ } | ||
export interface EventCallbackOptions<Ctx = unknown, R = unknown> { | ||
ctx: Ctx | ||
event?: KmoreEvent<R> | ||
} | ||
/** | ||
* @docs https://knexjs.org/guide/interfaces.html#query-response | ||
*/ | ||
export type EventCallback<Ctx = any> = (event: KmoreEvent, ctx?: Ctx) => Promise<void> | ||
/** | ||
* @docs https://knexjs.org/guide/interfaces.html#query-response | ||
*/ | ||
export type EventCallbackType = Exclude<EventType, 'unknown'> | ||
/** | ||
* @docs https://knexjs.org/guide/interfaces.html#query-response | ||
*/ | ||
export type EventCallbacks<Ctx = any> = Partial<Record<EventCallbackType, EventCallback<Ctx>>> | ||
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
116631
1
1849
296
6
- Removed@waiting/shared-types@^20.2.0
- Removedrxjs@^7.5.0