electrodb
Advanced tools
Comparing version 2.15.0 to 3.0.0
@@ -18,3 +18,8 @@ const { Entity } = require("./src/entity"); | ||
} = require("./src/errors"); | ||
const { createConversions } = require("./src/conversions"); | ||
const { | ||
ComparisonTypes | ||
} = require('./src/types'); | ||
module.exports = { | ||
@@ -25,2 +30,3 @@ Entity, | ||
createSchema, | ||
ComparisonTypes, | ||
CustomAttributeType, | ||
@@ -31,2 +37,5 @@ createCustomAttribute, | ||
createWriteTransaction, | ||
ElectroUserValidationError, | ||
ElectroAttributeValidationError, | ||
createConversions, | ||
}; |
{ | ||
"name": "electrodb", | ||
"version": "2.15.0", | ||
"version": "3.0.0", | ||
"description": "A library to more easily create and interact with multiple entities and heretical relationships in dynamodb", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -19,11 +19,15 @@ # ElectroDB | ||
<a href="https://electrodb.dev/en/core-concepts/v3-migration/"><h1 align="center">ElectroDB v3 now released</h1></a> | ||
<p align="center">Visit the <a href="https://electrodb.dev/en/core-concepts/v3-migration/">v3 migration page</a> to learn more about this new update.</p> | ||
--- | ||
<a href="https://electrodb.dev"><h1 align="center">New: Documentation now found at ElectroDB.dev</h1></a> | ||
<a href="https://electrodb.dev"><h1 align="center">Documentation now found at ElectroDB.dev</h1></a> | ||
<p align="center">ElectroDB's new website for Documentation is now live at <a href="https://electrodb.dev">www.ElectroDB.dev</a>.</p> | ||
<p align="center">ElectroDB's new website for Documentation is now live at <a href="https://electrodb.dev">electrodb.dev</a>.</p> | ||
--- | ||
<a href="https://electrodb.fun"><h1 align="center">Introducing: The NEW ElectroDB Playground</h1></a> | ||
<a href="https://electrodb.fun"><h1 align="center">The NEW ElectroDB Playground</h1></a> | ||
@@ -30,0 +34,0 @@ <p align="center"> |
@@ -12,2 +12,3 @@ const { | ||
UpsertOperations, | ||
ComparisonTypes, | ||
} = require("./types"); | ||
@@ -123,9 +124,23 @@ const { | ||
state.setSK(composites); | ||
// we must apply eq on filter on all provided because if the user then does a sort key operation, it'd actually then unexpect results | ||
if (sk.length > 1) { | ||
state.filterProperties(FilterOperationNames.eq, { | ||
...unused, | ||
...composites, | ||
}); | ||
} | ||
state.beforeBuildParams(({ options, state }) => { | ||
const accessPattern = | ||
entity.model.translations.indexes.fromIndexToAccessPattern[ | ||
state.query.index | ||
]; | ||
if ( | ||
options.compare === ComparisonTypes.attributes || | ||
options.compare === ComparisonTypes.v2 | ||
) { | ||
if ( | ||
!entity.model.indexes[accessPattern].sk.isFieldRef && | ||
sk.length > 1 | ||
) { | ||
state.filterProperties(FilterOperationNames.eq, { | ||
...unused, | ||
...composites, | ||
}); | ||
} | ||
} | ||
}); | ||
}) | ||
@@ -209,2 +224,3 @@ .whenOptions(({ options, state }) => { | ||
state.unsafeApplyFilter( | ||
{}, | ||
FilterOperationNames.eq, | ||
@@ -215,2 +231,3 @@ entity.identifiers.entity, | ||
state.unsafeApplyFilter( | ||
{}, | ||
FilterOperationNames.eq, | ||
@@ -331,5 +348,5 @@ entity.identifiers.version, | ||
const { pk, sk } = entity._getPrimaryIndexFieldNames(); | ||
filter.unsafeSet(FilterOperationNames.exists, pk); | ||
filter.unsafeSet({}, FilterOperationNames.exists, pk); | ||
if (sk) { | ||
filter.unsafeSet(FilterOperationNames.exists, sk); | ||
filter.unsafeSet({}, FilterOperationNames.exists, sk); | ||
} | ||
@@ -440,10 +457,11 @@ const pkComposite = entity._expectFacets(facets, attributes.pk); | ||
const { updatedKeys, setAttributes, indexKey, deletedKeys = [] } = entity._getPutKeys( | ||
pk, | ||
sk && sk.facets, | ||
onlySetAppliedData, | ||
); | ||
const { | ||
updatedKeys, | ||
setAttributes, | ||
indexKey, | ||
deletedKeys = [], | ||
} = entity._getPutKeys(pk, sk && sk.facets, onlySetAppliedData); | ||
for (const deletedKey of deletedKeys) { | ||
state.query.update.remove(deletedKey) | ||
state.query.update.remove(deletedKey); | ||
} | ||
@@ -549,5 +567,5 @@ | ||
const { pk, sk } = entity._getPrimaryIndexFieldNames(); | ||
filter.unsafeSet(FilterOperationNames.notExists, pk); | ||
filter.unsafeSet({}, FilterOperationNames.notExists, pk); | ||
if (sk) { | ||
filter.unsafeSet(FilterOperationNames.notExists, sk); | ||
filter.unsafeSet({}, FilterOperationNames.notExists, sk); | ||
} | ||
@@ -580,5 +598,5 @@ return state | ||
const { pk, sk } = entity._getPrimaryIndexFieldNames(); | ||
filter.unsafeSet(FilterOperationNames.exists, pk); | ||
filter.unsafeSet({}, FilterOperationNames.exists, pk); | ||
if (sk) { | ||
filter.unsafeSet(FilterOperationNames.exists, sk); | ||
filter.unsafeSet({}, FilterOperationNames.exists, sk); | ||
} | ||
@@ -934,12 +952,17 @@ const pkComposite = entity._expectFacets(facets, attributes.pk); | ||
state.setSK(state.buildQueryComposites(facets, sk)); | ||
// we must apply eq on filter on all provided because if the user then does a sort key operation, it'd actually then unexpect results | ||
if (sk.length > 1) { | ||
state.filterProperties(FilterOperationNames.eq, { | ||
...unused, | ||
...composites, | ||
}); | ||
} | ||
state.whenOptions(({ options, state }) => { | ||
if ( | ||
options.compare === ComparisonTypes.attributes || | ||
options.compare === ComparisonTypes.v2 | ||
) { | ||
if (sk.length > 1) { | ||
state.filterProperties(FilterOperationNames.eq, { | ||
...unused, | ||
...composites, | ||
}); | ||
} | ||
} | ||
if ( | ||
state.query.options.indexType === IndexTypes.clustered && | ||
@@ -952,2 +975,3 @@ Object.keys(composites).length < sk.length && | ||
.unsafeApplyFilter( | ||
{}, | ||
FilterOperationNames.eq, | ||
@@ -958,2 +982,3 @@ entity.identifiers.entity, | ||
.unsafeApplyFilter( | ||
{}, | ||
FilterOperationNames.eq, | ||
@@ -997,6 +1022,2 @@ entity.identifiers.version, | ||
if (!entity.model.indexes[accessPattern].sk.isFieldRef) { | ||
state.filterProperties(FilterOperationNames.lte, endingSk.composites); | ||
} | ||
return state | ||
@@ -1006,3 +1027,26 @@ .setType(QueryTypes.and) | ||
.setType(QueryTypes.between) | ||
.setSK(startingSk.composites); | ||
.setSK(startingSk.composites) | ||
.beforeBuildParams(({ options, state }) => { | ||
if ( | ||
options.compare === ComparisonTypes.attributes || | ||
options.compare === ComparisonTypes.v2 | ||
) { | ||
if (!entity.model.indexes[accessPattern].sk.isFieldRef) { | ||
state.filterProperties( | ||
FilterOperationNames.lte, | ||
endingSk.composites, | ||
{ asPrefix: true }, | ||
); | ||
} | ||
if (options.compare === ComparisonTypes.attributes) { | ||
if (!entity.model.indexes[accessPattern].sk.isFieldRef) { | ||
state.filterProperties( | ||
FilterOperationNames.gte, | ||
startingSk.composites, | ||
{ asPrefix: true }, | ||
); | ||
} | ||
} | ||
} | ||
}); | ||
} catch (err) { | ||
@@ -1048,10 +1092,19 @@ state.setError(err); | ||
state.setSK(composites); | ||
const accessPattern = | ||
entity.model.translations.indexes.fromIndexToAccessPattern[ | ||
state.query.index | ||
]; | ||
state.beforeBuildParams(({ options, state }) => { | ||
if ( | ||
options.compare === ComparisonTypes.attributes || | ||
options.compare === ComparisonTypes.v2 | ||
) { | ||
const accessPattern = | ||
entity.model.translations.indexes.fromIndexToAccessPattern[ | ||
state.query.index | ||
]; | ||
if (!entity.model.indexes[accessPattern].sk.isFieldRef) { | ||
state.filterProperties(FilterOperationNames.gt, composites); | ||
} | ||
if (!entity.model.indexes[accessPattern].sk.isFieldRef) { | ||
state.filterProperties(FilterOperationNames.gt, composites, { | ||
asPrefix: true, | ||
}); | ||
} | ||
} | ||
}); | ||
}); | ||
@@ -1075,2 +1128,23 @@ } catch (err) { | ||
state.setSK(state.buildQueryComposites(facets, attributes.sk)); | ||
state.beforeBuildParams(({ options, state }) => { | ||
const { composites } = state.identifyCompositeAttributes( | ||
facets, | ||
attributes.sk, | ||
attributes.pk, | ||
); | ||
if (options.compare === ComparisonTypes.attributes) { | ||
const accessPattern = | ||
entity.model.translations.indexes.fromIndexToAccessPattern[ | ||
state.query.index | ||
]; | ||
if ( | ||
!entity.model.indexes[accessPattern].sk.isFieldRef && | ||
attributes.sk.length > 1 | ||
) { | ||
state.filterProperties(FilterOperationNames.gte, composites, { | ||
asPrefix: true, | ||
}); | ||
} | ||
} | ||
}); | ||
}); | ||
@@ -1099,2 +1173,15 @@ } catch (err) { | ||
state.setSK(composites); | ||
state.beforeBuildParams(({ options, state }) => { | ||
if (options.compare === ComparisonTypes.attributes) { | ||
const accessPattern = | ||
entity.model.translations.indexes.fromIndexToAccessPattern[ | ||
state.query.index | ||
]; | ||
if (!entity.model.indexes[accessPattern].sk.isFieldRef) { | ||
state.filterProperties(FilterOperationNames.lt, composites, { | ||
asPrefix: true, | ||
}); | ||
} | ||
} | ||
}); | ||
}); | ||
@@ -1123,9 +1210,19 @@ } catch (err) { | ||
state.setSK(composites); | ||
const accessPattern = | ||
entity.model.translations.indexes.fromIndexToAccessPattern[ | ||
state.query.index | ||
]; | ||
if (!entity.model.indexes[accessPattern].sk.isFieldRef) { | ||
state.filterProperties(FilterOperationNames.lte, composites); | ||
} | ||
state.beforeBuildParams(({ options, state }) => { | ||
if ( | ||
options.compare === ComparisonTypes.attributes || | ||
options.compare === ComparisonTypes.v2 | ||
) { | ||
const accessPattern = | ||
entity.model.translations.indexes.fromIndexToAccessPattern[ | ||
state.query.index | ||
]; | ||
if (!entity.model.indexes[accessPattern].sk.isFieldRef) { | ||
state.filterProperties(FilterOperationNames.lte, composites, { | ||
asPrefix: true, | ||
}); | ||
} | ||
} | ||
}); | ||
}); | ||
@@ -1450,10 +1547,16 @@ } catch (err) { | ||
applyFilter(operation, name, ...values) { | ||
applyFilter(operation, name, values, filterOptions) { | ||
if ( | ||
(FilterOperationNames[operation] !== undefined) & (name !== undefined) && | ||
values.length > 0 | ||
FilterOperationNames[operation] !== undefined && | ||
name !== undefined && | ||
values !== undefined | ||
) { | ||
const attribute = this.attributes[name]; | ||
if (attribute !== undefined) { | ||
this.unsafeApplyFilter(operation, attribute.field, ...values); | ||
this.unsafeApplyFilter( | ||
filterOptions, | ||
operation, | ||
attribute.field, | ||
values, | ||
); | ||
} | ||
@@ -1473,3 +1576,3 @@ } | ||
const filter = this.query.filter[ExpressionTypes.ConditionExpression]; | ||
filter.unsafeSet(operation, attribute.field, ...values); | ||
filter.unsafeSet({}, operation, attribute.field, ...values); | ||
} | ||
@@ -1480,9 +1583,9 @@ } | ||
unsafeApplyFilter(operation, name, ...values) { | ||
unsafeApplyFilter(filterOptions = {}, operation, name, values) { | ||
if ( | ||
(FilterOperationNames[operation] !== undefined) & (name !== undefined) && | ||
values.length > 0 | ||
values !== undefined | ||
) { | ||
const filter = this.query.filter[ExpressionTypes.FilterExpression]; | ||
filter.unsafeSet(operation, name, ...values); | ||
filter.unsafeSet(filterOptions, operation, name, values); | ||
} | ||
@@ -1492,7 +1595,7 @@ return this; | ||
filterProperties(operation, obj = {}) { | ||
filterProperties(operation, obj = {}, filterOptions = {}) { | ||
for (const property in obj) { | ||
const value = obj[property]; | ||
if (value !== undefined) { | ||
this.applyFilter(operation, property, value); | ||
this.applyFilter(operation, property, value, filterOptions); | ||
} | ||
@@ -1575,4 +1678,7 @@ } | ||
} | ||
return this; | ||
} | ||
// these are ran before "beforeBuildParams" | ||
applyWithOptions(options = {}) { | ||
@@ -1588,2 +1694,3 @@ this.applyAfterOptions.forEach((fn) => fn(options)); | ||
} | ||
return this; | ||
} | ||
@@ -1590,0 +1697,0 @@ |
@@ -1,3 +0,3 @@ | ||
const lib = require('@aws-sdk/lib-dynamodb') | ||
const util = require('@aws-sdk/util-dynamodb') | ||
const lib = require("@aws-sdk/lib-dynamodb"); | ||
const util = require("@aws-sdk/util-dynamodb"); | ||
const { isFunction } = require("./validations"); | ||
@@ -14,8 +14,8 @@ const { ElectroError, ErrorCodes } = require("./errors"); | ||
value.Item = unmarshall(value.Item); | ||
} catch(err) { | ||
console.error('Internal Error: Failed to unmarshal input', err); | ||
} catch (err) { | ||
console.error("Internal Error: Failed to unmarshal input", err); | ||
} | ||
return value; | ||
} | ||
}; | ||
@@ -22,0 +22,0 @@ const v3Methods = ["send"]; |
@@ -222,4 +222,4 @@ // # Errors: | ||
code: 2012, | ||
section: 'invalid-index-composite-attributes-provided', | ||
name: 'IncompleteIndexCompositesAttributesProvided', | ||
section: "invalid-index-composite-attributes-provided", | ||
name: "IncompleteIndexCompositesAttributesProvided", | ||
sym: ErrorCode, | ||
@@ -226,0 +226,0 @@ }, |
@@ -316,8 +316,11 @@ const { | ||
const attribute = target.getChild(prop); | ||
const nestedAny = attribute.type === AttributeTypes.any && | ||
// if the name doesn't match that's because we are nested under 'any' | ||
attribute.name !== prop; | ||
const nestedAny = | ||
attribute.type === AttributeTypes.any && | ||
// if the name doesn't match that's because we are nested under 'any' | ||
attribute.name !== prop; | ||
let field; | ||
if (attribute === undefined) { | ||
throw new Error(`Invalid attribute "${prop}" at path "${target.path}.${prop}"`); | ||
throw new Error( | ||
`Invalid attribute "${prop}" at path "${target.path}.${prop}"`, | ||
); | ||
} else if (nestedAny) { | ||
@@ -324,0 +327,0 @@ field = prop; |
@@ -11,2 +11,3 @@ const { | ||
ItemOperations, | ||
DataOptions, | ||
} = require("./types"); | ||
@@ -470,22 +471,14 @@ const AttributeTypeNames = Object.keys(AttributeTypes); | ||
try { | ||
let reason = definition(val); | ||
const isValid = !reason; | ||
if (isValid) { | ||
return [isValid, []]; | ||
} else if (typeof reason === "boolean") { | ||
return [ | ||
isValid, | ||
[ | ||
new e.ElectroUserValidationError( | ||
this.path, | ||
"Invalid value provided", | ||
), | ||
], | ||
]; | ||
} else { | ||
return [ | ||
isValid, | ||
[new e.ElectroUserValidationError(this.path, reason)], | ||
]; | ||
} | ||
let isValid = !!definition(val); | ||
return [ | ||
isValid, | ||
isValid | ||
? [] | ||
: [ | ||
new e.ElectroUserValidationError( | ||
this.path, | ||
"Invalid value provided", | ||
), | ||
], | ||
]; | ||
} catch (err) { | ||
@@ -1692,3 +1685,2 @@ return [false, [new e.ElectroUserValidationError(this.path, err)]]; | ||
translateFromFields(item = {}, options = {}) { | ||
let { includeKeys } = options; | ||
let data = {}; | ||
@@ -1700,3 +1692,3 @@ let names = this.translationForRetrieval; | ||
data[name] = value; | ||
} else if (includeKeys) { | ||
} else if (options.data === DataOptions.includeKeys) { | ||
data[attr] = value; | ||
@@ -1703,0 +1695,0 @@ } |
@@ -12,3 +12,2 @@ const { | ||
ServiceVersions, | ||
Pager, | ||
ElectroInstance, | ||
@@ -18,2 +17,3 @@ ElectroInstanceTypes, | ||
IndexTypes, | ||
DataOptions, | ||
} = require("./types"); | ||
@@ -350,3 +350,3 @@ const { FilterFactory } = require("./filters"); | ||
cleanseRetrievedData(index = TableIndex, entities, data = {}, config = {}) { | ||
if (config.raw) { | ||
if (config.data === DataOptions.raw) { | ||
return data; | ||
@@ -468,3 +468,3 @@ } | ||
parse: (options, data) => { | ||
if (options.raw) { | ||
if (options.data === DataOptions.raw) { | ||
return data; | ||
@@ -641,7 +641,7 @@ } | ||
collectionDifferences.push( | ||
`The index scope value provided "${ | ||
providedIndex.scope || "undefined" | ||
}" does not match established index scope value "${ | ||
definition.scope || "undefined" | ||
}" on index "${providedIndexName}". Index scope options must match across all entities participating in a collection`, | ||
`The index scope value provided "${ | ||
providedIndex.scope || "undefined" | ||
}" does not match established index scope value "${ | ||
definition.scope || "undefined" | ||
}" on index "${providedIndexName}". Index scope options must match across all entities participating in a collection`, | ||
); | ||
@@ -648,0 +648,0 @@ } |
@@ -1,2 +0,2 @@ | ||
const { TableIndex, TransactionMethods } = require("./types"); | ||
const { TableIndex, TransactionMethods, DataOptions } = require("./types"); | ||
const { getEntityIdentifiers, matchToEntityAlias } = require("./entity"); | ||
@@ -10,3 +10,3 @@ | ||
) { | ||
if (config.raw) { | ||
if (config.data === DataOptions.raw) { | ||
return data; | ||
@@ -56,3 +56,3 @@ } | ||
) { | ||
if (config.raw) { | ||
if (config.data === DataOptions.raw) { | ||
return data; | ||
@@ -144,3 +144,3 @@ } | ||
parse: (options, data) => { | ||
if (options.raw) { | ||
if (options.data === DataOptions.raw) { | ||
return data; | ||
@@ -147,0 +147,0 @@ } else if (data.canceled) { |
@@ -6,2 +6,8 @@ const KeyTypes = { | ||
const DataOptions = { | ||
raw: "raw", | ||
includeKeys: "includeKeys", | ||
attributes: "attributes", | ||
}; | ||
const BatchWriteTypes = { | ||
@@ -12,2 +18,8 @@ batch: "batch", | ||
const ComparisonTypes = { | ||
keys: "keys", | ||
attributes: "attributes", | ||
v2: "v2", | ||
}; | ||
const QueryTypes = { | ||
@@ -91,3 +103,3 @@ and: "and", | ||
const PartialComparisons = { | ||
const KeyAttributesComparisons = { | ||
lt: "<", | ||
@@ -338,2 +350,3 @@ gte: ">=", | ||
MethodTypes, | ||
DataOptions, | ||
Comparisons, | ||
@@ -348,2 +361,3 @@ BuilderTypes, | ||
CastKeyOptions, | ||
ComparisonTypes, | ||
ServiceVersions, | ||
@@ -356,3 +370,2 @@ ExpressionTypes, | ||
TerminalOperation, | ||
PartialComparisons, | ||
FormatToReturnValues, | ||
@@ -364,2 +377,3 @@ AttributeProxySymbol, | ||
DynamoDBAttributeTypes, | ||
KeyAttributesComparisons, | ||
AttributeMutationMethods, | ||
@@ -373,2 +387,3 @@ AllPages, | ||
UpsertOperations, | ||
BatchWriteTypes, | ||
}; |
@@ -125,3 +125,3 @@ const e = require("./errors"); | ||
required: false, | ||
} | ||
}, | ||
}, | ||
@@ -182,3 +182,3 @@ }, | ||
format: "isFunction", | ||
} | ||
}, | ||
}, | ||
@@ -185,0 +185,0 @@ }; |
@@ -30,3 +30,4 @@ const { MethodTypes, ExpressionTypes, BuilderTypes } = require("./types"); | ||
add(newExpression) { | ||
add(newExpression, filterOptions = {}) { | ||
const asPrefix = !!filterOptions.asPrefix; | ||
let expression = ""; | ||
@@ -43,9 +44,15 @@ let existingExpression = this.expression; | ||
} | ||
let existingNeedsParens = | ||
if ( | ||
!asPrefix && | ||
!existingExpression.startsWith("(") && | ||
!existingExpression.endsWith(")"); | ||
if (existingNeedsParens) { | ||
!existingExpression.endsWith(")") | ||
) { | ||
existingExpression = `(${existingExpression})`; | ||
} | ||
expression = `${existingExpression} AND ${newExpression}`; | ||
if (asPrefix) { | ||
expression = `(${newExpression}) AND ${existingExpression}`; | ||
} else { | ||
expression = `${existingExpression} AND ${newExpression}`; | ||
} | ||
} else { | ||
@@ -58,3 +65,3 @@ expression = this._trim(newExpression); | ||
// applies operations without verifying them against known attributes. Used internally for key conditions. | ||
unsafeSet(operation, name, ...values) { | ||
unsafeSet(filterOptions, operation, name, ...values) { | ||
const { template } = FilterOperations[operation] || {}; | ||
@@ -74,3 +81,3 @@ if (template === undefined) { | ||
); | ||
this.add(condition); | ||
this.add(condition, filterOptions); | ||
} | ||
@@ -77,0 +84,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
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
17387
118
549997