Expose project revision timeline
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
import { and, asc, desc, eq } from "drizzle-orm";
|
||||
import { and, asc, desc, eq, lt } from "drizzle-orm";
|
||||
import { deserializeProjectCommand } from "../../domain/models/project-command.model.js";
|
||||
import type {
|
||||
ProjectHistoryCommand,
|
||||
ProjectHistoryDirection,
|
||||
ListProjectRevisionsInput,
|
||||
ProjectRevisionPage,
|
||||
ProjectHistoryState,
|
||||
ProjectHistoryStore,
|
||||
} from "../../domain/ports/project-history.store.js";
|
||||
import type { ProjectRevisionSource } from "../../domain/ports/project-revision.store.js";
|
||||
import type { AppDatabase } from "../database-context.js";
|
||||
import { projectChangeSets } from "../schema/project-change-sets.js";
|
||||
import { projectHistoryStackEntries } from "../schema/project-history-stack-entries.js";
|
||||
@@ -47,6 +50,74 @@ export class ProjectHistoryRepository implements ProjectHistoryStore {
|
||||
};
|
||||
}
|
||||
|
||||
listRevisions(
|
||||
input: ListProjectRevisionsInput
|
||||
): ProjectRevisionPage | null {
|
||||
validateRevisionPageInput(input);
|
||||
const project = this.database
|
||||
.select({ currentRevision: projects.currentRevision })
|
||||
.from(projects)
|
||||
.where(eq(projects.id, input.projectId))
|
||||
.get();
|
||||
if (!project) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const projectCondition = eq(
|
||||
projectRevisions.projectId,
|
||||
input.projectId
|
||||
);
|
||||
const rows = this.database
|
||||
.select({
|
||||
revisionId: projectRevisions.id,
|
||||
changeSetId: projectChangeSets.id,
|
||||
revisionNumber: projectRevisions.revisionNumber,
|
||||
createdAtIso: projectRevisions.createdAtIso,
|
||||
actorId: projectRevisions.actorId,
|
||||
source: projectRevisions.source,
|
||||
description: projectRevisions.description,
|
||||
commandType: projectChangeSets.commandType,
|
||||
payloadSchemaVersion: projectChangeSets.payloadSchemaVersion,
|
||||
})
|
||||
.from(projectRevisions)
|
||||
.innerJoin(
|
||||
projectChangeSets,
|
||||
eq(
|
||||
projectChangeSets.projectRevisionId,
|
||||
projectRevisions.id
|
||||
)
|
||||
)
|
||||
.where(
|
||||
input.beforeRevision === undefined
|
||||
? projectCondition
|
||||
: and(
|
||||
projectCondition,
|
||||
lt(
|
||||
projectRevisions.revisionNumber,
|
||||
input.beforeRevision
|
||||
)
|
||||
)
|
||||
)
|
||||
.orderBy(desc(projectRevisions.revisionNumber))
|
||||
.limit(input.limit + 1)
|
||||
.all();
|
||||
const hasMore = rows.length > input.limit;
|
||||
const revisions = rows.slice(0, input.limit).map((row) => ({
|
||||
...row,
|
||||
source: row.source as ProjectRevisionSource,
|
||||
}));
|
||||
|
||||
return {
|
||||
projectId: input.projectId,
|
||||
currentRevision: project.currentRevision,
|
||||
revisions,
|
||||
nextBeforeRevision:
|
||||
hasMore && revisions.length > 0
|
||||
? revisions.at(-1)!.revisionNumber
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
getNextCommand(
|
||||
projectId: string,
|
||||
direction: ProjectHistoryDirection
|
||||
@@ -93,3 +164,22 @@ export class ProjectHistoryRepository implements ProjectHistoryStore {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function validateRevisionPageInput(input: ListProjectRevisionsInput) {
|
||||
if (
|
||||
!Number.isSafeInteger(input.limit) ||
|
||||
input.limit < 1 ||
|
||||
input.limit > 100
|
||||
) {
|
||||
throw new Error("Project revision page limit must be between 1 and 100.");
|
||||
}
|
||||
if (
|
||||
input.beforeRevision !== undefined &&
|
||||
(!Number.isSafeInteger(input.beforeRevision) ||
|
||||
input.beforeRevision < 1)
|
||||
) {
|
||||
throw new Error(
|
||||
"Project revision cursor must be a positive integer."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user