ParqueDB
API Reference

ParqueDB Class

Main entry point for interacting with ParqueDB. Provides explicit namespace-based methods and proxy-based collection access.

The ParqueDB class is the main entry point for interacting with ParqueDB. It provides both explicit namespace-based methods and proxy-based collection access.

Constructor

new ParqueDB(config: ParqueDBConfig)

ParqueDBConfig

PropertyTypeRequiredDescription
storageStorageBackendYesStorage backend for data persistence
schemaSchemaNoSchema definition for entity validation
defaultNamespacestringNoDefault namespace for operations
snapshotConfigSnapshotConfigNoConfiguration for automatic snapshots

SnapshotConfig

PropertyTypeDescription
autoSnapshotThresholdnumberAutomatically create snapshot after this many events

Example

import { ParqueDB, MemoryBackend } from 'parquedb'

const db = new ParqueDB({
  storage: new MemoryBackend(),
  schema: {
    Post: {
      $ns: 'posts',
      title: 'string!',
      content: 'text',
      author: '-> User.posts',
    },
    User: {
      $ns: 'users',
      email: 'email!',
      posts: '<- Post.author[]',
    },
  },
  snapshotConfig: {
    autoSnapshotThreshold: 100,
  },
})

Collection Access

ParqueDB supports two patterns for accessing collections:

Explicit Collection Access

// Get a collection by namespace
const posts = db.collection('posts')
await posts.find({ status: 'published' })

// Or use namespace-based methods directly
await db.find('posts', { status: 'published' })

Proxy-based Collection Access

// Access collections as properties (PascalCase or lowercase)
await db.Posts.find({ status: 'published' })
await db.Users.get('users/123')

Core Methods

registerSchema

Register a schema for validation. Schemas define entity types, field types, and relationships.

registerSchema(schema: Schema): void

Parameters

NameTypeDescription
schemaSchemaSchema definition object

Example

db.registerSchema({
  Post: {
    $ns: 'posts',
    title: 'string!',
    content: 'text',
    status: 'string = "draft"',
    author: '-> User.posts',
  },
})

collection

Get a typed collection interface for a namespace.

collection<T = Record<string, unknown>>(namespace: string): Collection<T>

Parameters

NameTypeDescription
namespacestringCollection namespace (e.g., 'posts', 'users')

Returns

Collection<T> - A collection interface with find, get, create, update, and delete methods.

Example

interface Post {
  title: string
  content: string
  status: 'draft' | 'published'
}

const posts = db.collection<Post>('posts')
const result = await posts.find({ status: 'published' })

find

Find entities matching a filter.

find<T = Record<string, unknown>>(
  namespace: string,
  filter?: Filter,
  options?: FindOptions
): Promise<PaginatedResult<Entity<T>>>

Parameters

NameTypeDescription
namespacestringTarget namespace
filterFilterMongoDB-style filter (optional)
optionsFindOptionsQuery options (optional)

FindOptions

PropertyTypeDescription
sortSortSpecSort order (e.g., { createdAt: -1 })
limitnumberMaximum number of results
skipnumberNumber of results to skip
cursorstringCursor for pagination
projectProjectionField projection
populatePopulateSpecPopulate related entities
includeDeletedbooleanInclude soft-deleted entities
asOfDateTime-travel: query as of specific time
explainbooleanExplain query plan without executing
hintstring | objectHint for index to use
maxTimeMsnumberMaximum time in milliseconds

Returns

interface PaginatedResult<T> {
  items: T[]
  total?: number
  nextCursor?: string
  hasMore: boolean
}

Examples

// Simple filter
const result = await db.find('posts', { status: 'published' })

// With operators
const result = await db.find('posts', {
  score: { $gte: 100 },
  status: { $in: ['published', 'featured'] },
})

// With pagination and sorting
const result = await db.find('posts', {}, {
  sort: { createdAt: -1 },
  limit: 20,
  cursor: lastCursor,
})

// Time-travel query
const result = await db.find('posts', {}, {
  asOf: new Date('2024-01-01'),
})

get

Get a single entity by ID.

get<T = Record<string, unknown>>(
  namespace: string,
  id: string,
  options?: GetOptions
): Promise<Entity<T> | null>

Parameters

