Skip to content

Commit

Permalink
Merge pull request #105 from prisma-idb/104-atomic-operators
Browse files Browse the repository at this point in the history
104 atomic operators
  • Loading branch information
WhyAsh5114 authored Jan 2, 2025
2 parents 6ee24a5 + b4a2001 commit 14dd14e
Show file tree
Hide file tree
Showing 16 changed files with 693 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ export function addGenericComparator(utilsFile: SourceFile) {

handleStringComparison(writer);
handleNumberComparison(writer);
// TODO: rest
handleBigIntComparison(writer);
handleDateTimeComparison(writer);
handleBytesComparison(writer);
handleBooleanComparison(writer);
// TODO: decimal, json

handleComparisonTypeErrorAndReturn(writer);
},
Expand Down Expand Up @@ -58,6 +62,42 @@ function handleNumberComparison(writer: CodeBlockWriter) {
});
}

function handleBigIntComparison(writer: CodeBlockWriter) {
writer.writeLine(`if (typeof a === "bigint" && typeof b === "bigint")`).block(() => {
writer
.writeLine("if (a > b)")
.block(() => {
writer.writeLine("returnValue = 1;");
})
.writeLine("else if (a < b)")
.block(() => {
writer.writeLine("returnValue = -1;");
})
.writeLine("else")
.block(() => {
writer.writeLine("returnValue = 0;");
});
});
}

function handleDateTimeComparison(writer: CodeBlockWriter) {
writer.writeLine(`if (a instanceof Date && b instanceof Date)`).block(() => {
writer.writeLine(`returnValue = a.getTime() - b.getTime();`);
});
}

function handleBytesComparison(writer: CodeBlockWriter) {
writer.writeLine(`if (a instanceof Uint8Array && b instanceof Uint8Array)`).block(() => {
writer.writeLine(`returnValue = a.length - b.length;`);
});
}

function handleBooleanComparison(writer: CodeBlockWriter) {
writer.writeLine(`if (typeof a === "boolean" && typeof b === "boolean")`).block(() => {
writer.writeLine(`returnValue = a === b ? 0 : a ? 1 : -1;`);
});
}

