small-typeorm-strates
v0.1.0
Published
Snapshot-style versioned persistence for TypeORM with release pointers and optional partition-based garbage collection.
Maintainers
Readme
typeorm-versioned-persist
Snapshot-style versioned persistence for TypeORM.
Features
- Build versions generated with UUID v7
- O(1) release through a central release pointer table
- MySQL / MariaDB / PostgreSQL dialect detection from the injected
DataSource - Optional partition-based garbage collection
- Metadata validation for versioned entities
Entity requirements
Each versioned entity must define:
idbuildVersion- one configured scope id field, such as
cartIdorproductId
Example:
import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm";
import type { VersionedEntity } from "typeorm-versioned-persist";
@Entity("cart_item")
@Index(["cartId", "buildVersion"])
export class CartItemEntity implements VersionedEntity {
@PrimaryGeneratedColumn()
id!: number;
@Column()
cartId!: number;
@Column({ type: "varchar", length: 36 })
buildVersion!: string;
@Column()
sku!: string;
@Column({ type: "int" })
quantity!: number;
}Bootstrap
import { DataSource } from "typeorm";
import {
VersionedBuildEntity,
VersionedPersist,
VersionedReleaseEntity,
} from "typeorm-versioned-persist";
const dataSource = new DataSource({
type: "postgres",
entities: [CartItemEntity, VersionedBuildEntity, VersionedReleaseEntity],
});
const versionedPersist = new VersionedPersist(dataSource, [
{
entity: CartItemEntity,
scope: "cart",
scopeIdField: "cartId",
},
]);Build / persist / release
const version = await versionedPersist.createNewVersion(
[CartItemEntity],
"cart",
42,
);
const item = new CartItemEntity();
item.cartId = 42;
item.sku = "BIKE-001";
item.quantity = 2;
await versionedPersist.persist(item, version);
await versionedPersist.release("cart", 42, version);Query released data
const releasedItems = await versionedPersist.findReleasedByScopeId<CartItemEntity>(
"cart",
42,
);Garbage collection
Default strategy uses batched delete by buildVersion.
await versionedPersist.garbageCollector([CartItemEntity]);Optional partition strategy:
import { PartitionGarbageCollectorStrategy } from "typeorm-versioned-persist";
const versionedPersist = new VersionedPersist(
dataSource,
[{ entity: CartItemEntity, scope: "cart", scopeIdField: "cartId" }],
{
garbageCollectorStrategy: new PartitionGarbageCollectorStrategy(dataSource),
},
);Partition naming convention
The optional partition GC expects partition names generated from build versions:
- partition name:
p_<uuid_without_dashes>
Example:
- build version:
0195f88b-43fd-7f2d-a8fc-3f1fa48f8d29 - partition name:
p_0195f88b43fd7f2da8fc3f1fa48f8d29
Notes
releaseVersionis intentionally not duplicated in business tables.- The release pointer table is the single source of truth.
- Partition GC is optional and should only be enabled when your schema is partitioned accordingly.
