Skip to content

Commit

Permalink
Merge 721c74a into e116df6
Browse files Browse the repository at this point in the history
  • Loading branch information
fishcharlie committed Dec 19, 2020
2 parents e116df6 + 721c74a commit a024a3e
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 14 deletions.
10 changes: 6 additions & 4 deletions lib/Document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,13 +408,15 @@ Document.objectFromSchema = async function (object: any, model: Model<Document>,
"type": typeDetails
};
} catch (e) {} // eslint-disable-line no-empty
}).filter((item: any) => {
return Array.isArray(item.type) ? item.type.some((type) => type.name === "Combine") : item.type.name === "Combine";
}).map((obj: {"key": string; "type": DynamoDBTypeResult | DynamoDBSetTypeResult | DynamoDBTypeResult[] | DynamoDBSetTypeResult[]} | undefined): {"key": string; "type": DynamoDBTypeResult | DynamoDBSetTypeResult} => {
if (obj && Array.isArray(obj.type)) {
throw new Error.InvalidParameter("Combine type is not allowed to be used with multiple types.");
}

return obj as any;
}).filter((item) => item.type.name === "Combine").forEach((item) => {
}).forEach((item) => {
const {key, type} = item;

const value = type.typeSettings.attributes.map((attribute) => utils.object.get(returnObject, attribute)).filter((value) => typeof value !== "undefined" && value !== null).join(type.typeSettings.seperator);
Expand All @@ -425,7 +427,7 @@ Document.objectFromSchema = async function (object: any, model: Model<Document>,
await Promise.all(settings.modifiers.map(async (modifier) => {
return Promise.all((await Document.attributesWithSchema(returnObject, model)).map(async (key) => {
const value = utils.object.get(returnObject, key);
const modifierFunction = await schema.getAttributeSettingValue(modifier, key, {"returnFunction": true});
const modifierFunction = await schema.getAttributeSettingValue(modifier, key, {"returnFunction": true, typeIndexOptionMap});
const modifierFunctionExists: boolean = Array.isArray(modifierFunction) ? modifierFunction.some((val) => Boolean(val)) : Boolean(modifierFunction);
const isValueUndefined = typeof value === "undefined" || value === null;
if (modifierFunctionExists && !isValueUndefined) {
Expand All @@ -440,7 +442,7 @@ Document.objectFromSchema = async function (object: any, model: Model<Document>,
const value = utils.object.get(returnObject, key);
const isValueUndefined = typeof value === "undefined" || value === null;
if (!isValueUndefined) {
const validator = await schema.getAttributeSettingValue("validate", key, {"returnFunction": true});
const validator = await schema.getAttributeSettingValue("validate", key, {"returnFunction": true, typeIndexOptionMap});
if (validator) {
let result;
if (validator instanceof RegExp) {
Expand Down Expand Up @@ -486,7 +488,7 @@ Document.objectFromSchema = async function (object: any, model: Model<Document>,
const value = utils.object.get(returnObject, key);
const isValueUndefined = typeof value === "undefined" || value === null;
if (!isValueUndefined) {
const enumArray = await schema.getAttributeSettingValue("enum", key);
const enumArray = await schema.getAttributeSettingValue("enum", key, {"returnFunction": false, typeIndexOptionMap});
if (enumArray && !enumArray.includes(value)) {
throw new Error.ValidationError(`${key} must equal ${JSON.stringify(enumArray)}, but is set to ${value}`);
}
Expand Down
10 changes: 6 additions & 4 deletions lib/Model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -798,15 +798,17 @@ export class Model<T extends DocumentCarrier = AnyDocument> {
return obj;
})()));

schema.attributes().map((attribute) => {
const type = schema.getAttributeTypeDetails(attribute);
schema.attributes().map((attribute) => ({attribute, "type": schema.getAttributeTypeDetails(attribute)})).filter((item: any) => {
return Array.isArray(item.type) ? item.type.some((type) => type.name === "Combine") : item.type.name === "Combine";
}).map((details) => {
const {type} = details;

if (Array.isArray(type)) {
throw new CustomError.InvalidParameter("Combine type is not allowed to be used with multiple types.");
}

return {attribute, type};
}).filter((details) => details.type.name === "Combine").forEach((details) => {
return details;
}).forEach((details: any) => {
const {invalidAttributes} = details.type.typeSettings.attributes.reduce((result, attribute) => {
const expressionAttributeNameEntry = Object.entries(returnObject.ExpressionAttributeNames).find((entry) => entry[1] === attribute);
const doesExist = Boolean(expressionAttributeNameEntry);
Expand Down
31 changes: 25 additions & 6 deletions lib/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ interface SchemaGetAttributeTypeSettings {
}
interface SchemaGetAttributeSettingValue {
returnFunction: boolean;
typeIndexOptionMap?: any;
}

export class Schema {
Expand Down Expand Up @@ -354,7 +355,16 @@ export class Schema {
async defaultCheck (key: string, value: ValueType, settings: any): Promise<ValueType | void> {
const isValueUndefined = typeof value === "undefined" || value === null;
if (settings.defaults && isValueUndefined || settings.forceDefault && await this.getAttributeSettingValue("forceDefault", key)) {
const defaultValue = await this.getAttributeSettingValue("default", key);
const defaultValueRaw = await this.getAttributeSettingValue("default", key);

let hasMultipleTypes;
try {
hasMultipleTypes = Array.isArray(this.getAttributeType(key));
} catch (e) {
hasMultipleTypes = false;
}

const defaultValue = Array.isArray(defaultValueRaw) && hasMultipleTypes ? defaultValueRaw[0] : defaultValueRaw;
const isDefaultValueUndefined = typeof defaultValue === "undefined" || defaultValue === null;
if (!isDefaultValueUndefined) {
return defaultValue;
Expand All @@ -367,7 +377,7 @@ export class Schema {
const defaultPropertyValue = (attributeValue || {})[setting];
return typeof defaultPropertyValue === "function" && !settings.returnFunction ? defaultPropertyValue() : defaultPropertyValue;
}
const attributeValue = this.getAttributeValue(key);
const attributeValue = this.getAttributeValue(key, {"typeIndexOptionMap": settings.typeIndexOptionMap});
if (Array.isArray(attributeValue)) {
return attributeValue.map(func);
} else {
Expand Down Expand Up @@ -602,7 +612,7 @@ Schema.prototype.getRangeKey = function (this: Schema): string | void {
// This function will take in an attribute and value, and throw an error if the property is required and the value is undefined or null.
Schema.prototype.requiredCheck = async function (this: Schema, key: string, value: ValueType): Promise<void> {
const isRequired = await this.getAttributeSettingValue("required", key);
if ((typeof value === "undefined" || value === null) && isRequired) {
if ((typeof value === "undefined" || value === null) && (Array.isArray(isRequired) ? isRequired.some((val) => Boolean(val)) : isRequired)) {
throw new CustomError.ValidationError(`${key} is a required property but has no value when trying to save document`);
}
};
Expand All @@ -614,7 +624,7 @@ Schema.prototype.getIndexAttributes = async function (this: Schema): Promise<{in
attribute
}))
))
.filter((obj) => obj.index)
.filter((obj) => Array.isArray(obj.index) ? obj.index.some((index) => Boolean(index)) : obj.index)
.reduce((accumulator, currentValue) => {
if (Array.isArray(currentValue.index)) {
currentValue.index.forEach((currentIndex) => {
Expand Down Expand Up @@ -722,7 +732,7 @@ Schema.prototype.attributes = function (this: Schema, object?: ObjectType): stri

Schema.prototype.getAttributeValue = function (this: Schema, key: string, settings?: {standardKey?: boolean; typeIndexOptionMap?: {}}): AttributeDefinition {
const previousKeyParts = [];
return (settings?.standardKey ? key : key.replace(/\.\d+/gu, ".0")).split(".").reduce((result, part) => {
let result = (settings?.standardKey ? key : key.replace(/\.\d+/gu, ".0")).split(".").reduce((result, part) => {
if (Array.isArray(result)) {
const predefinedIndex = settings && settings.typeIndexOptionMap && settings.typeIndexOptionMap[previousKeyParts.join(".")];
if (predefinedIndex !== undefined) {
Expand All @@ -734,6 +744,15 @@ Schema.prototype.getAttributeValue = function (this: Schema, key: string, settin
previousKeyParts.push(part);
return utils.object.get(result.schema, part);
}, {"schema": this.schemaObject} as any);

if (Array.isArray(result)) {
const predefinedIndex = settings && settings.typeIndexOptionMap && settings.typeIndexOptionMap[previousKeyParts.join(".")];
if (predefinedIndex !== undefined) {
result = result[predefinedIndex];
}
}

return result;
};

function retrieveTypeInfo (type: string, isSet: boolean, key: string, typeSettings: AttributeDefinitionTypeSettings): DynamoDBTypeResult | DynamoDBSetTypeResult {
Expand All @@ -754,7 +773,7 @@ Schema.prototype.getAttributeTypeDetails = function (this: Schema, key: string,
if (typeof val === "undefined") {
throw new CustomError.UnknownAttribute(`Invalid Attribute: ${key}`);
}
let typeVal = typeof val === "object" && !Array.isArray(val) ? val.type : val;
let typeVal = typeof val === "object" && !Array.isArray(val) && val.type ? val.type : val;
let typeSettings: AttributeDefinitionTypeSettings = {};
if (typeof typeVal === "object" && !Array.isArray(typeVal)) {
typeSettings = (typeVal as {value: DateConstructor; settings?: AttributeDefinitionTypeSettings}).settings || {};
Expand Down
10 changes: 10 additions & 0 deletions test/unit/Document.js
Original file line number Diff line number Diff line change
Expand Up @@ -2453,6 +2453,16 @@ describe("Document", () => {
"input": [{"id": 1, "data1": "hello"}, {"type": "toDynamo"}],
"output": {"id": 1, "data1": "hello"}
},
{
"input": [{"id": 1, "data": 2}, {"type": "fromDynamo", "combine": true}],
"schema": {"id": Number, "data": [Number, String]},
"output": {"id": 1, "data": 2}
},
{
"input": [{"id": 1}, {"type": "fromDynamo", "required": true}],
"schema": {"id": Number, "data": [Number, String]},
"output": {"id": 1}
},
{
"schema": {"id": Number, "other": [{"type": "Combine"}, String]},
"input": [{"id": 1}, {"type": "toDynamo", "combine": true}],
Expand Down
26 changes: 26 additions & 0 deletions test/unit/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -3565,6 +3565,32 @@ describe("Model", () => {
return expect(callType.func(User).bind(User)({"id": 1}, {"data1": "Charlie"})).to.be.rejectedWith("You must update all or none of the combine attributes when running Model.update. Missing combine attributes: data2.");
});

it("Shouldn't throw error if update with property allowing multiple types", async () => {
updateItemFunction = () => Promise.resolve({});
User = dynamoose.model("User", {"id": Number, "data": [String, Number]});

await callType.func(User).bind(User)({"id": 1}, {"data": "Bob"});
expect(updateItemParams).to.be.an("object");
expect(updateItemParams).to.eql({
"ExpressionAttributeNames": {
"#a0": "data"
},
"ExpressionAttributeValues": {
":v0": {
"S": "Bob"
}
},
"UpdateExpression": "SET #a0 = :v0",
"Key": {
"id": {
"N": "1"
}
},
"TableName": "User",
"ReturnValues": "ALL_NEW"
});
});

it("Should throw error if using multiple types with combine type", () => {
updateItemFunction = () => Promise.resolve({});
User = dynamoose.model("User", {"id": Number, "data1": String, "data2": String, "combine": ["Combine", "String"]});
Expand Down
5 changes: 5 additions & 0 deletions test/unit/Schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,11 @@ describe("Schema", () => {
"name": "Should aggregate an array containing multiple definitions for all defined indexes",
"schema": {"id": {"type": String, "index": [{"global": true, "name": "id-index-1"}, {"global": false, "name": "id-index-2"}]}, "uid": {"type": String, "index": {"global": true, "name": "uid-index"}}, "uuid": {"type": String}},
"output": [{"attribute": "id", "index": {"global": true, "name": "id-index-1"}}, {"attribute": "id", "index": {"global": false, "name": "id-index-2"}}, {"attribute": "uid", "index": {"global": true, "name": "uid-index"}}]
},
{
"name": "Should work with multiple types for single attribute",
"schema": {"id": String, "data": [String, Number]},
"output": []
}
];

Expand Down

0 comments on commit a024a3e

Please sign in to comment.