NameTypeDescription
namespacestringTarget namespace
idstringEntity ID (can be full 'ns/id' or just 'id')
optionsGetOptionsGet options (optional)

GetOptions

PropertyTypeDescription
includeDeletedbooleanInclude soft-deleted entity
asOfDateTime-travel: get entity as of specific time
hydratestring[]Hydrate related entities (fetch full entity)
maxInboundnumberMaximum inbound references to inline
projectProjectionField projection

Returns

Entity<T> | null - The entity or null if not found.

Examples

// Get by ID
const post = await db.get('posts', 'posts/abc123')

// Get with hydrated relationships
const post = await db.get('posts', 'abc123', {
  hydrate: ['author', 'categories'],
})

// Get historical state
const post = await db.get('posts', 'abc123', {
  asOf: new Date('2024-01-01'),
})

create

Create a new entity.

create<T = Record<string, unknown>>(
  namespace: string,
  data: CreateInput<T>,
  options?: CreateOptions
): Promise<Entity<T>>

Parameters

NameTypeDescription
namespacestringTarget namespace
dataCreateInput<T>Entity data
optionsCreateOptionsCreate options (optional)

CreateInput

PropertyTypeRequiredDescription
$typestringYesEntity type name
namestringYesHuman-readable display name
...fieldsunknownNoAdditional data fields

CreateOptions

PropertyTypeDescription
actorEntityIdActor performing the create (for audit)
skipValidationbooleanSkip schema validation
returnDocumentbooleanReturn the created entity (default: true)

Returns

Entity<T> - The created entity with generated $id, timestamps, and version.

Example

const post = await db.create('posts', {
  $type: 'Post',
  name: 'My First Post',
  title: 'Hello World',
  content: 'This is my first post.',
  status: 'draft',
}, {
  actor: 'users/admin' as EntityId,
})

console.log(post.$id)       // 'posts/abc123'
console.log(post.version)   // 1
console.log(post.createdAt) // Date

update

Update an existing entity.

update<T = Record<string, unknown>>(
  namespace: string,
  id: string,
  update: UpdateInput<T>,
  options?: UpdateOptions
): Promise<Entity<T> | null>

Parameters

NameTypeDescription
namespacestringTarget namespace
idstringEntity ID
updateUpdateInput<T>Update operations
optionsUpdateOptionsUpdate options (optional)

UpdateInput

See Update Operators section for all available operators.

UpdateOptions

PropertyTypeDescription
actorEntityIdActor performing the update (for audit)
expectedVersionnumberExpected version for optimistic concurrency
upsertbooleanCreate if not exists
returnDocument'before' | 'after'Return the document before or after update
skipValidationbooleanSkip schema validation
arrayFiltersFilter[]Array filters for positional updates

Returns

Entity<T> | null - The updated entity or null if not found.

Examples

// Set fields
const post = await db.update('posts', 'posts/abc123', {
  $set: { status: 'published', publishedAt: new Date() },
})

// Increment counter
await db.update('posts', 'abc123', {
  $inc: { viewCount: 1 },
})

// With optimistic concurrency
await db.update('posts', 'abc123', {
  $set: { title: 'Updated Title' },
}, {
  expectedVersion: 5,
})

// Upsert
await db.update('posts', 'new-post', {
  $set: { title: 'New Post' },
  $setOnInsert: { status: 'draft' },
}, {
  upsert: true,
})

delete

Delete an entity (soft delete by default).

delete(
  namespace: string,
  id: string,
  options?: DeleteOptions
): Promise<DeleteResult>

Parameters

NameTypeDescription
namespacestringTarget namespace
idstringEntity ID
optionsDeleteOptionsDelete options (optional)

DeleteOptions

PropertyTypeDescription
actorEntityIdActor performing the delete (for audit)
hardbooleanHard delete (permanent, skip soft delete)
expectedVersionnumberExpected version for optimistic concurrency

Returns

interface DeleteResult {
  deletedCount: number
}

Examples

// Soft delete (default)
const result = await db.delete('posts', 'posts/abc123')

// Hard delete (permanent)
await db.delete('posts', 'abc123', { hard: true })

// With optimistic concurrency
await db.delete('posts', 'abc123', {
  expectedVersion: 5,
})

deleteMany

