Skip to content

Commit

Permalink
Merge pull request #37 from vitorgamer58/feat/save-and-find-nested-en…
Browse files Browse the repository at this point in the history
…tities

Save and find nested entities
  • Loading branch information
dalssoft authored Aug 22, 2023
2 parents d5e0de1 + 1122dd1 commit a6ef5c6
Show file tree
Hide file tree
Showing 6 changed files with 452 additions and 35 deletions.
144 changes: 133 additions & 11 deletions src/dataMapper.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const Convention = require('./convention')
const { entity } = require('@herbsjs/herbs')
const { entity, checker } = require('@herbsjs/herbs')
const dependency = { convention: Convention }

class DataMapper {
Expand Down Expand Up @@ -34,14 +34,27 @@ class DataMapper {

const fields = Object.keys(schema)
.map((field) => {
if (typeof schema[field] === 'function') return { type: Function }
if (typeof schema[field] === 'function') return null

const isArray = Array.isArray(schema[field].type)
const type = fieldType(schema[field].type)
const isEntity = entity.isEntity(type)
const nameDb = convention.toCollectionFieldName(field)

const isID = entityIDs.includes(field)
return { name: field, type, isEntity, nameDb, isArray, isID }

const object = { name: field, type, isEntity, nameDb, isArray, isID }

if (isEntity) {
const entitySchema = isArray
? schema[field].type[0].prototype.meta.schema
: schema[field].type.prototype.meta.schema
object.children = this.buildAllFields(entitySchema, [], convention)
}

return object
})
.filter(Boolean)

const allFields = fields.filter((f) => f.type !== Function)

Expand All @@ -58,16 +71,56 @@ class DataMapper {

collectionFields() {
return this.allFields
.filter((i) => !i.isEntity)
.map((i) => i.nameDb)
}

isNotNullOrUndefined(field, instance) {
if (instance[field.name] === null || instance[field.name] === undefined) return false
return true
}

transformField(field, instance) {
if (field.isEntity) {
return { [field.nameDb]: this.parseEntity(field, instance[field.name]) }
}

return { [field.nameDb]: instance[field.name] }
}

parseEntity(field, value) {
if (field.isArray && checker.isArray(value)) {
const parsedArray = value.map(item => this.parseEntity(field, item))
return parsedArray.reduce((acc, curr, index) => {
acc[index] = curr
return acc
}, {})
}

const parsedEntity = Object.keys(value).reduce((acc, key) => {
if (value[key] === null || value[key] === undefined) return acc

const childField = field.children.find((i) => i.name === key)

if (childField?.isEntity) {
acc[childField.nameDb] = this.parseEntity(childField, value[key])

return acc
}

acc[childField.nameDb] = value[key]

return acc
}, {})

return parsedEntity
}

collectionFieldsWithValue(instance) {

let collectionFields = this.allFields
.filter((i) => !i.isEntity)
.map(i => ({ [i.nameDb]: instance[i.name] }))
.reduce((x, y) => ({ ...x, ...y }))
.filter((field) => this.isNotNullOrUndefined(field, instance))
.map((field) => this.transformField(field, instance))
.reduce((acc, current) => ({ ...acc, ...current }), {})

if (instance.id === undefined) {
delete instance.id
Expand All @@ -83,9 +136,9 @@ class DataMapper {

buildProxy() {

function getDataParser(type, isArray) {
function getDataParser(type, isArray, isArrayOfEntities, field) {
function arrayDataParser(value, parser) {
if (value === null) return null
if (checker.isEmpty(value)) return null
return value.map((i) => parser(i))
}

Expand All @@ -94,11 +147,34 @@ class DataMapper {
return parser(value)
}

if (isArray) {
if (isArray && !isArrayOfEntities) {
const parser = getDataParser(type, false)
return (value) => arrayDataParser(value, parser)
}

if (isArrayOfEntities) {
return (value) => {
if (checker.isEmpty(value)) return null
return value?.map((item) => {
const object = Object.keys(item).reduce((obj, key) => {
const childField = field?.children.find((i) => i.nameDb === key)

if (childField.isEntity) {
obj[childField.name] = processEntity(childField, item)

return obj
}

const parser = getDataParser(field.type, false)
obj[childField.name] = parser(item[childField.nameDb])

return obj
}, {})
return object
})
}
}

if ((type === Date) || (!convention.isScalarType(type)))
return (x) => x

Expand All @@ -108,6 +184,44 @@ class DataMapper {
const convention = this.convention
const proxy = {}

function processEntity(field, payload) {
const entityValue = payload[field.nameDb]

if (checker.isEmpty(entityValue)) return undefined

const object = field.type.schema.fields.reduce((obj, entityField) => {
const fieldNameDb = convention.toCollectionFieldName(entityField.name)

const typeIsArray = checker.isArray(entityField.type)

const isEntity = typeIsArray
? entity.isEntity(entityField.type[0])
: entity.isEntity(entityField.type)

if (isEntity) {
const childField = field?.children.find((i) => i.name === entityField.name)

if (childField.isArray) {
const arrayOfEntityParser = getDataParser(childField.type, childField.isArray, childField.isEntity, childField)
obj[entityField.name] = arrayOfEntityParser(payload[field.nameDb][fieldNameDb])

return obj
}

obj[entityField.name] = processEntity(childField, payload[field.nameDb])

return obj
}

const fieldParser = getDataParser(entityField.type, Array.isArray(entityField.type))

obj[entityField.name] = fieldParser(payload[field.nameDb][fieldNameDb])
return obj
}, {})

return object
}

Object.defineProperty(proxy, '_payload', {
enumerable: false,
wricollection: true,
Expand All @@ -126,7 +240,15 @@ class DataMapper {
Object.defineProperty(proxy, field.name, {
enumerable: true,
get: function () {
if (field.isEntity) return undefined
if (field.isEntity && !field.isArray) {
return processEntity(field, this._payload)
}

if (field.isEntity && field.isArray) {
const arrayOfEntityParser = getDataParser(field.type, field.isArray, field.isEntity, field)
return arrayOfEntityParser(this._payload[nameDb])
}

return parser(this._payload[nameDb])
}
})
Expand Down
3 changes: 2 additions & 1 deletion src/herbs2mongo.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const Repository = require('./repository')
const DataMapper = require('./dataMapper')

module.exports = { Repository }
module.exports = { Repository, DataMapper }
Loading

0 comments on commit a6ef5c6

Please sign in to comment.