electrodb
Advanced tools
Comparing version 2.3.5 to 2.4.0
const { Entity } = require("./src/entity"); | ||
const { Service } = require("./src/service"); | ||
const { createCustomAttribute, CustomAttributeType } = require('./src/schema'); | ||
const { createCustomAttribute, CustomAttributeType, createSchema } = require('./src/schema'); | ||
const { ElectroError, ElectroValidationError, ElectroUserValidationError, ElectroAttributeValidationError } = require('./src/errors'); | ||
@@ -10,2 +10,3 @@ | ||
ElectroError, | ||
createSchema, | ||
CustomAttributeType, | ||
@@ -12,0 +13,0 @@ createCustomAttribute, |
{ | ||
"name": "electrodb", | ||
"version": "2.3.5", | ||
"version": "2.4.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", |
@@ -1,2 +0,2 @@ | ||
const {AttributeTypes, ItemOperations, AttributeProxySymbol, BuilderTypes} = require("./types"); | ||
const {AttributeTypes, ItemOperations, AttributeProxySymbol, BuilderTypes, DynamoDBAttributeTypes} = require("./types"); | ||
const e = require("./errors"); | ||
@@ -162,4 +162,22 @@ const u = require("./util"); | ||
const FilterOperations = { | ||
escape: { | ||
template: function escape(options, attr) { | ||
return `${attr}`; | ||
}, | ||
noAttribute: true, | ||
}, | ||
size: { | ||
template: function size(options, attr, name) { | ||
return `size(${name})` | ||
}, | ||
strict: false, | ||
}, | ||
type: { | ||
template: function attributeType(options, attr, name, value) { | ||
return `attribute_type(${name}, ${value})`; | ||
}, | ||
strict: false | ||
}, | ||
ne: { | ||
template: function eq(options, attr, name, value) { | ||
template: function ne(options, attr, name, value) { | ||
return `${name} <> ${value}`; | ||
@@ -383,5 +401,5 @@ }, | ||
let ops = {}; | ||
let seen = new Set(); | ||
let seen = new Map(); | ||
for (let operation of Object.keys(operations)) { | ||
let {template, canNest} = operations[operation]; | ||
let {template, canNest, noAttribute} = operations[operation]; | ||
Object.defineProperty(ops, operation, { | ||
@@ -393,18 +411,48 @@ get: () => { | ||
} | ||
if (property.__is_clause__ === AttributeProxySymbol) { | ||
const {paths, root, target} = property(); | ||
if (property[AttributeProxySymbol]) { | ||
const {commit, target} = property(); | ||
const fixedValues = values.map((value) => target.applyFixings(value)) | ||
.filter(value => value !== undefined); | ||
const isFilterBuilder = builder.type === BuilderTypes.filter; | ||
const takesValueArgument = template.length > 3; | ||
const isAcceptableValue = fixedValues.every(value => { | ||
const seenAttributes = seen.get(value); | ||
if (seenAttributes) { | ||
return seenAttributes.every(v => target.acceptable(v)) | ||
} | ||
return target.acceptable(value); | ||
}); | ||
const shouldCommit = | ||
// if it is a filterBuilder than we don't care what they pass because the user needs more freedom here | ||
isFilterBuilder || | ||
// if the operation does not take a value argument then not committing here could cause problems. | ||
// this should be revisited to make more robust, we could hypothetically store the commit in the | ||
// "seen" map for when the value is used, but that's a lot of new complexity | ||
!takesValueArgument || | ||
// if the operation takes a value, we should determine if that value is acceptable. For | ||
// example, in the cases of a "set" we check to see if it is empty, or if the value is | ||
// undefined, we should not commit. The "fixedValues" length check is because the | ||
// "fixedValues" array has been filtered for undefined, so no length there indicates an | ||
// undefined value was passed. | ||
(takesValueArgument && isAcceptableValue && fixedValues.length > 0); | ||
if (!shouldCommit) { | ||
return ''; | ||
} | ||
const paths = commit(); | ||
const attributeValues = []; | ||
let hasNestedValue = false; | ||
for (let value of values) { | ||
value = target.applyFixings(value); | ||
// template.length is to see if function takes value argument | ||
if (template.length > 3) { | ||
if (seen.has(value)) { | ||
attributeValues.push(value); | ||
hasNestedValue = true; | ||
} else { | ||
let attributeValueName = builder.setValue(target.name, value); | ||
builder.setPath(paths.json, {value, name: attributeValueName}); | ||
attributeValues.push(attributeValueName); | ||
} | ||
for (let fixedValue of fixedValues) { | ||
if (seen.has(fixedValue)) { | ||
attributeValues.push(fixedValue); | ||
hasNestedValue = true; | ||
} else { | ||
let attributeValueName = builder.setValue(target.name, fixedValue); | ||
builder.setPath(paths.json, { | ||
value: fixedValue, | ||
name: attributeValueName | ||
}); | ||
attributeValues.push(attributeValueName); | ||
} | ||
@@ -420,4 +468,4 @@ } | ||
if (canNest) { | ||
seen.add(paths.expression); | ||
seen.add(formatted); | ||
seen.set(paths.expression, attributeValues); | ||
seen.set(formatted, attributeValues); | ||
} | ||
@@ -431,2 +479,13 @@ | ||
return formatted; | ||
} else if (noAttribute) { | ||
// const {json, expression} = builder.setName({}, property, property); | ||
let attributeValueName = builder.setValue(property, property); | ||
builder.setPath(property, { | ||
value: property, | ||
name: attributeValueName, | ||
}); | ||
const formatted = template({}, attributeValueName); | ||
seen.set(attributeValueName, [property]); | ||
seen.set(formatted, [property]); | ||
return formatted; | ||
} else { | ||
@@ -445,11 +504,11 @@ throw new e.ElectroError(e.ErrorCodes.InvalidWhere, `Invalid Attribute in where clause passed to operation '${operation}'. Use injected attributes only.`); | ||
get: (_, prop, o) => { | ||
if (prop === "__is_clause__") { | ||
return AttributeProxySymbol; | ||
if (prop === AttributeProxySymbol) { | ||
return true; | ||
} else { | ||
return AttributeOperationProxy.pathProxy(() => { | ||
const { paths, root, target, builder } = build(); | ||
const { commit, root, target, builder } = build(); | ||
const attribute = target.getChild(prop); | ||
let field; | ||
if (attribute === undefined) { | ||
throw new Error(`Invalid attribute "${prop}" at path "${paths.json}".`); | ||
throw new Error(`Invalid attribute "${prop}" at path "${target.path}.${prop}"`); | ||
} else if (attribute === root && attribute.type === AttributeTypes.any) { | ||
@@ -466,3 +525,6 @@ // This function is only called if a nested property is called. If this attribute is ultimately the root, don't use the root's field name | ||
target: attribute, | ||
paths: builder.setName(paths, prop, field), | ||
commit: () => { | ||
const paths = commit(); | ||
return builder.setName(paths, prop, field); | ||
}, | ||
} | ||
@@ -481,8 +543,7 @@ }); | ||
return AttributeOperationProxy.pathProxy(() => { | ||
const paths = builder.setName({}, attribute.name, attribute.field); | ||
return { | ||
paths, | ||
root: attribute, | ||
target: attribute, | ||
builder, | ||
commit: () => builder.setName({}, attribute.name, attribute.field) | ||
} | ||
@@ -489,0 +550,0 @@ }); |
@@ -241,3 +241,7 @@ const { CastTypes, ValueTypes, KeyCasing, AttributeTypes, AttributeMutationMethods, AttributeWildCard, PathTypes, TableIndex, ItemOperations } = require("./types"); | ||
return (value) => { | ||
if ([AttributeTypes.string, AttributeTypes.enum].includes(this.type) && value !== undefined) { | ||
if (value === undefined) { | ||
return; | ||
} | ||
if ([AttributeTypes.string, AttributeTypes.enum].includes(this.type)) { | ||
value = `${prefix}${value}${postfix}`; | ||
@@ -309,2 +313,6 @@ } | ||
acceptable(val) { | ||
return val !== undefined; | ||
} | ||
getPathType(type, parentType) { | ||
@@ -881,3 +889,3 @@ if (parentType === AttributeTypes.list || parentType === AttributeTypes.set) { | ||
: value; | ||
return this.client.createSet(value, {validate: true}); | ||
return this.client.createSet(value, { validate: true }); | ||
} else { | ||
@@ -888,2 +896,8 @@ return new DynamoDBSet(value, this.items.type); | ||
acceptable(val) { | ||
return Array.isArray(val) | ||
? val.length > 0 | ||
: this.items.acceptable(val); | ||
} | ||
toDDBSet(value) { | ||
@@ -1481,9 +1495,14 @@ const valueType = getValueType(value); | ||
function createSchema(schema) { | ||
return v.model(schema); | ||
} | ||
module.exports = { | ||
Schema, | ||
Attribute, | ||
CastTypes, | ||
SetAttribute, | ||
CastTypes, | ||
createSchema, | ||
CustomAttributeType, | ||
createCustomAttribute, | ||
}; |
@@ -274,2 +274,19 @@ const KeyTypes = { | ||
const DynamoDBAttributeTypes = Object.entries({ | ||
string: 'S', | ||
stringSet: 'SS', | ||
number: 'N', | ||
numberSet: 'NS', | ||
binary: 'B', | ||
binarySet: 'BS', | ||
boolean: 'BOOL', | ||
null: 'NULL', | ||
list: 'L', | ||
map: 'M', | ||
}).reduce((obj, [name, type]) => { | ||
obj[name] = type; | ||
obj[type] = type; | ||
return obj; | ||
}, {}); | ||
module.exports = { | ||
@@ -307,2 +324,3 @@ Pager, | ||
EventSubscriptionTypes, | ||
DynamoDBAttributeTypes, | ||
AttributeMutationMethods, | ||
@@ -309,0 +327,0 @@ AllPages, |
Sorry, the diff of this file is too big to display
399837
10255