JS to a Local SQLite Database Get Certified
SQLite is a lightweight, file-based database that needs no separate server.
In this lesson we use a clean mock database that works exactly like the real better-sqlite3 / node:sqlite API, so you can learn the patterns safely in the browser.
Creating a Database and Table
What this code does: Creates an in-memory mock database and a simple users table.
function createMockDatabase() {
const tables = {};
return {
exec(sql) {
const match = sql.match(/CREATE TABLE(?: IF NOT EXISTS)?\s+(\w+)\s*\(([^)]+)\)/i);
if (match) {
const name = match[1];
tables[name] = { rows: [], nextId: 1 };
console.log(`Table "${name}" created`);
}
},
prepare(sql) {
// Will be expanded in next examples
return { run() {}, all() { return []; }, get() { return undefined; } };
},
// helper for demos
_tables: tables
};
}
const db = createMockDatabase();
db.exec(`CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)`);
console.log("Database ready");
Inserting Data
What this code does: Prepares an INSERT statement and inserts two users using safe ? placeholders.
function createMockDatabase() {
const tables = {};
return {
exec(sql) {
const m = sql.match(/CREATE TABLE(?: IF NOT EXISTS)?\s+(\w+)/i);
if (m) tables[m[1]] = { rows: [], nextId: 1 };
},
prepare(sql) {
const insertMatch = sql.match(/INSERT INTO\s+(\w+)\s*\(([^)]+)\)\s*VALUES\s*\(([^)]+)\)/i);
if (insertMatch) {
const tableName = insertMatch[1];
const cols = insertMatch[2].split(",").map(c => c.trim());
return {
run(...params) {
const table = tables[tableName];
const row = { id: table.nextId++ };
cols.forEach((col, i) => row[col] = params[i]);
table.rows.push(row);
return { lastInsertRowid: row.id, changes: 1 };
}
};
}
return { run() {}, all() { return []; } };
}
};
}
const db = createMockDatabase();
db.exec(`CREATE TABLE users (id, name, email)`);
const insert = db.prepare(`INSERT INTO users (name, email) VALUES (?, ?)`);
const r1 = insert.run("Ada Lovelace", "ada@example.com");
const r2 = insert.run("Grace Hopper", "grace@example.com");
console.log("Inserted Ada with id:", r1.lastInsertRowid);
console.log("Inserted Grace with id:", r2.lastInsertRowid);
Querying Data (.all and .get)
What this code does: Inserts users, then uses .all() to get every row and .get() to fetch one specific user.
function createMockDatabase() {
const tables = {};
return {
exec(sql) {
const m = sql.match(/CREATE TABLE(?: IF NOT EXISTS)?\s+(\w+)/i);
if (m) tables[m[1]] = { rows: [], nextId: 1 };
},
prepare(sql) {
// INSERT
const insertMatch = sql.match(/INSERT INTO\s+(\w+)\s*\(([^)]+)\)\s*VALUES/i);
if (insertMatch) {
const tableName = insertMatch[1];
const cols = insertMatch[2].split(",").map(c => c.trim());
return {
run(...params) {
const table = tables[tableName];
const row = { id: table.nextId++ };
cols.forEach((c, i) => row[c] = params[i]);
table.rows.push(row);
return { lastInsertRowid: row.id, changes: 1 };
}
};
}
// SELECT
const selectMatch = sql.match(/SELECT\s+.+\s+FROM\s+(\w+)(?:\s+WHERE\s+(\w+)\s*=\s*\?)?/i);
if (selectMatch) {
const tableName = selectMatch[1];
const whereCol = selectMatch[2];
return {
all(...params) {
let rows = tables[tableName].rows.slice();
if (whereCol) rows = rows.filter(r => r[whereCol] === params[0]);
return rows;
},
get(...params) {
return this.all(...params)[0];
}
};
}
return { run() {}, all() { return []; }, get() {} };
}
};
}
const db = createMockDatabase();
db.exec(`CREATE TABLE users (id, name, email)`);
const insert = db.prepare(`INSERT INTO users (name, email) VALUES (?, ?)`);
insert.run("Ada Lovelace", "ada@example.com");
insert.run("Grace Hopper", "grace@example.com");
insert.run("Alan Turing", "alan@example.com");
const allUsers = db.prepare(`SELECT * FROM users`).all();
console.log("All users:", allUsers);
const ada = db.prepare(`SELECT * FROM users WHERE name = ?`).get("Ada Lovelace");
console.log("Found Ada:", ada);
Updating and Deleting Rows
What this code does: Updates Ada’s email, deletes Grace, then shows the remaining rows.
function createMockDatabase() {
const tables = {};
return {
exec(sql) {
const m = sql.match(/CREATE TABLE(?: IF NOT EXISTS)?\s+(\w+)/i);
if (m) tables[m[1]] = { rows: [], nextId: 1 };
},
prepare(sql) {
// INSERT
if (/INSERT INTO/i.test(sql)) {
const tableName = sql.match(/INSERT INTO\s+(\w+)/i)[1];
const cols = sql.match(/\(([^)]+)\)/)[1].split(",").map(c => c.trim());
return {
run(...params) {
const table = tables[tableName];
const row = { id: table.nextId++ };
cols.forEach((c, i) => row[c] = params[i]);
table.rows.push(row);
return { lastInsertRowid: row.id, changes: 1 };
}
};
}
// UPDATE
if (/UPDATE/i.test(sql)) {
const tableName = sql.match(/UPDATE\s+(\w+)/i)[1];
const setCol = sql.match(/SET\s+(\w+)/i)[1];
const whereCol = sql.match(/WHERE\s+(\w+)/i)[1];
return {
run(setValue, whereValue) {
let changes = 0;
tables[tableName].rows.forEach(row => {
if (row[whereCol] === whereValue) {
row[setCol] = setValue;
changes++;
}
});
return { changes };
}
};
}
// DELETE
if (/DELETE FROM/i.test(sql)) {
const tableName = sql.match(/DELETE FROM\s+(\w+)/i)[1];
const whereCol = sql.match(/WHERE\s+(\w+)/i)[1];
return {
run(whereValue) {
const before = tables[tableName].rows.length;
tables[tableName].rows = tables[tableName].rows.filter(r => r[whereCol] !== whereValue);
return { changes: before - tables[tableName].rows.length };
}
};
}
// SELECT
if (/SELECT/i.test(sql)) {
const tableName = sql.match(/FROM\s+(\w+)/i)[1];
return {
all() { return tables[tableName].rows.slice(); }
};
}
return { run() {}, all() { return []; } };
}
};
}
const db = createMockDatabase();
db.exec(`CREATE TABLE users (id, name, email)`);
const insert = db.prepare(`INSERT INTO users (name, email) VALUES (?, ?)`);
insert.run("Ada Lovelace", "ada@example.com");
insert.run("Grace Hopper", "grace@example.com");
const update = db.prepare(`UPDATE users SET email = ? WHERE name = ?`);
const updateResult = update.run("ada.lovelace@newmail.com", "Ada Lovelace");
console.log("Rows updated:", updateResult.changes);
const remove = db.prepare(`DELETE FROM users WHERE name = ?`);
const deleteResult = remove.run("Grace Hopper");
console.log("Rows deleted:", deleteResult.changes);
console.log("Remaining users:", db.prepare(`SELECT * FROM users`).all());
Practice: Todo List Database
What this code does: Creates a todos table, inserts tasks, marks one as done, and shows the remaining pending tasks.
function createMockDatabase() {
const tables = {};
return {
exec(sql) {
const m = sql.match(/CREATE TABLE(?: IF NOT EXISTS)?\s+(\w+)/i);
if (m) tables[m[1]] = { rows: [], nextId: 1 };
},
prepare(sql) {
if (/INSERT INTO/i.test(sql)) {
const tableName = sql.match(/INSERT INTO\s+(\w+)/i)[1];
const cols = sql.match(/\(([^)]+)\)\s*VALUES/i)[1].split(",").map(c => c.trim());
return {
run(...params) {
const table = tables[tableName];
const row = { id: table.nextId++ };
cols.forEach((c, i) => row[c] = params[i]);
table.rows.push(row);
return { lastInsertRowid: row.id, changes: 1 };
}
};
}
if (/UPDATE/i.test(sql)) {
const tableName = sql.match(/UPDATE\s+(\w+)/i)[1];
const setCol = sql.match(/SET\s+(\w+)/i)[1];
const whereCol = sql.match(/WHERE\s+(\w+)/i)[1];
return {
run(setValue, whereValue) {
let changes = 0;
tables[tableName].rows.forEach(row => {
if (row[whereCol] === whereValue) {
row[setCol] = setValue;
changes++;
}
});
return { changes };
}
};
}
if (/SELECT/i.test(sql)) {
const tableName = sql.match(/FROM\s+(\w+)/i)[1];
const whereMatch = sql.match(/WHERE\s+(\w+)\s*=\s*\?/i);
return {
all(...params) {
let rows = tables[tableName].rows.slice();
if (whereMatch) {
rows = rows.filter(r => r[whereMatch[1]] === params[0]);
}
return rows;
}
};
}
return { run() {}, all() { return []; } };
}
};
}
const db = createMockDatabase();
db.exec(`CREATE TABLE todos (id, task, done)`);
const insert = db.prepare(`INSERT INTO todos (task, done) VALUES (?, ?)`);
insert.run("Write SQLite lesson", false);
insert.run("Review pull requests", false);
insert.run("Deploy to production", false);
console.log("All todos:", db.prepare(`SELECT * FROM todos`).all());
const markDone = db.prepare(`UPDATE todos SET done = ? WHERE task = ?`);
markDone.run(true, "Review pull requests");
console.log("--- after marking one done ---");
const pending = db.prepare(`SELECT * FROM todos WHERE done = ?`).all(false);
console.log("Still pending:", pending);
Quick Summary
db.exec()→ create tables / run schema SQLdb.prepare(sql)→ compile a reusable statementstmt.run(...)→ INSERT / UPDATE / DELETEstmt.all()→ get every matching rowstmt.get()→ get the first matching row- Always use
?placeholders instead of string concatenation
Tip: The patterns you learn with this mock database are exactly the same ones used with real libraries likebetter-sqlite3and Node’s built-innode:sqlite.
🧪 Test Your JavaScript Code
Edit the code on the left and click “Run Code” to see the console output.
Click “Run Code” to see the output here.