Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Commit diff page #21

Merged
merged 6 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion packages/graphql-server/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,33 @@ type DoltDatabaseDetails {
hideDoltFeatures: Boolean!
}

type DiffStat {
rowsUnmodified: Float!
rowsAdded: Float!
rowsDeleted: Float!
rowsModified: Float!
cellsModified: Float!
rowCount: Float!
cellCount: Float!
}

type DiffSummary {
_id: ID!
fromTableName: String!
toTableName: String!
tableName: String!
tableType: TableDiffType!
hasDataChanges: Boolean!
hasSchemaChanges: Boolean!
}

enum TableDiffType {
Added
Dropped
Modified
Renamed
}

type ColumnValue {
displayValue: String!
}
Expand All @@ -121,6 +148,28 @@ type DocList {
list: [Doc!]!
}

type RowDiff {
added: Row
deleted: Row
}

type RowDiffList {
nextOffset: Int
list: [RowDiff!]!
columns: [Column!]!
}

type TextDiff {
leftLines: String!
rightLines: String!
}

type SchemaDiff {
schemaDiff: TextDiff
schemaPatch: [String!]
numChangedSchemas: Int
}

type SqlSelect {
_id: ID!
databaseName: String!
Expand Down Expand Up @@ -166,15 +215,19 @@ type Query {
branchOrDefault(databaseName: String!, branchName: String): Branch
branches(databaseName: String!, sortBy: SortBranchesBy): BranchNamesList!
defaultBranch(databaseName: String!): Branch
commits(offset: Int, databaseName: String!, refName: String!): CommitList!
commits(offset: Int, databaseName: String!, refName: String, afterCommitId: String): CommitList!
currentDatabase: String
hasDatabaseEnv: Boolean!
databases: [String!]!
doltDatabaseDetails: DoltDatabaseDetails!
diffStat(databaseName: String!, fromRefName: String!, toRefName: String!, refName: String, type: CommitDiffType, tableName: String): DiffStat!
diffSummaries(databaseName: String!, fromRefName: String!, toRefName: String!, refName: String, type: CommitDiffType, tableName: String): [DiffSummary!]!
docs(databaseName: String!, refName: String!): DocList!
docOrDefaultDoc(refName: String!, databaseName: String!, docType: DocType): Doc
rowDiffs(offset: Int, databaseName: String!, fromCommitId: String!, toCommitId: String!, refName: String, tableName: String!, filterByRowType: DiffRowType): RowDiffList!
rows(refName: String!, databaseName: String!, tableName: String!, offset: Int): RowList!
views(databaseName: String!, refName: String!): RowList!
schemaDiff(databaseName: String!, fromCommitId: String!, toCommitId: String!, refName: String, tableName: String!): SchemaDiff
sqlSelect(refName: String!, databaseName: String!, queryString: String!): SqlSelect!
sqlSelectForCsvDownload(refName: String!, databaseName: String!, queryString: String!): String!
status(databaseName: String!, refName: String!): [Status!]!
Expand All @@ -190,12 +243,25 @@ enum SortBranchesBy {
LastUpdated
}

enum CommitDiffType {
TwoDot
ThreeDot
Unspecified
}

enum DocType {
Unspecified
Readme
License
}

enum DiffRowType {
Added
Removed
Modified
All
}

type Mutation {
createBranch(databaseName: String!, newBranchName: String!, fromRefName: String!): Branch!
deleteBranch(databaseName: String!, branchName: String!): Boolean!
Expand Down
41 changes: 32 additions & 9 deletions packages/graphql-server/src/commits/commit.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import { doltLogsQuery } from "./commit.queries";
@ArgsType()
export class ListCommitsArgs extends DBArgsWithOffset {
// either refName or afterCommitId must be set
@Field()
refName: string;
@Field({ nullable: true })
refName?: string;

// @Field({ nullable: true })
// afterCommitId?: string;
@Field({ nullable: true })
afterCommitId?: string;

// @Field(_type => Boolean, { nullable: true })
// twoDot?: boolean;
Expand All @@ -33,13 +33,12 @@ export class CommitResolver {
@Args()
args: ListCommitsArgs,
): Promise<CommitList> {
const err = handleArgsErr(args);
if (err) throw err;
const refName = args.refName ?? args.afterCommitId ?? "";
const offset = args.offset ?? 0;
return this.dss.query(async query => {
const logs = await query(doltLogsQuery, [
args.refName,
ROW_LIMIT + 1,
offset,
]);
const logs = await query(doltLogsQuery, [refName, ROW_LIMIT + 1, offset]);
return getCommitListRes(logs, args);
}, args.databaseName);
}
Expand All @@ -53,3 +52,27 @@ function getCommitListRes(logs: RawRow[], args: ListCommitsArgs): CommitList {
nextOffset: getNextOffset(logs.length, args.offset ?? 0),
};
}

function handleArgsErr(args: ListCommitsArgs): Error | undefined {
if (!args.refName && !args.afterCommitId) {
return new Error(
"must supply either `refName` or `afterCommitId` to list commits",
);
}
if (args.refName && args.afterCommitId) {
return new Error(
"cannot supply both `refName` and `afterCommitId` when listing commits",
);
}
// if (args.twoDot && !args.excludingCommitsFromRefName) {
// return new Error(
// "must supply `excludingCommitsFromRefName` if twoDot is true",
// );
// }
// if (!args.twoDot && args.excludingCommitsFromRefName) {
// return new Error(
// "cannot supply `excludingCommitsFromRefName` if twoDot is not provided or false",
// );
// }
return undefined;
}
54 changes: 54 additions & 0 deletions packages/graphql-server/src/diffStats/diffStat.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Field, Float, ObjectType } from "@nestjs/graphql";
import { RawRow, RawRows } from "../utils/commonTypes";

@ObjectType()
export class DiffStat {
@Field(_type => Float)
rowsUnmodified: number;

@Field(_type => Float)
rowsAdded: number;

@Field(_type => Float)
rowsDeleted: number;

@Field(_type => Float)
rowsModified: number;

@Field(_type => Float)
cellsModified: number;

@Field(_type => Float)
rowCount: number;

@Field(_type => Float)
cellCount: number;
}

const defaultStat = {
rowsUnmodified: 0,
rowsAdded: 0,
rowsDeleted: 0,
rowsModified: 0,
cellsModified: 0,
rowCount: 0,
cellCount: 0,
};

export function fromDoltDiffStat(res: RawRows): DiffStat {
if (!res.length) return defaultStat;

const reduced = res.reduce((acc: DiffStat, row: RawRow) => {
return {
rowsUnmodified: Number(row.rows_unmodified) + acc.rowsUnmodified,
rowsAdded: Number(row.rows_added) + acc.rowsAdded,
rowsDeleted: Number(row.rows_deleted) + acc.rowsDeleted,
rowsModified: Number(row.rows_modified) + acc.rowsModified,
cellsModified: Number(row.cells_modified) + acc.cellsModified,
rowCount: Number(row.new_row_count) + acc.rowCount,
cellCount: Number(row.new_cell_count) + acc.cellCount,
};
}, defaultStat);

return reduced;
}
5 changes: 5 additions & 0 deletions packages/graphql-server/src/diffStats/diffStat.queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const getThreeDotDiffStatQuery = (hasTableName?: boolean): string =>
`SELECT * FROM DOLT_DIFF_STAT(?${hasTableName ? `, ?` : ""})`;

export const getDiffStatQuery = (hasTableName?: boolean): string =>
`SELECT * FROM DOLT_DIFF_STAT(?, ?${hasTableName ? `, ?` : ""})`;
67 changes: 67 additions & 0 deletions packages/graphql-server/src/diffStats/diffStat.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Args, ArgsType, Field, Query, Resolver } from "@nestjs/graphql";
import { DataSourceService } from "../dataSources/dataSource.service";
import { CommitDiffType } from "../diffSummaries/diffSummary.enums";
import { DBArgs } from "../utils/commonTypes";
import { DiffStat, fromDoltDiffStat } from "./diffStat.model";
import { getDiffStatQuery, getThreeDotDiffStatQuery } from "./diffStat.queries";

@ArgsType()
export class DiffStatArgs extends DBArgs {
@Field()
fromRefName: string;

@Field()
toRefName: string;

@Field({ nullable: true })
refName?: string;

@Field(_type => CommitDiffType, { nullable: true })
type?: CommitDiffType;

@Field({ nullable: true })
tableName?: string;
}

@Resolver(_of => DiffStat)
export class DiffStatResolver {
constructor(private readonly dss: DataSourceService) {}

@Query(_returns => DiffStat)
async diffStat(@Args() args: DiffStatArgs): Promise<DiffStat> {
const type = args.type ?? CommitDiffType.TwoDot;
checkArgs(args);

return this.dss.query(async query => {
if (type === CommitDiffType.ThreeDot) {
const res = await query(getThreeDotDiffStatQuery(!!args.tableName), [
`${args.toRefName}...${args.fromRefName}`,
args.tableName,
]);
return fromDoltDiffStat(res);
}

const res = await query(getDiffStatQuery(!!args.tableName), [
args.fromRefName,
args.toRefName,
args.tableName,
]);
return fromDoltDiffStat(res);
}, args.databaseName);
}
}

export function checkArgs(args: DiffStatArgs): void {
if (
args.type === CommitDiffType.TwoDot &&
(isRefKeyword(args.fromRefName) || isRefKeyword(args.toRefName)) &&
!args.refName
) {
throw new Error("refName is required for TwoDot diff with ref keyword");
}
}

function isRefKeyword(refName: string): boolean {
const upper = refName.toUpperCase();
return upper === "WORKING" || upper === "HEAD" || upper === "STAGED";
}
33 changes: 33 additions & 0 deletions packages/graphql-server/src/diffSummaries/diffSummary.enums.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { registerEnumType } from "@nestjs/graphql";

export enum TableDiffType {
Added,
Dropped,
Modified,
Renamed,
}

registerEnumType(TableDiffType, { name: "TableDiffType" });

export function toTableDiffType(t: string): TableDiffType {
switch (t) {
case "added":
return TableDiffType.Added;
case "dropped":
return TableDiffType.Dropped;
case "modified":
return TableDiffType.Modified;
case "renamed":
return TableDiffType.Renamed;
default:
throw new Error(`Unknown table diff type: ${t}`);
}
}

export enum CommitDiffType {
TwoDot,
ThreeDot,
Unspecified,
}

registerEnumType(CommitDiffType, { name: "CommitDiffType" });
53 changes: 53 additions & 0 deletions packages/graphql-server/src/diffSummaries/diffSummary.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Field, ID, ObjectType } from "@nestjs/graphql";
import { RawRow } from "../utils/commonTypes";
import { TableDiffType, toTableDiffType } from "./diffSummary.enums";

@ObjectType()
export class DiffSummary {
@Field(_type => ID)
_id: string;

@Field()
fromTableName: string;

@Field()
toTableName: string;

@Field()
tableName: string;

@Field(_type => TableDiffType)
tableType: TableDiffType;

@Field()
hasDataChanges: boolean;

@Field()
hasSchemaChanges: boolean;
}

export function fromDoltDiffSummary(row: RawRow): DiffSummary {
const fromTableName = row.from_table_name;
const toTableName = row.to_table_name;
const tableName = getTableName(fromTableName, toTableName);
const _id = `tableDiffSummaries/${tableName}`;
return {
_id,
fromTableName,
toTableName,
tableName,
tableType: toTableDiffType(row.diff_type),
hasDataChanges: row.data_change,
hasSchemaChanges: row.schema_change,
};
}

function getTableName(fromTableName: string, toTableName: string): string {
if (!fromTableName.length && !toTableName.length) return "";
if (!fromTableName.length) return toTableName;
if (!toTableName.length) return fromTableName;
if (fromTableName !== toTableName) {
return toTableName;
}
return toTableName;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const getDiffSummaryQuery = (hasTableName?: boolean): string =>
`SELECT * FROM DOLT_DIFF_SUMMARY(?, ?${hasTableName ? `, ?` : ""})`;

export const getThreeDotDiffSummaryQuery = (hasTableName?: boolean): string =>
`SELECT * FROM DOLT_DIFF_SUMMARY(?${hasTableName ? `, ?` : ""})`;
Loading
Loading