Comparing version 0.1.9-alpha.5 to 0.1.10-alpha.0
@@ -41,2 +41,6 @@ const { DatabaseMapper } = require('./DatabaseMapper') | ||
createWriteStream () { | ||
throw new NotImplemented() | ||
} | ||
async connectDb () { | ||
@@ -43,0 +47,0 @@ throw new NotImplemented() |
@@ -14,2 +14,24 @@ const { getModelName } = require('../models/ModelRegistry') | ||
static updateInstanceValues (inst, values, prefix) { | ||
const entries = Object.entries(values) | ||
for (const [fieldName, fieldValue] of entries) { | ||
const fieldNameStripped = this.parseFieldName(fieldName, prefix) | ||
if (fieldNameStripped) { | ||
try { | ||
inst.setFromDb(fieldNameStripped, fieldValue) | ||
} catch (e) { | ||
// Avoid killing mapper by parsing errors | ||
inst.set(fieldNameStripped, null) | ||
// @TODO: Warn about this error! | ||
} | ||
} | ||
} | ||
} | ||
static mapInstanceValues (Model, values, prefix) { | ||
const inst = new Model() | ||
this.updateInstanceValues(inst, values, prefix) | ||
return inst | ||
} | ||
static createMapper = Model => { | ||
@@ -20,19 +42,3 @@ if (!Model) { | ||
const prefix = `${getModelName(Model)}__` | ||
return item => { | ||
const inst = new Model() | ||
const entries = Object.entries(item) | ||
for (const [fieldName, fieldValue] of entries) { | ||
const fieldNameStripped = this.parseFieldName(fieldName, prefix) | ||
if (fieldNameStripped) { | ||
try { | ||
inst.setFromDb(fieldNameStripped, fieldValue) | ||
} catch (e) { | ||
// Avoid killing mapper by parsing errors | ||
inst.set(fieldNameStripped, null) | ||
// @TODO: Warn about this error! | ||
} | ||
} | ||
} | ||
return inst | ||
} | ||
return values => this.mapInstanceValues(Model, values, prefix) | ||
} | ||
@@ -39,0 +45,0 @@ |
const camelCase = require('camelcase') | ||
const { Field } = require('../models/AttrModel') | ||
const { getModel, getModelName } = require('../models/ModelRegistry') | ||
const { getModel, getModelName, SELF } = require('../models/ModelRegistry') | ||
const { PositiveIntegerField } = require('./PositiveIntegerField') | ||
@@ -9,3 +9,5 @@ const { Relation } = require('./Relation') | ||
/** Field used for foreign key objects */ | ||
/** Field used for foreign key objects | ||
* @augments {Relation} | ||
*/ | ||
class ForeignKey extends Relation { | ||
@@ -22,4 +24,10 @@ static keyField = new Field() | ||
if (!this.keyField) { | ||
this.keyField = `${camelCase(this.get('model'))}Id` | ||
this.keyField = this.getKeyFieldName() | ||
} | ||
if (!this.relatedName) { | ||
this.relatedName = this.getTargetModelName() | ||
} | ||
if (!this.parentModel) { | ||
this.parentModel = SELF | ||
} | ||
this.foreignKeyField = new KeyFieldType() | ||
@@ -31,2 +39,10 @@ this.expandedField = { | ||
getKeyFieldName () { | ||
return `${camelCase(this.getTargetModelName())}Id` | ||
} | ||
getTargetModelName () { | ||
return this.get('model') | ||
} | ||
expand () { | ||
@@ -36,7 +52,8 @@ return this.expandedField | ||
parse (value) { | ||
parse (value, inst) { | ||
let parsed = value | ||
const Model = getModel(this.model) | ||
if (value && !(value instanceof Model)) { | ||
if (typeof value === 'object') { | ||
return new Model(value) | ||
if (parsed && !(parsed instanceof Model)) { | ||
if (typeof parsed === 'object') { | ||
parsed = Model.from(parsed) | ||
} | ||
@@ -46,10 +63,11 @@ throw new ValueError( | ||
Model | ||
)}" or null, but "${value}" was given` | ||
)}" or null, but "${parsed}" was given` | ||
) | ||
} | ||
return value | ||
inst[this.keyField] = parsed.pk | ||
return parsed | ||
} | ||
queryParentModel (primaryInstance) { | ||
return getModel(this.parentModel).objects.filter({ | ||
queryParentModel (modelName, primaryInstance) { | ||
return getModel(modelName).objects.filter({ | ||
[this.keyField]: primaryInstance.pk | ||
@@ -60,3 +78,6 @@ }) | ||
queryTargetModel (fkInstance) { | ||
const Model = getModel(this.model) | ||
const modelName = this.getTargetModelName() | ||
const Model = getModel( | ||
modelName === SELF ? getModelName(fkInstance.constructor) : modelName | ||
) | ||
return Model.objects.filter({ | ||
@@ -63,0 +84,0 @@ [Model.pkName]: fkInstance.get(this.keyField) |
@@ -10,10 +10,10 @@ const { FieldError, UnknownField } = require('../errors') | ||
.filter(([key, value]) => value && value instanceof FieldModel) | ||
.reduce( | ||
(aggr, fieldTuple) => [ | ||
...aggr, | ||
fieldTuple, | ||
...Object.entries(fieldTuple[1].expand()) | ||
], | ||
[] | ||
) | ||
.reduce((aggr, fieldTuple) => { | ||
const expanded = fieldTuple[1].expand() | ||
aggr.push(fieldTuple) | ||
if (expanded) { | ||
return aggr.concat(Object.entries(expanded)) | ||
} | ||
return aggr | ||
}, []) | ||
} | ||
@@ -37,6 +37,5 @@ | ||
} | ||
const fields = Model.fields | ||
const values = Object.entries(value) | ||
.map(([fieldName, value]) => ({ | ||
[fieldName]: fields[fieldName].fromDb(value) | ||
[fieldName]: Model.getField(fieldName).fromDb(value) | ||
})) | ||
@@ -163,4 +162,8 @@ .reduce((aggr, chunk) => Object.assign(aggr, chunk), {}) | ||
class GenericField extends AttrModel { | ||
/** Break down complex field into additional field instances. This enables | ||
* complex fields, like ForeignKey - as it is composed of the non-db field | ||
* and the database foreign key value field. | ||
*/ | ||
expand () { | ||
return {} | ||
return null | ||
} | ||
@@ -177,10 +180,24 @@ } | ||
parse (value) { | ||
/** Based on Robustness principle, fields will accept various representations | ||
* of the actual value and try to parse it into a strict model value | ||
* representation or fail | ||
* @param {any} value Field value | ||
* @param {DatabaseModel} inst Model instance | ||
* @returns {any} Model value representation | ||
*/ | ||
parse (value, inst) { | ||
return value | ||
} | ||
fromDb (value) { | ||
/** Convert database representation of the value into the instance | ||
* representation of the value | ||
* @param {any} value | ||
* @param {DatabaseModel} inst Model instance | ||
* @return {any} Model value representation | ||
*/ | ||
fromDb (value, inst) { | ||
return this.parse(value) | ||
} | ||
/** Serialize value in a way that would be represented in the database */ | ||
toDb (value) { | ||
@@ -190,2 +207,3 @@ return this.serialize(value) | ||
/** Serialize model value representation into JSON */ | ||
serialize (value) { | ||
@@ -195,6 +213,6 @@ return value | ||
hasDefault () { | ||
return this.default !== undefined | ||
} | ||
/** Get default value for this field based on the current instance | ||
* @param {AttrModel} inst | ||
* @returns {any} | ||
*/ | ||
getDefault (inst) { | ||
@@ -207,2 +225,6 @@ if (this.default instanceof Function) { | ||
/** Given this field has a validator, try to run it as a callback. Callback | ||
* will receive field value, the model instance, and field name as | ||
* arguments. | ||
*/ | ||
async validateValue (inst, fieldName) { | ||
@@ -209,0 +231,0 @@ return this.validator |
@@ -11,3 +11,8 @@ const { DatabaseModelBase } = require('./DatabaseModelBase') | ||
const { Update } = require('../db/Update') | ||
const { isAbstract, getModelName, getRelationship } = require('./ModelRegistry') | ||
const { | ||
isAbstract, | ||
getModel, | ||
getModelName, | ||
getRelationship | ||
} = require('./ModelRegistry') | ||
@@ -65,8 +70,13 @@ const nonEmpty = item => Boolean(item) | ||
try { | ||
return this.constructor.getField(relatedName).queryTargetModel(this) | ||
const field = this.constructor.getField(relatedName) | ||
return field.queryTargetModel(this) | ||
} catch (e) { | ||
if (e instanceof UnknownField) { | ||
return getRelationship(this.constructor, relatedName).queryParentModel( | ||
this | ||
const [parentModelName, parentFieldName] = getRelationship( | ||
this.constructor, | ||
relatedName | ||
) | ||
return getModel(parentModelName) | ||
.getField(parentFieldName) | ||
.queryParentModel(parentModelName, this) | ||
} | ||
@@ -152,7 +162,7 @@ throw e | ||
async reload () { | ||
const obj = await this.constructor.objects.get({ | ||
const values = await this.constructor.objects.query.mapModel(null).get({ | ||
[this.constructor.pkName]: this.pk | ||
}) | ||
const values = obj.serializeDbValues() | ||
return this.setValues(values) | ||
this.constructor.db.Mapper.updateInstanceValues(this, values) | ||
return this | ||
} | ||
@@ -159,0 +169,0 @@ |
const { ModelError } = require('../errors') | ||
const SELF = Symbol('models.Self') | ||
const models = {} | ||
const relationships = {} | ||
const refs = {} | ||
@@ -10,6 +11,16 @@ const getModelName = model => | ||
const getModels = () => models | ||
const getRelationships = () => relationships | ||
const getRelationships = () => refs | ||
const getRelationRefName = (modelName, relatedName) => | ||
`${modelName}__${relatedName}` | ||
const getMeta = model => { | ||
const desc = Object.getOwnPropertyDescriptor(model, 'meta') | ||
return desc && desc.value | ||
} | ||
const isAbstract = model => { | ||
const meta = getMeta(model) | ||
return Boolean(meta && meta.abstract) | ||
} | ||
function getModel (name) { | ||
@@ -25,8 +36,10 @@ const m = models[name] | ||
const modelRelations = model.relationFields | ||
if (modelRelations) { | ||
for (const [, field] of modelRelations) { | ||
if (!field.parentModel) { | ||
field.parentModel = modelName | ||
} | ||
relationships[getRelationRefName(field.model, field.relatedName)] = field | ||
if (!isAbstract(model) && modelRelations) { | ||
for (const [fieldName, field] of modelRelations) { | ||
const parentModel = | ||
field.get('parentModel') === SELF ? modelName : field.parentModel | ||
const targetModel = | ||
field.get('model') === SELF ? modelName : field.get('model') | ||
const refName = getRelationRefName(targetModel, field.get('relatedName')) | ||
refs[refName] = [parentModel, fieldName] | ||
} | ||
@@ -37,5 +50,5 @@ } | ||
function unregisterModelRelations (modelName) { | ||
for (const key of Object.keys(relationships)) { | ||
for (const key of Object.keys(refs)) { | ||
if (key.startsWith(`${modelName}__`)) { | ||
delete relationships[key] | ||
delete refs[key] | ||
} | ||
@@ -59,3 +72,3 @@ } | ||
function getRelationship (model, relatedName) { | ||
return relationships[getRelationRefName(getModelName(model), relatedName)] | ||
return refs[getRelationRefName(getModelName(model), relatedName)] | ||
} | ||
@@ -70,10 +83,5 @@ | ||
clearObj(models) | ||
clearObj(relationships) | ||
clearObj(refs) | ||
} | ||
const isAbstract = model => { | ||
const meta = Object.getOwnPropertyDescriptor(model, 'meta') | ||
return Boolean(meta && meta.value && meta.value.abstract) | ||
} | ||
module.exports = { | ||
@@ -88,3 +96,4 @@ clearModels, | ||
registerModel, | ||
unregisterModel | ||
unregisterModel, | ||
SELF | ||
} |
@@ -22,3 +22,3 @@ const { Delete } = require('../db/Delete') | ||
createWriteStream () { | ||
return this.db().createWriteStream() | ||
return this.db.createWriteStream(this.model) | ||
} | ||
@@ -25,0 +25,0 @@ |
{ | ||
"name": "djorm", | ||
"version": "0.1.9-alpha.5", | ||
"version": "0.1.10-alpha.0", | ||
"description": "Django like ORM framework", | ||
@@ -39,3 +39,3 @@ "author": "Pavel Žák <pavel@zak.global>", | ||
}, | ||
"gitHead": "bd772620388f18e9e592661d1431d719228bb234" | ||
"gitHead": "e3bc0f06ea74de2c501e5349187ea7787acef321" | ||
} |
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
65844
2333