Improve Model class' rehydratable implementation
This commit is contained in:
parent
a27618d5a3
commit
48f5da1747
@ -1,5 +1,5 @@
|
||||
|
||||
export type JSONState = { [key: string]: string | boolean | number | JSONState | Array<string | boolean | number | JSONState> }
|
||||
export type JSONState = { [key: string]: string | boolean | number | undefined | JSONState | Array<string | boolean | number | undefined | JSONState> }
|
||||
|
||||
export function isJSONState(what: any): what is JSONState {
|
||||
try {
|
||||
|
@ -16,6 +16,13 @@ import {JSONState, Rehydratable} from '../../../lib/src/support/Rehydratable.ts'
|
||||
// TODO separate read/write connections
|
||||
// TODO manual dirty flags
|
||||
|
||||
export type ModelJSONState = {
|
||||
key_name: string,
|
||||
key?: string | number,
|
||||
fields?: string[],
|
||||
ephemeral_values?: string,
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for database models.
|
||||
* @extends Builder
|
||||
@ -310,6 +317,21 @@ export abstract class Model<T extends Model<T>> extends Builder<T> implements Re
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a model object, load the values into this model.
|
||||
* @param object
|
||||
* @return Model
|
||||
*/
|
||||
public assume(object: { [key: string]: any }) {
|
||||
get_fields_meta(this).each(field_def => {
|
||||
// TODO special type casting
|
||||
if ( field_def.model_key in object )
|
||||
// @ts-ignore
|
||||
this[field_def.model_key] = object[field_def.model_key]
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* If applicable get an object of normalized timestamps.
|
||||
* @return { updated_at?: Date, created_at?: Date }
|
||||
@ -839,18 +861,55 @@ export abstract class Model<T extends Model<T>> extends Builder<T> implements Re
|
||||
return `${this.table_name()}.${this.key}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Like to_object, but only the fields that have changed.
|
||||
* @return object
|
||||
*/
|
||||
public collect_dirty(): { [key: string]: any } {
|
||||
const fields = this.dirty_fields()
|
||||
const values: any = {}
|
||||
for ( const field of fields ) {
|
||||
// @ts-ignore
|
||||
values[field] = this[field]
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
/**
|
||||
* Dehydrate the model. Implements Rehydratable interface.
|
||||
*/
|
||||
public async dehydrate(): Promise<JSONState> {
|
||||
return this.to_object()
|
||||
public async dehydrate(): Promise<ModelJSONState> {
|
||||
const constructor = this.constructor as typeof Model
|
||||
return {
|
||||
key_name: constructor.qualified_key_name(),
|
||||
...(this.exists() ? {
|
||||
key: this.key(),
|
||||
fields: this._loaded_database_fields(),
|
||||
ephemeral_values: JSON.stringify(this.collect_dirty()),
|
||||
} : {
|
||||
ephemeral_values: JSON.stringify(this.to_object()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rehydrate the model. Implements Rehydratable interface.
|
||||
* @param state
|
||||
*/
|
||||
public async rehydrate(state: JSONState) {
|
||||
this.assume_from_source(state)
|
||||
public async rehydrate(state: ModelJSONState) {
|
||||
if ( state.key && state.fields ) {
|
||||
const results = await this.select(state.fields)
|
||||
.where(state.key_name, '=', state.key)
|
||||
.limit(1)
|
||||
.target_operator(make(ObjectResultOperator))
|
||||
.results()
|
||||
|
||||
const result = results.first()
|
||||
if ( result ) this.assume_from_source(result)
|
||||
}
|
||||
|
||||
if ( state.ephemeral_values ) {
|
||||
this.assume(JSON.parse(state.ephemeral_values))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user