A TypeScript library for building composite database indexes with lexicographic ordering. This library provides a type-safe builder pattern for creating partition keys and sort keys that can be used with databases like DynamoDB GSIs, Cassandra composite keys, MongoDB compound indexes, and other systems that use lexicographically sorted keys.
Key Features:
- Type-safe composite key construction
- Support for partial sort keys with undefined field filtering
- Flexible value transformation capabilities
- Database-agnostic design
- Works with any lexicographic encoding method
Define your entity type and create a composite index with partition and sort keys:
import { CompositeIndexBuilder } from '@lexicographic/index-builder';
interface User {
firstName: string;
lastName: string;
createdAt?: number;
}
// Define your encoding method (use @lexicographic/keys or your own)
const encode = (...segments: (string | number)[]) => segments.join('#');
// Build the composite index
const userIndex = CompositeIndexBuilder.forEntity<User>()
.withName('users-by-name-and-date')
.withPartitionKey({
prefix: 'users-by-name',
fields: ['firstName', 'lastName']
})
.withSortKey({
prefix: 'created-at',
fields: ['createdAt'],
transformValues: (values) => ({
...values,
createdAt: values.createdAt || Date.now()
})
})
.withEncodingMethod(encode)
.build();
// Generate keys
const partitionKey = userIndex.partitionKey({
firstName: 'John',
lastName: 'Smith'
});
// Result: "users-by-name#John#Smith"
const sortKey = userIndex.sortKey({ createdAt: 1640995200000 });
// Result: "created-at#1640995200000"
// Partial sort keys (undefined values are filtered out)
const partialSortKey = userIndex.sortKey({});
// Result: "created-at#[current_timestamp]" (due to transform)
npm install @lexicographic/index-builder
For lexicographic encoding, you'll likely want to pair this with:
npm install @lexicographic/keys
The main builder class for creating composite indexes.
Methods:
forEntity<Entity>()
- Static factory method to start building an index for a specific entity typewithName(name: string)
- Set the index namewithPartitionKey(options: PartitionKeyOptions)
- Define partition key configurationwithSortKey(options: SortKeyOptions)
- Define sort key configurationwithEncodingMethod(encoder: (...segments) => string)
- Set the encoding methodbuild()
- Create the final CompositeIndex instance
The built index that generates keys.
Methods:
name()
- Returns the index namepartitionKey(fields)
- Generate partition key from entity fieldssortKey(fields?)
- Generate sort key from entity fields (partial fields supported)
interface PartitionKeyOptions<Entity, PK extends (keyof Entity)[]> {
prefix: string;
fields: PK;
transformValues?: (values: Pick<Entity, PK[number]>) => Pick<Entity, PK[number]>;
}
interface SortKeyOptions<Entity, SK extends (keyof Entity)[]> {
prefix: string;
fields: SK;
transformValues?: (values: Partial<Pick<Entity, SK[number]>>) => Partial<Pick<Entity, SK[number]>>;
}
This library works with any database that uses lexicographically sorted composite keys:
- DynamoDB - Global Secondary Indexes (GSI) and Local Secondary Indexes (LSI)
- Cassandra/ScyllaDB - Clustering columns and composite partition keys
- MongoDB - Compound indexes
- Azure Cosmos DB - Composite indexes
- Google Cloud Firestore - Composite indexes
- Redis - Sorted sets with lexicographic ordering
- RocksDB/LevelDB - Composite key patterns
Run the test suite:
yarn test
The tests cover:
- CompositeIndex builder pattern validation
- Partition key generation with transformations
- Sort key generation with partial field support
- Error handling for missing configuration
Contributions to @lexicographic/index-builder are welcome! Please see CONTRIBUTING.md for details.
Copyright (c) 2025 Atlassian US., Inc. Apache 2.0 licensed, see LICENSE file.