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
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@ import type Ref from "@dbml/core/types/model_structure/ref";

import { dbmlTestCodeInJSONTableFormat } from "@/tests/data";


describe("create relational tables map", () => {
test("create relational tables map", () => {
expect(
createRelationalTalesMap([
...(dbmlTestCodeInJSONTableFormat.refs as unknown as Ref[]),
...(dbmlTestCodeInJSONTableFormat.refs as unknown as Ref[]),
const relationalTablesMap = createRelationalTalesMap([
...(dbmlTestCodeInJSONTableFormat.refs as unknown as Ref[]),
...(dbmlTestCodeInJSONTableFormat.refs as unknown as Ref[]),
]);

const normalizedMap = new Map(
Array.from(relationalTablesMap.entries()).map(([field, tables]) => [
field,
new Set(tables),
]),
).toEqual(
);

expect(normalizedMap).toEqual(
new Map([
["users.id", new Set(["follows"])],
["follows.following_user_id", new Set(["users"])],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,66 @@ import { dbmlFieldToJSONTableField } from "./dbmlFieldToJSONTableField";

import { dbmlTestCodeInJSONTableFormat, parsedDBML } from "@/tests/data";

const normalizeField = (
field: ReturnType<typeof dbmlFieldToJSONTableField>,
): unknown => {
if (Array.isArray(field.relational_tables)) {
return {
...field,
relational_tables: new Set(field.relational_tables),
} as any;
}

return field;
};

describe("transform dbml field to json table field", () => {
const enumsSet = createEnumsSet(parsedDBML.enums);
const relationalFieldMap = createRelationalTalesMap(parsedDBML.refs);
const table = parsedDBML.tables[0];
const relationalFieldMap = createRelationalTalesMap(parsedDBML.refs);
const table = parsedDBML.tables[0];

test("transform simple field", () => {
const field = table.fields[0];

expect(
dbmlFieldToJSONTableField({
field,
enumsSet,
ownerTable: table.name,
relationalFieldMap,
}),
normalizeField(
dbmlFieldToJSONTableField({
field,
enumsSet,
ownerTable: table.name,
relationalFieldMap,
}),
),
).toEqual(dbmlTestCodeInJSONTableFormat.tables[0].fields[0]);
});

test("transform relational field", () => {
const field = table.fields[2];

expect(
dbmlFieldToJSONTableField({
field,
enumsSet,
ownerTable: table.name,
relationalFieldMap,
}),
normalizeField(
dbmlFieldToJSONTableField({
field,
enumsSet,
ownerTable: table.name,
relationalFieldMap,
}),
),
).toEqual(dbmlTestCodeInJSONTableFormat.tables[0].fields[2]);
});

test("transform enum field", () => {
const field = table.fields[4];

expect(
dbmlFieldToJSONTableField({
field,
enumsSet,
ownerTable: table.name,
relationalFieldMap,
}),
normalizeField(
dbmlFieldToJSONTableField({
field,
enumsSet,
ownerTable: table.name,
relationalFieldMap,
}),
),
).toEqual(dbmlTestCodeInJSONTableFormat.tables[0].fields[4]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,54 @@ import { dbmlSchemaToJSONTableSchema } from "./dbmlSchemaToJSONTableSchema";

import { dbmlTestCodeInJSONTableFormat, parsedDBML } from "@/tests/data";

type SchemaResult = ReturnType<typeof dbmlSchemaToJSONTableSchema>;
type TableResult = SchemaResult["tables"][number];
type FieldResult = TableResult["fields"][number];
type IndexResult = TableResult["indexes"][number];

const normalizeField = (field: FieldResult): unknown => {
if (Array.isArray(field.relational_tables)) {
return {
...field,
relational_tables: new Set(field.relational_tables),
} as any;
}

return field;
};

const normalizeIndex = (index: IndexResult): unknown => {
if (typeof index.pk === "boolean" && !index.pk) {
const { pk: _removed, ...rest } = index;
return rest as any;
}

return index;
};

const normalizeTable = (table: TableResult): unknown => {
const withNormalizedFieldsAndIndexes = {
...table,
fields: table.fields.map((field) => normalizeField(field)),
indexes: table.indexes.map((index) => normalizeIndex(index)),
} as any;

if (withNormalizedFieldsAndIndexes.headerColor === undefined) {
const { headerColor: _removed, ...rest } = withNormalizedFieldsAndIndexes;
return rest;
}

return withNormalizedFieldsAndIndexes;
};

const normalizeSchema = (schema: SchemaResult): unknown => ({
...schema,
tables: schema.tables.map((table) => normalizeTable(table)),
});

describe("transform dbml schema to json table schema", () => {
test("transform dbml schema to json table schema", () => {
expect(dbmlSchemaToJSONTableSchema(parsedDBML)).toEqual(
expect(normalizeSchema(dbmlSchemaToJSONTableSchema(parsedDBML))).toEqual(
dbmlTestCodeInJSONTableFormat,
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,58 @@ import { dbmlTableToJSONTableTable } from "./dbmlTableToJSONTableTable";

import { dbmlTestCodeInJSONTableFormat, parsedDBML } from "@/tests/data";

type TableResult = ReturnType<typeof dbmlTableToJSONTableTable>;
type FieldResult = TableResult["fields"][number];
type IndexResult = TableResult["indexes"][number];

const normalizeField = (field: FieldResult): unknown => {
if (Array.isArray(field.relational_tables)) {
return {
...field,
relational_tables: new Set(field.relational_tables),
} as any;
}

return field;
};

const normalizeIndex = (index: IndexResult): unknown => {
if (typeof index.pk === "boolean" && !index.pk) {
const { pk: _removed, ...rest } = index;
return rest as any;
}

return index;
};

const normalizeTable = (table: TableResult): unknown => {
const withNormalizedFieldsAndIndexes = {
...table,
fields: table.fields.map((field) => normalizeField(field)),
indexes: table.indexes.map((index) => normalizeIndex(index)),
} as any;

if (withNormalizedFieldsAndIndexes.headerColor === undefined) {
const { headerColor: _removed, ...rest } = withNormalizedFieldsAndIndexes;
return rest;
}

return withNormalizedFieldsAndIndexes;
};

describe("transform dbml table to json table table", () => {
test("transform table", () => {
const enumSet = createEnumsSet(parsedDBML.enums);
const relationalFieldMap = createRelationalTalesMap(parsedDBML.refs);
expect(
dbmlTableToJSONTableTable(
parsedDBML.tables[0],
relationalFieldMap,
enumSet,
),
).toEqual(dbmlTestCodeInJSONTableFormat.tables[0]);

const result = dbmlTableToJSONTableTable(
parsedDBML.tables[0],
relationalFieldMap,
enumSet,
);

expect(normalizeTable(result)).toEqual(
dbmlTestCodeInJSONTableFormat.tables[0],
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,36 @@ const Search = ({ tables }: SearchProps) => {
});
});

return results;
const collator = new Intl.Collator(undefined, {
sensitivity: "base",
numeric: true,
});

const isExact = (r: SearchResult) =>
r.name.toLowerCase() === search.toLowerCase();

const resultsSorted = results.sort((a, b) => {
// 0) exact name match goes to the very top (table or column)
const aExact = isExact(a);
const bExact = isExact(b);
if (aExact !== bExact) return aExact ? -1 : 1;

// 1) put tables before columns
if (a.type !== b.type) return a.type === "table" ? -1 : 1;

// 2) within tables: sort by table name (same as `name`)
if (a.type === "table") {
return collator.compare(a.name, b.name);
}

// 3) within columns: sort by column name, then by table name
const byColName = collator.compare(a.name, b.name);
if (byColName !== 0) return byColName;

return collator.compare(a.tableName, b.tableName);
});

return resultsSorted;
}, [tables, search]);

const handleSelect = (result: SearchResult) => {
Expand Down Expand Up @@ -172,6 +201,9 @@ const Search = ({ tables }: SearchProps) => {
className="w-full px-4 py-2 text-left text-sm focus:outline-none hover:bg-gray-100 dark:hover:bg-gray-600 focus:bg-gray-100 dark:focus:bg-gray-600 flex flex-col items-start"
>
<div className="flex space-x-2 w-full items-start">
<span className="text-xs mt-[3px]">
{result.type === "table" ? "📋" : "🔤"}
</span>
<span className="font-medium break-all text-gray-700 dark:text-gray-200">
{result.name}
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ const computeTablesPositions = (
tables: JSONTableTable[],
refs: JSONTableRef[],
): Map<string, XYPosition> => {
const tablesPositions = new Map<string, XYPosition>();

const graph = new dagre.graphlib.Graph();
graph.setGraph({
nodesep: TABLES_GAP_X * 3,
Expand All @@ -34,10 +32,36 @@ const computeTablesPositions = (

dagre.layout(graph);

const rawPositions: Array<{ name: string; x: number; y: number }> = [];

graph.nodes().forEach((node) => {
const { x, y } = graph.node(node);
tablesPositions.set(node, { x, y });
const nodeData = graph.node(node);
if (nodeData == null) return;
const width = !isNaN(nodeData.width) ? nodeData.width : 0;
const height = !isNaN(nodeData.height) ? nodeData.height : 0;
const topLeftX = nodeData.x - width / 2;
const topLeftY = nodeData.y - height / 2;
rawPositions.push({ name: node, x: topLeftX, y: topLeftY });
});

if (rawPositions.length === 0) {
return new Map<string, XYPosition>();
}

const minX = Math.min(...rawPositions.map((pos) => pos.x));
const minY = Math.min(...rawPositions.map((pos) => pos.y));

const paddingX = TABLES_GAP_X;
const paddingY = TABLES_GAP_Y;

const tablesPositions = new Map<string, XYPosition>();
rawPositions.forEach((pos) => {
tablesPositions.set(pos.name, {
x: pos.x - minX + paddingX,
y: pos.y - minY + paddingY,
});
});

return tablesPositions;
};

Expand Down
Loading