mediumReact Native#32

SQLite database setup (expo-sqlite)

Prompt

Initialize an expo-sqlite database with a "users" table (id, name, email). Write functions to: create the table, insert a user, and query all users.

Solution

function useDatabase() {
  const db = SQLite.openDatabaseSync('app.db')
  const init = () => {
    db.execSync(`CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, email TEXT)`)
  }
  const insertUser = (name, email) => {
    db.runSync('INSERT INTO users (name, email) VALUES (?, ?)', [name, email])
  }
  const getUsers = () => {
    return db.getAllSync('SELECT * FROM users')
  }
  return { init, insertUser, getUsers }
}
Mentor's take

SQLite enters the conversation when data stops being a blob and starts being a model: the moment you need "notes containing X, sorted by date, joined to tags," AsyncStorage forces you to load everything and filter in JS, while SQLite indexes, filters, and joins on disk. That's the architectural line — key-value for small unstructured state, relational for anything you query.

The modern expo-sqlite API is worth naming precisely: the synchronous methods (openDatabaseSync, execSync, runSync, getAllSync) exist because the driver rides JSI — direct native calls, no bridge serialization — replacing the old callback-pyramid transaction API. Synchronous is a capability to spend deliberately: fine for a small query, wrong for bulk work on the JS thread — the async twins (runAsync, getAllAsync) exist for exactly that reason. The method split also carries meaning: execSync for DDL you fully control, runSync for writes, getAllSync returning rows as plain objects for reads.

Two disciplines in the code that interviewers check: CREATE TABLE IF NOT EXISTS makes init idempotent — safe on every launch, and the seed of a migrations story (PRAGMA user_version) as the schema evolves. And the ? placeholders are not optional style: parameterized queries are the SQL-injection boundary, and they let SQLite cache the statement plan.

Red flag: string-concatenating values into SQL. Injection plus broken escaping on the first apostrophe in a name — instant fail in any review.

Say it: "I reach for SQLite when data becomes queryable structure, use the JSI-backed sync API for cheap reads and async for bulk work, and parameterize every value — concatenated SQL is an injection, not a query."