Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save zach2825/bb29e6bfc665e86f9432de022c9e90ff to your computer and use it in GitHub Desktop.

Select an option

Save zach2825/bb29e6bfc665e86f9432de022c9e90ff to your computer and use it in GitHub Desktop.
A minimal BaseModel in TypeScript that tracks field-level changes and generates diff payloads.
import { isEqual, cloneDeep, set, get } from 'lodash'
// === BaseModel Class ===
class BaseModel {
static _original: Record<string, any> = {}
static _changes: Record<string, any> = {}
id: string
constructor(data: Partial<any> = {}) {
Object.assign(this, data)
this.id = data.id || Math.random().toString(36).substring(2)
this.$initChangesTracking()
}
$initChangesTracking() {
const Ctor = this.constructor as typeof BaseModel
Ctor._original[this.id] = cloneDeep(this)
Ctor._changes[this.id] = {}
}
trackChange(key: string, value: any) {
const Ctor = this.constructor as typeof BaseModel
const originalValue = get(Ctor._original[this.id], key)
const isReverted = isEqual(originalValue, value)
if (isReverted) {
delete Ctor._changes[this.id][key]
} else {
set(Ctor._changes[this.id], key, value)
}
set(this, key, value)
}
get $changeRegistry(): Record<string, any> {
const Ctor = this.constructor as typeof BaseModel
const changes = Ctor._changes[this.id] || {}
const original = Ctor._original[this.id] || {}
const result: Record<string, any> = {}
for (const key in changes) {
const current = get(this, key)
const originalValue = get(original, key)
if (!isEqual(current, originalValue)) {
result[key] = current
}
}
return result
}
// Example $update override that uses trackChange
$update(payload: Record<string, any>) {
for (const [key, value] of Object.entries(payload)) {
this.trackChange(key, value)
}
}
}
// === User Class (Example Model) ===
class User extends BaseModel {
name = ''
email = ''
constructor(data: Partial<User> = {}) {
super(data)
Object.assign(this, data)
}
}
// === Usage Example ===
const user = new User({ id: 'u1', name: 'Alice', email: 'alice@example.com' })
console.log('Initial:', user)
user.$update({ name: 'Alicia' })
console.log('After name change:', user.$changeRegistry)
user.$update({ name: 'Alice' }) // revert
console.log('After reverting name:', user.$changeRegistry)
user.$update({ email: 'new@example.com' })
console.log('Final patch payload to send:', user.$changeRegistry)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment