Skip to content

Commit

Permalink
Merge pull request #21 from dolthub/taylor/diffs
Browse files Browse the repository at this point in the history
Commit diff page
  • Loading branch information
tbantle22 authored Oct 25, 2023
2 parents fdff685 + 42b60af commit 4ed1202
Show file tree
Hide file tree
Showing 138 changed files with 6,258 additions and 127 deletions.
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

0 comments on commit 4ed1202

Please sign in to comment.