# prorm

[![npm version](https://img.shields.io/npm/v/@mstone6969/prorm.svg?logo=npm)](https://www.npmjs.com/package/@mstone6969/prorm)
[![npm downloads](https://img.shields.io/npm/dm/@mstone6969/prorm.svg)](https://www.npmjs.com/package/@mstone6969/prorm)
[![license](https://img.shields.io/npm/l/@mstone6969/prorm.svg)](./LICENSE)
[![TypeScript](https://img.shields.io/badge/TypeScript-ready-3178C6.svg?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
[![pipeline status](https://gitlab.com/Malcolmston/prod-orm/badges/main/pipeline.svg)](https://gitlab.com/Malcolmston/prod-orm/-/pipelines)

A TypeScript ORM supporting multiple database dialects with full TypeScript support.

> Published on npm as **[`@mstone6969/prorm`](https://www.npmjs.com/package/@mstone6969/prorm)** — `npm install @mstone6969/prorm`

## Features

- **Multi-database support**: 14 dialects — SQLite, MySQL, PostgreSQL, MariaDB, Oracle, MSSQL, CockroachDB, Amazon Redshift, IBM Db2, Snowflake, ClickHouse, DuckDB, SAP HANA, Google Cloud Spanner
- **TypeScript-first**: Full TypeScript support with decorators
- **CRUD operations**: Full query builder with associations, scopes, transactions
- **Migrations**: Database versioning and seeding
- **Hooks**: Lifecycle events for models
- **Validation**: Built-in and custom validators
- **Stored Procedures**: Create and call stored procedures (across supported dialects)
- **Triggers**: Database triggers with FOR EACH ROW and WHEN clauses (across supported dialects)
- **Sequences**: Sequence support across all dialects
- **Table Partitions**: RANGE, LIST, HASH partitioning (across supported dialects)
- **Partial Indexes**: Conditional indexes for MySQL, MariaDB, PostgreSQL, Oracle, MSSQL
- **Row-Level Security (RLS)**: PostgreSQL, Oracle VPD, MSSQL Security Policies
- **Materialized Views**: With FAST/COMPLETE refresh (PostgreSQL, Oracle)
- **Views**: Database views support
- **Full-Text Search**: SQLite FTS5 and PostgreSQL full-text search
- **JSON/JSONB**: Native JSON data type support
- **Spatial Data**: PostGIS support for PostgreSQL
- **Foreign Data Wrappers**: PostgreSQL FDW support
- **User Management**: Database users and privileges (PostgreSQL, Oracle, MSSQL)
- **Connection Pooling**: Efficient connection pool management
- **Query Optimization**: Prepared statements, query hints, caching
- **Audit Logging**: Built-in audit trail functionality
- **Polymorphic Associations**: Built-in helpers for polymorphic relationships
- **Self-referential Associations**: Tree structure support

## Installation

```bash
npm install ts-prorm-orm
```

## Quick Start

```typescript
import { Prorm, DataTypes } from 'ts-prorm-orm';

const prorm = new Prorm({
  dialect: 'sqlite',
  storage: ':memory:',
  logging: console.log,
});

const User = prorm.define('User', {
  name: DataTypes.STRING,
  email: {
    type: DataTypes.STRING,
    validate: { isEmail: true },
  },
});

await prorm.sync();
const user = await User.create({ name: 'John', email: 'john@example.com' });
console.log(user.toJSON());
```

## Database type coverage

prorm spans **22 database types, each with at least 5 supported engines** — 27
SQL dialects and 102 NoSQL/data stores (129 engines). Full taxonomy:
[`docs/database-types.md`](./docs/database-types.md).

| Type | Engines |
|------|---------|
| Relational (OLTP) | SQLite, MySQL, PostgreSQL, MariaDB, Oracle, MSSQL, Db2, Firebird, Turso |
| Warehouse / OLAP | ClickHouse, DuckDB, Redshift, Snowflake, Vertica, Greenplum, Exasol, HANA, Databricks, Trino |
| NewSQL / distributed | CockroachDB, YugabyteDB, TiDB, SingleStore, Spanner |
| Document | MongoDB, Couchbase, RethinkDB, SurrealDB, ArangoDB |
| Key-value | Redis, Memcached, etcd, DynamoDB, Aerospike |
| Wide-column | Cassandra, ScyllaDB, Keyspaces, HBase, Bigtable |
| Graph | Neo4j, ArangoDB, TigerGraph, Neptune, Dgraph |
| Vector | Pinecone, Milvus, Qdrant, Weaviate, Chroma |
| Time-series | InfluxDB, TimescaleDB, QuestDB, Prometheus, VictoriaMetrics |
| Search | Elasticsearch, OpenSearch, Meilisearch, Typesense, Solr |
| Object storage | S3, GCS, Azure Blob, MinIO, Cloudflare R2 |
| Streaming / queue | Kafka, NATS, RabbitMQ, Pulsar, Redpanda |
| In-memory data grid | Hazelcast, Ignite, GridGain, Infinispan, Geode, Coherence |
| Embedded storage engine | RocksDB, LevelDB, LMDB, UnQLite, NeDB, PouchDB |
| Ledger / immutable | QLDB, immudb, BigchainDB, TerminusDB, Fluree, ProvenDB |
| Multi-model | Cosmos DB, FaunaDB, OrientDB, MarkLogic, Firestore, RavenDB |
| RDF / triplestore | Fuseki, GraphDB, Stardog, Blazegraph, Virtuoso, AllegroGraph |
| Real-time OLAP | Druid, Pinot, StarRocks, Doris, Rockset, Materialize |
| Cloud pub/sub | Kinesis, Event Hubs, Pub/Sub, SQS, SNS, EventStoreDB |
| Edge / serverless KV | Cloudflare KV, Vercel KV, Upstash, Deno KV, Momento, DAX |
| Job / task queue | Beanstalkd, Gearman, BullMQ, NSQ, Resque, Bee-Queue |
| Log / observability | Loki, Splunk, Graylog, Sumo Logic, SigNoz, Papertrail |

## Supported Dialects

| Dialect | Status | Features |
|---------|--------|-----------|
| SQLite | Stable | FTS5, CTEs, Window Functions, UPSERT |
| MySQL | Stable | Stored procedures, triggers, partitions |
| PostgreSQL | Stable | RLS, FDW, PostGIS, Sequences, Extensions |
| MariaDB | Stable | Stored procedures, triggers, virtual columns |
| Oracle | Stable | Sequences, stored procedures |
| MSSQL | Stable | Sequences, stored procedures, RLS |
| CockroachDB | Stable | Distributed SQL, Postgres wire protocol/driver (`pg`), horizontal scalability |
| Amazon Redshift | Stable | Postgres-derived cloud data warehouse (`pg` driver), DISTKEY/SORTKEY instead of indexes, no FK/unique enforcement |
| IBM Db2 | Stable | `ibm_db` driver, FETCH FIRST pagination, MERGE upsert |
| Snowflake | Stable | `snowflake-sdk` driver, VARIANT semi-structured type, warehouse-based compute, no traditional indexes |
| ClickHouse | Stable | `@clickhouse/client` driver, columnar OLAP, requires ENGINE clause on CREATE TABLE, no multi-statement transactions, no FK enforcement |
| DuckDB | Stable | `duckdb` driver, embedded/in-process OLAP (file or `:memory:`, no server), window functions, recursive CTEs, `LIST`/`STRUCT`/`MAP` types, direct Parquet/CSV/JSON table functions |
| SAP HANA | Stable | `hdb` driver, in-memory column-store tables, native `UPSERT ... WITH PRIMARY KEY`, `LIMIT n OFFSET m` pagination requiring a sentinel `LIMIT` |
| Google Cloud Spanner | Stable | `@google-cloud/spanner` driver (GoogleSQL), globally distributed with externally-consistent transactions, Mutation API for bulk/blind writes, `INSERT OR UPDATE` upsert syntax |

### Extended dialects

Twelve additional dialects subclass the nearest wire-compatible base dialect and
override the grammar / type-mapping that genuinely differs, reusing the base's
driver. Each has a dedicated page under [`docs/dialects/`](./docs/dialects/) and
a connection-free SQL-generation test suite (`tests/dialects/<name>*.test.ts`).

| Dialect | Base (driver) | Key differences |
|---------|---------------|-----------------|
| [TiDB](./docs/dialects/tidb.md) | MySQL (`mysql2`) | `AUTO_RANDOM`, `SHARD_ROW_ID_BITS`/`PRE_SPLIT_REGIONS`, `SPLIT TABLE` |
| [SingleStore](./docs/dialects/singlestore.md) | MySQL (`mysql2`) | `SHARD KEY`/`SORT KEY`, ROWSTORE/columnstore, REFERENCE tables, FK omitted |
| [Databricks](./docs/dialects/databricks.md) | MySQL (`mysql2`) | `USING DELTA`, `MERGE INTO` upsert, Spark types, `GENERATED ALWAYS AS IDENTITY` |
| [YugabyteDB](./docs/dialects/yugabytedb.md) | PostgreSQL (`pg`) | `SPLIT INTO TABLETS`, colocation, `HASH` primary keys, tablegroups |
| [TimescaleDB](./docs/dialects/timescaledb.md) | PostgreSQL (`pg`) | `create_hypertable`, compression/retention policies, continuous aggregates |
| [Greenplum](./docs/dialects/greenplum.md) | PostgreSQL (`pg`) | `DISTRIBUTED BY`, append-optimized storage, external tables, staging-table upsert |
| [Vertica](./docs/dialects/vertica.md) | PostgreSQL (`pg`) | `ORDER BY`/`SEGMENTED BY`, projections, `IDENTITY`, `LONG VARCHAR` |
| [Trino](./docs/dialects/trino.md) | PostgreSQL (`pg`) | `catalog.schema.table`, `WITH (format=…)`, CTAS, no PK/FK/index |
| [Exasol](./docs/dialects/exasol.md) | PostgreSQL (`pg`) | `DISTRIBUTE BY`, `IDENTITY`, `IMPORT`/`EXPORT`, MERGE upsert |
| [QuestDB](./docs/dialects/questdb.md) | PostgreSQL (`pg`) | designated `TIMESTAMP`, `PARTITION BY`, `SYMBOL`, `DEDUP` |
| [CrateDB](./docs/dialects/cratedb.md) | PostgreSQL (`pg`) | `CLUSTERED`/`PARTITIONED`, `OBJECT`/`ARRAY` types |
| [Firebird](./docs/dialects/firebird.md) | PostgreSQL (`pg`) | `FIRST`/`SKIP` paging, `GENERATED … IDENTITY`, generators |

> These dialect layers are verified at the SQL-generation level (connection-free
> tests); end-to-end execution against a live server of each engine is not part
> of the automated suite. See each page's "verification status" section.

## Diagrams

The [`src/diagrams`](./docs/diagrams/README.md) module renders standalone SVG
diagrams from schema data — 15 generators (model card, ER, migration, UML class,
crow's-foot relational, sequence, state, dependency graph, data-dictionary,
index map, flowchart, tree, Chen-ER, package, gantt) built on a shared
DOM-backed SVG builder with light/dark themes and configurable accent colours.

```ts
import { ModelDiagram } from '@mstone6969/prorm';

new ModelDiagram({
  name: 'User',
  fields: { id: { type: 'INTEGER', primaryKey: true }, email: { type: 'VARCHAR(255)', unique: true } },
  theme: 'dark',
  color: 'emerald',
}).save('./diagrams/User.svg');
```

See the [diagram module guide](./docs/diagrams/README.md) for every generator.

## NoSQL Stores

NoSQL engines don't share the SQL-shaped `Dialect` interface used above (no `query(sql)`, no identifier escaping, no DDL). Instead, each is its own store class under `src/nosql/<name>/`, exposing the operations that engine actually supports — see each store's README for full details.

| Store | Status | Features |
|-------|--------|-----------|
| MongoDB | Stable | `mongodb` driver, document CRUD, filters, aggregation pipeline, indexes, multi-document transactions (requires replica set) |
| Redis | Stable | `ioredis` driver, string/hash/list/set/sorted-set commands, pub/sub, pipelining/`MULTI`, no query language |
| Amazon DynamoDB | Stable | `@aws-sdk/client-dynamodb` + `@aws-sdk/lib-dynamodb`, partition/sort-key CRUD, Query/Scan, batch and transactional writes, no arbitrary queries |

```ts
import { MongoStore, RedisStore, DynamoDbStore } from '@mstone6969/prorm';

const mongo = new MongoStore({ uri: 'mongodb://localhost:27017', database: 'app' });
await mongo.connect();
await mongo.collection('users').insertOne({ name: 'Ada' });

const redis = new RedisStore({ host: 'localhost', port: 6379 });
await redis.connect();
await redis.set('session:1', 'active', { ex: 3600 });

const dynamo = new DynamoDbStore({ region: 'us-east-1' });
await dynamo.connect();
await dynamo.putItem('Users', { id: '1', name: 'Ada' });
```

### Object storage, streaming & additional stores

Twelve more adapters cover object storage, streaming/queues, wide-column,
document, cache, and search engines. Each **lazy-loads** its driver (none is a
hard dependency) and accepts an **injected client**, so it can be used and
unit-tested without the driver installed. Full pages under
[`docs/stores/`](./docs/stores/README.md).

| Store | Driver | Kind |
|-------|--------|------|
| [S3Store](./docs/stores/s3.md) | `@aws-sdk/client-s3` | Amazon S3 object storage |
| [GCSStore](./docs/stores/gcs.md) | `@google-cloud/storage` | Google Cloud Storage |
| [AzureBlobStore](./docs/stores/azure-blob.md) | `@azure/storage-blob` | Azure Blob Storage |
| [KafkaStore](./docs/stores/kafka.md) | `kafkajs` | Apache Kafka streaming |
| [NatsStore](./docs/stores/nats.md) | `nats` | NATS + JetStream KV |
| [RabbitMQStore](./docs/stores/rabbitmq.md) | `amqplib` | RabbitMQ / AMQP |
| [CassandraStore](./docs/stores/cassandra.md) | `cassandra-driver` | Apache Cassandra (CQL) |
| [CouchbaseStore](./docs/stores/couchbase.md) | `couchbase` | Couchbase (N1QL) |
| [MemcachedStore](./docs/stores/memcached.md) | `memjs` | Memcached cache |
| [SurrealStore](./docs/stores/surrealdb.md) | `surrealdb` | SurrealDB multi-model |
| [OpenSearchStore](./docs/stores/opensearch.md) | `@opensearch-project/opensearch` | OpenSearch |
| [RethinkDBStore](./docs/stores/rethinkdb.md) | `rethinkdb-ts` | RethinkDB |

```ts
import { S3Store, KafkaStore } from '@mstone6969/prorm';

const s3 = new S3Store({ region: 'us-east-1' });
await s3.connect();
await s3.putObject('bucket', 'hello.txt', 'hi');

const kafka = new KafkaStore({ clientId: 'app', brokers: ['localhost:9092'] });
await kafka.connect();
await kafka.produce('events', [{ value: JSON.stringify({ hello: 'world' }) }]);
```

## Usage Examples by Dialect

### SQLite

```typescript
import { Prorm, DataTypes } from 'ts-prorm-orm';

const prorm = new Prorm({
  dialect: 'sqlite',
  storage: './database.db',
});

// Define model with SQLite-specific features
const User = prorm.define('User', {
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  name: DataTypes.STRING,
  email: DataTypes.STRING(255),
  // SQLite supports virtual columns
  fullName: {
    type: DataTypes.VIRTUAL,
    get() {
      return `${this.name}`;
    }
  }
});

// Use FTS5 for full-text search
await prorm.query(`
  CREATE VIRTUAL TABLE IF NOT EXISTS users_fts USING fts5(
    name, email, content='users', content_rowid='id'
  )
`);

// Upsert (INSERT OR REPLACE)
await User.upsert({
  id: 1,
  name: 'John',
  email: 'john@example.com'
});
```

### MySQL

```typescript
import { Prorm, DataTypes } from 'ts-prorm-orm';

const prorm = new Prorm({
  dialect: 'mysql',
  host: 'localhost',
  port: 3306,
  database: 'mydb',
  username: 'root',
  password: 'password',
});

const User = prorm.define('User', {
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  name: DataTypes.STRING(100),
  email: {
    type: DataTypes.STRING(255),
    unique: true,
  },
  // MySQL JSON column
  preferences: DataTypes.JSON,
  // MySQL enum
  status: {
    type: DataTypes.ENUM('active', 'inactive', 'pending'),
    defaultValue: 'active',
  }
});

// Create stored procedure
await prorm.query(`
  CREATE PROCEDURE get_user_by_email(IN user_email VARCHAR(255))
  BEGIN
    SELECT * FROM users WHERE email = user_email;
  END
`);

// Call stored procedure
await prorm.query('CALL get_user_by_email(?)', {
  replacements: ['john@example.com']
});
```

### PostgreSQL

```typescript
import { Prorm, DataTypes } from 'ts-prorm-orm';

const prorm = new Prorm({
  dialect: 'postgres',
  host: 'localhost',
  port: 5432,
  database: 'mydb',
  username: 'postgres',
  password: 'password',
});

const User = prorm.define('User', {
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  name: DataTypes.STRING(100),
  email: {
    type: DataTypes.STRING(255),
    unique: true,
  },
  // PostgreSQL UUID
  uuid: {
    type: DataTypes.UUID,
    defaultValue: DataTypes.UUIDV4,
  },
  // PostgreSQL JSONB
  metadata: DataTypes.JSONB,
  // PostgreSQL array
  tags: DataTypes.ARRAY(DataTypes.STRING),
  // PostgreSQL hstore
  properties: DataTypes.HSTORE,
});

// Row-Level Security (RLS)
await prorm.query(`
  ALTER TABLE users ENABLE ROW LEVEL SECURITY
`);

await prorm.query(`
  CREATE POLICY users_policy ON users
  USING (user_id = current_user_id())
`);

// Full-text search
await prorm.query(`
  CREATE INDEX users_fts_idx ON users
  USING GIN (to_tsvector('english', name || ' ' || email))
`);

// Sequence example
await prorm.query(`
  CREATE SEQUENCE user_id_seq START WITH 1000
`);
```

### MariaDB

```typescript
import { Prorm, DataTypes } from 'ts-prorm-orm';

const prorm = new Prorm({
  dialect: 'mariadb',
  host: 'localhost',
  port: 3306,
  database: 'mydb',
  username: 'root',
  password: 'password',
});

const Product = prorm.define('Product', {
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  name: DataTypes.STRING(200),
  price: DataTypes.DECIMAL(10, 2),
  // MariaDB virtual column
  price_with_tax: {
    type: DataTypes.VIRTUAL,
    get() {
      return parseFloat(this.price) * 1.2;
    }
  },
  // MariaDB JSON
  attributes: DataTypes.JSON,
});

// Stored procedure
await prorm.query(`
  CREATE PROCEDURE get_products_by_price(IN min_price DECIMAL(10,2))
  BEGIN
    SELECT * FROM products WHERE price >= min_price;
  END
`);

await prorm.query('CALL get_products_by_price(?)', {
  replacements: [10.00]
});
```

### Oracle

```typescript
import { Prorm, DataTypes } from 'ts-prorm-orm';

const prorm = new Prorm({
  dialect: 'oracle',
  host: 'localhost',
  port: 1521,
  database: 'ORCL',
  username: 'system',
  password: 'password',
});

const Employee = prorm.define('Employee', {
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  name: DataTypes.STRING(100),
  email: DataTypes.STRING(255),
  // Oracle BLOB for binary data
  resume: DataTypes.BLOB,
  // Oracle CLOB for large text
  description: DataTypes.TEXT,
});

// Oracle sequence
await prorm.query(`
  CREATE SEQUENCE employee_seq START WITH 1000 INCREMENT BY 1
`);

// Stored procedure with OUT parameter
await prorm.query(`
  CREATE OR REPLACE PROCEDURE get_employee_count(
    p_count OUT NUMBER
  ) AS
  BEGIN
    SELECT COUNT(*) INTO p_count FROM employees;
  END;
`);
```

### MSSQL

```typescript
import { Prorm, DataTypes } from 'ts-prorm-orm';

const prorm = new Prorm({
  dialect: 'mssql',
  host: 'localhost',
  port: 1433,
  database: 'mydb',
  username: 'sa',
  password: 'password',
});

const Order = prorm.define('Order', {
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  customer_id: DataTypes.INTEGER,
  total: DataTypes.DECIMAL(10, 2),
  // MSSQL datetime2
  order_date: DataTypes.DATE,
  // MSSQL-specific geometry
  location: DataTypes.GEOMETRY('POINT'),
  // MSSQL XML
  details: DataTypes.XML,
});

// MSSQL sequence
await prorm.query(`
  CREATE SEQUENCE order_id_seq START WITH 1000 INCREMENT BY 1
`);

// Row-Level Security
await prorm.query(`
  CREATE SECURITY POLICY SalesFilter
  ADD FILTER PREDICATE dbo.fn_tenantAccessPredicate(TenantId)
  ON dbo.Sales
`);
```

## CLI Commands

```bash
# Generate a model
npm run model:generate -- --name User --attributes name:string,email:string

# Run migrations
npm run model:create

# Generate ER diagram
npm run diagram:model
```

## Documentation

Full documentation is available in the `docs/` directory:

- [Getting Started](./docs/) - Main documentation entry point
- [Dialects](./docs/dialects/) - Database-specific documentation
  - [SQLite](./docs/dialects/sqlite.md)
  - [MySQL](./docs/dialects/mysql.md)
  - [PostgreSQL](./docs/dialects/postgres.md)
  - [MariaDB](./docs/dialects/mariadb.md)
  - [Oracle](./docs/dialects/oracle.md)
  - [MSSQL](./docs/dialects/mssql.md)
- [API Reference](./docs/api/) - API documentation
  - [Models](./docs/api/models.md)
  - [Query Builder](./docs/api/queries.md)
  - [Hooks](./docs/api/hooks.md)
  - [Associations](./docs/api/associations.md)

Additional documentation:
- [Models](./docs/MODELS.md) - Model definition
- [Migrations](./docs/MIGRATIONS.md) - Database migrations
- [Associations](./docs/ASSOCIATIONS.md) - Relationship types
- [Hooks](./docs/HOOKS.md) - Lifecycle hooks
- [Stored Procedures](./docs/STORED_PROCEDURES.md) - Advanced database features
- [Triggers](./docs/TRIGGERS.md) - Database triggers

### Architecture / Component Guides

In-depth, code-level reference docs for each major subsystem, living alongside the source under `src/`:

- [Dialects](src/dialects/README.md) - The `Dialect` interface and per-database (SQLite/MySQL/PostgreSQL/MariaDB/Oracle/MSSQL/CockroachDB/Redshift/Db2/Snowflake/ClickHouse/DuckDB/HANA/Spanner) implementations of connections, DDL, views, partitioning, RLS, and query building.
- [Models](src/models/README.md) - The model layer: attribute/data types, `prorm.define()`, associations, scopes, indexes/constraints, and the model registry.
- [Query Builders](src/query-builders/README.md) - Translates `where`/`order`/`limit`/`include` options into dialect-specific SQL strings and bound parameter values. Includes a typed SQL function-builder library (`src/query-builders/functions/**` - window functions, date/time, JSON paths, string/math functions, CASE expressions, cross-dialect aggregates, full-text search) usable via `import { ... } from 'ts-prorm-orm'`; see [SQL Functions](docs/query-features/queries.md#sql-functions) for worked examples.
- [Extension Catalog](src/extensions/README.md) - A discoverability reference (not executable code) of ~124 verified real extensions/plugins/licensed features across dialects, queryable via `findExtension()`/`listExtensionsForDialect()`/`listExtensionsByCategory()`/`searchExtensions()`.
- [Query Optimizers](src/query-optimizers/README.md) - Opt-in performance tooling (query hints, explain plans, slow-query logging, batch optimization, prepared-statement/result caching).
- [Migrations](src/migrations/README.md) - Migration files, the `Migrator`, `PrormMeta` history tracking, seeders, `QueryInterface`, and schema diffing (`src/schema/`).
- [Compliance](src/compliance/README.md) - GDPR/privacy/security tooling layered on the ORM core: DSAR workflows, right to erasure, consent tracking, and the composite `@Security` decorator.
- [Decorators](src/decorators/README.md) - TypeScript decorator API for defining models (`@Table`, `@Column`, etc.) plus a larger set of feature decorators for constraints, associations, and dialect-specific column types.
- [Connections, Transactions & Hooks](src/CONNECTIONS.md) - Connection pooling, connection/replica management, transactions, and the lifecycle hooks manager.
- [CLI Tooling](src/cli/README.md) - Reference for the multiple (non-unified) CLI entry points for model generation, migrations, seeding, and diagrams.
- [Utilities](src/UTILITIES.md) - Supporting modules: error hierarchy, validators, logging, audit logging, caching, diagram generation, streams, foreign-data helpers, and user management.

Online documentation: [GitLab Pages](https://malcolmston.gitlab.io/prod-orm)

## License

MIT