@memberjunction/postgresql-dataprovider
v5.33.0
Published
MemberJunction: PostgreSQL Data Provider
Downloads
3,050
Maintainers
Keywords
Readme
@memberjunction/postgresql-dataprovider
Overview
Full-featured PostgreSQL data provider for MemberJunction. This package implements DatabaseProviderBase from @memberjunction/core to provide a complete PostgreSQL backend for MemberJunction applications. It also includes a CodeGen provider for generating PostgreSQL-native database objects (views, PL/pgSQL functions, triggers, indexes, full-text search, and more).
Key capabilities:
- Connection pooling via
pg.Poolwith configurable min/max connections - Transaction support with BEGIN/COMMIT/ROLLBACK and variable dependencies between items
- Parameterized queries using PostgreSQL
$1, $2, ...positional parameters - Full CRUD operations through generated PL/pgSQL functions
- CodeGen provider that produces PostgreSQL-native DDL from MemberJunction metadata
- Type conversion for booleans, dates, UUIDs, numbers, and binary data
- Pluggable cache backend inherited from
GenericDatabaseProvider— default in-memory, with optional Redis support for shared, persistent caching
Architecture
Class Hierarchy
DatabaseProviderBase (@memberjunction/core)
└── PostgreSQLDataProvider
├── PGConnectionManager (connection pooling)
├── PGQueryParameterProcessor (type conversion)
└── PostgreSQLTransactionGroup (transaction support)
CodeGenDatabaseProvider (@memberjunction/codegen-lib)
└── PostgreSQLCodeGenProvider (DDL generation)
└── PostgreSQLCodeGenConnection (query execution)Source Files
| File | Purpose |
|------|---------|
| PostgreSQLDataProvider.ts | Main provider: CRUD, queries, view execution, dataset handling, caching |
| pgConnectionManager.ts | Connection pool lifecycle with pg.Pool, shared pool support |
| queryParameterProcessor.ts | Boolean, date, UUID, number, and binary type conversion |
| types.ts | PostgreSQLProviderConfigData and PostgreSQLProviderConfigOptions interfaces |
| PostgreSQLTransactionGroup.ts | BEGIN/COMMIT/ROLLBACK with variable dependencies between transaction items |
| codegen/PostgreSQLCodeGenProvider.ts | CodeGen: views, CRUD functions, triggers, indexes, FTS, permissions |
| codegen/PostgreSQLCodeGenConnection.ts | Translates @ParamName notation to $N positional parameters |
Configuration
Connection Configuration
interface PGConnectionConfig {
Host: string;
Port?: number; // Default: 5432
Database: string;
User: string;
Password: string;
SSL?: boolean | pg.ConnectionConfig['ssl'];
MaxConnections?: number; // Default: 20
MinConnections?: number; // Default: 2
IdleTimeoutMillis?: number; // Default: 30000
ConnectionTimeoutMillis?: number; // Default: 30000
MJCoreSchemaName?: string; // Default: '__mj'
}Provider Configuration
The PostgreSQLProviderConfigData class wraps the connection config and adds MemberJunction-specific options:
const configData = new PostgreSQLProviderConfigData(
connectionConfig, // PGConnectionConfig
'__mj', // MJCoreSchemaName (default: '__mj')
0, // CheckRefreshIntervalSeconds (0 = disabled)
['public', '__mj'], // includeSchemas (optional)
[], // excludeSchemas (optional)
true // ignoreExistingMetadata (default: true)
);Environment Variables
For CodeGen shell execution (psql):
PGHOST-- PostgreSQL server hostPGPORT-- PostgreSQL server portPGDATABASE-- Database namePGUSER-- UsernamePGPASSWORD-- Password (or use.pgpassfile)
Usage
Basic Setup
import { PostgreSQLDataProvider } from '@memberjunction/postgresql-dataprovider';
const provider = new PostgreSQLDataProvider();
await provider.Config(new PostgreSQLProviderConfigData(
{
Host: 'localhost',
Port: 5432,
Database: 'memberjunction',
User: 'mj_user',
Password: 'secret',
MJCoreSchemaName: '__mj'
},
'__mj'
));Running Queries
// Execute raw SQL with positional parameters
const result = await provider.ExecuteSQL<MyType>(
'SELECT * FROM __mj."User" WHERE "ID" = $1',
[$userId]
);
// Run views (MJ pattern)
const results = await provider.InternalRunView<UserEntity>({
EntityName: 'Users',
ExtraFilter: "Status='Active'",
OrderBy: 'Name',
MaxRows: 100
});Transactions
const txGroup = await provider.CreateTransactionGroup();
// Add operations to the transaction group...
await txGroup.Submit(); // Executes all items in a single BEGIN/COMMIT blockThe PostgreSQLTransactionGroup supports variable dependencies between transaction items, allowing later items to reference values produced by earlier items in the same transaction.
Nested transactions (SAVEPOINTs)
BeginTransaction() / CommitTransaction() / RollbackTransaction() support arbitrary nesting that mirrors the SQLServerDataProvider's depth/savepoint-stack model:
| Depth | Begin emits | Commit emits | Rollback emits |
|---|---|---|---|
| 1 (outermost) | BEGIN on a fresh client | COMMIT + release client | ROLLBACK + release client |
| 2+ (nested) | SAVEPOINT mj_sp_<n> | RELEASE SAVEPOINT mj_sp_<n> | ROLLBACK TO SAVEPOINT mj_sp_<n> + RELEASE SAVEPOINT |
await provider.BeginTransaction(); // BEGIN; depth=1
await provider.BeginTransaction(); // SAVEPOINT mj_sp_1; depth=2
// ...do work...
await provider.RollbackTransaction(); // ROLLBACK TO + RELEASE mj_sp_1; depth=1
await provider.CommitTransaction(); // COMMIT; depth=0Use provider.TransactionDepth to inspect the current nesting depth (0 = no active transaction). If COMMIT or ROLLBACK itself fails at depth 1, the provider force-releases the client to avoid leaking a poisoned connection back to the pool.
Connection Pool Sharing
The PGConnectionManager supports shared pools for scenarios where multiple provider instances need to share a single connection pool (e.g., per-request providers):
// Primary provider creates the pool
const primary = new PGConnectionManager();
await primary.Initialize(config);
// Per-request providers share the pool (won't close it on Close())
const perRequest = new PGConnectionManager();
perRequest.InitializeWithExistingPool(primary.Pool, config);CodeGen Provider
What It Generates
The PostgreSQLCodeGenProvider generates PostgreSQL-native database objects during the MemberJunction code generation process:
- Base Views --
CREATE OR REPLACE VIEWwith joins and soft-delete filtering - CRUD Functions -- PL/pgSQL functions (not stored procedures) with
RETURNINGclause - Timestamp Triggers -- PL/pgSQL trigger functions for automatic
__mj_UpdatedAtmaintenance - Foreign Key Indexes --
CREATE INDEX IF NOT EXISTSwith 63-character name limit enforcement - Full-Text Search -- tsvector columns, GIN indexes, PL/pgSQL trigger for auto-update, and search functions
- Cascade Deletes -- Recursive delete/update-to-NULL operations for related records
- Permissions -- GRANT statements per entity role
- Drop Guards --
DROP ... IF EXISTS ... CASCADEstatements before object creation
Key PostgreSQL-Specific Patterns
- Uses PL/pgSQL
CREATE OR REPLACE FUNCTIONinstead of SQL Server stored procedures - Functions return query results via
RETURNS TABLE(...)orRETURNS SETOF - Uses dollar-quoted strings (
$$...$$) for function bodies - Implements
LATERALjoins instead of SQL Server'sOUTER APPLY - Full-text search uses
tsvector/tsquerywith GIN indexes (notCONTAINSTABLE) - Index names are truncated to 63 characters to respect the PostgreSQL identifier limit
- Boolean columns use native
true/falseinstead of SQL Server's1/0 - Uses
LIMIT/OFFSETfor pagination instead ofTOP/OFFSET-FETCH - Identifier quoting uses
"double quotes"instead of SQL Server's[brackets]
Registration
The CodeGen provider is registered via the MemberJunction class factory:
@RegisterClass(CodeGenDatabaseProvider, 'PostgreSQLCodeGenProvider')
export class PostgreSQLCodeGenProvider extends CodeGenDatabaseProvider { ... }Relationship to Other Packages
@memberjunction/sql-dialect
- Provides
PostgreSQLDialectfor identifier quoting, pagination syntax, and type mapping - Used by both
PostgreSQLDataProviderandPostgreSQLCodeGenProvider - Zero-dependency abstraction layer shared across all database-specific code
@memberjunction/codegen-lib
- Provides
CodeGenDatabaseProviderabstract base class with ~55 methods PostgreSQLCodeGenProviderimplements all abstract methods with PostgreSQL-native SQL- The CodeGen orchestration layer calls these methods to generate DDL during code generation runs
@memberjunction/core
- Provides
DatabaseProviderBaseabstract class defining the full MJ data provider contract PostgreSQLDataProviderimplements CRUD, view execution, dataset operations, and metadata access
@memberjunction/global
- Provides
@RegisterClassfor class factory registration PostgreSQLCodeGenProviderregisters itself so the CodeGen system can discover it at runtime
Dependencies
| Package | Purpose |
|---------|---------|
| @memberjunction/core | Base provider interfaces and entity framework |
| @memberjunction/codegen-lib | CodeGen base class and orchestration types |
| @memberjunction/sql-dialect | SQL dialect abstraction (quoting, pagination, types) |
| @memberjunction/global | Class registration via @RegisterClass |
| pg | PostgreSQL Node.js driver (connection pooling, queries) |
Testing
cd packages/PostgreSQLDataProvider
npm run test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # Coverage reportTests use Vitest with mocked database connections (no live database required).
Platform Key
The provider identifies itself with PlatformKey: 'postgresql', which is used throughout MemberJunction to select the correct SQL dialect, CodeGen templates, and runtime behavior for PostgreSQL deployments.