function handleComparisonTypeErrorAndReturn(writer: CodeBlockWriter) {
writer
.writeLine(`if (returnValue === undefined)`)
Expand Down
18 changes: 11 additions & 7 deletions packages/generator/src/fileCreators/idb-utils/create.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
import { SourceFile, VariableDeclarationKind } from "ts-morph";
import { Model } from "../types";
import { addGenericComparator } from "./comparator/genericComparator";
import { addBigIntFilter } from "./filters/BigIntFilter";
import { addBoolFilter } from "./filters/BoolFilter";
import { addBytesFilter } from "./filters/BytesFilter";
import { addDateTimeFilter } from "./filters/DateTimeFilter";
import { addNumberFilter } from "./filters/NumberFilter";
import { addStringFilter } from "./filters/StringFilter";
import { addBigIntListFilter } from "./listFilters/BigIntListFilter";
import { addBooleanListFilter } from "./listFilters/BooleanListFilter";
import { addBytesListFilter } from "./listFilters/BytesListFilter";
import { addDateTimeListFilter } from "./listFilters/DateTimeListFilter";
import { addNumberListFilter } from "./listFilters/NumberListFilter";
import { addStringListFilter } from "./listFilters/StringListFilter";
import { addApplyLogicalFilters } from "./logicalFilters/applyLogicalFilters";
import { addIntersectArraysByNestedKeyFunction } from "./logicalFilters/intersectArraysByNestedKey";
import { addRemoveDuplicatesByKeyPath } from "./logicalFilters/removeDuplicatesByKeyPath";
import { addBigIntUpdateHandler } from "./updateHandlers/BigIntHandler";
import { addBooleanUpdateHandler } from "./updateHandlers/BooleanHandler";
import { addBytesUpdateHandler } from "./updateHandlers/BytesHandler";
import { addDateTimeUpdateHandler } from "./updateHandlers/DateTimeHandler";
import { addFloatUpdateHandler } from "./updateHandlers/FloatHandler";
import { addIntUpdateHandler } from "./updateHandlers/IntHandler";
import { addScalarListUpdateHandler } from "./updateHandlers/ScalarListHandler";
import { addStringUpdateHandler } from "./updateHandlers/StringHandler";
import { addGenericComparator } from "./comparator/genericComparator";
import { addStringListFilter } from "./listFilters/StringListFilter";
import { addNumberListFilter } from "./listFilters/NumberListFilter";
import { addBigIntListFilter } from "./listFilters/BigIntListFilter";
import { addBooleanListFilter } from "./listFilters/BooleanListFilter";
import { addBytesListFilter } from "./listFilters/BytesListFilter";
import { addDateTimeListFilter } from "./listFilters/DateTimeListFilter";

export function createUtilsFile(idbUtilsFile: SourceFile, models: readonly Model[]) {
idbUtilsFile.addImportDeclarations([
Expand Down Expand Up @@ -84,6 +86,8 @@ export function createUtilsFile(idbUtilsFile: SourceFile, models: readonly Model
addDateTimeUpdateHandler(idbUtilsFile, models);
addBytesUpdateHandler(idbUtilsFile, models);
addIntUpdateHandler(idbUtilsFile, models);
addBigIntUpdateHandler(idbUtilsFile, models);
addFloatUpdateHandler(idbUtilsFile, models);
addScalarListUpdateHandler(idbUtilsFile, models);

addGenericComparator(idbUtilsFile);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Model } from "src/fileCreators/types";
import type { SourceFile } from "ts-morph";

export function addBigIntUpdateHandler(utilsFile: SourceFile, models: readonly Model[]) {
const bigIntFields = models.flatMap(({ fields }) => fields).filter((field) => field.type === "BigInt");
if (bigIntFields.length === 0) return;

let updateOperationType = "undefined | bigint | number";
let fieldType = "bigint";

const nonNullableBigIntFieldPresent = bigIntFields.some(({ isRequired }) => isRequired);
const nullableBigIntFieldPresent = bigIntFields.some(({ isRequired }) => !isRequired);

if (nonNullableBigIntFieldPresent) {
updateOperationType += " | Prisma.BigIntFieldUpdateOperationsInput";
}
if (nullableBigIntFieldPresent) {
updateOperationType += " | null | Prisma.NullableBigIntFieldUpdateOperationsInput";
fieldType += " | null";
}

utilsFile.addFunction({
name: "handleBigIntUpdateField",
isExported: true,
typeParameters: [{ name: "T" }, { name: "R", constraint: `Prisma.Result<T, object, "findFirstOrThrow">` }],
parameters: [
{ name: "record", type: `R` },
{ name: "fieldName", type: "keyof R" },
{
name: "bigIntUpdate",
type: updateOperationType,
},
],
statements: (writer) => {
writer
.writeLine(`if (bigIntUpdate === undefined) return;`)
.write(`if (typeof bigIntUpdate === "bigint" || typeof bigIntUpdate === "number"`)
.conditionalWrite(nullableBigIntFieldPresent, ` || bigIntUpdate === null`)
.writeLine(`)`)
.block(() => {
if (nullableBigIntFieldPresent) {
writer.writeLine(
`(record[fieldName] as ${fieldType}) = bigIntUpdate === null ? null : BigInt(bigIntUpdate);`,
);
} else {
writer.writeLine(`(record[fieldName] as ${fieldType}) = BigInt(bigIntUpdate);`);
}
})
.writeLine(`else if (bigIntUpdate.set !== undefined)`)
.block(() => {
if (nullableBigIntFieldPresent) {
writer.writeLine(
`(record[fieldName] as ${fieldType}) = bigIntUpdate.set === null ? null : BigInt(bigIntUpdate.set);`,
);
} else {
writer.writeLine(`(record[fieldName] as ${fieldType}) = BigInt(bigIntUpdate.set);`);
}
})
.writeLine(`else if (bigIntUpdate.increment !== undefined && record[fieldName] !== null)`)
.block(() => {
writer.writeLine(`(record[fieldName] as bigint) += BigInt(bigIntUpdate.increment);`);
})
.writeLine(`else if (bigIntUpdate.decrement !== undefined && record[fieldName] !== null)`)
.block(() => {
writer.writeLine(`(record[fieldName] as bigint) -= BigInt(bigIntUpdate.decrement);`);
})
.writeLine(`else if (bigIntUpdate.multiply !== undefined && record[fieldName] !== null)`)
.block(() => {
writer.writeLine(`(record[fieldName] as bigint) *= BigInt(bigIntUpdate.multiply);`);
})
.writeLine(`else if (bigIntUpdate.divide !== undefined && record[fieldName] !== null)`)
.block(() => {
writer.writeLine(`(record[fieldName] as bigint) /= BigInt(bigIntUpdate.divide);`);
});
},
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { Model } from "src/fileCreators/types";
import type { SourceFile } from "ts-morph";

export function addFloatUpdateHandler(utilsFile: SourceFile, models: readonly Model[]) {
const floatFields = models.flatMap(({ fields }) => fields).filter((field) => field.type === "Float");
if (floatFields.length === 0) return;

let updateOperationType = "undefined | number";
let fieldType = "number";

const nonNullableFloatFieldPresent = floatFields.some(({ isRequired }) => isRequired);
const nullableFloatFieldPresent = floatFields.some(({ isRequired }) => !isRequired);

if (nonNullableFloatFieldPresent) {
updateOperationType += " | Prisma.FloatFieldUpdateOperationsInput";
}
if (nullableFloatFieldPresent) {
updateOperationType += " | null | Prisma.NullableFloatFieldUpdateOperationsInput";
fieldType += " | null";
}

utilsFile.addFunction({
name: "handleFloatUpdateField",
isExported: true,
typeParameters: [{ name: "T" }, { name: "R", constraint: `Prisma.Result<T, object, "findFirstOrThrow">` }],
parameters: [
{ name: "record", type: `R` },
{ name: "fieldName", type: "keyof R" },
{
name: "floatUpdate",
type: updateOperationType,
},
],
statements: (writer) => {
writer
.writeLine(`if (floatUpdate === undefined) return;`)
.write(`if (typeof floatUpdate === "number"`)
.conditionalWrite(nullableFloatFieldPresent, ` || floatUpdate === null`)
.writeLine(`)`)
.block(() => {
writer.writeLine(`(record[fieldName] as ${fieldType}) = floatUpdate;`);
})
.writeLine(`else if (floatUpdate.set !== undefined)`)
.block(() => {
writer.writeLine(`(record[fieldName] as ${fieldType}) = floatUpdate.set;`);
})
.writeLine(`else if (floatUpdate.increment !== undefined && record[fieldName] !== null)`)
.block(() => {
writer.writeLine(`(record[fieldName] as number) += floatUpdate.increment;`);
})
.writeLine(`else if (floatUpdate.decrement !== undefined && record[fieldName] !== null)`)
.block(() => {
writer.writeLine(`(record[fieldName] as number) -= floatUpdate.decrement;`);
})
.writeLine(`else if (floatUpdate.multiply !== undefined && record[fieldName] !== null)`)
.block(() => {
writer.writeLine(`(record[fieldName] as number) *= floatUpdate.multiply;`);
})
.writeLine(`else if (floatUpdate.divide !== undefined && record[fieldName] !== null)`)
.block(() => {
writer.writeLine(`(record[fieldName] as number) /= floatUpdate.divide;`);
});
},
});
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Model } from "src/fileCreators/types";
import type { SourceFile } from "ts-morph";

// TODO: atomic operations

export function addIntUpdateHandler(utilsFile: SourceFile, models: readonly Model[]) {
const intFields = models.flatMap(({ fields }) => fields).filter((field) => field.type === "Int");
if (intFields.length === 0) return;
Expand Down Expand Up @@ -41,10 +39,27 @@ export function addIntUpdateHandler(utilsFile: SourceFile, models: readonly Mode
.writeLine(`)`)
.block(() => {
writer.writeLine(`(record[fieldName] as ${fieldType}) = intUpdate;`);
})
.writeLine(`else if (intUpdate.set !== undefined)`)
.block(() => {
writer.writeLine(`(record[fieldName] as ${fieldType}) = intUpdate.set;`);
})
.writeLine(`else if (intUpdate.increment !== undefined && record[fieldName] !== null)`)
.block(() => {
writer.writeLine(`(record[fieldName] as number) += intUpdate.increment;`);
})
.writeLine(`else if (intUpdate.decrement !== undefined && record[fieldName] !== null)`)
.block(() => {
writer.writeLine(`(record[fieldName] as number) -= intUpdate.decrement;`);
})
.writeLine(`else if (intUpdate.multiply !== undefined && record[fieldName] !== null)`)
.block(() => {
writer.writeLine(`(record[fieldName] as number) *= intUpdate.multiply;`);
})
.writeLine(`else if (intUpdate.divide !== undefined && record[fieldName] !== null)`)
.block(() => {
writer.writeLine(`(record[fieldName] as number) /= intUpdate.divide;`);
});
writer.writeLine(`else if (intUpdate.set !== undefined)`).block(() => {
writer.writeLine(`(record[fieldName] as ${fieldType}) = intUpdate.set;`);
});
},
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ export function addUpdateMethod(modelClass: ClassDeclaration, model: Model, mode
addBooleanUpdateHandling(writer, model);
addBytesUpdateHandling(writer, model);
addIntUpdateHandling(writer, model);
// TODO: the numeric types
addBigIntUpdateHandling(writer, model);
addFloatUpdateHandling(writer, model);
// TODO: decimal, json
addScalarListUpdateHandling(writer, model);
addRelationUpdateHandling(writer, model, models);
addFkValidation(writer, model);
Expand Down Expand Up @@ -101,6 +103,30 @@ function addIntUpdateHandling(writer: CodeBlockWriter, model: Model) {
});
}

function addBigIntUpdateHandling(writer: CodeBlockWriter, model: Model) {
const bigIntFields = model.fields.filter((field) => field.type === "BigInt" && !field.isList).map(({ name }) => name);
if (bigIntFields.length === 0) return;

writer
.writeLine(`const bigIntFields = ${JSON.stringify(bigIntFields)} as const;`)
.writeLine(`for (const field of bigIntFields)`)
.block(() => {
writer.writeLine(`IDBUtils.handleBigIntUpdateField(record, field, query.data[field]);`);
});
}

function addFloatUpdateHandling(writer: CodeBlockWriter, model: Model) {
const floatFields = model.fields.filter((field) => field.type === "Float" && !field.isList).map(({ name }) => name);
if (floatFields.length === 0) return;

writer
.writeLine(`const floatFields = ${JSON.stringify(floatFields)} as const;`)
.writeLine(`for (const field of floatFields)`)
.block(() => {
writer.writeLine(`IDBUtils.handleFloatUpdateField(record, field, query.data[field]);`);
});
}

function addDateTimeUpdateHandling(writer: CodeBlockWriter, model: Model) {
const dateTimeFields = model.fields
.filter((field) => field.type === "DateTime" && !field.isList)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function addFillDefaultsFunction(modelClass: ClassDeclaration, model: Mod
.forEach((field) => {
writer.writeLine(`if (data.${field.name} === undefined) `).block(() => {
if (typeof field.default === "object" && "name" in field.default) {
if (field.default.name === "uuid(4)") {
if (field.default.name === "uuid") {
addUuidDefault(writer, field);
} else if (field.default.name === "cuid") {
addCuidDefault(writer, field);
Expand Down
Loading

0 comments on commit 14dd14e

Please sign in to comment.