import { SQLCore } from './core' ; import { ICollection , ensureArray , IInsertItem , IGetItem , IQuery , IInsert , ICollections } from 'debe' ; export abstract class SQLJsonCore extends SQLCore { chunks = 10000 ; bodyField = 'body' ; async initialize ( collections , options ) { for ( var key in collections ) { collections [ key ] . fields [ this . bodyField ] = 'json' ; collections [ key ] . specialFields . body = this . bodyField ; } await super . initialize ( collections , options ) ; } getCollectionBodyField ( collection ) { return collection . specialFields . body ; } abstract selectJSONField ( collection , field ) ; createWhere ( collection , where ) { where = ensureArray ( where ) ; let [ clause , ... args ] = where ; if ( clause ) { for ( var key in collection . index ) { if ( ! collection . fields [ key ] ) { clause = clause . split ( key ) . join ( this . selectJSONField ( collection , key ) ) ; } } return [ `WHERE ${ clause }` , ... args ] ; } return [ `` , ... args ] ; } createOrderBy ( collection , orderBy ) { let clause = super . createOrderBy ( collection , orderBy ) ; if ( clause ) { for ( var key in collection . index ) { if ( ! collection . fields [ key ] ) { clause = clause . split ( key ) . join ( this . selectJSONField ( collection , key ) ) ; } } } return clause ; } createSelect ( collection , fields = [ ] ) { if ( fields ) { fields = fields . map ( key => { if ( collection . fields [ key ] ) { return key ; } return `${ this . selectJSONField ( collection , key ) } as "${ key }"` ; } ) ; } return super . createSelect ( collection , fields ) ; } async insert < T > ( collection , value , options ) { const statement = this . createInsertStatement ( collection ) ; let items = undefined ; if ( options . update && options . existing . length ) { const existing = await this . query < T & IGetItem [ ] > ( collection , { where : [ `id IN (?)` , options . existing ] } , 'all' , true ) ; if ( existing . length ) { const map = existing . reduce ( ( state , { id = '' } , i ) => ( { ... state , [ id || '' ] : i } ) , { } ) ; items = value . map ( item => { if ( item . id && map [ item . id ] !== undefined ) { const exItem = existing [ map [ item . id ] ] ; const body = exItem [ collection . specialFields . body ] ; item = Object . assign ( typeof body === 'string' ? JSON . parse ( body ) : body , item ) ; } item = this . transformForStorage ( collection , item ) ; return Object . keys ( collection . fields ) . map ( key => item [ key ] ) ; } ) ; } } if ( ! items ) { items = value . map ( item => { item = this . transformForStorage ( collection , item ) ; return Object . keys ( collection . fields ) . map ( key => item [ key ] ) ; } ) ; } await this . exec ( statement , items , 'insert' ) ; return value as any ; } async query < T > ( collection , queryArgs , queryType , skipTransform = false ) { const result = await super . query < T > ( collection , queryArgs , queryType ) ; if ( ! skipTransform ) { if ( queryType === 'get' || queryType === 'all' ) { return this . transformForFrontend ( collection , result ) ; } } return result ; } filterItem ( collection , item ) { const rest = { } ; return [ Object . keys ( item ) . reduce ( ( state , key ) => { if ( collection . fields [ key ] ) { state [ key ] = item [ key ] ; } else { rest [ key ] = item [ key ] ; } return state ; } , { } ) , rest ] ; } transformForFrontend ( collection , result ) { if ( Array . isArray ( result ) ) { return result . map ( x => this . transformForFrontend ( collection , x ) ) ; } if ( ! result ) { return result ; } const [ obj , rest ] = this . filterItem ( collection , result ) ; const body = obj [ this . bodyField ] && typeof obj [ this . bodyField ] === 'string' ? JSON . parse ( obj [ this . bodyField ] ) : obj [ this . bodyField ] ; delete obj [ this . bodyField ] ; return { ... rest , ... body , ... obj } ; } transformForStorage ( collection , result ) { if ( Array . isArray ( result ) ) { return result . map ( x => this . transformForStorage ( collection , x ) ) ; } if ( ! result ) { return result ; } const [ obj , rest ] = this . filterItem ( collection , result ) ; obj [ this . bodyField ] = JSON . stringify ( rest ) ; return obj ; } }