Skip to content

@memberjunction/postgresql-dataprovider

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.Pool with 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
DatabaseProviderBase (@memberjunction/core)
└── PostgreSQLDataProvider
├── PGConnectionManager (connection pooling)
├── PGQueryParameterProcessor (type conversion)
└── PostgreSQLTransactionGroup (transaction support)
CodeGenDatabaseProvider (@memberjunction/codegen-lib)
└── PostgreSQLCodeGenProvider (DDL generation)
└── PostgreSQLCodeGenConnection (query execution)
FilePurpose
PostgreSQLDataProvider.tsMain provider: CRUD, queries, view execution (supports both OFFSET StartRow and keyset AfterKey pagination — see KEYSET_PAGINATION_GUIDE.md), dataset handling, caching
pgConnectionManager.tsConnection pool lifecycle with pg.Pool, shared pool support
queryParameterProcessor.tsBoolean, date, UUID, number, and binary type conversion
types.tsPostgreSQLProviderConfigData and PostgreSQLProviderConfigOptions interfaces
PostgreSQLTransactionGroup.tsBEGIN/COMMIT/ROLLBACK with variable dependencies between transaction items
codegen/PostgreSQLCodeGenProvider.tsCodeGen: views, CRUD functions, triggers, indexes, FTS, permissions
codegen/PostgreSQLCodeGenConnection.tsTranslates @ParamName notation to $N positional parameters
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'
}

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)
);

For CodeGen shell execution (psql):

  • PGHOST — PostgreSQL server host
  • PGPORT — PostgreSQL server port
  • PGDATABASE — Database name
  • PGUSER — Username
  • PGPASSWORD — Password (or use .pgpass file)
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'
));
// 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
});
const txGroup = await provider.CreateTransactionGroup();
// Add operations to the transaction group...
await txGroup.Submit(); // Executes all items in a single BEGIN/COMMIT block

The PostgreSQLTransactionGroup supports variable dependencies between transaction items, allowing later items to reference values produced by earlier items in the same transaction.

BeginTransaction() / CommitTransaction() / RollbackTransaction() support arbitrary nesting that mirrors the SQLServerDataProvider’s depth/savepoint-stack model:

DepthBegin emitsCommit emitsRollback emits
1 (outermost)BEGIN on a fresh clientCOMMIT + release clientROLLBACK + 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=0

Use 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.

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);

The PostgreSQLCodeGenProvider generates PostgreSQL-native database objects during the MemberJunction code generation process:

  • Base ViewsCREATE OR REPLACE VIEW with joins and soft-delete filtering
  • CRUD Functions — PL/pgSQL functions (not stored procedures) with RETURNING clause
  • Timestamp Triggers — PL/pgSQL trigger functions for automatic __mj_UpdatedAt maintenance
  • Foreign Key IndexesCREATE INDEX IF NOT EXISTS with 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 GuardsDROP ... IF EXISTS ... CASCADE statements before object creation
  • Uses PL/pgSQL CREATE OR REPLACE FUNCTION instead of SQL Server stored procedures
  • Functions return query results via RETURNS TABLE(...) or RETURNS SETOF
  • Uses dollar-quoted strings ($$...$$) for function bodies
  • Implements LATERAL joins instead of SQL Server’s OUTER APPLY
  • Full-text search uses tsvector/tsquery with GIN indexes (not CONTAINSTABLE)
  • Index names are truncated to 63 characters to respect the PostgreSQL identifier limit
  • Boolean columns use native true/false instead of SQL Server’s 1/0
  • Uses LIMIT/OFFSET for pagination instead of TOP/OFFSET-FETCH
  • Identifier quoting uses "double quotes" instead of SQL Server’s [brackets]

The CodeGen provider is registered via the MemberJunction class factory:

@RegisterClass(CodeGenDatabaseProvider, 'PostgreSQLCodeGenProvider')
export class PostgreSQLCodeGenProvider extends CodeGenDatabaseProvider { ... }
  • Provides PostgreSQLDialect for identifier quoting, pagination syntax, and type mapping
  • Used by both PostgreSQLDataProvider and PostgreSQLCodeGenProvider
  • Zero-dependency abstraction layer shared across all database-specific code
  • Provides CodeGenDatabaseProvider abstract base class with ~55 methods
  • PostgreSQLCodeGenProvider implements all abstract methods with PostgreSQL-native SQL
  • The CodeGen orchestration layer calls these methods to generate DDL during code generation runs
  • Provides DatabaseProviderBase abstract class defining the full MJ data provider contract
  • PostgreSQLDataProvider implements CRUD, view execution, dataset operations, and metadata access
  • Provides @RegisterClass for class factory registration
  • PostgreSQLCodeGenProvider registers itself so the CodeGen system can discover it at runtime
PackagePurpose
@memberjunction/coreBase provider interfaces and entity framework
@memberjunction/codegen-libCodeGen base class and orchestration types
@memberjunction/sql-dialectSQL dialect abstraction (quoting, pagination, types)
@memberjunction/globalClass registration via @RegisterClass
pgPostgreSQL Node.js driver (connection pooling, queries)
Terminal window
cd packages/PostgreSQLDataProvider
npm run test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # Coverage report

Tests use Vitest with mocked database connections (no live database required).

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.