type-mongodb
Advanced tools
Comparing version 1.0.0-beta.8 to 1.0.0-beta.9
@@ -16,2 +16,3 @@ import 'reflect-metadata'; | ||
extensions?: Record<any, any>; | ||
create?: boolean; | ||
} | ||
@@ -18,0 +19,0 @@ export declare function Field(options?: FieldOptions): PropertyDecorator; |
@@ -24,3 +24,3 @@ "use strict"; | ||
} | ||
addFieldDefinition(field, Object.assign(Object.assign({}, options), { DocumentClass: target.constructor, type: reflection_1.fieldToType(target, field, options.type), propertyName: field, fieldName: options.name || field, isEmbedded: typeof embedded !== 'undefined', embedded })); | ||
addFieldDefinition(field, Object.assign(Object.assign({}, options), { DocumentClass: target.constructor, type: reflection_1.fieldToType(target, field, options.type), propertyName: field, fieldName: options.name || field, isEmbedded: typeof embedded !== 'undefined', embedded, create: options.create })); | ||
}; | ||
@@ -27,0 +27,0 @@ } |
@@ -23,5 +23,5 @@ import { DocumentClass, Newable } from '..'; | ||
}, parent?: any): T; | ||
fromDB(doc: Partial<T> | { | ||
fromDB(doc?: Partial<T> | { | ||
[key: string]: any; | ||
}, parent?: any): T; | ||
}, parent?: any): T | void; | ||
toDB(model: Partial<T> | { | ||
@@ -28,0 +28,0 @@ [key: string]: any; |
@@ -42,2 +42,3 @@ "use strict"; | ||
this.assertIsCompiled(); | ||
props = props || {}; | ||
if (this.meta.discriminator) { | ||
@@ -73,2 +74,6 @@ const { propertyName, mapping } = this.meta.discriminator; | ||
this.assertIsCompiled(); | ||
// don't attempt transforming invalid documents into models | ||
if (typeof doc !== 'object') { | ||
return doc; | ||
} | ||
if (this.meta.discriminator) { | ||
@@ -84,2 +89,6 @@ const { fieldName, mapping } = this.meta.discriminator; | ||
this.assertIsCompiled(); | ||
// don't attempt transforming invalid models into documents | ||
if (typeof model !== 'object') { | ||
return model; | ||
} | ||
if (this.meta.discriminator) { | ||
@@ -95,70 +104,123 @@ const { propertyName, mapping } = this.meta.discriminator; | ||
const context = new Map(); | ||
const has = (accessor) => { | ||
return `(source && typeof source["${accessor}"] !== "undefined")`; | ||
}; | ||
const getComparator = (fieldMetadata, accessor, setter) => { | ||
const { embeddedMetadata, fieldName, isEmbeddedArray, isEmbedded } = fieldMetadata; | ||
if (!isEmbedded) { | ||
const fieldType = fieldMetadata.type; | ||
// trust values if field type is undefined | ||
if (!fieldType) { | ||
return ` | ||
if (${has(accessor)}) { | ||
target["${setter}"] = source["${accessor}"]; | ||
// gets the code for computing field values | ||
const fieldCode = ({ fieldMetadata, accessor, setter }) => { | ||
const { fieldName, shouldCreateJSValue } = fieldMetadata; | ||
// use raw value if field does not have a "type" | ||
if (!fieldMetadata.type) { | ||
return ` | ||
if (typeof source["${accessor}"] !== 'undefined') { | ||
target["${setter}"] = source["${accessor}"]; | ||
} | ||
`; | ||
} | ||
`; | ||
const createJsVar = reserveVariable(`${fieldName}_new_value`); | ||
const typeVar = reserveVariable(`${fieldName}_type`); | ||
context.set(typeVar, fieldMetadata.type); | ||
const createJSValueCode = (variable) => { | ||
if (!shouldCreateJSValue) { | ||
return ''; | ||
} | ||
const typeVar = reserveVariable(`${fieldName}_type`); | ||
context.set(typeVar, fieldType); | ||
return ` | ||
if (${has(accessor)}) { | ||
target["${setter}"] = ${typeVar}.${isToDB ? 'convertToDatabaseValue' : 'convertToJSValue'}(source["${accessor}"]); | ||
if (typeof ${variable} === 'undefined') { | ||
const ${createJsVar} = ${typeVar}.createJSValue(); | ||
if (typeof ${createJsVar} !== 'undefined') { | ||
${variable} = ${createJsVar}; | ||
} | ||
} | ||
`; | ||
}; | ||
const setTargetCode = (convertFn = 'convertToJSValue') => { | ||
return ` | ||
if (typeof source["${accessor}"] !== 'undefined') { | ||
target["${setter}"] = ${typeVar}.${convertFn}(source["${accessor}"]); | ||
} | ||
`; | ||
}; | ||
switch (type) { | ||
case 'toDB': | ||
return ` | ||
${createJSValueCode(`source["${accessor}"]`)} | ||
${setTargetCode('convertToDatabaseValue')} | ||
`; | ||
case 'fromDB': | ||
return setTargetCode(); | ||
case 'merge': | ||
return ` | ||
${createJSValueCode(`target["${setter}"]`)} | ||
${setTargetCode()} | ||
`; | ||
case 'init': | ||
return ` | ||
${createJSValueCode(`source["${accessor}"]`)} | ||
${setTargetCode()} | ||
`; | ||
} | ||
const embeddedTransformer = DocumentTransformer.create(embeddedMetadata); | ||
const transformerFnVar = reserveVariable(`${fieldName}_transformer`); | ||
context.set(transformerFnVar, embeddedTransformer[type].bind(embeddedTransformer)); | ||
if (isEmbeddedArray) { | ||
}; | ||
// gets the code for computing embedded document values | ||
const embeddedCode = ({ fieldMetadata, accessor, setter }) => { | ||
const { embeddedMetadata, isEmbeddedArray, fieldName } = fieldMetadata; | ||
// bypasses null & undefined | ||
const template = (code) => { | ||
return ` | ||
if (${has(accessor)} && Array.isArray(source["${accessor}"])) { | ||
${type === 'merge' | ||
? `target["${setter}"] = source["${accessor}"].map(v => ${transformerFnVar}(undefined, v, target));` | ||
: `target["${setter}"] = source["${accessor}"].map(v => ${transformerFnVar}(v, target));`} | ||
// bypass null & undefined values | ||
if (typeof source["${accessor}"] === 'undefined') { | ||
// ignore undefined values | ||
} else if (source["${accessor}"] === null) { | ||
target["${setter}"] = null; | ||
} else { | ||
${code} | ||
} | ||
`; | ||
}; | ||
const transformerVar = reserveVariable(`${fieldName}_transformer`); | ||
context.set(transformerVar, DocumentTransformer.create(embeddedMetadata)); | ||
const transformCode = (source, target = 'undefined') => { | ||
switch (type) { | ||
case 'toDB': | ||
return `${transformerVar}.toDB(${source})`; | ||
case 'fromDB': | ||
return `${transformerVar}.fromDB(${source}, target)`; | ||
case 'merge': | ||
return `${transformerVar}.merge(${target}, ${source}, target)`; | ||
case 'init': | ||
return `${transformerVar}.init(${source}, target)`; | ||
} | ||
}; | ||
if (isEmbeddedArray) { | ||
return template(` | ||
if (Array.isArray(source["${accessor}"])) { | ||
target["${setter}"] = source["${accessor}"].map(value => ${transformCode('value')}); | ||
} | ||
`); | ||
} | ||
return ` | ||
if (${has(accessor)}) { | ||
${type === 'merge' | ||
? `target["${setter}"] = ${transformerFnVar}(target["${setter}"], source["${accessor}"], target);` | ||
: `target["${setter}"] = ${transformerFnVar}(source["${accessor}"], target);`} | ||
} | ||
`; | ||
return template(`target["${setter}"] = ${transformCode(`source["${accessor}"]`, `target["${setter}"]`)};`); | ||
}; | ||
const props = []; | ||
for (const fieldMetadata of this.meta.fields.values()) { | ||
const { fieldName, propertyName } = fieldMetadata; | ||
const accessor = isFromDB ? fieldName : propertyName; | ||
const setter = isToDB ? fieldName : propertyName; | ||
props.push(getComparator(fieldMetadata, accessor, setter)); | ||
const { fieldName, propertyName, isEmbedded } = fieldMetadata; | ||
const opts = { | ||
fieldMetadata, | ||
accessor: isFromDB ? fieldName : propertyName, | ||
setter: isToDB ? fieldName : propertyName | ||
}; | ||
props.push(isEmbedded ? embeddedCode(opts) : fieldCode(opts)); | ||
} | ||
const parentMapper = () => { | ||
if (isToDB || !this.meta.parent) { | ||
return ''; | ||
} | ||
return ` | ||
target["${this.meta.parent.propertyName}"] = parent; | ||
`; | ||
}; | ||
const functionCode = ` | ||
return function(target, source, parent) { | ||
const compiled = new Function(...context.keys(), ` | ||
return function(target, source, parent) { | ||
let currentValue; | ||
if (source) { | ||
${props.join('\n')} | ||
${parentMapper()} | ||
} | ||
${ | ||
/* parent mapping */ | ||
!isToDB && this.meta.parent | ||
? ` target["${this.meta.parent.propertyName}"] = parent;` | ||
: ''} | ||
return target; | ||
} | ||
`; | ||
const compiled = new Function(...context.keys(), functionCode); | ||
return target; | ||
} | ||
`); | ||
return compiled(...context.values()); | ||
@@ -171,3 +233,4 @@ } | ||
if (typeof object._id === 'undefined' && | ||
typeof this.meta.idField !== 'undefined') { | ||
typeof this.meta.idField !== 'undefined' && | ||
this.meta.idField.shouldCreateJSValue) { | ||
object._id = this.meta.idField.createJSValue(); | ||
@@ -174,0 +237,0 @@ } |
@@ -23,2 +23,3 @@ import { DocumentClass, Newable } from '../typings'; | ||
extensions?: Record<any, any>; | ||
create: boolean; | ||
} | ||
@@ -25,0 +26,0 @@ export interface ParentDefinition<T = any> { |
@@ -21,5 +21,7 @@ import { Newable } from '../typings'; | ||
readonly type: Type; | ||
readonly shouldCreateJSValue: boolean; | ||
constructor(opts: FieldMetadataOpts); | ||
createJSValue(value?: any): any; | ||
private prepareOpts; | ||
} | ||
//# sourceMappingURL=FieldMetadata.d.ts.map |
@@ -8,2 +8,3 @@ "use strict"; | ||
constructor(opts) { | ||
this.prepareOpts(opts); | ||
this.DocumentClass = opts.DocumentClass; | ||
@@ -18,2 +19,3 @@ this.propertyName = opts.propertyName; | ||
this.type = opts.type; | ||
this.shouldCreateJSValue = this.type ? opts.create === true : false; | ||
if (this.type && !(this.type instanceof types_1.Type)) { | ||
@@ -24,6 +26,22 @@ errors_1.InternalError.throw(`Invalid type for property "${this.propertyName}"`); | ||
createJSValue(value) { | ||
return this.type ? this.type.createJSValue(value) : value; | ||
return this.shouldCreateJSValue ? this.type.createJSValue(value) : value; | ||
} | ||
prepareOpts(opts) { | ||
// don't allow "create" option with type is not set | ||
if (typeof opts.type === 'undefined' && | ||
typeof opts.create !== 'undefined') { | ||
errors_1.InternalError.throw(`${opts.DocumentClass.name} document cannot use "create" field option without a "type"`); | ||
} | ||
// force "_id" fields to auto-create values | ||
if (opts.fieldName === '_id' && typeof opts.type !== 'undefined') { | ||
opts.create = true; | ||
} | ||
// don't auto-create type values by default | ||
else if (typeof opts.type !== 'undefined' && | ||
typeof opts.create === 'undefined') { | ||
opts.create = false; | ||
} | ||
} | ||
} | ||
exports.FieldMetadata = FieldMetadata; | ||
//# sourceMappingURL=FieldMetadata.js.map |
{ | ||
"name": "type-mongodb", | ||
"version": "1.0.0-beta.8", | ||
"version": "1.0.0-beta.9", | ||
"description": "A simple decorator based MongoDB ODM.", | ||
@@ -5,0 +5,0 @@ "keywords": [], |
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
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
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
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
227092
2859