Skip to content

Commit

Permalink
support change column collation for mysql (#206)
Browse files Browse the repository at this point in the history
  • Loading branch information
invisal authored Dec 15, 2024
1 parent 4cff920 commit f791252
Show file tree
Hide file tree
Showing 9 changed files with 421 additions and 35 deletions.
21 changes: 21 additions & 0 deletions src/components/gui/schema-editor/column-collation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export default function ColumnCollation({
value,
onChange,
disabled,
}: {
value?: string;
onChange: (value: string) => void;
disabled?: boolean;
}) {
return (
<input
value={value || ""}
placeholder="Collation"
disabled={disabled}
list="collation-list"
className="p-2 text-xs outline-none w-[150px] bg-inherit"
spellCheck={false}
onChange={(e) => onChange(e.currentTarget.value)}
/>
);
}
1 change: 0 additions & 1 deletion src/components/gui/schema-editor/column-type-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ export default function ColumnTypeSelector({
onFocus={() => setShowSuggestion(true)}
onBlur={() => {
setShowSuggestion(false);
console.log("blur");
}}
value={value}
onChange={(e) => {
Expand Down
7 changes: 7 additions & 0 deletions src/components/gui/schema-editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ export default function SchemaEditor({
return databaseDriver.createUpdateTableSchema(value).join(";\n");
}, [value, databaseDriver]);

const editorOptions = useMemo(() => {
return {
collations: databaseDriver.getCollationList(),
};
}, [databaseDriver]);

return (
<div className="w-full h-full flex flex-col">
<div className="grow-0 shrink-0">
Expand Down Expand Up @@ -188,6 +194,7 @@ export default function SchemaEditor({
onChange={onChange}
onAddColumn={onAddColumn}
schemaName={value.schemaName}
options={editorOptions}
disabledEditExistingColumn={
!databaseDriver.getFlags().supportModifyColumn
}
Expand Down
107 changes: 77 additions & 30 deletions src/components/gui/schema-editor/schema-editor-column-list.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Dispatch, SetStateAction, useCallback } from "react";
import { Dispatch, SetStateAction, useCallback, useMemo } from "react";
import {
DropdownMenu,
DropdownMenuContent,
Expand Down Expand Up @@ -42,11 +42,16 @@ import {
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
import { useDatabaseDriver } from "@/context/driver-provider";
import ColumnTypeSelector from "./column-type-selector";
import ColumnCollation from "./column-collation";

export type ColumnChangeEvent = (
newValue: Partial<DatabaseTableColumn> | null
) => void;

export interface SchemaEditorOptions {
collations: string[];
}

function changeColumnOnIndex(
idx: number,
value: Partial<DatabaseTableColumn> | null,
Expand Down Expand Up @@ -135,13 +140,15 @@ function ColumnItem({
idx,
schemaName,
onChange,
options,
disabledEditExistingColumn,
}: {
value: DatabaseTableColumnChange;
idx: number;
schemaName?: string;
onChange: Dispatch<SetStateAction<DatabaseTableSchemaChange>>;
disabledEditExistingColumn?: boolean;
options: SchemaEditorOptions;
}) {
const {
setNodeRef,
Expand Down Expand Up @@ -344,6 +351,21 @@ function ColumnItem({
</DropdownMenu>
</div>
</td>
{options.collations.length > 0 && (
<td className="border">
<ColumnCollation
value={column.constraint?.collate}
onChange={(value) => {
change({
constraint: {
...column.constraint,
collate: value || undefined,
},
});
}}
/>
</td>
)}
<td className="px-1 border">
<button
className="p-1"
Expand All @@ -364,12 +386,14 @@ export default function SchemaEditorColumnList({
schemaName,
onAddColumn,
disabledEditExistingColumn,
options,
}: Readonly<{
columns: DatabaseTableColumnChange[];
onChange: Dispatch<SetStateAction<DatabaseTableSchemaChange>>;
schemaName?: string;
onAddColumn: () => void;
disabledEditExistingColumn?: boolean;
options: SchemaEditorOptions;
}>) {
const headerStyle = "text-xs p-2 text-left bg-secondary border";

Expand All @@ -394,25 +418,47 @@ export default function SchemaEditorColumnList({
[columns, onChange]
);

const headerCounter = useMemo(() => {
let initialCounter = 7;
if (options.collations.length > 0) {
initialCounter++;
}

return initialCounter;
}, [options]);

return (
<div className="p-4">
<table className="w-full rounded overflow-hidden">
<thead>
<tr>
<td className={cn(headerStyle, "w-[20px]")}></td>
<th className={cn(headerStyle, "w-[100px]")}>Name</th>
<th className={cn(headerStyle, "w-[150px]")}>Type</th>
<th className={cn(headerStyle, "w-[150px]")}>Default</th>
<th className={cn(headerStyle, "w-[50px]")}>Null</th>
<th className={cn(headerStyle)}>Constraint</th>
<th className={cn(headerStyle, "w-[30px]")}></th>
</tr>
</thead>
<tbody>
<DndContext
onDragEnd={handleDragEnd}
modifiers={[restrictToVerticalAxis]}
>
{options.collations.length > 0 && (
<datalist id="collation-list" className="hidden">
{options.collations.map((collation) => (
<option key={collation} value={collation} />
))}
</datalist>
)}

<DndContext
onDragEnd={handleDragEnd}
modifiers={[restrictToVerticalAxis]}
>
<table className="w-full rounded overflow-hidden">
<thead>
<tr>
<td className={cn(headerStyle, "w-[20px]")}></td>
<th className={cn(headerStyle, "w-[100px]")}>Name</th>
<th className={cn(headerStyle, "w-[150px]")}>Type</th>
<th className={cn(headerStyle, "w-[150px]")}>Default</th>
<th className={cn(headerStyle, "w-[50px]")}>Null</th>
<th className={cn(headerStyle)}>Constraint</th>

{options.collations.length > 0 && (
<th className={cn(headerStyle, "w-[160px]")}>Collation</th>
)}

<th className={cn(headerStyle, "w-[30px]")}></th>
</tr>
</thead>
<tbody>
<SortableContext
items={columns.map((c) => c.key)}
strategy={verticalListSortingStrategy}
Expand All @@ -425,21 +471,22 @@ export default function SchemaEditorColumnList({
onChange={onChange}
schemaName={schemaName}
disabledEditExistingColumn={disabledEditExistingColumn}
options={options}
/>
))}
</SortableContext>
</DndContext>
</tbody>
<tfoot>
<tr>
<td colSpan={7} className="px-4 py-2 border">
<Button size="sm" onClick={onAddColumn}>
<LucidePlus className="w-4 h-4 mr-1" /> Add Column
</Button>
</td>
</tr>
</tfoot>
</table>
</tbody>
<tfoot>
<tr>
<td colSpan={headerCounter} className="px-4 py-2 border">
<Button size="sm" onClick={onAddColumn}>
<LucidePlus className="w-4 h-4 mr-1" /> Add Column
</Button>
</td>
</tr>
</tfoot>
</table>
</DndContext>
</div>
);
}
1 change: 1 addition & 0 deletions src/drivers/base-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ export abstract class BaseDriver {
abstract getFlags(): DriverFlags;
abstract getCurrentSchema(): Promise<string | null>;
abstract columnTypeSelector: ColumnTypeSelector;
abstract getCollationList(): string[];

// Helper class
abstract escapeId(id: string): string;
Expand Down
4 changes: 4 additions & 0 deletions src/drivers/common-sql-imp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export default abstract class CommonSQLImplement extends BaseDriver {
return null;
}

getCollationList(): string[] {
return [];
}

async updateTableData(
schemaName: string,
tableName: string,
Expand Down
7 changes: 5 additions & 2 deletions src/drivers/mysql/generate-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { omit, isEqual } from "lodash";

function wrapParen(str: string) {
if (str.toUpperCase() === "NULL") return str;
if (str.length >= 2 && str.startsWith("(") && str.endsWith(")")) return str;
return "(" + str + ")";
}
Expand Down Expand Up @@ -81,6 +82,10 @@ function generateCreateColumn(
);
}

if (col.constraint?.collate) {
tokens.push("COLLATE " + driver.escapeValue(col.constraint.collate));
}

if (col.constraint?.checkExpression) {
tokens.push("CHECK " + wrapParen(col.constraint.checkExpression));
}
Expand Down Expand Up @@ -149,8 +154,6 @@ export function generateMySqlSchemaChange(
);
}

console.log(col.old, col.new);

// check if there is any changed except name
if (!isEqual(omit(col.old, ["name"]), omit(col.new, ["name"]))) {
lines.push(`MODIFY COLUMN ${generateCreateColumn(driver, col.new)}`);
Expand Down
Loading

0 comments on commit f791252

Please sign in to comment.