That distinction matters because it explains both the strengths and the limits of the library.
What Inquire does
Inquire gives you:
- schema builders for
create()andalter() - query builders for
select(),insert(),update(), anddelete() - a shared
EngineAPI across dialects - connection wrappers that adapt native drivers
- typed query results through TypeScript generics
What Inquire does not do
Inquire does not give you:
- model classes
- relationship mapping
- identity maps
- change tracking
- lazy loading
- domain architecture
You still decide how your application is structured. That is intentional.
The four main parts
Engine
Engine is the entry point. It creates builders, runs raw queries, and exposes table-level helpers such as drop(), rename(), and truncate().
Builders
Builders hold intent until you ask for SQL or execute them.
CreateandAlterare for schema changes.Select,Insert,Update, andDeleteare for data access.
Each builder can:
- collect state
- generate SQL with
.query() - expose its internal shape with
.build() - execute when awaited, if it has an engine
Dialects
Dialects translate builder state into SQL.
MysqlPgsqlSqlite
They handle differences such as identifier quoting, placeholder syntax, type mapping, JSON extraction, RETURNING, and TRUNCATE.
Connections
A connection wrapper adapts a native driver to Inquire's Connection interface. It is responsible for:
- formatting values for that driver
- running the query
- handling transactions
- exposing the active dialect
Why this design is useful
This design keeps SQL visible.
You can:
- keep your own repository or service layer
- inspect generated SQL before execution
- fall back to raw SQL at any time
- stay close to the underlying database
That makes Inquire a good fit when you want a small abstraction over SQL, not a system that designs your data layer for you.
Typical workflow
const engine = connect(resource);
await engine.create('users')
.addField('id', { type: 'integer', autoIncrement: true })
.addPrimaryKey('id');
await engine.insert('users').values({ id: 1 });
const rows = await engine.select<{ id: number }>('id').from('users');
The library stays focused on schema and query building. Everything above that level remains your decision.