2021-06-17 16:17:15 +02:00
'use strict' ;
2021-06-22 17:13:11 +02:00
const _ = require ( 'lodash/fp' ) ;
const types = require ( './types' ) ;
2021-06-17 16:17:15 +02:00
const { createQueryBuilder } = require ( './query' ) ;
const { createRepository } = require ( './entity-repository' ) ;
2021-06-22 17:13:11 +02:00
const pickScalarAtttibutes = ( metadata , data ) => {
const { attributes } = metadata ;
const scalarKeys = Object . keys ( attributes ) . filter ( key => types . isScalar ( attributes [ key ] . type ) ) ;
const picker = _ . pick ( scalarKeys ) ;
return Array . isArray ( data ) ? data . map ( data => picker ( data ) ) : picker ( data ) ;
} ;
2021-06-17 16:17:15 +02:00
const createEntityManager = db => {
const repoMap = { } ;
return {
async findOne ( uid , params ) {
const qb = this . createQueryBuilder ( uid )
. init ( params )
. first ( ) ;
return await qb . execute ( ) ;
} ,
// should we name it findOne because people are used to it ?
async findMany ( uid , params ) {
const qb = this . createQueryBuilder ( uid ) . init ( params ) ;
return await qb . execute ( ) ;
} ,
// support search directly in find & count -> a search param ? a different feature with a search tables rather
async findWithCount ( uid , params ) {
return await Promise . all ( [ this . findMany ( uid , params ) , this . count ( uid , params ) ] ) ;
} ,
// TODO: define api
2021-06-22 17:13:11 +02:00
async count ( uid , params = { } ) {
2021-06-17 16:17:15 +02:00
const qb = this . createQueryBuilder ( uid ) . where ( params . where ) ;
const res = await qb
. count ( )
. first ( )
. execute ( ) ;
return Number ( res . count ) ;
} ,
// TODO: make it create one somehow
async create ( uid , params ) {
// create entry in DB
// select fields that go into db
// format input values for the db
// change name to column names
// select relations
const { data } = params ;
// remove unknow fields or throw
// rename to columns
// transform value to storage value
// apply programatic defaults if any -> I think this should be handled outside of this layer as we might have some applicative rules in the entity service
// remove relation entries
2021-06-22 17:13:11 +02:00
const dataToInsert = pickScalarAtttibutes ( db . metadata . get ( uid ) , data ) ;
2021-06-17 16:17:15 +02:00
const [ id ] = await this . createQueryBuilder ( uid )
2021-06-22 17:13:11 +02:00
. insert ( dataToInsert )
2021-06-17 16:17:15 +02:00
. execute ( ) ;
// create relation associations or move this to the entity service & call attach on the repo instead
return this . findOne ( uid , { where : { id } , select : params . select , populate : params . populate } ) ;
} ,
async createMany ( uid , params ) {
const { data } = params ;
2021-06-22 17:13:11 +02:00
// pick scalar fields only
const dataToInsert = pickScalarAtttibutes ( db . metadata . get ( uid ) , data ) ;
2021-06-17 16:17:15 +02:00
const ids = await this . createQueryBuilder ( uid )
2021-06-22 17:13:11 +02:00
. insert ( dataToInsert )
2021-06-17 16:17:15 +02:00
. execute ( ) ;
2021-06-22 17:13:11 +02:00
// TODO: create relation links
2021-06-17 16:17:15 +02:00
return ids . map ( id => ( { id } ) ) ;
} ,
// TODO: make it update one somehow
// findOne + update with a return
async update ( uid , params ) {
const { where , data } = params ;
2021-06-22 17:13:11 +02:00
const dataToUpdate = pickScalarAtttibutes ( db . metadata . get ( uid ) , data ) ;
2021-06-17 16:17:15 +02:00
/*const r =*/ await this . createQueryBuilder ( uid )
. where ( where )
2021-06-22 17:13:11 +02:00
. update ( dataToUpdate )
2021-06-17 16:17:15 +02:00
. execute ( ) ;
return { } ;
} ,
async updateMany ( uid , params ) {
const { where , data } = params ;
2021-06-22 17:13:11 +02:00
const dataToUpdate = pickScalarAtttibutes ( db . metadata . get ( uid ) , data ) ;
2021-06-17 16:17:15 +02:00
return this . createQueryBuilder ( uid )
. where ( where )
2021-06-22 17:13:11 +02:00
. update ( dataToUpdate )
2021-06-17 16:17:15 +02:00
. execute ( ) ;
} ,
// TODO: make it deleteOne somehow
// findOne + delete with a return -> should go in the entity service
async delete ( uid , params ) {
return await this . createQueryBuilder ( uid )
. init ( params )
. delete ( )
. execute ( ) ;
} ,
async deleteMany ( uid , params ) {
const { where } = params ;
return await this . createQueryBuilder ( uid )
. where ( where )
. delete ( )
. execute ( ) ;
} ,
// populate already loaded entry
async populate ( uid , entry , name , params ) {
return {
... entry ,
relation : await this . load ( entry , name , params ) ,
} ;
} ,
// loads a relation
load ( uid , entry , name , params ) {
const { attributes } = db . metadata . get ( uid ) ;
return this . getRepository ( attributes [ name ] . target . uid ) . findMany ( {
... params ,
where : {
... params . where ,
// [parent]: entry.id,
} ,
} ) ;
} ,
// method to work with components & dynamic zones
// addComponent() {},
// removeComponent() {},
// setComponent() {},
// method to work with relations
attachRelation ( ) { } ,
detachRelation ( ) { } ,
setRelation ( ) { } ,
// cascading
// aggregations
// -> avg
// -> min
// -> max
// -> grouping
// formulas
// custom queries
// utilities
// -> format
// -> parse
// -> map result
// -> map input
// -> validation
// extra features
// -> virtuals
// -> private
createQueryBuilder ( uid ) {
return createQueryBuilder ( uid , db ) ;
} ,
getRepository ( uid ) {
if ( ! repoMap [ uid ] ) {
repoMap [ uid ] = createRepository ( uid , db ) ;
}
return repoMap [ uid ] ;
} ,
clearRepositories ( ) {
repoMap . clear ( ) ;
} ,
} ;
} ;
module . exports = {
createEntityManager ,
} ;