Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save and find nested entities #37

Merged
merged 27 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d62cb04
feat(datamapper): enabling nested entity saving with improved null an…
vitorgamer58 Jul 10, 2023
5871b7b
test(datamapper.test): adds tests to enforce rules regarding nested e…
vitorgamer58 Jul 10, 2023
68dfcf0
feat(datamapper): enable find of nested entities
vitorgamer58 Jul 10, 2023
8d4b6b2
test(datamapper.test): validate toEntity with nested entities
vitorgamer58 Jul 10, 2023
2453cb7
fix(datamapper): improved empty object checking in arrayDataParse
vitorgamer58 Jul 10, 2023
e34049e
feat(herbs2mongo): enable export of DataMapper class
vitorgamer58 Jul 10, 2023
e9c006e
test: adjust array type return rule when value is empty
vitorgamer58 Jul 10, 2023
4f460ae
feat(datamapper): enable find of nested entities
vitorgamer58 Jul 12, 2023
9818b6b
test(findbyid): add test to validate nested entity
vitorgamer58 Jul 12, 2023
16d2e54
refactor(datamapper): field transformation and filter of null and und…
vitorgamer58 Aug 19, 2023
8a4e05d
refactor(datamapper): refine parsing for entity processing
vitorgamer58 Aug 19, 2023
6190f0b
feat(datamapper): adds recursion and childrenm key in field mapping
vitorgamer58 Aug 20, 2023
6418b2b
feat(datamapper): adds recursion to work with nested entities
vitorgamer58 Aug 20, 2023
00f598e
test(datamapper.test): adds tests with multi-level nested entities
vitorgamer58 Aug 20, 2023
636c9ab
feat(datamapper): recursive parse of entities from collection to entity
vitorgamer58 Aug 20, 2023
b56dd30
feat(datamapper): add recursive entity array parser
vitorgamer58 Aug 20, 2023
9830cdc
feat: adjust nested entity array compatibility
vitorgamer58 Aug 20, 2023
2acfe31
test(findbyid): coverage of more nested entity scenarios
vitorgamer58 Aug 20, 2023
135587d
refactor(datamapper): refactor ifs to use ternary if
vitorgamer58 Aug 20, 2023
b87c6b1
test(datamapper.test): add more test cases
vitorgamer58 Aug 20, 2023
f94144e
refactor(datamapper): remove unused code
vitorgamer58 Aug 20, 2023
66b91af
test(datamapper.test): add null nested entity test case
vitorgamer58 Aug 20, 2023
ac90924
refactor(datamapper): remove if useless
vitorgamer58 Aug 20, 2023
75d91d0
style(datamapper): code formatting and styling
vitorgamer58 Aug 20, 2023
09a3740
test(datamapper.test): use new to create GreatGreatGrandChildEntity
vitorgamer58 Aug 20, 2023
3896da7
test(datamapper): fix unit test
vitorgamer58 Aug 20, 2023
1122dd1
feat: adjust entity checking when entityField.type is an array
vitorgamer58 Aug 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 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 @@ -58,15 +58,31 @@ class DataMapper {

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

filterNullAndUndefined(i, instance) {
if (instance[i.name] === null || instance[i.name] === undefined) return null
vitorgamer58 marked this conversation as resolved.
Show resolved Hide resolved
if (i.isEntity) {
const entity = instance[i.name]
const newObject = Object.keys(entity).reduce((acc, key) => {
if (entity[key] === null || entity[key] === undefined) return acc

acc[key] = entity[key]

return acc
}, {})

return { [i.nameDb]: newObject }
}
return { [i.nameDb]: instance[i.name] }
}

collectionFieldsWithValue(instance) {

let collectionFields = this.allFields
.filter((i) => !i.isEntity)
.map(i => ({ [i.nameDb]: instance[i.name] }))
.map(i => this.filterNullAndUndefined(i, instance))
.filter(Boolean)
.reduce((x, y) => ({ ...x, ...y }))

if (instance.id === undefined) {
Expand All @@ -85,7 +101,7 @@ class DataMapper {

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

Expand Down Expand Up @@ -126,7 +142,7 @@ class DataMapper {
Object.defineProperty(proxy, field.name, {
enumerable: true,
get: function () {
if (field.isEntity) return undefined
if (field.isEntity) return parser(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 }
113 changes: 112 additions & 1 deletion test/dataMapper.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ describe('Data Mapper', () => {
assert.deepStrictEqual(toEntity.idField, 1)
assert.deepStrictEqual(toEntity.field1, true)
assert.deepStrictEqual(toEntity.fieldName, false)

})

it('should convert an entity field to the collection string convetion', () => {
Expand Down Expand Up @@ -98,6 +97,118 @@ describe('Data Mapper', () => {
})
})

describe('Simple Nested Entity', () => {
const ChildEntity = entity('Child entity', {
field1: field(String)
})

const givenAnNestedEntity = () => {

return entity('A nested entity', {
idField: field(Number),
field1: field(Boolean),
childEntity: field(ChildEntity),
arrayChildEntity: field([ChildEntity])
})
}

it('should convert data from collection to nested entity', () => {
//given
const Entity = givenAnNestedEntity()
const entityIDs = ['idField']
const dataMapper = new DataMapper(Entity, entityIDs)
const childEntity = new ChildEntity()
childEntity.field1 = 'String'

//when
const toEntity = dataMapper.toEntity({
id_field: 1,
field1: true,
child_entity: {
field1: 'String'
},
array_child_entity: [
{ field1: 'String' }
]
})

//then
assert.deepStrictEqual(toEntity.idField, 1)
assert.deepStrictEqual(toEntity.field1, true)
assert.deepStrictEqual(toEntity.childEntity, childEntity)
assert.deepStrictEqual(toEntity.arrayChildEntity, [childEntity])
})

it('should retrieve collection fields an nested entity', () => {
//given
const Entity = givenAnNestedEntity()
const entityInstance = new Entity()
entityInstance.idField = 1
entityInstance.field1 = true
entityInstance.childEntity = {
field1: 'String'
}
const entityIDs = ['idField']
const dataMapper = new DataMapper(Entity, entityIDs)

//when
const toEntity = dataMapper.collectionFields()

//then
assert.deepStrictEqual(toEntity, ['id_field', 'field1', 'child_entity', 'array_child_entity'])
})

it('should retrieve collection fields with values of an nested entity', () => {
//given
const Entity = givenAnNestedEntity()
const entityInstance = new Entity()
entityInstance.idField = 1
entityInstance.field1 = true
entityInstance.childEntity = {
field1: 'String'
}
entityInstance.arrayChildEntity = [
{
field1: 'String'
}
]
const entityIDs = ['idField']
const dataMapper = new DataMapper(Entity, entityIDs)

//when
const toEntity = dataMapper.collectionFieldsWithValue(entityInstance)

//then
assert.deepStrictEqual(toEntity, {
id_field: 1,
field1: true,
child_entity: {
field1: 'String'
},
array_child_entity: {
0: { field1: 'String' }
}
})
})

it('should retrieve collection fields with values of an nested entity with child entity as empty object', () => {
//given
const Entity = givenAnNestedEntity()
const entityInstance = new Entity()
entityInstance.idField = 1
entityInstance.field1 = true
entityInstance.childEntity = {}
const entityIDs = ['idField']
const dataMapper = new DataMapper(Entity, entityIDs)

//when
const toEntity = dataMapper.collectionFieldsWithValue(entityInstance)

//then
assert.deepStrictEqual(toEntity, { id_field: 1, field1: true, child_entity: {} })
})
})

describe('Complex Entity - Multiple Types', () => {

const givenAnComplexEntity = () => {
Expand Down
2 changes: 1 addition & 1 deletion test/queries/find.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ describe('Query Find', () => {
const ret = await itemRepo.find({ filter: { stringTest: ["aString"] } })

//then
assert.deepStrictEqual(ret[0].toJSON(), { id: '60edc25fc39277307ca9a7ff', stringTest: "aString", numberTest: 100, booleanTest: true , entityTest: undefined, entitiesTest: undefined })
assert.deepStrictEqual(ret[0].toJSON(), { id: '60edc25fc39277307ca9a7ff', stringTest: "aString", numberTest: 100, booleanTest: true , entityTest: undefined, entitiesTest: null })
assert.deepStrictEqual(ret[0].isValid(),true )

})
Expand Down
2 changes: 1 addition & 1 deletion test/queries/findByID.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe('Query Find by ID', () => {
const ret = await itemRepo.findByID(anEntity.id)

//then
assert.deepStrictEqual(ret[0].toJSON(), { id: '60edc25fc39277307ca9a7ff', stringTest: "aString", numberTest: 100, booleanTest: true , entityTest: undefined, entitiesTest: undefined })
assert.deepStrictEqual(ret[0].toJSON(), { id: '60edc25fc39277307ca9a7ff', stringTest: "aString", numberTest: 100, booleanTest: true , entityTest: undefined, entitiesTest: null })
assert.deepStrictEqual(ret[0].isValid(),true )

})
Expand Down