Delete multiple entities matching a filter.

deleteMany(
  namespace: string,
  filter: Filter,
  options?: DeleteOptions
): Promise<DeleteResult>

Parameters

NameTypeDescription
namespacestringTarget namespace
filterFilterFilter to match entities
optionsDeleteOptionsDelete options (optional)

Example

// Delete all drafts
const result = await db.deleteMany('posts', { status: 'draft' })
console.log(result.deletedCount) // Number of deleted entities

restore

Restore a soft-deleted entity.

restore<T = Record<string, unknown>>(
  namespace: string,
  id: string,
  options?: { actor?: EntityId }
): Promise<Entity<T> | null>

Example

const post = await db.restore('posts', 'posts/abc123')

Upsert Operations

upsert

Find and update an entity, or create if not found.

upsert<T = Record<string, unknown>>(
  namespace: string,
  filter: Filter,
  update: UpdateInput<T>,
  options?: { returnDocument?: 'before' | 'after' }
): Promise<Entity<T> | null>

Example

// Find by email or create new user
const user = await db.upsert('users',
  { email: 'user@example.com' },
  {
    $set: { lastLogin: new Date() },
    $setOnInsert: {
      $type: 'User',
      name: 'New User',
      role: 'member',
    },
  }
)

upsertMany

Upsert multiple entities in a single operation.

upsertMany<T = Record<string, unknown>>(
  namespace: string,
  items: UpsertManyItem<T>[],
  options?: UpsertManyOptions
): Promise<UpsertManyResult>

UpsertManyItem

PropertyTypeDescription
filterFilterFilter to find existing document
updateUpdateInput<T>Update operations to apply
options.expectedVersionnumberExpected version for optimistic concurrency

UpsertManyOptions

PropertyTypeDescription
orderedbooleanStop on first error if true (default: true)
actorEntityIdActor performing the operation

UpsertManyResult

PropertyTypeDescription
okbooleanWhether all operations succeeded
insertedCountnumberNumber of documents inserted
modifiedCountnumberNumber of documents modified
matchedCountnumberNumber of documents matched
upsertedCountnumberNumber of documents upserted (inserted)
upsertedIdsEntityId[]IDs of upserted documents
errorsUpsertManyError[]Errors that occurred

Example

const result = await db.upsertMany('users', [
  {
    filter: { email: 'alice@example.com' },
    update: { $set: { name: 'Alice' } },
  },
  {
    filter: { email: 'bob@example.com' },
    update: { $set: { name: 'Bob' } },
  },
])

Relationship Methods

getRelated

Get related entities with pagination support.

getRelated<T = Record<string, unknown>>(
  namespace: string,
  id: string,
  relationField: string,
  options?: GetRelatedOptions
): Promise<GetRelatedResult<T>>

GetRelatedOptions

PropertyTypeDescription
cursorstringCursor for pagination
limitnumberMaximum results
filterFilterFilter related entities
sortSortSpecSort order
projectProjectionField projection
includeDeletedbooleanInclude soft-deleted

GetRelatedResult

PropertyTypeDescription
itemsEntity<T>[]Related entities
totalnumberTotal count of related entities
hasMorebooleanWhether there are more results
nextCursorstringCursor for next page

Example

// Get posts by a user
const posts = await db.getRelated('users', 'users/123', 'posts', {
  limit: 10,
  sort: { createdAt: -1 },
})

History and Time-Travel

history

Get the history of changes for an entity.

history(
  entityId: EntityId,
  options?: HistoryOptions
): Promise<HistoryResult>

HistoryOptions

PropertyTypeDescription
fromDateStart of time range
toDateEnd of time range
limitnumberMaximum number of events
cursorstringCursor for pagination
op'CREATE' | 'UPDATE' | 'DELETE'Filter by operation type
actorEntityIdFilter by actor

HistoryResult

PropertyTypeDescription
itemsHistoryItem[]History items
hasMorebooleanWhether there are more results
nextCursorstringCursor for next page

HistoryItem

PropertyTypeDescription
idstringEvent ID
tsDateTimestamp
opEventOpOperation type
entityIdstringEntity ID
nsstringNamespace
beforeEntity | nullState before change
afterEntity | nullState after change
actorEntityIdWho made the change
metadataRecord<string, unknown>Additional metadata

