CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-pg

PostgreSQL client library for Node.js with both pure JavaScript and optional native libpq bindings

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

types.mddocs/

Type System

The pg type system provides comprehensive data conversion between JavaScript and PostgreSQL types, with support for custom type parsers, extensible type handling, and both text and binary format support.

Capabilities

Type Parser Management

The main types object provides global type parser configuration.

/**
 * Global type parser registry from pg-types module
 * Handles conversion between PostgreSQL and JavaScript types
 */
interface types {
  /**
   * Get the parser function for a PostgreSQL type
   * @param oid - PostgreSQL type OID
   * @param format - Format ('text' or 'binary', default 'text')
   * @returns Parser function that converts string to JavaScript type
   */
  getTypeParser(oid: number, format?: string): (value: string) => any;
  
  /**
   * Set a custom parser for a PostgreSQL type
   * @param oid - PostgreSQL type OID
   * @param format - Format ('text' or 'binary')
   * @param parseFn - Parser function
   */
  setTypeParser(oid: number, format: string, parseFn: (value: string) => any): void;
  
  /**
   * Set a custom parser for a PostgreSQL type (defaults to text format)
   * @param oid - PostgreSQL type OID
   * @param parseFn - Parser function
   */
  setTypeParser(oid: number, parseFn: (value: string) => any): void;
}

Usage Examples:

const { types } = require('pg');

// Get existing parser
const dateParser = types.getTypeParser(1082, 'text');
console.log(dateParser('2023-12-25')); // Parsed date

// Set custom date parser to return Date objects
types.setTypeParser(1082, (val) => new Date(val));

// Set custom JSON parser with error handling
types.setTypeParser(114, (val) => {
  try {
    return JSON.parse(val);
  } catch (err) {
    console.warn('Invalid JSON:', val);
    return val;
  }
});

// Binary format parser
types.setTypeParser(17, 'binary', (val) => {
  return Buffer.from(val, 'hex');
});

// Numeric type with precision handling
types.setTypeParser(1700, (val) => {
  return parseFloat(val);
});

TypeOverrides Class

Per-client type parser overrides for customized type handling.

/**
 * Client-specific type parser overrides
 * Simple container for text and binary type parsers
 */
function TypeOverrides(userTypes) {
  this.text = userTypes || {};
  this.binary = userTypes || {};
}

TypeOverrides.prototype.setTypeParser = function(oid, format, parseFn) {
  if (typeof format === 'function') {
    parseFn = format;
    format = 'text';
  }
  this[format][oid] = parseFn;
};

TypeOverrides.prototype.getTypeParser = function(oid, format) {
  format = format || 'text';
  return this[format][oid];
};

Usage Examples:

const { TypeOverrides } = require('pg');

// Create client-specific type overrides
const customTypes = new TypeOverrides();

// Override date parsing for this client only
customTypes.setTypeParser(1082, (val) => {
  const date = new Date(val);
  return date.toISOString().split('T')[0]; // Return YYYY-MM-DD format
});

// Use with client
const client = new Client({
  // ... connection config
  types: customTypes
});

// Override JSON parsing with custom reviver
const apiTypes = new TypeOverrides();
apiTypes.setTypeParser(114, (val) => {
  return JSON.parse(val, (key, value) => {
    // Convert ISO date strings to Date objects
    if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(value)) {
      return new Date(value);
    }
    return value;
  });
});

const apiClient = new Client({
  // ... connection config
  types: apiTypes
});

Common PostgreSQL Type OIDs

Reference for common PostgreSQL type identifiers (use these numeric values when setting custom parsers).

// Numeric types
types.setTypeParser(21, parseFn);    // smallint (INT2)
types.setTypeParser(23, parseFn);    // integer (INT4)
types.setTypeParser(20, parseFn);    // bigint (INT8)
types.setTypeParser(700, parseFn);   // real (FLOAT4)
types.setTypeParser(701, parseFn);   // double precision (FLOAT8)
types.setTypeParser(1700, parseFn);  // numeric/decimal (NUMERIC)

// String types
types.setTypeParser(18, parseFn);    // char (CHAR)
types.setTypeParser(1043, parseFn);  // varchar (VARCHAR)
types.setTypeParser(25, parseFn);    // text (TEXT)
types.setTypeParser(19, parseFn);    // name (NAME)

// Date/time types
types.setTypeParser(1082, parseFn);  // date (DATE)
types.setTypeParser(1083, parseFn);  // time (TIME)
types.setTypeParser(1114, parseFn);  // timestamp without timezone (TIMESTAMP)
types.setTypeParser(1184, parseFn);  // timestamp with timezone (TIMESTAMPTZ)
types.setTypeParser(1186, parseFn);  // interval (INTERVAL)

// Other common types
types.setTypeParser(17, parseFn);    // bytea (BYTEA)
types.setTypeParser(16, parseFn);    // boolean (BOOL)
types.setTypeParser(114, parseFn);   // json (JSON)
types.setTypeParser(3802, parseFn);  // jsonb (JSONB)
types.setTypeParser(2950, parseFn);  // uuid (UUID)

// Array types
types.setTypeParser(1007, parseFn);  // integer[] (INT4_ARRAY)
types.setTypeParser(1009, parseFn);  // text[] (TEXT_ARRAY)

Usage Examples:

// Custom UUID parser
types.setTypeParser(2950, (val) => val.toUpperCase());

// Custom JSONB parser
types.setTypeParser(3802, (val) => JSON.parse(val));

// Custom timestamp parser
types.setTypeParser(1184, (val) => new Date(val));

// Array type parsing
types.setTypeParser(1007, (val) => {
  // Parse PostgreSQL array format: {1,2,3}
  return val.slice(1, -1).split(',').map(Number);
});

