@boostercloud/framework-provider-azure
Advanced tools
Comparing version 0.12.1 to 0.12.2
import { CosmosClient } from '@azure/cosmos'; | ||
import { BoosterConfig, FilterOld, Logger } from '@boostercloud/framework-types'; | ||
export declare function searchReadModel(cosmosDb: CosmosClient, config: BoosterConfig, logger: Logger, readModelName: string, filters: Record<string, FilterOld<any>>): Promise<Array<any>>; | ||
import { BoosterConfig, Logger, FilterFor } from '@boostercloud/framework-types'; | ||
export declare function searchReadModel(cosmosDb: CosmosClient, config: BoosterConfig, logger: Logger, readModelName: string, filters: FilterFor<unknown>): Promise<Array<any>>; |
@@ -6,4 +6,5 @@ "use strict"; | ||
async function searchReadModel(cosmosDb, config, logger, readModelName, filters) { | ||
const filterExpression = buildFilterExpression(filters); | ||
const querySpec = { | ||
query: `SELECT * FROM c ${buildFilterExpression(filters)}`, | ||
query: `SELECT * FROM c ${filterExpression !== '' ? `WHERE ${filterExpression}` : filterExpression}`, | ||
parameters: buildExpressionAttributeValues(filters), | ||
@@ -21,56 +22,113 @@ }; | ||
exports.searchReadModel = searchReadModel; | ||
function buildFilterExpression(filters) { | ||
const filterExpression = Object.entries(filters) | ||
.map(([propName, filter]) => buildOperation(propName, filter)) | ||
function buildFilterExpression(filters, usedPlaceholders = []) { | ||
return Object.entries(filters) | ||
.map(([propName, filter]) => { | ||
switch (propName) { | ||
case 'not': | ||
return `NOT (${buildFilterExpression(filter, usedPlaceholders)})`; | ||
case 'and': | ||
case 'or': | ||
return `(${filter | ||
.map((arrayFilter) => buildFilterExpression(arrayFilter, usedPlaceholders)) | ||
.join(` ${propName} `)})`; | ||
default: | ||
return buildOperation(propName, filter, usedPlaceholders); | ||
} | ||
}) | ||
.join(' AND '); | ||
if (filterExpression !== '') { | ||
return `WHERE ${filterExpression}`; | ||
} | ||
return filterExpression; | ||
} | ||
function buildOperation(propName, filter) { | ||
const holder = placeholderBuilderFor(propName); | ||
switch (filter.operation) { | ||
case '=': | ||
return `c["${propName}"] = ${holder(0)}`; | ||
case '!=': | ||
return `c["${propName}"] <> ${holder(0)}`; | ||
case '<': | ||
return `c["${propName}"] < ${holder(0)}`; | ||
case '>': | ||
return `c["${propName}"] > ${holder(0)}`; | ||
case '>=': | ||
return `c["${propName}"] >= ${holder(0)}`; | ||
case '<=': | ||
return `c["${propName}"] <= ${holder(0)}`; | ||
case 'in': | ||
return `c["${propName}"] IN (${filter.values.map((value, index) => holder(index)).join(',')})`; | ||
case 'between': | ||
return `c["${propName}"] BETWEEN ${holder(0)} AND ${holder(1)}`; | ||
case 'contains': | ||
return `CONTAINS(c["${propName}"], ${holder(0)})`; | ||
case 'not-contains': | ||
return `NOT CONTAINS(c["${propName}"], ${holder(0)})`; | ||
case 'begins-with': | ||
return `STARTSWITH(c["${propName}"], ${holder(0)})`; | ||
default: | ||
throw new framework_types_1.InvalidParameterError(`Operator "${filter.operation}" is not supported`); | ||
} | ||
function buildOperation(propName, filter = {}, usedPlaceholders) { | ||
const holder = placeholderBuilderFor(propName, usedPlaceholders); | ||
return Object.entries(filter) | ||
.map(([operation, value], index) => { | ||
switch (operation) { | ||
case 'eq': | ||
return `c["${propName}"] = ${holder(index)}`; | ||
case 'ne': | ||
return `c["${propName}"] <> ${holder(index)}`; | ||
case 'lt': | ||
return `c["${propName}"] < ${holder(index)}`; | ||
case 'gt': | ||
return `c["${propName}"] > ${holder(index)}`; | ||
case 'gte': | ||
return `c["${propName}"] >= ${holder(index)}`; | ||
case 'lte': | ||
return `c["${propName}"] <= ${holder(index)}`; | ||
case 'in': | ||
return `c["${propName}"] IN (${value | ||
.map((value, subIndex) => holder(index, subIndex)) | ||
.join(',')})`; | ||
case 'contains': | ||
return `CONTAINS(c["${propName}"], ${holder(index)})`; | ||
case 'beginsWith': | ||
return `STARTSWITH(c["${propName}"], ${holder(index)})`; | ||
case 'includes': | ||
return `CONTAINS(c["${propName}"], ${holder(index)})`; | ||
default: | ||
if (typeof value === 'object') { | ||
return `c["${propName}"].${buildOperation(operation, value, usedPlaceholders)}`; | ||
} | ||
throw new framework_types_1.InvalidParameterError(`Operator "${operation}" is not supported`); | ||
} | ||
}) | ||
.join(' AND '); | ||
} | ||
function placeholderBuilderFor(propName) { | ||
return (valueIndex) => `@${propName}_${valueIndex}`; | ||
function placeholderBuilderFor(propName, usedPlaceholders) { | ||
return (valueIndex, valueSubIndex) => { | ||
const placeholder = `@${propName}_${valueIndex}` + (typeof valueSubIndex === 'number' ? `_${valueSubIndex}` : ''); | ||
if (usedPlaceholders.includes(placeholder)) | ||
return placeholderBuilderFor(propName, usedPlaceholders)(valueIndex + 1); | ||
usedPlaceholders.push(placeholder); | ||
return placeholder; | ||
}; | ||
} | ||
function buildExpressionAttributeValues(filters) { | ||
const attributeValues = []; | ||
for (const propName in filters) { | ||
const filter = filters[propName]; | ||
const holder = placeholderBuilderFor(propName); | ||
filter.values.forEach((value, index) => { | ||
function buildExpressionAttributeValues(filters, usedPlaceholders = []) { | ||
let attributeValues = []; | ||
Object.entries(filters).forEach(([propName]) => { | ||
switch (propName) { | ||
case 'not': | ||
attributeValues = [ | ||
...attributeValues, | ||
...buildExpressionAttributeValues(filters[propName], usedPlaceholders), | ||
]; | ||
break; | ||
case 'and': | ||
case 'or': | ||
for (const filter of filters[propName]) { | ||
attributeValues = [ | ||
...attributeValues, | ||
...buildExpressionAttributeValues(filter, usedPlaceholders), | ||
]; | ||
} | ||
break; | ||
default: | ||
attributeValues = [...attributeValues, ...buildAttributeValue(propName, filters[propName], usedPlaceholders)]; | ||
break; | ||
} | ||
}); | ||
return attributeValues; | ||
} | ||
function buildAttributeValue(propName, filter = {}, usedPlaceholders) { | ||
let attributeValues = []; | ||
const holder = placeholderBuilderFor(propName, usedPlaceholders); | ||
Object.entries(filter).forEach(([key, value], index) => { | ||
if (Array.isArray(value)) { | ||
value.forEach((element, subIndex) => { | ||
attributeValues.push({ | ||
name: holder(index, subIndex), | ||
value: element, | ||
}); | ||
}); | ||
} | ||
else if (typeof value === 'object' && key !== 'includes') { | ||
attributeValues = [...attributeValues, ...buildExpressionAttributeValues({ [key]: value }, usedPlaceholders)]; | ||
} | ||
else { | ||
attributeValues.push({ | ||
name: holder(index), | ||
value, | ||
value: value, | ||
}); | ||
}); | ||
} | ||
} | ||
}); | ||
return attributeValues; | ||
} |
{ | ||
"name": "@boostercloud/framework-provider-azure", | ||
"version": "0.12.1", | ||
"version": "0.12.2", | ||
"description": "Handle Booster's integration with Azure", | ||
@@ -25,3 +25,3 @@ "keywords": [ | ||
"@azure/functions": "^1.2.2", | ||
"@boostercloud/framework-types": "^0.12.1", | ||
"@boostercloud/framework-types": "^0.12.2", | ||
"chai": "4.2.0", | ||
@@ -43,3 +43,3 @@ "chai-as-promised": "7.1.1", | ||
}, | ||
"gitHead": "2460bb0598147479e5924dc6ee5acb032ba6a5c8" | ||
"gitHead": "ba1b6217f9ff564eb73ffe90b74f234cbe94eb80" | ||
} |
31146
425