The ODAC.JS Query Builder

March 23, 2026
4 min read
The ODAC.JS Query Builder

Node.js developers are exhausted by the ORM pendulum. On one side, you have massive, AST-parsing monoliths that devour RAM, generate unpredictable SQL queries under the hood, and add seconds to your cold starts. On the other side, raw driver wrappers leave you writing boilerplate just to manage a basic connection pool.

When architecting ODAC.JS, we refused to compromise between developer experience and raw performance. We needed an enterprise-grade data access layer that was fully database-agnostic—supporting PostgreSQL, MySQL, and SQLite out of the box—without violating our core philosophy: Zero Dependency, Maximum Power.

The result is the built-in Odac.DB query builder.

The "Why": Smart Optional Dependencies

A major flaw in modern web frameworks is the "kitchen sink" approach to dependencies. If a framework supports five different databases, you often end up downloading the compilation toolchains for all of them, bloat that sits idly in your node_modules.

We took a different path. Under the hood, ODAC.JS orchestrates the battle-tested Knex.js query builder engine, but we implemented a custom runtime ConnectionFactory. We classified heavy database drivers (pg, mysql2, sqlite3) strictly as optionalDependencies.

You only install the driver you actually intend to use. At startup, ODAC.JS performs intelligent runtime validation, dynamically binding your chosen driver to Odac.DB. The framework core remains unapologetically lightweight, and your deployment artifacts stay incredibly small.

Show Me The Code: The Proxy Advantage

Because Odac.DB is globally accessible and initialized during the framework's bootstrap phase, there is zero boilerplate required to start querying. No client instantiations, no passing connection objects through a middleware chain.

But we didn't stop at just exposing a Knex instance. We wrapped it in an intelligent JavaScript Proxy to fix some of the most annoying developer experience papercuts in the Node.js database ecosystem.

Take counting rows, for example. In many query builders, .count() returns an array of objects like [{ 'count(*)': '42' }]. You have to manually unwrap the array, parse the key, and convert the string to a number.

In ODAC.JS, our proxy intercepts .count() queries and automatically unwraps scalar results into a clean JavaScript Number.

// src/class/MetricsController.js

class MetricsController {
  static async getDashboard(req, res) {
    // Odac.DB is ready to use instantly, fully agnostic of the underlying DB
    
    // Automatically returns a clean Number, bypassing the [{count: '42'}] boilerplate
    const totalUsers = await Odac.DB('users').count('id as count');

    const activeUsers = await Odac.DB('users')
      .select('id', 'email', 'created_at')
      .where('status', 'active')
      .orderBy('created_at', 'desc')
      .limit(50);

    return res.json({ totalUsers, activeUsers });
  }
}

module.exports = MetricsController;

Zero-Config NanoIDs on Insert

Enterprise applications require rigorous schema evolution, but managing primary keys is notoriously frustrating. Instead of relying on predictable auto-incrementing integers or bulky UUIDv4 strings, ODAC.JS natively embraces NanoIDs for secure, URL-friendly unique identifiers.

We built this directly into the framework's lifecycle. During startup, ODAC.JS performs a lightweight scan of your schema/ directory, caching the metadata for any columns defined as type nanoid.

When you execute an insert via Odac.DB, the proxy checks this O(1) cache. If the table expects a NanoID and you haven't provided one, ODAC.JS generates it automatically before the query hits the database.

// schema/users.js
module.exports = {
  columns: {
    // ODAC.JS detects this type and caches it
    id: { type: 'nanoid', length: 21 },
    email: { type: 'string' },
    status: { type: 'string' }
  }
}
// In your controller:
// Zero boilerplate — the proxy automatically generates the NanoID for 'id'
const [newUser] = await Odac.DB.users.insert({
  email: 'hello@odac.run',
  status: 'active'
}).returning('*');

Graceful Shutdowns: The Unsung Hero

Why go through all the trouble of centralizing connection management inside a global Odac.DB object? Graceful degradation.

When a container orchestrator like Kubernetes sends a SIGTERM to your application, killing database connections immediately causes in-flight queries to fail, resulting in data corruption and dropped user requests.

Because Odac.DB holds the master reference to your database connection pool, ODAC.JS can execute an enterprise-grade graceful shutdown sequence. As seen in our Server.js implementation, when termination is requested, the primary process orchestrates a deterministic shutdown:

  1. Stop schedulers (cron jobs and LMDB session garbage collection).
  2. Gracefully drain all workers (stop accepting new requests).
  3. Wait for active workers to complete in-flight requests.
  4. Finally, release shared resources—safely closing the IPC channels and the Odac.DB connection pool.

No dropped queries. No corrupted states. Just pure, sub-millisecond reliability.

That is the standard we demand from ODAC.JS. Stop fighting your ORM, and get back to building.