I'm building a very rudimentary ORM while I learn Node. I have the constructor currently accept either a name or id parameter but not both. If the name is provided, the class creates the record in the database. If the id is provided, it looks up the record. Here's the complete file.
const mysql = require('mysql2/promise');
const { v4: uuid } = require('uuid');
const pool = require('../helpers/pool.js');
const xor = require('../helpers/xor.js');
class List {
constructor({ name = null, id = null} = {}) {
if (!xor(name, id)) {
throw new TypeError('Lists must have either a name or an id');
}
this.table_name = 'lists';
if (name) {
this.name = name;
this.uuid = uuid();
this.#insert_record();
return;
}
this.id = id;
this.#retrieve_record();
}
async #insert_record() {
await pool.query(
`INSERT INTO ${this.table_name} SET ?`,
{
name: this.name,
uuid: this.uuid
}
).then(async (results) => {
this.id = results[0].insertId;
return this.#retrieve_record();
});
}
async #retrieve_record() {
return await pool.execute(
`SELECT * FROM ${this.table_name} WHERE id = ?`,
[this.id]
).then(([records, fields]) => {
this.#assign_props(records[0], fields);
pool.end();
})
}
#assign_props(record, fields) {
fields.forEach((field) => {
this[field.name] = record[field.name];
})
console.log(this);
}
}
const list = new List({name: 'my list'});
const db_list = new List({id: 50});
You probably see the problem run this as is. I get intermittent errors. Sometimes everything works fine. Generally I see a console log of the retrieved list first, and then a see a log of the new list. But sometimes the pool gets closed with the retrieval before the insert can happen.
I tried placing the pool within the class, but that just caused other errors.
So, what's the proper way to have an ORM class use a connection pool? Note that I'm building features as I learn, and eventually there'll be a Table
class from which all of the entity classes will inherit. But I'm first just trying to get this one class to work properly on its own.