Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changeset/fresh-mice-introspect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@prisma/studio-core": patch
---

Fix MySQL introspection when JSON aggregated columns are returned as strings.
24 changes: 22 additions & 2 deletions data/mysql-core/adapter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
type Adapter,
type AdapterUpdateDetails,
type AdapterDeleteResult,
type AdapterError,
type AdapterInsertResult,
Expand All @@ -10,6 +9,7 @@ import {
type AdapterRequirements,
type AdapterSqlLintResult,
type AdapterSqlSchemaResult,
type AdapterUpdateDetails,
type AdapterUpdateManyResult,
type AdapterUpdateResult,
type Column,
Expand Down Expand Up @@ -599,7 +599,7 @@ function createIntrospection(args: {
const { schemas } = result;
const { columns, name: tableName, schema } = table;

const columnsRecord = columns
const columnsRecord = normalizeColumns(columns)
.sort((a, b) => a.position - b.position)
.reduce(
(columns, column) => {
Expand Down Expand Up @@ -683,6 +683,26 @@ function createIntrospection(args: {
);
}

function normalizeColumns(
columns: QueryResult<typeof getTablesQuery>[number]["columns"],
): QueryResult<typeof getTablesQuery>[number]["columns"] {
if (Array.isArray(columns)) {
return columns;
}

if (typeof columns === "string") {
const parsedColumns: unknown = JSON.parse(columns);

if (Array.isArray(parsedColumns)) {
return parsedColumns as QueryResult<
typeof getTablesQuery
>[number]["columns"];
}
}

throw new TypeError("Expected MySQL introspection columns to be an array");
}

const filterOperators = [
"=",
"!=",
Expand Down
26 changes: 26 additions & 0 deletions data/mysql-core/introspection-hardening.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,32 @@ import { createMySQLAdapter } from "./adapter";
import { mockTablesQuery } from "./introspection";

describe("mysql-core introspection hardening", () => {
it("parses JSON string columns returned by MariaDB introspection", async () => {
const tables = mockTablesQuery().map((table) => ({
...table,
columns: JSON.stringify(table.columns),
}));
const execute: SequenceExecutor["execute"] = (query) => {
if (query.sql.toLowerCase().includes("timezone")) {
return Promise.resolve([null, [{ timezone: "UTC" }]] as never);
}

return Promise.resolve([null, tables] as never);
};
const executor: SequenceExecutor = {
execute,
executeSequence: vi.fn() as SequenceExecutor["executeSequence"],
};
const adapter = createMySQLAdapter({ executor });

const [error, result] = await adapter.introspect({});

expect(error).toBeNull();
expect(
result?.schemas.studio?.tables.animals?.columns.id?.isAutoincrement,
).toBe(true);
});

it("falls back to UTC when timezone introspection fails", async () => {
const execute: SequenceExecutor["execute"] = (query) => {
if (query.sql.toLowerCase().includes("timezone")) {
Expand Down