Skip to content

Commit f791252

Browse files
authored
support change column collation for mysql (#206)
1 parent 4cff920 commit f791252

9 files changed

Lines changed: 421 additions & 35 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export default function ColumnCollation({
2+
value,
3+
onChange,
4+
disabled,
5+
}: {
6+
value?: string;
7+
onChange: (value: string) => void;
8+
disabled?: boolean;
9+
}) {
10+
return (
11+
<input
12+
value={value || ""}
13+
placeholder="Collation"
14+
disabled={disabled}
15+
list="collation-list"
16+
className="p-2 text-xs outline-none w-[150px] bg-inherit"
17+
spellCheck={false}
18+
onChange={(e) => onChange(e.currentTarget.value)}
19+
/>
20+
);
21+
}

src/components/gui/schema-editor/column-type-selector.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,6 @@ export default function ColumnTypeSelector({
170170
onFocus={() => setShowSuggestion(true)}
171171
onBlur={() => {
172172
setShowSuggestion(false);
173-
console.log("blur");
174173
}}
175174
value={value}
176175
onChange={(e) => {

src/components/gui/schema-editor/index.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ export default function SchemaEditor({
6565
return databaseDriver.createUpdateTableSchema(value).join(";\n");
6666
}, [value, databaseDriver]);
6767

68+
const editorOptions = useMemo(() => {
69+
return {
70+
collations: databaseDriver.getCollationList(),
71+
};
72+
}, [databaseDriver]);
73+
6874
return (
6975
<div className="w-full h-full flex flex-col">
7076
<div className="grow-0 shrink-0">
@@ -188,6 +194,7 @@ export default function SchemaEditor({
188194
onChange={onChange}
189195
onAddColumn={onAddColumn}
190196
schemaName={value.schemaName}
197+
options={editorOptions}
191198
disabledEditExistingColumn={
192199
!databaseDriver.getFlags().supportModifyColumn
193200
}

src/components/gui/schema-editor/schema-editor-column-list.tsx

Lines changed: 77 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Dispatch, SetStateAction, useCallback } from "react";
1+
import { Dispatch, SetStateAction, useCallback, useMemo } from "react";
22
import {
33
DropdownMenu,
44
DropdownMenuContent,
@@ -42,11 +42,16 @@ import {
4242
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
4343
import { useDatabaseDriver } from "@/context/driver-provider";
4444
import ColumnTypeSelector from "./column-type-selector";
45+
import ColumnCollation from "./column-collation";
4546

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

51+
export interface SchemaEditorOptions {
52+
collations: string[];
53+
}
54+
5055
function changeColumnOnIndex(
5156
idx: number,
5257
value: Partial<DatabaseTableColumn> | null,
@@ -135,13 +140,15 @@ function ColumnItem({
135140
idx,
136141
schemaName,
137142
onChange,
143+
options,
138144
disabledEditExistingColumn,
139145
}: {
140146
value: DatabaseTableColumnChange;
141147
idx: number;
142148
schemaName?: string;
143149
onChange: Dispatch<SetStateAction<DatabaseTableSchemaChange>>;
144150
disabledEditExistingColumn?: boolean;
151+
options: SchemaEditorOptions;
145152
}) {
146153
const {
147154
setNodeRef,
@@ -344,6 +351,21 @@ function ColumnItem({
344351
</DropdownMenu>
345352
</div>
346353
</td>
354+
{options.collations.length > 0 && (
355+
<td className="border">
356+
<ColumnCollation
357+
value={column.constraint?.collate}
358+
onChange={(value) => {
359+
change({
360+
constraint: {
361+
...column.constraint,
362+
collate: value || undefined,
363+
},
364+
});
365+
}}
366+
/>
367+
</td>
368+
)}
347369
<td className="px-1 border">
348370
<button
349371
className="p-1"
@@ -364,12 +386,14 @@ export default function SchemaEditorColumnList({
364386
schemaName,
365387
onAddColumn,
366388
disabledEditExistingColumn,
389+
options,
367390
}: Readonly<{
368391
columns: DatabaseTableColumnChange[];
369392
onChange: Dispatch<SetStateAction<DatabaseTableSchemaChange>>;
370393
schemaName?: string;
371394
onAddColumn: () => void;
372395
disabledEditExistingColumn?: boolean;
396+
options: SchemaEditorOptions;
373397
}>) {
374398
const headerStyle = "text-xs p-2 text-left bg-secondary border";
375399

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

421+
const headerCounter = useMemo(() => {
422+
let initialCounter = 7;
423+
if (options.collations.length > 0) {
424+
initialCounter++;
425+
}
426+
427+
return initialCounter;
428+
}, [options]);
429+
397430
return (
398431
<div className="p-4">
399-
<table className="w-full rounded overflow-hidden">
400-
<thead>
401-
<tr>
402-
<td className={cn(headerStyle, "w-[20px]")}></td>
403-
<th className={cn(headerStyle, "w-[100px]")}>Name</th>
404-
<th className={cn(headerStyle, "w-[150px]")}>Type</th>
405-
<th className={cn(headerStyle, "w-[150px]")}>Default</th>
406-
<th className={cn(headerStyle, "w-[50px]")}>Null</th>
407-
<th className={cn(headerStyle)}>Constraint</th>
408-
<th className={cn(headerStyle, "w-[30px]")}></th>
409-
</tr>
410-
</thead>
411-
<tbody>
412-
<DndContext
413-
onDragEnd={handleDragEnd}
414-
modifiers={[restrictToVerticalAxis]}
415-
>
432+
{options.collations.length > 0 && (
433+
<datalist id="collation-list" className="hidden">
434+
{options.collations.map((collation) => (
435+
<option key={collation} value={collation} />
436+
))}
437+
</datalist>
438+
)}
439+
440+
<DndContext
441+
onDragEnd={handleDragEnd}
442+
modifiers={[restrictToVerticalAxis]}
443+
>
444+
<table className="w-full rounded overflow-hidden">
445+
<thead>
446+
<tr>
447+
<td className={cn(headerStyle, "w-[20px]")}></td>
448+
<th className={cn(headerStyle, "w-[100px]")}>Name</th>
449+
<th className={cn(headerStyle, "w-[150px]")}>Type</th>
450+
<th className={cn(headerStyle, "w-[150px]")}>Default</th>
451+
<th className={cn(headerStyle, "w-[50px]")}>Null</th>
452+
<th className={cn(headerStyle)}>Constraint</th>
453+
454+
{options.collations.length > 0 && (
455+
<th className={cn(headerStyle, "w-[160px]")}>Collation</th>
456+
)}
457+
458+
<th className={cn(headerStyle, "w-[30px]")}></th>
459+
</tr>
460+
</thead>
461+
<tbody>
416462
<SortableContext
417463
items={columns.map((c) => c.key)}
418464
strategy={verticalListSortingStrategy}
@@ -425,21 +471,22 @@ export default function SchemaEditorColumnList({
425471
onChange={onChange}
426472
schemaName={schemaName}
427473
disabledEditExistingColumn={disabledEditExistingColumn}
474+
options={options}
428475
/>
429476
))}
430477
</SortableContext>
431-
</DndContext>
432-
</tbody>
433-
<tfoot>
434-
<tr>
435-
<td colSpan={7} className="px-4 py-2 border">
436-
<Button size="sm" onClick={onAddColumn}>
437-
<LucidePlus className="w-4 h-4 mr-1" /> Add Column
438-
</Button>
439-
</td>
440-
</tr>
441-
</tfoot>
442-
</table>
478+
</tbody>
479+
<tfoot>
480+
<tr>
481+
<td colSpan={headerCounter} className="px-4 py-2 border">
482+
<Button size="sm" onClick={onAddColumn}>
483+
<LucidePlus className="w-4 h-4 mr-1" /> Add Column
484+
</Button>
485+
</td>
486+
</tr>
487+
</tfoot>
488+
</table>
489+
</DndContext>
443490
</div>
444491
);
445492
}

src/drivers/base-driver.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ export abstract class BaseDriver {
270270
abstract getFlags(): DriverFlags;
271271
abstract getCurrentSchema(): Promise<string | null>;
272272
abstract columnTypeSelector: ColumnTypeSelector;
273+
abstract getCollationList(): string[];
273274

274275
// Helper class
275276
abstract escapeId(id: string): string;

src/drivers/common-sql-imp.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ export default abstract class CommonSQLImplement extends BaseDriver {
2828
return null;
2929
}
3030

31+
getCollationList(): string[] {
32+
return [];
33+
}
34+
3135
async updateTableData(
3236
schemaName: string,
3337
tableName: string,

src/drivers/mysql/generate-schema.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
import { omit, isEqual } from "lodash";
99

1010
function wrapParen(str: string) {
11+
if (str.toUpperCase() === "NULL") return str;
1112
if (str.length >= 2 && str.startsWith("(") && str.endsWith(")")) return str;
1213
return "(" + str + ")";
1314
}
@@ -81,6 +82,10 @@ function generateCreateColumn(
8182
);
8283
}
8384

85+
if (col.constraint?.collate) {
86+
tokens.push("COLLATE " + driver.escapeValue(col.constraint.collate));
87+
}
88+
8489
if (col.constraint?.checkExpression) {
8590
tokens.push("CHECK " + wrapParen(col.constraint.checkExpression));
8691
}
@@ -149,8 +154,6 @@ export function generateMySqlSchemaChange(
149154
);
150155
}
151156

152-
console.log(col.old, col.new);
153-
154157
// check if there is any changed except name
155158
if (!isEqual(omit(col.old, ["name"]), omit(col.new, ["name"]))) {
156159
lines.push(`MODIFY COLUMN ${generateCreateColumn(driver, col.new)}`);

0 commit comments

Comments
 (0)