This is a simple demo of how latest Bun could've implemented .as(Class)
instead of using the quite jurassic Object.create
which is slow, bloated due descriptors logic, if used at all, and incapable to play nicely with features introduced after Object.create
was even specified.
// what `as(Class)` should return
const { assign } = Object;
const asClass = new WeakMap;
const setAsClass = Class => {
class As extends Class {
constructor(fields) {
assign(super(), fields);
}
}
asClass.set(Class, As);
return As;
};
const as = Class => asClass.get(Class) || setAsClass(Class);
// a db mock for this demo
const db = {
query(_) {
return {
as(Class) {
const As = as(Class);
return {
all() {
return [
new As({ name: 'Alice' }),
new As({ name: 'Bob' }),
new As({ name: 'Chuck' }),
];
}
};
}
};
}
};
// a class for this demo
class User {
name = '';
#age = 0;
birthday() {
this.#age++;
}
toString() {
return `${this.name} is ${this.#age}`;
}
}
// just asserting expectations
console.assert(new User().name === '');
// an actual result
const results = db.query('SELECT name FROM users').as(User);
for (const user of results.all()) {
console.assert(user instanceof User);
console.assert(user.name !== '');
if (Math.random() < .7) user.birthday();
console.log(`${user}`);
}
The output would be likely similar to this one with no assertions failed whatsoever:
Alice is 1
Bob is 0
Chuck is 1
The only contract around this ORM like logic is that classes should have no constructor or one that has defaults or regular setup without implying result fields are already known AOT.
Right now instead, we have a mechanism that really doesn't play well at all with modern classes abilities 😥
If worth exploring, the
as
could take an optional second argument that indicates theinit
method to use if / when desired ...