Example

const history = await db.history('posts/abc123' as EntityId, {
  limit: 50,
  op: 'UPDATE',
})

for (const item of history.items) {
  console.log(`${item.op} at ${item.ts} by ${item.actor}`)
}

getHistory

Alias for history with namespace-based ID resolution.

getHistory(
  namespace: string,
  id: string,
  options?: HistoryOptions
): Promise<HistoryResult>

getAtVersion

Get an entity at a specific version number.

getAtVersion<T = Record<string, unknown>>(
  namespace: string,
  id: string,
  version: number
): Promise<Entity<T> | null>

Example

// Get the entity as it was at version 3
const post = await db.getAtVersion('posts', 'abc123', 3)

diff

Compute the difference between entity states at two timestamps.

diff(
  entityId: EntityId,
  t1: Date,
  t2: Date
): Promise<DiffResult>

DiffResult

PropertyTypeDescription
addedstring[]Fields that were added
removedstring[]Fields that were removed
changedstring[]Fields that were changed
valuesobjectBefore/after values for changed fields

Example

const changes = await db.diff(
  'posts/abc123' as EntityId,
  new Date('2024-01-01'),
  new Date('2024-02-01')
)

console.log('Added fields:', changes.added)
console.log('Changed fields:', changes.changed)
for (const field of changes.changed) {
  const { before, after } = changes.values[field]
  console.log(`  ${field}: ${before} -> ${after}`)
}

revert

Revert an entity to its state at a specific timestamp.

revert<T = Record<string, unknown>>(
  entityId: EntityId,
  targetTime: Date,
  options?: RevertOptions
): Promise<Entity<T>>

RevertOptions

PropertyTypeDescription
actorEntityIdActor performing the revert

Example

// Revert to yesterday's state
const post = await db.revert(
  'posts/abc123' as EntityId,
  new Date(Date.now() - 24 * 60 * 60 * 1000)
)

Transactions

beginTransaction

Begin a transaction for atomic operations.

beginTransaction(): ParqueDBTransaction

ParqueDBTransaction

MethodDescription
create(namespace, data, options)Create entity within transaction
update(namespace, id, update, options)Update entity within transaction
delete(namespace, id, options)Delete entity within transaction
commit()Commit all changes
rollback()Rollback all changes

Example

const tx = db.beginTransaction()

try {
  const post = await tx.create('posts', {
    $type: 'Post',
    name: 'New Post',
    title: 'Transaction Example',
  })

  await tx.update('users', 'users/123', {
    $inc: { postCount: 1 },
  })

  await tx.commit()
} catch (error) {
  await tx.rollback()
  throw error
}

Event Log

getEventLog

Get the event log interface for querying events.

getEventLog(): EventLog

EventLog Interface

MethodDescription
getEvents(entityId)Get events for a specific entity
getEventsByNamespace(ns)Get events by namespace
getEventsByTimeRange(from, to)Get events by time range
getEventsByOp(op)Get events by operation type
getRawEvent(id)Get raw event data

Example

const eventLog = db.getEventLog()

// Get all events for an entity
const events = await eventLog.getEvents('posts/abc123' as EntityId)

// Get events in a time range
const recentEvents = await eventLog.getEventsByTimeRange(
  new Date('2024-01-01'),
  new Date()
)

Snapshot Management

getSnapshotManager

Get the snapshot manager for manual snapshot operations.

getSnapshotManager(): SnapshotManager

SnapshotManager Interface

MethodDescription
createSnapshot(entityId)Create a snapshot of current state
createSnapshotAtEvent(entityId, eventId)Create snapshot at specific event
listSnapshots(entityId)List all snapshots for an entity
deleteSnapshot(snapshotId)Delete a snapshot
pruneSnapshots(options)Prune old snapshots
getRawSnapshot(snapshotId)Get raw snapshot data
getQueryStats(entityId)Get query statistics
getStorageStats()Get storage statistics

Example

const snapshots = db.getSnapshotManager()

// Create a snapshot
const snapshot = await snapshots.createSnapshot('posts/abc123' as EntityId)

// List snapshots
const list = await snapshots.listSnapshots('posts/abc123' as EntityId)

