pg-sequelize package
Sequelize and sequelize-typescript, refined for @imqueue services.
The problem it was built for: a caller describes the query it wants as DATA — a filter, a page, an order, and the fields it actually needs — and the service has to turn that into one efficient statement, without trusting any of it and without knowing in advance which shape will arrive. Anything can hand you a query described that way; a GraphQL API is the case this was written against, where a resolver passes the arguments and the selected field set through almost untouched and gets back a query that selects the columns asked for, joins only the relations the selection reaches into, and filters on values that arrived as JSON. An RPC method taking a filter object, or a REST endpoint with query parameters, is the same problem with different packaging.
Which version, and which package. This targets Sequelize v6 — mature, proven in production, and what this package is actively developed against. Sequelize v7 is still in alpha upstream, so v6 is the line to build on for now, and if v7 lands this follows it. If you would rather build on Prisma, @imqueue/pg-prisma covers the same ground for that stack. Both are supported: pick the ORM you want to live with.
The query namespace and the serializable input types are what do it. Sequelize writes a filter with ES symbols as its operators, and a symbol cannot survive a JSON payload, so FilterInput, FieldsInput, PaginationInput and OrderByInput give the wire an equivalent that can. query.autoQuery turns them back into Sequelize options, and builds the include tree the requested fields imply — which is where the efficiency comes from: a field nobody asked for is not selected, and a relation nobody reached into is not joined.
database() builds and caches the connection and discovers your compiled model files. It is a process-wide singleton: the first call configures it, every later one hands back the same instance, and SQL logging that can prettify and colourise statements is installed along the way.
It is also the single import surface for the ORM stack, which is what most files in a service touch it for. Everything sequelize and sequelize-typescript export is re-exported here — Table, Column, DataType, AllowNull, ForeignKey, BelongsTo, HasMany, QueryInterface and the rest — so a model imports from one place rather than three, and several option types are widened on the way through (see ReturningOptions). A migration usually needs nothing but QueryInterface.
The decorators are the smallest part and the most opinionated: CreatedBy(), UpdatedBy() and DeletedBy() stamp the acting user from the RPC request context, AssociatedWith() declares a relation the query helpers can walk, and View and DynamicView let a model be a database view — a parameterised one, whose placeholders are filled in per query.
Example
// the shape every paginated read method in a service ends up with
const where = query.toWhereOptions(query.withRangeFilters(filter));
const rows = await LeadModel.findAll(query.autoQuery<FindOptions>(
LeadModel,
fields,
where,
query.toLimitOptions(pageOptions),
query.toOrderOptions(orderBy),
));
Classes
|
Class |
Description |
|---|---|
|
A range between two dates, as an | |
|
Which fields to return, nested to match the shape of the relations. | |
|
A where clause as plain, serializable JSON. | |
|
A directed, unweighted graph with depth-first traversal and cycle detection. | |
|
A free-form object, describable to | |
|
A range between two numbers, as an | |
|
Which columns to order by, and in which direction. | |
|
Where a page starts and how big it is. | |
|
Sequelize's own connection class, taught about views, column indices and the widened |
Abstract Classes
|
Abstract Class |
Description |
|---|---|
|
The class every model in an |
Enumerations
|
Enumeration |
Description |
|---|---|
|
The index methods Postgres offers, for ColumnIndexOptions.method. | |
|
The two directions a column can be ordered in. | |
|
Sort direction of an index key, for ColumnIndexOptions.order. |
Functions
|
Function |
Description |
|---|---|
|
Marks a field of a filter input as standing for an association rather than for a column. | |
|
Declares an index on a model column, with Postgres's own index options. | |
|
Declares a plain btree index on a model column. | |
|
Stamps the decorated column with the acting user id on INSERT, taken from the in-flight IMQ request metadata ( A property decorator, reusable on any model field. The hook is a no-op when there is no acting user (system / unattributed writes) and never overwrites a value the application set explicitly. Two hooks are registered, because rows are inserted in two ways: - instance / single Mechanism: a property decorator receives the prototype, but Sequelize hook decorators must target a static method on the constructor, so generated static methods are attached to | |
|
Connects to the database, loads the models, and returns the Sequelize instance. | |
|
Stamps the decorated column with the acting user id on soft-delete (and clears it on restore), taken from the in-flight IMQ request metadata ( A property decorator for paranoid models, reusable on any field. Soft-delete runs through The sibling UPDATE runs on
| |
|
Declares a model to be a view whose definition is parameterised per query. | |
|
Placeholder for change notifications, which are not implemented. | |
|
Reformats a SQL string for logging, when SQL_PRETTIFY is on. | |
|
Declares a pair of partial indices on a nullable column, one for the rows where it is null and one for the rows where it is not. | |
|
Declares the pair of partial indices with no options of their own. | |
|
Stamps the decorated column with the acting user id on INSERT and UPDATE, taken from the in-flight IMQ request metadata ( A property decorator, reusable on any model field. It mirrors Four hooks are registered, because models are written in four ways: - single INSERT → No-op when there is no acting user (system / unattributed writes). | |
|
Declares a model to be a database view rather than a table. |
Interfaces
|
Interface |
Description |
|---|---|
|
The clauses of the | |
|
One page of results together with the size of the whole set. | |
|
Sequelize's own find options, plus the parameters of a dynamic view. | |
|
Describes the association a filter field stands for. | |
|
Options for a view whose definition is parameterised. | |
|
Everything database() needs on its first call. | |
|
What a model's | |
|
The shape every range filter shares: a start and an end. | |
|
Sequelize's model options, plus the SQL that defines the view. | |
|
Sequelize's query interface, extended with view creation and removal. | |
|
Widens | |
|
Sequelize's own sync options, extended for views and column indices. | |
|
Values for a dynamic view's placeholders, keyed by placeholder name. | |
|
The shape sequelize's resolved include tree actually has, as this module reads it. |
Namespaces
|
Namespace |
Description |
|---|---|
|
Turns a caller's serialized query into Sequelize options, and back out as SQL. |
Variables
|
Variable |
Description |
|---|---|
|
| |
|
The | |
|
Maps each | |
|
The placeholder pattern as a source string: | |
|
MATCHER compiled to find every placeholder in a definition. | |
|
MATCHER compiled to pull the name out of a single placeholder. | |
|
Whether logged SQL carries ANSI colour. Off by default. | |
|
Whether logged SQL is reformatted across multiple lines. Off by default. |
Type Aliases
|
Type Alias |
Description |
|---|---|
|
Options for | |
|
Options for | |
|
Options for | |
|
The property decorator a decorator factory hands back. | |
|
Called once per vertex during a traversal. | |
|
A graph as adjacency lists: each vertex mapped to the vertices it points at. | |
|
Names a model class by the instance type it produces. | |
|
Replaces every member of | |
|
What NullableIndex accepts: every ColumnIndexOptions field except | |
|
Options for a raw | |
|
Options for an instance's | |
|
A sequelize | |
|
Options for the static | |
|
Options for |