Skip to content

Commit

Permalink
feat(first): add first method feature
Browse files Browse the repository at this point in the history
re #26
  • Loading branch information
jhomarolo committed Oct 10, 2021
1 parent c2ed159 commit 0bfe46e
Show file tree
Hide file tree
Showing 8 changed files with 2,148 additions and 1,837 deletions.
3,317 changes: 1,677 additions & 1,640 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"dependencies": {
"@herbsjs/gotu": "^1.0.0",
"knex": "^0.95.6",
"@herbsjs/suma": "^1.0.0"
"@herbsjs/suma": "^1.1.0"
},
"devDependencies": {
"@semantic-release/changelog": "^5.0.1",
Expand Down
149 changes: 99 additions & 50 deletions src/repository.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,17 @@ module.exports = class Repository {
this.dataMapper = new DataMapper(this.entity, this.entityIDs, this.foreignKeys)
}

runner(){
runner() {
return this.knex(this.tableQualifiedName)
}

/**
*
* Find by id method
*
* @param {type} ids The id or the array of id's to search
* @return {type} List of entities
*/
async findByID(ids) {
const tableIDs = this.dataMapper.tableIDs()
const tableFields = this.dataMapper.tableFields()
Expand All @@ -43,37 +50,57 @@ module.exports = class Repository {
return entities
}

/**
*
* Find all method
*
* @param {type} object.limit Limit items to list
* @param {type} object.orderBy Order by query
* @param {type} object.offset Rows that will be skipped from the resultset
*
* @return {type} List of entities
*/
async findAll(options = {
limit: 0,
offset: 0,
orderBy: null
}) {
async #findQuery(query, options) {


if (options.where) {
const conditionTermTableField = this.dataMapper.toTableFieldName(Object.keys(options.where)[0])
const conditionTerm = Object.keys(options.where)[0]
if (!conditionTerm || conditionTerm === "0") throw "condition term is invalid"

const conditionValue = Array.isArray(options.where[conditionTerm])
? options.where[conditionTerm]
: [options.where[conditionTerm]]

if (!options.where[conditionTerm] ||
(typeof options.where[conditionTerm] === "object" && !Array.isArray(options.where[conditionTerm])) ||
(Array.isArray(options.where[conditionTerm]) && !options.where[conditionTerm].length))
throw "condition value is invalid"

query = query.whereIn(conditionTermTableField, conditionValue)
}

if (options.orderBy) {
if (!options.orderBy || typeof options.orderBy === "object" && !Array.isArray(options.orderBy) && checker.isEmpty(options.orderBy)) throw "order by is invalid"
query = query.orderBy(options.orderBy)
}

const entities = []
const ret = await query

if (checker.isIterable(ret)) {
for (const row of ret) {
if (row === undefined) continue
entities.push(this.dataMapper.toEntity(row))
}
}
else
entities.push(this.dataMapper.toEntity(ret))

const entities = this.find({ limit: options.limit, offset: options.offset, orderBy: options.orderBy })
return entities
}

/**
*
* Find entities
*
* @param {type} object.limit Limit items to list
* @param {type} object.offset Rows that will be skipped from the resultset
* @param {type} object.search Where query term
* @param {type} object.orderBy Order by query
*
* @return {type} List of entities
*/
*
* Find entities
*
* @param {type} object.limit Limit items to list
* @param {type} object.offset Rows that will be skipped from the resultset
* @param {type} object.search Where query term
* @param {type} object.orderBy Order by query
*
* @return {type} List of entities
*/
async find(options = {
limit: 0,
offset: 0,
Expand All @@ -94,37 +121,54 @@ module.exports = class Repository {
if (options.limit > 0) query = query.limit(options.limit)
if (options.offset > 0) query = query.offset(options.offset)

if (options.where) {
const conditionTermTableField = this.dataMapper.toTableFieldName(Object.keys(options.where)[0])
const conditionTerm = Object.keys(options.where)[0]
if (!conditionTerm || conditionTerm === "0") throw "condition term is invalid"
return this.#findQuery(query, options)
}

const conditionValue = Array.isArray(options.where[conditionTerm])
? options.where[conditionTerm]
: [options.where[conditionTerm]]
/**
*
* Find all method
*
* @param {type} object.limit Limit items to list
* @param {type} object.orderBy Order by query
* @param {type} object.offset Rows that will be skipped from the resultset
*
* @return {type} List of entities
*/
async findAll(options = {
limit: 0,
offset: 0,
orderBy: null
}) {

if (!options.where[conditionTerm] ||
(typeof options.where[conditionTerm] === "object" && !Array.isArray(options.where[conditionTerm])) ||
(Array.isArray(options.where[conditionTerm]) && !options.where[conditionTerm].length))
throw "condition value is invalid"
const entities = this.find({ limit: options.limit, offset: options.offset, orderBy: options.orderBy })
return entities
}

query = query.whereIn(conditionTermTableField, conditionValue)
}
/**
*
* First method
*
* @param {type} object.orderBy Order by query to get the first element of, if null will return the first element without order
*
* @return {type} Entity
*/
async first(options = {
orderBy: null,
where: null
}) {

if (options.orderBy) {
if (!options.orderBy || typeof options.orderBy === "object" && !Array.isArray(options.orderBy) && checker.isEmpty(options.orderBy)) throw "order by is invalid"
query = query.orderBy(options.orderBy)
if (!options.orderBy || (typeof options.orderBy === "object" && checker.isArray(options.orderBy)) || !checker.isString(options.orderBy)) throw "order by is invalid"
}

const entities = []
const ret = await query
options.orderBy = options.orderBy || null
options.where = options.where || null

for (const row of ret) {
if (row === undefined) continue
entities.push(this.dataMapper.toEntity(row))
}
const tableFields = this.dataMapper.tableFields()

return entities
let query = this.runner().first(tableFields)

return this.#findQuery(query, options)
}

/**
Expand Down Expand Up @@ -171,7 +215,7 @@ module.exports = class Repository {
*
* Delete entity
*
* @param {type} entityInstance Entity instance
* @param {type} entityInstance Entity instance
*
* @return {type} True when success
*/
Expand All @@ -185,4 +229,9 @@ module.exports = class Repository {
return ret === 1
}



}



144 changes: 0 additions & 144 deletions test/queries/find.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,148 +227,4 @@ describe('Query Find', () => {
}
})
})

context('Find with conditions', () => {
const givenAnEntity = () => {
const ParentEntity = entity('A Parent Entity', {})

return entity('A entity', {
id: field(Number),
stringTest: field(String),
booleanTest: field(Boolean),
entityTest: field(ParentEntity),
entitiesTest: field([ParentEntity]),
})
}

const givenAnRepositoryClass = (options) => {
return class ItemRepositoryBase extends Repository {
constructor(options) {
super(options)
}
}
}

const knex = (ret, spy = {}) => (
() => ({
select: (s) => {
spy.select = s
return {
whereIn: (w, v) => {
spy.where = w
spy.value = v
return ret
}
}
}
})
)

it('should return entities using table field', async () => {
//given
let spy = {}
const retFromDeb = [
{ id: 1, string_test: "john", boolean_test: true },
{ id: 2, string_test: "clare", boolean_test: false }
]
const anEntity = givenAnEntity()
const ItemRepository = givenAnRepositoryClass()
const itemRepo = new ItemRepository({
entity: anEntity,
table: 'aTable',
ids: ['id'],
knex: knex(retFromDeb, spy)
})

//when
const ret = await itemRepo.find({ where: { stringTest: ["john"] } })

//then
assert.deepStrictEqual(ret[0].toJSON(), { id: 1, stringTest: 'john', booleanTest: true, entityTest: undefined, entitiesTest: undefined })
assert.deepStrictEqual(ret[1].toJSON(), { id: 2, stringTest: 'clare', booleanTest: false, entityTest: undefined, entitiesTest: undefined })
assert.deepStrictEqual(spy.select, ['id', 'string_test', 'boolean_test'])
assert.deepStrictEqual(spy.value, ["john"])
})

it('should return entities using foreing key', async () => {
//given
let spy = {}
const retFromDeb = [
{ id: 1, string_test: "john", boolean_test: true, fk_field: 21 },
{ id: 2, string_test: "clare", boolean_test: false, fk_field: null }
]
const anEntity = givenAnEntity()
const ItemRepository = givenAnRepositoryClass()
const itemRepo = new ItemRepository({
entity: anEntity,
table: 'aTable',
ids: ['id'],
foreignKeys: [{ fkField: String }],
knex: knex(retFromDeb, spy)
})

//when
const ret = await itemRepo.find({ where: { fkField: 1 } })

//then
assert.deepStrictEqual(ret[0].toJSON({ allowExtraKeys: true }), { id: 1, stringTest: 'john', booleanTest: true, entityTest: undefined, entitiesTest: undefined, fkField: "21" })
assert.deepStrictEqual(ret[1].toJSON({ allowExtraKeys: true }), { id: 2, stringTest: 'clare', booleanTest: false, entityTest: undefined, entitiesTest: undefined, fkField: null })
assert.deepStrictEqual(spy.select, ['id', 'string_test', 'boolean_test', 'fk_field'])
assert.deepStrictEqual(spy.where, 'fk_field')
assert.deepStrictEqual(spy.value, [1])
})


it('should return error because a wrong search', async () => {
//given
let spy = {}
const retFromDeb = [
{ id: 1, string_test: "john", boolean_test: true, fk_field: 21 },
{ id: 2, string_test: "clare", boolean_test: false, fk_field: null }
]
const anEntity = givenAnEntity()
const ItemRepository = givenAnRepositoryClass()
const itemRepo = new ItemRepository({
entity: anEntity,
table: 'aTable',
ids: ['id'],
knex: knex(retFromDeb, spy)
})

try {
//when
const ret = await itemRepo.find({ where: "wrong" })
} catch (error) {
//then
assert.deepStrictEqual(error, "condition term is invalid")
}
})

it('should return error because a type search', async () => {
//given
let spy = {}
const retFromDeb = [
{ id: 1, string_test: "john", boolean_test: true, fk_field: 21 },
{ id: 2, string_test: "clare", boolean_test: false, fk_field: null }
]
const anEntity = givenAnEntity()
const ItemRepository = givenAnRepositoryClass()
const itemRepo = new ItemRepository({
entity: anEntity,
table: 'aTable',
ids: ['id'],
knex: knex(retFromDeb, spy)

})

try {
//when
const ret = await itemRepo.find({ where: { wrong: { wrong: "wrong" } } })
} catch (error) {
//then
assert.deepStrictEqual(error, "condition value is invalid")
}
})
})

})
Loading

0 comments on commit 0bfe46e

Please sign in to comment.