// Prune old snapshots
await snapshots.pruneSnapshots({
  olderThan: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000),
  keepMinimum: 5,
})

Index Management

createIndex

Create a new index on a namespace.

createIndex(
  ns: string,
  definition: IndexDefinition
): Promise<IndexMetadata>

IndexDefinition

PropertyTypeDescription
namestringIndex name
type'hash' | 'sst' | 'fts'Index type
fieldsIndexField[]Fields to index

Examples

// Create a hash index for equality lookups
await db.createIndex('orders', {
  name: 'idx_status',
  type: 'hash',
  fields: [{ path: 'status' }],
})

// Create an SST index for range queries
await db.createIndex('products', {
  name: 'idx_price',
  type: 'sst',
  fields: [{ path: 'price' }],
})

// Create an FTS index for full-text search
await db.createIndex('articles', {
  name: 'idx_fts_content',
  type: 'fts',
  fields: [{ path: 'title' }, { path: 'body' }],
})

dropIndex

Drop an index.

dropIndex(ns: string, indexName: string): Promise<void>

listIndexes

List all indexes for a namespace.

listIndexes(ns: string): Promise<IndexMetadata[]>

getIndex

Get metadata for a specific index.

getIndex(ns: string, indexName: string): Promise<IndexMetadata | null>

rebuildIndex

Rebuild an index.

rebuildIndex(ns: string, indexName: string): Promise<void>

getIndexStats

Get statistics for an index.

getIndexStats(ns: string, indexName: string): Promise<IndexStats>

getIndexManager

Get the index manager instance for advanced use cases.

getIndexManager(): IndexManager

Update Operators

ParqueDB supports MongoDB-style update operators:

Field Operators

OperatorDescriptionExample
$setSet field values{ $set: { status: 'published' } }
$unsetRemove fields{ $unset: { tempField: '' } }
$renameRename fields{ $rename: { oldName: 'newName' } }
$setOnInsertSet only on insert{ $setOnInsert: { createdBy: 'system' } }

Numeric Operators

OperatorDescriptionExample
$incIncrement{ $inc: { viewCount: 1 } }
$mulMultiply{ $mul: { price: 1.1 } }
$minSet to minimum{ $min: { lowScore: 50 } }
$maxSet to maximum{ $max: { highScore: 100 } }

Array Operators

OperatorDescriptionExample
$pushPush to array{ $push: { tags: 'new' } }
$pullRemove from array{ $pull: { tags: 'old' } }
$addToSetAdd unique to array{ $addToSet: { tags: 'unique' } }
$popRemove first/last{ $pop: { queue: 1 } }

Relationship Operators

OperatorDescriptionExample
$linkAdd relationship{ $link: { author: 'users/123' } }
$unlinkRemove relationship{ $unlink: { author: 'users/123' } }

Date Operators

OperatorDescriptionExample
$currentDateSet to current date{ $currentDate: { updatedAt: true } }

Error Handling

VersionConflictError

Thrown when optimistic concurrency check fails.

class VersionConflictError extends Error {
  expectedVersion: number
  actualVersion: number | undefined
}

Example

try {
  await db.update('posts', 'abc123', {
    $set: { title: 'Updated' },
  }, {
    expectedVersion: 5,
  })
} catch (error) {
  if (error instanceof VersionConflictError) {
    console.log(`Expected version ${error.expectedVersion}, got ${error.actualVersion}`)
  }
}

Type Definitions

Entity

// Entity type properly uses TData for typed data fields
type Entity<TData = Record<string, unknown>> = EntityRef & AuditFields & TData & {
  [key: string]: unknown
}

interface EntityRef {
  $id: EntityId
  $type: string
  name: string
}

interface AuditFields {
  createdAt: Date
  createdBy: EntityId
  updatedAt: Date
  updatedBy: EntityId
  deletedAt?: Date
  deletedBy?: EntityId
  version: number
}

EntityId

type EntityId = `${string}/${string}` & { readonly __brand: unique symbol }

Filter

interface Filter {
  [field: string]: FieldFilter | undefined
  $and?: Filter[]
  $or?: Filter[]
  $not?: Filter
  $nor?: Filter[]
  $text?: TextOperator['$text']
  $vector?: VectorOperator['$vector']
  $geo?: GeoOperator['$geo']
}

On this page