@qrvey/data-persistence
Advanced tools
Comparing version 0.0.4 to 0.0.6-1
@@ -5,2 +5,3 @@ "use strict"; | ||
const constants_1 = require("../utils/constants"); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
function buildFilter(attribute, value, operator = 'EQUAL') { | ||
@@ -24,3 +25,3 @@ return { | ||
column, | ||
direction, | ||
direction: direction, | ||
}; | ||
@@ -27,0 +28,0 @@ } |
@@ -29,2 +29,3 @@ "use strict"; | ||
__exportStar(require("./updateOptions.interface"), exports); | ||
__exportStar(require("./createMultipleResponse.interface"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -14,2 +14,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
const crudHelpers_1 = require("../helpers/crudHelpers"); | ||
@@ -20,6 +21,26 @@ const crudFactory_service_1 = require("./crudFactory.service"); | ||
this.crudService = crudFactory_service_1.CrudFactory.databaseClientService(crudSchema); | ||
this.crudSchema = crudSchema; | ||
} | ||
create(entity) { | ||
return this.crudService.create(entity); | ||
getDefaultValue(columnName) { | ||
const column = this.crudSchema.columns[columnName]; | ||
return column ? column.default : undefined; | ||
} | ||
setDefaultValues(data) { | ||
const defaultValues = {}; | ||
const columns = this.crudSchema.columns; | ||
for (const columnName in columns) { | ||
const missingColumnValue = !(columnName in data); | ||
const columnDefaultValue = this.getDefaultValue(columnName); | ||
if (missingColumnValue && columnDefaultValue) { | ||
defaultValues[columnName] = columnDefaultValue; | ||
} | ||
} | ||
return Object.assign(Object.assign({}, defaultValues), data); | ||
} | ||
create(data) { | ||
const processedData = Array.isArray(data) | ||
? data.map(this.setDefaultValues.bind(this)) | ||
: this.setDefaultValues(data); | ||
return this.crudService.create(processedData); | ||
} | ||
find(options) { | ||
@@ -43,5 +64,3 @@ return this.crudService.find(options); | ||
findCount(options) { | ||
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars | ||
const { pagination } = options, findAllOptions = __rest(options, ["pagination"]); | ||
return this.crudService.findCount(findAllOptions); | ||
return this.crudService.findCount(options); | ||
} | ||
@@ -48,0 +67,0 @@ buildFilter(attribute, value, operator = 'EQUAL') { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb"); | ||
@@ -98,4 +99,18 @@ const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb"); | ||
} | ||
batchWrittenPut(data) { | ||
const putRequests = data.map((item) => ({ | ||
PutRequest: { | ||
Item: item, | ||
}, | ||
})); | ||
const params = { | ||
RequestItems: { | ||
[this.tableName]: putRequests, | ||
}, | ||
}; | ||
const insertCommand = new lib_dynamodb_1.BatchWriteCommand(params); | ||
return this.dynamoDBClient.send(insertCommand); | ||
} | ||
} | ||
exports.default = DynamoDbClientService; | ||
//# sourceMappingURL=dynamoDbClient.service.js.map |
@@ -26,5 +26,14 @@ "use strict"; | ||
} | ||
async create(entity) { | ||
await this.dynamoDbClientService.put(entity); | ||
return entity; | ||
async create(data) { | ||
var _a; | ||
if (Array.isArray(data)) { | ||
const response = await this.dynamoDbClientService.batchWrittenPut(data); | ||
return { | ||
unprocessedItems: (_a = response.UnprocessedItems) !== null && _a !== void 0 ? _a : [], | ||
}; | ||
} | ||
else { | ||
await this.dynamoDbClientService.put(data); | ||
return data; | ||
} | ||
} | ||
@@ -47,2 +56,4 @@ // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars | ||
this.applyFilters(query, options); | ||
if (options.aggregateFunction === constants_1.AGGREGATE_FUNCTIONS.COUNT) | ||
query.count(); | ||
return this.fetchResults(query.get(), (_d = options.pagination) === null || _d === void 0 ? void 0 : _d.limit, options.useScan).then((res) => { | ||
@@ -58,3 +69,3 @@ var _a, _b; | ||
pagination, | ||
count: res.items.length, | ||
count: res.count, | ||
}; | ||
@@ -64,22 +75,34 @@ }); | ||
async fetchResults(command, limit = 100, useScan = false) { | ||
var _a, _b, _c, _d, _e; | ||
var _a, _b; | ||
let results = []; | ||
let LastEvaluatedKey = {}; | ||
let lastEvaluatedKey = {}; | ||
let rowsCount = 0; | ||
do { | ||
if (this.isNotEmptyObject(LastEvaluatedKey)) | ||
command.ExclusiveStartKey = LastEvaluatedKey; | ||
const result = await (useScan | ||
? this.dynamoDbClientService.scan(command) | ||
: this.dynamoDbClientService.query(command)); | ||
command.Limit = ((_a = command.Limit) !== null && _a !== void 0 ? _a : 0) - ((_c = (_b = result.Items) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0); | ||
const rows = (_d = result.Items) !== null && _d !== void 0 ? _d : []; | ||
const result = await this.fetchBatch(command, useScan, lastEvaluatedKey); | ||
const rows = (_a = result.Items) !== null && _a !== void 0 ? _a : []; | ||
results = results.concat(rows); | ||
LastEvaluatedKey = (_e = result.LastEvaluatedKey) !== null && _e !== void 0 ? _e : {}; | ||
} while (results.length < limit && | ||
this.isNotEmptyObject(LastEvaluatedKey)); | ||
const lastEvaluatedKey = this.isNotEmptyObject(LastEvaluatedKey) | ||
? this.encryptPaginationKey(LastEvaluatedKey) | ||
lastEvaluatedKey = (_b = result.LastEvaluatedKey) !== null && _b !== void 0 ? _b : {}; | ||
rowsCount += result.Count || rows.length; | ||
} while (rowsCount < limit && this.isNotEmptyObject(lastEvaluatedKey)); | ||
const encryptedLastEvaluatedKey = this.isNotEmptyObject(lastEvaluatedKey) | ||
? this.encryptPaginationKey(lastEvaluatedKey) | ||
: null; | ||
return { items: results, lastEvaluatedKey }; | ||
return { | ||
items: results, | ||
lastEvaluatedKey: encryptedLastEvaluatedKey, | ||
count: rowsCount, | ||
}; | ||
} | ||
async fetchBatch(command, useScan, lastEvaluatedKey) { | ||
var _a, _b, _c; | ||
if (this.isNotEmptyObject(lastEvaluatedKey)) | ||
command.ExclusiveStartKey = lastEvaluatedKey; | ||
const result = await (useScan | ||
? this.dynamoDbClientService.scan(command) | ||
: this.dynamoDbClientService.query(command)); | ||
if (command.Select !== constants_1.AGGREGATE_FUNCTIONS.COUNT) { | ||
command.Limit = ((_a = command.Limit) !== null && _a !== void 0 ? _a : 0) - ((_c = (_b = result.Items) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0); | ||
} | ||
return result; | ||
} | ||
applyPagination(query, pagination) { | ||
@@ -91,5 +114,6 @@ if (pagination === null || pagination === void 0 ? void 0 : pagination.limit) | ||
} | ||
async findAll(options = {}, allResults = []) { | ||
const { items, pagination } = await this.find(options); | ||
async findAll(options = {}, allResults = [], rowsCount = 0) { | ||
const { items, pagination, count } = await this.find(options); | ||
allResults.push(...items); | ||
rowsCount += count; | ||
if (pagination === null || pagination === void 0 ? void 0 : pagination.from) | ||
@@ -100,27 +124,36 @@ await this.findAll(Object.assign(Object.assign({}, options), { pagination }), allResults); | ||
pagination: null, | ||
count: allResults.length, | ||
count: rowsCount, | ||
}; | ||
} | ||
async findCount(options = {}) { | ||
const { items } = await this.find(options); | ||
return items.length; | ||
var _a; | ||
const findOptions = Object.assign(Object.assign({}, options), { aggregateFunction: constants_1.AGGREGATE_FUNCTIONS.COUNT }); | ||
if ((_a = options.pagination) === null || _a === void 0 ? void 0 : _a.from) { | ||
return this.find(findOptions).then((res) => res.count); | ||
} | ||
else { | ||
return this.findAll(findOptions).then((res) => res.count); | ||
} | ||
} | ||
async findItem(options) { | ||
var _a, _b, _c; | ||
buildFindItemQuery(options) { | ||
var _a; | ||
const query = new queryBuilder_service_1.default(); | ||
if ((_a = options.index) === null || _a === void 0 ? void 0 : _a.indexName) | ||
query.usingIndex((_b = options.index) === null || _b === void 0 ? void 0 : _b.indexName); | ||
query.usingIndex(options.index.indexName); | ||
this.applyFilters(query, options); | ||
if (options.fields) | ||
query.projection(options.fields); | ||
query.projection(options.fields); | ||
query.limit(1); | ||
const command = query.get(); | ||
const result = await this.dynamoDbClientService.query(command); | ||
if ((result === null || result === void 0 ? void 0 : result.Items) && ((_c = result.Items) === null || _c === void 0 ? void 0 : _c.length) > 0) { | ||
return result.Items[0]; | ||
} | ||
if (options.throwErrorIfNull) | ||
throw new Error('NOT_FOUND'); | ||
return null; | ||
return query; | ||
} | ||
findItem(options) { | ||
const query = this.buildFindItemQuery(options); | ||
return this.dynamoDbClientService.query(query.get()).then((result) => { | ||
var _a; | ||
if ((_a = result.Items) === null || _a === void 0 ? void 0 : _a.length) | ||
return result.Items[0]; | ||
if (options.throwErrorIfNull) | ||
throw new Error('NOT_FOUND'); | ||
return null; | ||
}); | ||
} | ||
applyWhereFilter(query, filter) { | ||
@@ -145,4 +178,4 @@ var _a, _b; | ||
applySimpleFilters(query, options) { | ||
var _a; | ||
const queryIndexColumns = ((_a = options.index) === null || _a === void 0 ? void 0 : _a.columns) || []; | ||
var _a, _b; | ||
const queryIndexColumns = (_b = (_a = options.index) === null || _a === void 0 ? void 0 : _a.columns) !== null && _b !== void 0 ? _b : []; | ||
const defaultWhereProperties = this.defaultPrimaryKeys; | ||
@@ -149,0 +182,0 @@ const whereProperties = (queryIndexColumns === null || queryIndexColumns === void 0 ? void 0 : queryIndexColumns.length) |
@@ -8,2 +8,3 @@ "use strict"; | ||
const queryHelpers_1 = require("../../../helpers/queryHelpers"); | ||
const constants_1 = require("../../../utils/constants"); | ||
class QueryBuilderService { | ||
@@ -42,3 +43,5 @@ constructor(useScan = false) { | ||
} | ||
projection(fields) { | ||
projection(fields = []) { | ||
if (!fields.length) | ||
return this; | ||
const expression = []; | ||
@@ -77,4 +80,8 @@ fields.forEach((field) => { | ||
} | ||
count() { | ||
this.command.Select = constants_1.AGGREGATE_FUNCTIONS.COUNT; | ||
return this; | ||
} | ||
} | ||
exports.default = QueryBuilderService; | ||
//# sourceMappingURL=queryBuilder.service.js.map |
@@ -120,3 +120,3 @@ "use strict"; | ||
attribute_exists(keyValue) { | ||
const { key } = this.generateKeyValue(keyValue); | ||
const { key } = this.generateKeyValue(keyValue, null, true); | ||
let expression = `attribute_exists(${key})`; | ||
@@ -129,3 +129,3 @@ if (this.tempLogicOperator) | ||
attribute_not_exists(keyValue) { | ||
const { key } = this.generateKeyValue(keyValue); | ||
const { key } = this.generateKeyValue(keyValue, null, true); | ||
let expression = `attribute_not_exists(${key})`; | ||
@@ -161,3 +161,3 @@ if (this.tempLogicOperator) | ||
} | ||
generateKeyValue(value, separatorCharacter = ',') { | ||
generateKeyValue(value, separatorCharacter = ',', omitAttributeValues = false) { | ||
const keyExpression = `#${this.tempKey}1`; | ||
@@ -182,3 +182,3 @@ this.attributeNames[keyExpression] = this.tempKey; | ||
let valueExpression = `:${this.tempKey}1`; | ||
if (this.attributeValues[valueExpression]) { | ||
if (valueExpression in this.attributeValues) { | ||
for (const [index] of Object.entries(this.attributeValues)) { | ||
@@ -189,3 +189,4 @@ if (index === valueExpression) | ||
} | ||
this.attributeValues[valueExpression] = value; | ||
if (!omitAttributeValues) | ||
this.attributeValues[valueExpression] = value; | ||
return { key: keyExpression, value: valueExpression }; | ||
@@ -192,0 +193,0 @@ } |
@@ -65,14 +65,30 @@ "use strict"; | ||
} | ||
// else if (filters) { | ||
// const operator: FilterLogicOperator = | ||
// filters.logicOperator ?? FILTER_LOGIC_OPERATORS.AND; | ||
// const simpleFilters = filters.filters as IFilter[]; | ||
// const filterClauses = this.buildFilterClause( | ||
// simpleFilters, | ||
// operator, | ||
// ); | ||
// return filterClauses; | ||
// } | ||
return ''; | ||
else { | ||
return this.buildQueryByClause(filters); | ||
} | ||
} | ||
buildQueryByClause(filters) { | ||
let filterClauses = ''; | ||
let isFirstFilter = true; | ||
for (const [key, value] of Object.entries(filters)) { | ||
if (!isFirstFilter) { | ||
filterClauses += key === 'AND' ? ' AND ' : ' OR '; | ||
} | ||
const isCompositeFilter = 'OR' in value || 'AND' in value; | ||
if (isCompositeFilter) { | ||
filterClauses += '('; | ||
filterClauses += this.buildQueryByClause(value); | ||
filterClauses += ')'; | ||
} | ||
else { | ||
value.forEach((filter) => { | ||
const clause = this.buildClause(filter.operator, filter.attribute, filter.value); | ||
filterClauses += `${clause} ${key} `; | ||
}); | ||
} | ||
isFirstFilter = false; | ||
} | ||
filterClauses = filterClauses.replace(/\s+(AND|OR)\s*$/, ''); | ||
return filterClauses; | ||
} | ||
formatOrderByItem(sort) { | ||
@@ -90,5 +106,5 @@ return `${pg_format_1.default.ident(sort.column)} ${sort.direction || constants_1.SORT_DIRECTIONS.ASC}`; | ||
async createCommand(data) { | ||
const keys = Object.keys(data); | ||
const values = Object.values(data); | ||
const query = (0, pg_format_1.default)(`INSERT INTO ${pg_format_1.default.ident(this.dbSchema)}.${pg_format_1.default.ident(this.tableName)} (%I) VALUES (%L) RETURNING *;`, keys, values); | ||
const keys = Object.keys(data[0]); // Assuming all objects have the same keys | ||
const values = data.map((item) => Object.values(item)); | ||
const query = (0, pg_format_1.default)(`INSERT INTO ${pg_format_1.default.ident(this.dbSchema)}.${pg_format_1.default.ident(this.tableName)} (%I) VALUES %L RETURNING *;`, keys, values); | ||
return this.runQuery(query); | ||
@@ -121,4 +137,16 @@ } | ||
return '*'; | ||
return fields.join(', '); | ||
return this.parseFields(fields).join(', '); | ||
} | ||
parseFields(fields) { | ||
const columnsFromSchema = Object.keys(this.crudSchema.columns); | ||
const attributes = fields | ||
.filter((field) => columnsFromSchema.indexOf(field) !== -1) | ||
.map((field) => `"${field}"`); | ||
fields | ||
.filter((field) => columnsFromSchema.indexOf(field) === -1) | ||
.forEach((field) => { | ||
attributes.push(`"qvAttributes" ->> '${field}' as "${field}"`); | ||
}); | ||
return attributes; | ||
} | ||
async findCommand(options = {}) { | ||
@@ -125,0 +153,0 @@ let query = `SELECT ${this.getSelectClause(options.aggregateFunction, options.fields)} FROM ${pg_format_1.default.ident(this.dbSchema)}.${pg_format_1.default.ident(this.tableName)}`; |
@@ -20,3 +20,3 @@ "use strict"; | ||
} | ||
moveUndefinedColumnsToQvAttributes(inputData) { | ||
normalizeInputData(inputData) { | ||
inputData.qvAttributes = {}; | ||
@@ -28,2 +28,5 @@ for (const key in inputData) { | ||
} | ||
else if (Array.isArray(inputData[key])) { | ||
inputData[key] = JSON.stringify(inputData[key]); | ||
} | ||
} | ||
@@ -36,7 +39,21 @@ } | ||
} | ||
create(entity) { | ||
const inputData = Object.assign({}, entity); | ||
this.moveUndefinedColumnsToQvAttributes(inputData); | ||
return this.createCommand(inputData).then((data) => data.rows[0]); | ||
prepareData(data) { | ||
const inputData = Object.assign({}, data); | ||
this.normalizeInputData(inputData); | ||
return inputData; | ||
} | ||
create(data) { | ||
if (Array.isArray(data)) { | ||
const inputDataArray = data.map((item) => this.prepareData(item)); | ||
return this.createCommand(inputDataArray).then((result) => ({ | ||
unprocessedItems: result | ||
.filter((r) => !r.success) | ||
.map((r) => r.inputData), | ||
})); | ||
} | ||
else { | ||
const inputData = this.prepareData(data); | ||
return this.createCommand([inputData]).then((result) => result.rowCount ? result.rows[0] : null); | ||
} | ||
} | ||
findItem(findOptions) { | ||
@@ -75,3 +92,3 @@ return this.findCommand(findOptions).then((data) => { | ||
const inputData = Object.assign(Object.assign({}, savedRecord), data); | ||
this.moveUndefinedColumnsToQvAttributes(inputData); | ||
this.normalizeInputData(inputData); | ||
await this.updateCommand(filters, inputData); | ||
@@ -78,0 +95,0 @@ return this.getItem(inputData); |
@@ -12,2 +12,6 @@ interface IFilter { | ||
interface ICreateMultipleResponse { | ||
unprocessedItems: Record<string, any>; | ||
} | ||
type FilterInput = string | IFilter[] | ICompositeFilter[] | ICompositeFilter; | ||
@@ -65,3 +69,3 @@ | ||
interface ICrudService<T> { | ||
create(entity: T): Promise<T>; | ||
create(data: T | T[]): Promise<T | ICreateMultipleResponse>; | ||
findItem(options?: IFindOptions): Promise<T | null>; | ||
@@ -86,2 +90,3 @@ find(options?: IFindOptions): Promise<IFindResult<T>>; | ||
columnId?: boolean; | ||
default?: any; | ||
}; | ||
@@ -99,4 +104,7 @@ } | ||
private crudService; | ||
private crudSchema; | ||
constructor(crudSchema: typeof CrudSchema); | ||
create(entity: T): Promise<T>; | ||
private getDefaultValue; | ||
private setDefaultValues; | ||
create(data: T | T[]): Promise<T | ICreateMultipleResponse>; | ||
find(options: IFindOptions): Promise<IFindResult<T>>; | ||
@@ -111,3 +119,3 @@ findItem(options: IFindOptions): Promise<T | null>; | ||
operator: string; | ||
value: string; | ||
value: any; | ||
}; | ||
@@ -118,9 +126,9 @@ buildQueryIndex(indexName: string, columns: string[]): { | ||
}; | ||
buildSort(column: string, direction: SortDirection): ISorting; | ||
buildSort(column: string, direction: string): ISorting; | ||
} | ||
declare function buildFilter(attribute: string, value: string, operator?: string): { | ||
declare function buildFilter(attribute: string, value: any, operator?: string): { | ||
attribute: string; | ||
operator: string; | ||
value: string; | ||
value: any; | ||
}; | ||
@@ -131,4 +139,4 @@ declare function buildQueryIndex(indexName: string, columns: string[]): { | ||
}; | ||
declare function buildSort(column: string, direction?: SortDirection): ISorting; | ||
declare function buildSort(column: string, direction?: string): ISorting; | ||
export { AggregateFunction, CrudSchema, CrudService, FilterInput, ICrudService, IFilter, IFindOptions, IFindPagination, ISorting, SortDirection, buildFilter, buildQueryIndex, buildSort }; |
@@ -5,3 +5,3 @@ { | ||
"main": "dist/cjs/index.js", | ||
"version": "0.0.4", | ||
"version": "0.0.6-1", | ||
"license": "MIT", | ||
@@ -8,0 +8,0 @@ "exports": { |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
118816
85
1587