import { RESERVED_PROPERTIES } from "./constants" ; import errors from "./errors" ; import { ExtendedRecord , FieldSchema , ModelFactory , RecordClass , RecordFactory , Table , TableRecord , TableRecordSet , TableSchema } from "./types" ; import * as utils from "./utils" ; export const createRecordModelClass = ( Base ) => { return class ExtendedRecordModel extends Base implements ExtendedRecord { _fields : { [ key ] : any ; } = { } ; constructor ( id , table ) { super ( id , table ) ; } } ; } ; export class RecordModelFactory { private _recordClass : { [ key ] : RecordClass ; } = { } ; private _recordBaseType : RecordClass ; private _factory : ModelFactory ; constructor ( recordBaseType , factory ) { this . _recordBaseType = recordBaseType ; this . _factory = factory ; } newRecordModel ( id , table ) { utils . ensureParamString ( "id" , id ) ; utils . ensureParamObject ( "table" , table ) ; const model = this . createRecordModel ( table . schema ) ; return new model ( id , table ) as TableRecord ; } protected createRecordModel ( schema ) { if ( this . _recordClass [ schema . name ] ) return this . _recordClass [ schema . name ] ; else { const model = createRecordModelClass ( this . _recordBaseType ) ; schema . fields . forEach ( f => ( f . isForeignKey || ! f . isPrimaryKey ) && this . _defineProperty ( model , f . propName , f , this . _newRecordField . bind ( this ) , false ) ) ; schema . relations . forEach ( f => f . relationName && this . _defineProperty ( model , f . relationName , f , f . unique ? this . _newRecordRelation . bind ( this ) : this . _newRecordSet . bind ( this ) , ! f . unique ) ) ; return this . _recordClass [ schema . name ] = model ; } } private _newRecordField ( schema , record ) { if ( ! schema . isForeignKey ) return this . _factory . newRecordFieldModel ( schema , record ) ; const refTable = schema . references && record . table . session . tables [ schema . references ] ; if ( ! refTable ) throw new Error ( errors . fkReferenceNotInSession ( schema . name , schema . references ) ) ; const recordId = schema . getRecordValue ( record ) ; if ( recordId === undefined ) return null ; return refTable . get ( recordId ) ; } private _newRecordSet ( schema , record ) { const refTable = record . table . session . tables [ schema . table . name ] ; if ( ! refTable ) throw new Error ( errors . tableNotInSession ( schema . table . name ) ) ; return this . _factory . newRecordSetModel ( refTable , schema , record ) ; } private _newRecordRelation ( schema , record ) { const refTable = record . table . session . tables [ schema . table . name ] ; if ( ! refTable ) throw new Error ( errors . tableNotInSession ( schema . table . name ) ) ; const [ id ] = refTable . getIndex ( schema . name , record . id ) ; if ( id === undefined ) return null ; return this . newRecordModel ( id , refTable ) ; } private _defineProperty = ( model , name , field , factory , cache = true ) => { if ( RESERVED_PROPERTIES . indexOf ( name ) >= 0 ) throw new Error ( errors . reservedProperty ( field . table . name , name ) ) ; Object . defineProperty ( model . prototype , name , { get ( this ) { return cache ? ( this . _fields [ name ] || ( this . _fields [ name ] = factory ( field , this ) ) ) : factory ( field , this ) ; } } ) ; } ; } const createModelFactory = ( factory , RecordModel ) => { const recordFactory = new RecordModelFactory ( RecordModel , factory ) ; return { ... factory , newRecordModel : ( id , table ) => recordFactory . newRecordModel ( id , table ) } as ModelFactory & RecordFactory ; } ; export default createModelFactory ;