Improve Model class' rehydratable implementation

This commit is contained in:
garrettmills 2020-07-28 09:35:11 -05:00
parent a27618d5a3
commit 48f5da1747
No known key found for this signature in database
GPG Key ID: 6ACD58D6ADACFC6E
2 changed files with 64 additions and 5 deletions

View File

@ -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 {

View File

@ -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))
}
}
}