types.setTypeParser(1009, (val) => {
  // Handle quoted strings in arrays: {"hello","world"}
  return val.slice(1, -1).split(',').map(s => s.replace(/^"|"$/g, ''));
});

Built-in Type Conversions

Standard type conversions provided by pg-types.

/**
 * Default type conversions applied by pg
 * These can be overridden using setTypeParser
 */
interface DefaultTypeConversions {
  // Numeric conversions
  smallint: number;        // INT2 -> number
  integer: number;         // INT4 -> number  
  bigint: string;          // INT8 -> string (to avoid precision loss)
  real: number;            // FLOAT4 -> number
  double: number;          // FLOAT8 -> number
  numeric: string;         // NUMERIC -> string (preserves precision)
  
  // String conversions
  char: string;            // CHAR -> string
  varchar: string;         // VARCHAR -> string
  text: string;            // TEXT -> string
  
  // Date/time conversions
  date: string;            // DATE -> 'YYYY-MM-DD'
  time: string;            // TIME -> 'HH:MM:SS'
  timestamp: string;       // TIMESTAMP -> 'YYYY-MM-DD HH:MM:SS'
  timestamptz: string;     // TIMESTAMPTZ -> ISO string
  interval: string;        // INTERVAL -> PostgreSQL interval format
  
  // Other conversions
  boolean: boolean;        // BOOL -> boolean
  bytea: Buffer;           // BYTEA -> Buffer
  json: string;            // JSON -> string (not parsed)
  jsonb: string;           // JSONB -> string (not parsed)
  uuid: string;            // UUID -> string
}

Custom Type Parser Examples

Common patterns for implementing custom type parsers.

/**
 * Example custom parsers for common use cases
 */

Usage Examples:

// Parse bigint as number (with precision loss warning)
types.setTypeParser(20, (val) => {
  const num = parseInt(val, 10);
  if (num > Number.MAX_SAFE_INTEGER) {
    console.warn('Bigint value exceeds JavaScript safe integer range');
  }
  return num;
});

// Parse numeric/decimal with precision
types.setTypeParser(1700, (val) => {
  // Use decimal.js for precision
  const Decimal = require('decimal.js');
  return new Decimal(val);
});

// Parse timestamps as Date objects with timezone handling
types.setTypeParser(1114, (val) => {
  // Timestamp without timezone - assume UTC
  return new Date(val + 'Z');
});

types.setTypeParser(1184, (val) => {
  // Timestamp with timezone
  return new Date(val);
});

// Parse intervals as duration objects
types.setTypeParser(1186, (val) => {
  // Parse PostgreSQL interval format
  const match = val.match(/(\d+):(\d+):(\d+)/);
  if (match) {
    return {
      hours: parseInt(match[1], 10),
      minutes: parseInt(match[2], 10),
      seconds: parseInt(match[3], 10)
    };
  }
  return val;
});

// Parse JSON/JSONB automatically
types.setTypeParser(114, JSON.parse);   // json
types.setTypeParser(3802, JSON.parse);  // jsonb

// Parse arrays with proper handling
types.setTypeParser(1007, (val) => {
  // integer[] parser
  if (val === '{}') return [];
  return val.slice(1, -1).split(',').map(v => v === 'NULL' ? null : parseInt(v, 10));
});

// Parse UUIDs with validation
types.setTypeParser(2950, (val) => {
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
  if (!uuidRegex.test(val)) {
    throw new Error(`Invalid UUID format: ${val}`);
  }
  return val.toLowerCase();
});

// Parse network addresses
types.setTypeParser(869, (val) => {  // inet
  return {
    address: val.split('/')[0],
    netmask: val.split('/')[1] ? parseInt(val.split('/')[1], 10) : 32
  };
});

Type Parser Debugging

Utilities for debugging and inspecting type parsing.

/**
 * Debug utilities for type system
 */

Usage Examples:

// Log all registered parsers
function debugTypeParsers() {
  const { types } = require('pg');
  
  // Common type OIDs to check
  const typeOIDs = [16, 17, 20, 21, 23, 25, 114, 1082, 1114, 1184, 1700, 2950, 3802];
  
  typeOIDs.forEach(oid => {
    const textParser = types.getTypeParser(oid, 'text');
    const binaryParser = types.getTypeParser(oid, 'binary');
    console.log(`OID ${oid}: text=${textParser.name || 'anonymous'}, binary=${binaryParser.name || 'anonymous'}`);
  });
}

// Test type parsing
function testTypeParser(oid, testValue) {
  const { types } = require('pg');
  const parser = types.getTypeParser(oid, 'text');
  
  try {
    const result = parser(testValue);
    console.log(`OID ${oid}: "${testValue}" -> ${typeof result} ${JSON.stringify(result)}`);
    return result;
  } catch (err) {
    console.error(`OID ${oid}: Error parsing "${testValue}":`, err.message);
    return null;
  }
}

// Usage
debugTypeParsers();
testTypeParser(1082, '2023-12-25');
testTypeParser(114, '{"key": "value"}');
testTypeParser(20, '9223372036854775807');

Type System Configuration

/**
 * Configuration interfaces for type system
 */
interface TypeSystemConfig {
  /** Global types object */
  types: types;
  /** Client-specific overrides */
  TypeOverrides: typeof TypeOverrides;
  /** Common type OID constants */
  oids: { [typeName: string]: number };
}

/**
 * Type parser function signature
 */
type TypeParser<T = any> = (value: string) => T;

/**
 * Type override map
 */
interface TypeOverrideMap {
  [oid: number]: TypeParser;
}

Install with Tessl CLI

npx tessl i tessl/npm-pg

docs

client.md

connection-string.md

cursor.md

index.md

pool.md

query-stream.md

query.md

types.md

utilities.md

tile.json