@directus/api
Version:
Directus is a real-time API and App dashboard for managing SQL database content
116 lines (114 loc) • 5.19 kB
JavaScript
import database_default from "../../index.js";
import { ContainsNullValuesError, InvalidForeignKeyError, NotNullViolationError, RecordNotUniqueError, ValueOutOfRangeError, ValueTooLongError } from "@directus/errors";
//#region src/database/errors/dialects/mssql.ts
var MSSQLErrorCodes = /* @__PURE__ */ function(MSSQLErrorCodes$1) {
MSSQLErrorCodes$1[MSSQLErrorCodes$1["FOREIGN_KEY_VIOLATION"] = 547] = "FOREIGN_KEY_VIOLATION";
MSSQLErrorCodes$1[MSSQLErrorCodes$1["NOT_NULL_VIOLATION"] = 515] = "NOT_NULL_VIOLATION";
MSSQLErrorCodes$1[MSSQLErrorCodes$1["NUMERIC_VALUE_OUT_OF_RANGE"] = 220] = "NUMERIC_VALUE_OUT_OF_RANGE";
MSSQLErrorCodes$1[MSSQLErrorCodes$1["UNIQUE_VIOLATION_INDEX"] = 2601] = "UNIQUE_VIOLATION_INDEX";
MSSQLErrorCodes$1[MSSQLErrorCodes$1["UNIQUE_VIOLATION_CONSTRAINT"] = 2627] = "UNIQUE_VIOLATION_CONSTRAINT";
MSSQLErrorCodes$1[MSSQLErrorCodes$1["VALUE_LIMIT_VIOLATION"] = 2628] = "VALUE_LIMIT_VIOLATION";
return MSSQLErrorCodes$1;
}(MSSQLErrorCodes || {});
async function extractError(error, data) {
switch (error.number) {
case MSSQLErrorCodes.UNIQUE_VIOLATION_CONSTRAINT:
case MSSQLErrorCodes.UNIQUE_VIOLATION_INDEX: return await uniqueViolation(error);
case MSSQLErrorCodes.NUMERIC_VALUE_OUT_OF_RANGE: return numericValueOutOfRange();
case MSSQLErrorCodes.VALUE_LIMIT_VIOLATION: return valueLimitViolation();
case MSSQLErrorCodes.NOT_NULL_VIOLATION: return notNullViolation();
case MSSQLErrorCodes.FOREIGN_KEY_VIOLATION: return foreignKeyViolation();
}
return error;
async function uniqueViolation(error$1) {
/**
* NOTE:
* SQL Server doesn't return the name of the offending column when a unique error is thrown:
*
* Constraint:
* insert into [articles] ([unique]) values (@p0)
* - Violation of UNIQUE KEY constraint 'unique_contraint_name'. Cannot insert duplicate key in object 'dbo.article'.
* The duplicate key value is (rijk).
*
* Index:
* insert into [articles] ([unique]) values (@p0)
* - Cannot insert duplicate key row in object 'dbo.articles' with unique index 'unique_index_name'.
* The duplicate key value is (rijk).
*
* While it's not ideal, the best next thing we can do is extract the column name from
* information_schema when this happens
*/
const betweenQuotes = /'([^']+)'/g;
const betweenParens = /\(([^)]+)\)/g;
const quoteMatches = error$1.message.match(betweenQuotes);
const parenMatches = error$1.message.match(betweenParens);
if (!quoteMatches || !parenMatches) return error$1;
const [keyNameMatchIndex, collectionNameMatchIndex] = error$1.number === MSSQLErrorCodes.UNIQUE_VIOLATION_INDEX ? [1, 0] : [0, 1];
const keyName = quoteMatches[keyNameMatchIndex].slice(1, -1);
let collection = quoteMatches[collectionNameMatchIndex].slice(1, -1);
let field = null;
if (keyName) {
const database = database_default();
const constraintUsage = await database.select("sys.columns.name as field", database.raw("OBJECT_NAME(??) as collection", ["sys.columns.object_id"])).from("sys.indexes").innerJoin("sys.index_columns", (join) => {
join.on("sys.indexes.object_id", "=", "sys.index_columns.object_id").andOn("sys.indexes.index_id", "=", "sys.index_columns.index_id");
}).innerJoin("sys.columns", (join) => {
join.on("sys.index_columns.object_id", "=", "sys.columns.object_id").andOn("sys.index_columns.column_id", "=", "sys.columns.column_id");
}).where("sys.indexes.name", "=", keyName).first();
collection = constraintUsage?.collection;
field = constraintUsage?.field;
}
return new RecordNotUniqueError({
collection,
field,
value: field ? data[field] : null
});
}
function numericValueOutOfRange() {
const bracketMatches = error.message.match(/\[([^\]]+)\]/g);
if (!bracketMatches) return error;
return new ValueOutOfRangeError({
collection: bracketMatches[0].slice(1, -1),
field: null,
value: null
});
}
function valueLimitViolation() {
const betweenBrackets = /\[([^\]]+)\]/g;
const betweenQuotes = /'([^']+)'/g;
const bracketMatches = error.message.match(betweenBrackets);
const quoteMatches = error.message.match(betweenQuotes);
if (!bracketMatches || !quoteMatches) return error;
const collection = bracketMatches[0].slice(1, -1);
const field = quoteMatches[1].slice(1, -1);
return new ValueTooLongError({
collection,
field,
value: field ? data[field] : null
});
}
function notNullViolation() {
const betweenBrackets = /\[([^\]]+)\]/g;
const betweenQuotes = /'([^']+)'/g;
const bracketMatches = error.message.match(betweenBrackets);
const quoteMatches = error.message.match(betweenQuotes);
if (!bracketMatches || !quoteMatches) return error;
const collection = bracketMatches[0].slice(1, -1);
const field = quoteMatches[0].slice(1, -1);
if (error.message.includes("Cannot insert the value NULL into column")) return new ContainsNullValuesError({
collection,
field
});
return new NotNullViolationError({
collection,
field
});
}
function foreignKeyViolation() {
return new InvalidForeignKeyError({
value: null,
constraint: /constraint ["']([^"']+)["']/i.exec(error.message)?.[1] ?? null
});
}
}
//#endregion
export { extractError };