Comparing version 51.3.4 to 52.0.0
@@ -9,2 +9,3 @@ import assert from 'node:assert'; | ||
kmoreQueryId, | ||
columns: [], | ||
}; | ||
@@ -19,6 +20,12 @@ const opts = { | ||
.queryContext(queryCtxOpts) | ||
.on('start', (builder) => callCbOnStart({ | ||
...opts, | ||
builder, | ||
})) | ||
.on('start', (builder) => { | ||
const columns2 = pickColumnsFromBuilder(builder); | ||
if (columns2.length) { | ||
columns2.forEach(row => queryCtxOpts.columns.push(row)); | ||
} | ||
return callCbOnStart({ | ||
...opts, | ||
builder, | ||
}); | ||
}) | ||
.on('query', (data) => callCbOnQuery({ | ||
@@ -50,2 +57,26 @@ ...opts, | ||
} | ||
function pickColumnsFromBuilder(builder) { | ||
const ret = []; | ||
// @ts-ignore | ||
const statements = builder._statements; | ||
if (Array.isArray(statements) && statements.length) { | ||
statements.forEach((statement) => { | ||
if (statement.grouping !== 'columns') { | ||
return; | ||
} | ||
const { value } = statement; | ||
if (Array.isArray(value)) { | ||
value.forEach((item) => { | ||
if (typeof item === 'string') { | ||
ret.push({ [item]: item }); | ||
} | ||
else if (typeof item === 'object') { | ||
ret.push(item); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
return ret; | ||
} | ||
//# sourceMappingURL=builder.event.js.map |
@@ -12,3 +12,3 @@ import { CaseConvertTable, CaseType, DbScopedColsByKey, DbScopedColsByTableType, JoinTableWithCaseConvert, SplitScopedColumn, StrKey, UnwrapArrayMember } from '@waiting/shared-types'; | ||
export type KmoreQueryBuilder<D extends {} = {}, CaseConvert extends CaseType = CaseType, EnablePage extends PagingCategory = 0, TRecord extends {} = any, TResult = any> = QueryBuilderExtName<D> & QueryBuilderExtMethod<D, CaseConvert, EnablePage, TRecord> & QueryBuilder<D, CaseConvert, EnablePage, TRecord, AddPagingMeta<TResult, EnablePage>>; | ||
type OmitQueryBuilderKeys = 'select' | 'where' | 'orderBy' | keyof Knex.ChainableInterface; | ||
type OmitQueryBuilderKeys = 'select' | 'where' | 'orderBy' | 'columns' | keyof Knex.ChainableInterface; | ||
interface QueryBuilder<D extends {} = {}, CaseConvert extends CaseType = CaseType, EnablePage extends PagingCategory = 0, TRecord extends {} = any, TResult = any> extends Knex.ChainableInterface<AddPagingMeta<ResolveResult<TResult>, EnablePage>>, Omit<Knex.QueryBuilder<TRecord, TResult>, OmitQueryBuilderKeys> { | ||
@@ -18,2 +18,3 @@ select: Select<D, CaseConvert, EnablePage, TRecord, TResult>; | ||
orderBy: OrderBy<D, CaseConvert, EnablePage, TRecord, TResult>; | ||
columns: Select<D, CaseConvert, EnablePage, TRecord, TResult>; | ||
} | ||
@@ -20,0 +21,0 @@ export type DbQueryBuilder<Context, D, Prefix extends string, CaseConvert extends CaseType> = { |
@@ -5,2 +5,6 @@ import { RecordCamelKeys, RecordPascalKeys, RecordSnakeKeys } from '@waiting/shared-types'; | ||
export declare function getCurrentTime(dbh: Knex, clientType: KnexConfig['client']): Promise<string>; | ||
/** | ||
* Convert identifier (field) to snakecase | ||
*/ | ||
export declare function wrapIdentifier(value: string, origImpl: (input: string) => string, queryContext?: QueryContext): string; | ||
export declare function postProcessResponse<T extends PostProcessInput = PostProcessInput>(result: T, queryContext?: QueryContext): T | PostProcessRespRet<T, QueryContext['postProcessResponseCaseConvert']>; | ||
@@ -27,6 +31,2 @@ export type PostProcessPlain = number | string | undefined | null | boolean; | ||
/** | ||
* Convert identifier (field) to snakecase | ||
*/ | ||
export declare function wrapIdentifier(value: string, origImpl: (input: string) => string, queryContext?: QueryContext): string; | ||
/** | ||
* @description only one level | ||
@@ -33,0 +33,0 @@ */ |
@@ -30,2 +30,40 @@ import { camelToSnake, camelKeys, snakeKeys, snakeToCamel, } from '@waiting/shared-core'; | ||
} | ||
/** | ||
* Convert identifier (field) to snakecase | ||
*/ | ||
export function wrapIdentifier(value, origImpl, queryContext) { | ||
let ret = ''; | ||
// do not convert if value is add by builder.columns(columns) | ||
if (isIdentifierInColumns(value, queryContext?.columns)) { | ||
ret = origImpl(value); | ||
return ret; | ||
} | ||
if (queryContext) { | ||
switch (queryContext.wrapIdentifierCaseConvert) { | ||
case CaseType.camel: { | ||
ret = origImpl(snakeToCamel(value)); | ||
break; | ||
} | ||
case CaseType.snake: { | ||
ret = origImpl(camelToSnake(value)); | ||
break; | ||
} | ||
case CaseType.pascal: { | ||
throw new TypeError('CaseType.pascal for wrapIdentifierCaseConvert not implemented yet'); | ||
} | ||
default: | ||
ret = origImpl(value); | ||
break; | ||
} | ||
} | ||
else { | ||
ret = origImpl(value); | ||
} | ||
if (value === '' && ret === '``') { | ||
// fix for mysql when identifier is empty string | ||
// e.g. SELECT '' AS foo => SELECT `` AS foo, will be converted to SELECT '' AS foo | ||
ret = '\'\''; | ||
} | ||
return ret; | ||
} | ||
export function postProcessResponse(result, queryContext) { | ||
@@ -60,3 +98,30 @@ if (!queryContext) { | ||
else if (typeof result === 'object' && result) { | ||
const ret = genCamelKeysFrom(result); | ||
const columns = _queryContext?.columns; | ||
if (!columns) { | ||
const ret = genCamelKeysFrom(result); | ||
return ret; | ||
} | ||
const resultNotConvertKeys = {}; | ||
const resultNeedConvertKeys = {}; | ||
Object.entries(result).forEach(([key, value]) => { | ||
// do not convert if value is add by builder.columns(columns) | ||
if (isIdentifierInColumns(key, columns)) { | ||
Object.defineProperty(resultNotConvertKeys, key, { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value, | ||
}); | ||
} | ||
else { | ||
Object.defineProperty(resultNeedConvertKeys, key, { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value, | ||
}); | ||
} | ||
}); | ||
const reulst2 = genCamelKeysFrom(resultNeedConvertKeys); | ||
const ret = Object.assign(resultNotConvertKeys, reulst2); | ||
return ret; | ||
@@ -92,3 +157,30 @@ } | ||
else if (typeof result === 'object' && result) { | ||
const ret = genSnakeKeysFrom(result); | ||
const columns = _queryContext?.columns; | ||
if (!columns) { | ||
const ret = genSnakeKeysFrom(result); | ||
return ret; | ||
} | ||
const resultNotConvertKeys = {}; | ||
const resultNeedConvertKeys = {}; | ||
Object.entries(result).forEach(([key, value]) => { | ||
// do not convert if value is add by builder.columns(columns) | ||
if (isIdentifierInColumns(key, columns)) { | ||
Object.defineProperty(resultNotConvertKeys, key, { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value, | ||
}); | ||
} | ||
else { | ||
Object.defineProperty(resultNeedConvertKeys, key, { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value, | ||
}); | ||
} | ||
}); | ||
const reulst2 = genSnakeKeysFrom(resultNeedConvertKeys); | ||
const ret = Object.assign(resultNotConvertKeys, reulst2); | ||
return ret; | ||
@@ -110,35 +202,2 @@ } | ||
/** | ||
* Convert identifier (field) to snakecase | ||
*/ | ||
export function wrapIdentifier(value, origImpl, queryContext) { | ||
let ret = ''; | ||
if (queryContext) { | ||
switch (queryContext.wrapIdentifierCaseConvert) { | ||
case CaseType.camel: { | ||
ret = origImpl(snakeToCamel(value)); | ||
break; | ||
} | ||
case CaseType.snake: { | ||
ret = origImpl(camelToSnake(value)); | ||
break; | ||
} | ||
case CaseType.pascal: { | ||
throw new TypeError('CaseType.pascal for wrapIdentifierCaseConvert not implemented yet'); | ||
} | ||
default: | ||
ret = origImpl(value); | ||
break; | ||
} | ||
} | ||
else { | ||
ret = origImpl(value); | ||
} | ||
if (value === '' && ret === '``') { | ||
// fix for mysql when identifier is empty string | ||
// e.g. SELECT '' AS foo => SELECT `` AS foo, will be converted to SELECT '' AS foo | ||
ret = '\'\''; | ||
} | ||
return ret; | ||
} | ||
/** | ||
* @description only one level | ||
@@ -170,2 +229,17 @@ */ | ||
} | ||
function isIdentifierInColumns(value, columns) { | ||
if (!columns || !columns.length) { | ||
return false; | ||
} | ||
const found = columns.some((row) => { | ||
if (row['fromSmartJoin']) { | ||
return false; | ||
} | ||
if (typeof row[value] !== 'undefined' && row[value] !== value) { | ||
return true; | ||
} | ||
return false; | ||
}); | ||
return found; | ||
} | ||
//# sourceMappingURL=helper.js.map |
@@ -8,11 +8,13 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
const pm1 = ctxBuilderResultPreProcessor | ||
? input.then((response) => ctxBuilderResultPreProcessor({ | ||
kmoreQueryId, | ||
kmoreTrxId, | ||
response, | ||
transactionalProcessed, | ||
trxPropagateOptions, | ||
trxPropagated, | ||
rowLockLevel, | ||
})) | ||
? input.then((response) => { | ||
return ctxBuilderResultPreProcessor({ | ||
kmoreQueryId, | ||
kmoreTrxId, | ||
response, | ||
transactionalProcessed, | ||
trxPropagateOptions, | ||
trxPropagated, | ||
rowLockLevel, | ||
}); | ||
}) | ||
: input; | ||
@@ -19,0 +21,0 @@ const pm2 = ctxExceptionHandler |
@@ -28,2 +28,5 @@ import assert from 'assert'; | ||
if (!pagingFlag || pagingFlag === 'pager') { | ||
Object.defineProperty(aliasObject, 'forSmartJoin', { | ||
value: true, | ||
}); | ||
void builder.columns(aliasObject); | ||
@@ -30,0 +33,0 @@ } |
@@ -85,2 +85,3 @@ import type { TraceContext, Span } from '@mwcp/otel'; | ||
kmoreQueryId: symbol; | ||
columns: Record<string, string>[]; | ||
} | ||
@@ -87,0 +88,0 @@ export interface OnQueryData { |
{ | ||
"name": "kmore", | ||
"author": "waiting", | ||
"version": "51.3.4", | ||
"version": "52.0.0", | ||
"description": "A SQL query builder based on knex with powerful TypeScript type support", | ||
@@ -46,4 +46,4 @@ "keywords": [ | ||
"cross-env": "7", | ||
"kmore-cli": "^51.1.3", | ||
"kmore-types": "^51.0.0", | ||
"kmore-cli": "^52.0.0", | ||
"kmore-types": "^52.0.0", | ||
"knex": "^2.3.0", | ||
@@ -82,3 +82,3 @@ "pg": "^8.8.0" | ||
}, | ||
"gitHead": "b4eef27b6f1efd6092f305687e8f5bc271797aee" | ||
"gitHead": "7a9749481135a69ad9430e1d69dc404656077e9d" | ||
} |
@@ -37,2 +37,3 @@ import assert from 'node:assert' | ||
kmoreQueryId, | ||
columns: [], | ||
} | ||
@@ -50,6 +51,12 @@ const opts: CallCbOptionsBase = { | ||
'start', | ||
(builder: KmoreQueryBuilder) => callCbOnStart({ | ||
...opts, | ||
builder, | ||
}), | ||
(builder: KmoreQueryBuilder) => { | ||
const columns2 = pickColumnsFromBuilder(builder) | ||
if (columns2.length) { | ||
columns2.forEach(row => queryCtxOpts.columns.push(row)) | ||
} | ||
return callCbOnStart({ | ||
...opts, | ||
builder, | ||
}) | ||
}, | ||
) | ||
@@ -92,1 +99,27 @@ .on( | ||
} | ||
function pickColumnsFromBuilder(builder: KmoreQueryBuilder): Record<string, string>[] { | ||
const ret: Record<string, string>[] = [] | ||
// @ts-ignore | ||
const statements = builder._statements as { grouping: string, value: unknown }[] | ||
if (Array.isArray(statements) && statements.length) { | ||
statements.forEach((statement) => { | ||
if (statement.grouping !== 'columns') { return } | ||
const { value } = statement | ||
if (Array.isArray(value)) { | ||
value.forEach((item) => { | ||
if (typeof item === 'string') { | ||
ret.push({ [item]: item }) | ||
} | ||
else if (typeof item === 'object') { | ||
ret.push(item as Record<string, string>) | ||
} | ||
}) | ||
} | ||
}) | ||
} | ||
return ret | ||
} | ||
@@ -38,3 +38,3 @@ /* eslint-disable max-len */ | ||
type OmitQueryBuilderKeys = 'select' | 'where' | 'orderBy' | keyof Knex.ChainableInterface | ||
type OmitQueryBuilderKeys = 'select' | 'where' | 'orderBy' | 'columns' | keyof Knex.ChainableInterface | ||
@@ -54,2 +54,3 @@ interface QueryBuilder< | ||
orderBy: OrderBy<D, CaseConvert, EnablePage, TRecord, TResult> | ||
columns: Select<D, CaseConvert, EnablePage, TRecord, TResult> | ||
} | ||
@@ -56,0 +57,0 @@ |
@@ -60,2 +60,53 @@ import { | ||
/** | ||
* Convert identifier (field) to snakecase | ||
*/ | ||
export function wrapIdentifier( | ||
value: string, | ||
origImpl: (input: string) => string, | ||
queryContext?: QueryContext, | ||
): string { | ||
let ret = '' | ||
// do not convert if value is add by builder.columns(columns) | ||
if (isIdentifierInColumns(value, queryContext?.columns)) { | ||
ret = origImpl(value) | ||
return ret | ||
} | ||
if (queryContext) { | ||
switch (queryContext.wrapIdentifierCaseConvert) { | ||
case CaseType.camel: { | ||
ret = origImpl(snakeToCamel(value)) | ||
break | ||
} | ||
case CaseType.snake: { | ||
ret = origImpl(camelToSnake(value)) | ||
break | ||
} | ||
case CaseType.pascal: { | ||
throw new TypeError('CaseType.pascal for wrapIdentifierCaseConvert not implemented yet') | ||
} | ||
default: | ||
ret = origImpl(value) | ||
break | ||
} | ||
} | ||
else { | ||
ret = origImpl(value) | ||
} | ||
if (value === '' && ret === '``') { | ||
// fix for mysql when identifier is empty string | ||
// e.g. SELECT '' AS foo => SELECT `` AS foo, will be converted to SELECT '' AS foo | ||
ret = '\'\'' | ||
} | ||
return ret | ||
} | ||
export function postProcessResponse<T extends PostProcessInput = PostProcessInput>( | ||
@@ -118,3 +169,33 @@ result: T, | ||
else if (typeof result === 'object' && result) { | ||
const ret = genCamelKeysFrom(result) | ||
const columns = _queryContext?.columns | ||
if (! columns) { | ||
const ret = genCamelKeysFrom(result) | ||
return ret as PostProcessRespRet<T, CaseType.camel> | ||
} | ||
const resultNotConvertKeys = {} | ||
const resultNeedConvertKeys = {} | ||
Object.entries(result).forEach(([key, value]) => { | ||
// do not convert if value is add by builder.columns(columns) | ||
if (isIdentifierInColumns(key, columns)) { | ||
Object.defineProperty(resultNotConvertKeys, key, { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value, | ||
}) | ||
} | ||
else { | ||
Object.defineProperty(resultNeedConvertKeys, key, { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value, | ||
}) | ||
} | ||
}) | ||
const reulst2 = genCamelKeysFrom(resultNeedConvertKeys) | ||
const ret = Object.assign(resultNotConvertKeys, reulst2) | ||
return ret as PostProcessRespRet<T, CaseType.camel> | ||
@@ -159,3 +240,34 @@ } | ||
else if (typeof result === 'object' && result) { | ||
const ret = genSnakeKeysFrom(result) | ||
const columns = _queryContext?.columns | ||
if (! columns) { | ||
const ret = genSnakeKeysFrom(result) | ||
return ret as PostProcessRespRet<T, CaseType.snake> | ||
} | ||
const resultNotConvertKeys = {} | ||
const resultNeedConvertKeys = {} | ||
Object.entries(result).forEach(([key, value]) => { | ||
// do not convert if value is add by builder.columns(columns) | ||
if (isIdentifierInColumns(key, columns)) { | ||
Object.defineProperty(resultNotConvertKeys, key, { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value, | ||
}) | ||
} | ||
else { | ||
Object.defineProperty(resultNeedConvertKeys, key, { | ||
configurable: true, | ||
enumerable: true, | ||
writable: true, | ||
value, | ||
}) | ||
} | ||
}) | ||
const reulst2 = genSnakeKeysFrom(resultNeedConvertKeys) | ||
const ret = Object.assign(resultNotConvertKeys, reulst2) | ||
return ret as PostProcessRespRet<T, CaseType.snake> | ||
@@ -186,46 +298,3 @@ } | ||
/** | ||
* Convert identifier (field) to snakecase | ||
*/ | ||
export function wrapIdentifier( | ||
value: string, | ||
origImpl: (input: string) => string, | ||
queryContext?: QueryContext, | ||
): string { | ||
let ret = '' | ||
if (queryContext) { | ||
switch (queryContext.wrapIdentifierCaseConvert) { | ||
case CaseType.camel: { | ||
ret = origImpl(snakeToCamel(value)) | ||
break | ||
} | ||
case CaseType.snake: { | ||
ret = origImpl(camelToSnake(value)) | ||
break | ||
} | ||
case CaseType.pascal: { | ||
throw new TypeError('CaseType.pascal for wrapIdentifierCaseConvert not implemented yet') | ||
} | ||
default: | ||
ret = origImpl(value) | ||
break | ||
} | ||
} | ||
else { | ||
ret = origImpl(value) | ||
} | ||
if (value === '' && ret === '``') { | ||
// fix for mysql when identifier is empty string | ||
// e.g. SELECT '' AS foo => SELECT `` AS foo, will be converted to SELECT '' AS foo | ||
ret = '\'\'' | ||
} | ||
return ret | ||
} | ||
/** | ||
@@ -265,1 +334,18 @@ * @description only one level | ||
} | ||
function isIdentifierInColumns(value: string, columns: Record<string, string>[] | undefined): boolean { | ||
if (! columns || ! columns.length) { | ||
return false | ||
} | ||
const found = columns.some((row) => { | ||
if (row['fromSmartJoin']) { | ||
return false | ||
} | ||
if (typeof row[value] !== 'undefined' && row[value] !== value) { | ||
return true | ||
} | ||
return false | ||
}) | ||
return found | ||
} |
@@ -41,12 +41,15 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
const pm1 = ctxBuilderResultPreProcessor | ||
? input.then((response: unknown) => ctxBuilderResultPreProcessor({ | ||
kmoreQueryId, | ||
kmoreTrxId, | ||
response, | ||
transactionalProcessed, | ||
trxPropagateOptions, | ||
trxPropagated, | ||
rowLockLevel, | ||
})) | ||
? input.then((response: unknown) => { | ||
return ctxBuilderResultPreProcessor({ | ||
kmoreQueryId, | ||
kmoreTrxId, | ||
response, | ||
transactionalProcessed, | ||
trxPropagateOptions, | ||
trxPropagated, | ||
rowLockLevel, | ||
}) | ||
}) | ||
: input | ||
const pm2 = ctxExceptionHandler | ||
@@ -53,0 +56,0 @@ ? pm1.catch((ex: unknown) => ctxExceptionHandler({ |
@@ -39,2 +39,5 @@ import assert from 'assert' | ||
if (! pagingFlag || pagingFlag === 'pager') { | ||
Object.defineProperty(aliasObject, 'forSmartJoin', { | ||
value: true, | ||
}) | ||
void builder.columns(aliasObject) | ||
@@ -41,0 +44,0 @@ } |
@@ -105,2 +105,3 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
kmoreQueryId: symbol | ||
columns: Record<string, string>[] | ||
} | ||
@@ -107,0 +108,0 @@ |
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
Sorry, the diff of this file is not supported yet
425149
7182