mirror of
https://github.com/chartdb/chartdb.git
synced 2025-10-24 16:43:59 +00:00
Compare commits
1 Commits
jf/add_edi
...
jf/add_sup
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21ba816a6d |
@@ -143,6 +143,7 @@ export const en = {
|
||||
title: 'Field Attributes',
|
||||
unique: 'Unique',
|
||||
auto_increment: 'Auto Increment',
|
||||
array: 'Declare Array',
|
||||
character_length: 'Max Length',
|
||||
precision: 'Precision',
|
||||
scale: 'Scale',
|
||||
|
||||
@@ -165,3 +165,21 @@ export const supportsAutoIncrementDataType = (
|
||||
'decimal',
|
||||
].includes(dataTypeName.toLocaleLowerCase());
|
||||
};
|
||||
|
||||
export const supportsArrayDataType = (dataTypeName: string): boolean => {
|
||||
// Types that do NOT support arrays in PostgreSQL
|
||||
const unsupportedTypes = [
|
||||
'serial',
|
||||
'bigserial',
|
||||
'smallserial',
|
||||
'serial2',
|
||||
'serial4',
|
||||
'serial8',
|
||||
'xml',
|
||||
'money',
|
||||
];
|
||||
|
||||
// Check if the type is in the unsupported list
|
||||
const normalizedType = dataTypeName.toLowerCase();
|
||||
return !unsupportedTypes.includes(normalizedType);
|
||||
};
|
||||
|
||||
@@ -286,10 +286,14 @@ export function exportPostgreSQL({
|
||||
}
|
||||
}
|
||||
|
||||
// Handle array types (check if the type name ends with '[]')
|
||||
if (typeName.endsWith('[]')) {
|
||||
typeWithSize =
|
||||
typeWithSize.replace('[]', '') + '[]';
|
||||
// Handle array types (check if the field has array property or type name ends with '[]')
|
||||
if (field.array || typeName.endsWith('[]')) {
|
||||
if (!typeName.endsWith('[]')) {
|
||||
typeWithSize = typeWithSize + '[]';
|
||||
} else {
|
||||
typeWithSize =
|
||||
typeWithSize.replace('[]', '') + '[]';
|
||||
}
|
||||
}
|
||||
|
||||
const notNull = field.nullable ? '' : ' NOT NULL';
|
||||
|
||||
@@ -29,6 +29,7 @@ export interface SQLColumn {
|
||||
comment?: string;
|
||||
default?: string;
|
||||
increment?: boolean;
|
||||
array?: boolean;
|
||||
}
|
||||
|
||||
export interface SQLTable {
|
||||
@@ -612,6 +613,7 @@ export function convertToChartDBDiagram(
|
||||
default: column.default || '',
|
||||
createdAt: Date.now(),
|
||||
increment: column.increment,
|
||||
array: column.array,
|
||||
};
|
||||
|
||||
// Add type arguments if present
|
||||
|
||||
@@ -373,6 +373,13 @@ function extractColumnsFromSQL(sql: string): SQLColumn[] {
|
||||
'SMALLSERIAL',
|
||||
].includes(upperType.split('(')[0]);
|
||||
|
||||
// Check if it's an array type
|
||||
let isArrayType = false;
|
||||
if (columnType.endsWith('[]')) {
|
||||
isArrayType = true;
|
||||
columnType = columnType.slice(0, -2);
|
||||
}
|
||||
|
||||
// Normalize the type
|
||||
columnType = normalizePostgreSQLType(columnType);
|
||||
|
||||
@@ -395,6 +402,7 @@ function extractColumnsFromSQL(sql: string): SQLColumn[] {
|
||||
trimmedLine.includes('uuid_generate_v4()') ||
|
||||
trimmedLine.includes('GENERATED ALWAYS AS IDENTITY') ||
|
||||
trimmedLine.includes('GENERATED BY DEFAULT AS IDENTITY'),
|
||||
array: isArrayType,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -782,6 +790,16 @@ export async function fromPostgres(
|
||||
normalizePostgreSQLType(rawDataType);
|
||||
}
|
||||
|
||||
// Check if it's an array type
|
||||
let isArrayType = false;
|
||||
if (normalizedBaseType.endsWith('[]')) {
|
||||
isArrayType = true;
|
||||
normalizedBaseType = normalizedBaseType.slice(
|
||||
0,
|
||||
-2
|
||||
);
|
||||
}
|
||||
|
||||
// Now handle parameters - but skip for integer types that shouldn't have them
|
||||
let finalDataType = normalizedBaseType;
|
||||
|
||||
@@ -874,6 +892,7 @@ export async function fromPostgres(
|
||||
stmt.sql
|
||||
.toUpperCase()
|
||||
.includes('IDENTITY')),
|
||||
array: isArrayType,
|
||||
});
|
||||
}
|
||||
} else if (def.resource === 'constraint') {
|
||||
|
||||
@@ -19,6 +19,7 @@ export interface DBField {
|
||||
unique: boolean;
|
||||
nullable: boolean;
|
||||
increment?: boolean | null;
|
||||
array?: boolean | null;
|
||||
createdAt: number;
|
||||
characterMaximumLength?: string | null;
|
||||
precision?: number | null;
|
||||
@@ -36,6 +37,7 @@ export const dbFieldSchema: z.ZodType<DBField> = z.object({
|
||||
unique: z.boolean(),
|
||||
nullable: z.boolean(),
|
||||
increment: z.boolean().or(z.null()).optional(),
|
||||
array: z.boolean().or(z.null()).optional(),
|
||||
createdAt: z.number(),
|
||||
characterMaximumLength: z.string().or(z.null()).optional(),
|
||||
precision: z.number().or(z.null()).optional(),
|
||||
@@ -71,13 +73,48 @@ export const createFieldsFromMetadata = ({
|
||||
pk.column.trim()
|
||||
);
|
||||
|
||||
return sortedColumns.map(
|
||||
(col: ColumnInfo): DBField => ({
|
||||
return sortedColumns.map((col: ColumnInfo): DBField => {
|
||||
// Check if type is an array (ends with [])
|
||||
const isArrayType = col.type.endsWith('[]');
|
||||
let baseType = col.type;
|
||||
|
||||
// Extract base type and any parameters if it's an array
|
||||
if (isArrayType) {
|
||||
baseType = col.type.slice(0, -2); // Remove the [] suffix
|
||||
}
|
||||
|
||||
// Extract parameters from types like "character varying(100)" or "numeric(10,2)"
|
||||
let charMaxLength = col.character_maximum_length;
|
||||
let precision = col.precision?.precision;
|
||||
let scale = col.precision?.scale;
|
||||
|
||||
// Handle types with single parameter like varchar(100)
|
||||
const singleParamMatch = baseType.match(/^(.+?)\((\d+)\)$/);
|
||||
if (singleParamMatch) {
|
||||
baseType = singleParamMatch[1];
|
||||
if (!charMaxLength || charMaxLength === 'null') {
|
||||
charMaxLength = singleParamMatch[2];
|
||||
}
|
||||
}
|
||||
|
||||
// Handle types with two parameters like numeric(10,2)
|
||||
const twoParamMatch = baseType.match(/^(.+?)\((\d+),\s*(\d+)\)$/);
|
||||
if (twoParamMatch) {
|
||||
baseType = twoParamMatch[1];
|
||||
if (!precision) {
|
||||
precision = parseInt(twoParamMatch[2]);
|
||||
}
|
||||
if (!scale) {
|
||||
scale = parseInt(twoParamMatch[3]);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: generateId(),
|
||||
name: col.name,
|
||||
type: {
|
||||
id: col.type.split(' ').join('_').toLowerCase(),
|
||||
name: col.type.toLowerCase(),
|
||||
id: baseType.split(' ').join('_').toLowerCase(),
|
||||
name: baseType.toLowerCase(),
|
||||
},
|
||||
primaryKey: tablePrimaryKeysColumns.includes(col.name),
|
||||
unique: Object.values(aggregatedIndexes).some(
|
||||
@@ -87,20 +124,18 @@ export const createFieldsFromMetadata = ({
|
||||
idx.columns[0].name === col.name
|
||||
),
|
||||
nullable: Boolean(col.nullable),
|
||||
...(col.character_maximum_length &&
|
||||
col.character_maximum_length !== 'null'
|
||||
? { characterMaximumLength: col.character_maximum_length }
|
||||
...(isArrayType ? { array: true } : {}),
|
||||
...(charMaxLength && charMaxLength !== 'null'
|
||||
? { characterMaximumLength: charMaxLength }
|
||||
: {}),
|
||||
...(col.precision?.precision
|
||||
? { precision: col.precision.precision }
|
||||
: {}),
|
||||
...(col.precision?.scale ? { scale: col.precision.scale } : {}),
|
||||
...(precision ? { precision } : {}),
|
||||
...(scale ? { scale } : {}),
|
||||
...(col.default ? { default: col.default } : {}),
|
||||
...(col.collation ? { collation: col.collation } : {}),
|
||||
createdAt: Date.now(),
|
||||
comments: col.comment ? col.comment : undefined,
|
||||
})
|
||||
);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const generateDBFieldSuffix = (
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { FieldAttributeRange } from '@/lib/data/data-types/data-types';
|
||||
import {
|
||||
findDataTypeDataById,
|
||||
supportsAutoIncrementDataType,
|
||||
supportsArrayDataType,
|
||||
} from '@/lib/data/data-types/data-types';
|
||||
import {
|
||||
Popover,
|
||||
@@ -87,6 +88,7 @@ export const TableFieldPopover: React.FC<TableFieldPopoverProps> = ({
|
||||
unique: localField.unique,
|
||||
default: localField.default,
|
||||
increment: localField.increment,
|
||||
array: localField.array,
|
||||
});
|
||||
}
|
||||
prevFieldRef.current = localField;
|
||||
@@ -102,6 +104,13 @@ export const TableFieldPopover: React.FC<TableFieldPopoverProps> = ({
|
||||
[field.type.name]
|
||||
);
|
||||
|
||||
const supportsArray = useMemo(
|
||||
() =>
|
||||
databaseType === 'postgresql' &&
|
||||
supportsArrayDataType(field.type.name),
|
||||
[field.type.name, databaseType]
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
open={isOpen}
|
||||
@@ -168,6 +177,27 @@ export const TableFieldPopover: React.FC<TableFieldPopoverProps> = ({
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{supportsArray ? (
|
||||
<div className="flex items-center justify-between">
|
||||
<Label
|
||||
htmlFor="array"
|
||||
className="text-subtitle"
|
||||
>
|
||||
{t(
|
||||
'side_panel.tables_section.table.field_actions.array'
|
||||
)}
|
||||
</Label>
|
||||
<Checkbox
|
||||
checked={localField.array ?? false}
|
||||
onCheckedChange={(value) =>
|
||||
setLocalField((current) => ({
|
||||
...current,
|
||||
array: !!value,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="default" className="text-subtitle">
|
||||
{t(
|
||||
|
||||
@@ -7,6 +7,7 @@ import type { DataTypeData } from '@/lib/data/data-types/data-types';
|
||||
import {
|
||||
dataTypeDataToDataType,
|
||||
sortedDataTypeMap,
|
||||
supportsArrayDataType,
|
||||
} from '@/lib/data/data-types/data-types';
|
||||
import {
|
||||
Tooltip,
|
||||
@@ -175,6 +176,13 @@ export const TableField: React.FC<TableFieldProps> = ({
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the new type supports arrays - if not, clear the array property
|
||||
const newTypeName = dataType?.name ?? (value as string);
|
||||
const shouldClearArray =
|
||||
databaseType === 'postgresql' &&
|
||||
!supportsArrayDataType(newTypeName) &&
|
||||
field.array;
|
||||
|
||||
updateField({
|
||||
characterMaximumLength,
|
||||
precision,
|
||||
@@ -185,6 +193,7 @@ export const TableField: React.FC<TableFieldProps> = ({
|
||||
name: value as string,
|
||||
}
|
||||
),
|
||||
...(shouldClearArray ? { array: false } : {}),
|
||||
});
|
||||
},
|
||||
[
|
||||
@@ -193,6 +202,7 @@ export const TableField: React.FC<TableFieldProps> = ({
|
||||
field.characterMaximumLength,
|
||||
field.precision,
|
||||
field.scale,
|
||||
field.array,
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user