This is an automated email from the ASF dual-hosted git repository.
liuxun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 85e9918ac [#5454] feat(web): different data table column types are
supported depending on the provider (#5636)
85e9918ac is described below
commit 85e9918ac0058cc58fad87bc63716cb977c244e3
Author: JUN <[email protected]>
AuthorDate: Thu Nov 21 17:18:44 2024 +0800
[#5454] feat(web): different data table column types are supported
depending on the provider (#5636)
### What changes are proposed in this pull request?
When creating or updating a table, the column types will vary depending
on the provider.
### Why are these changes needed?
Fixes: #5454
### Does this PR introduce _any_ user-facing changes?
No.
### How was this patch tested?
Tested by creating and updating tables with different providers to
verify that the column types differ as expected and match the
[documentation](https://gravitino.apache.org/docs/0.6.1-incubating/lakehouse-iceberg-catalog/#table-column-types).
Additionally, verified the success of the create/update operations.
---
.../metalake/rightContent/CreateTableDialog.js | 57 +++---
web/web/src/lib/utils/initial.js | 196 ++++++++++++++++-----
2 files changed, 181 insertions(+), 72 deletions(-)
diff --git
a/web/web/src/app/metalakes/metalake/rightContent/CreateTableDialog.js
b/web/web/src/app/metalakes/metalake/rightContent/CreateTableDialog.js
index df0091a26..547382dcd 100644
--- a/web/web/src/app/metalakes/metalake/rightContent/CreateTableDialog.js
+++ b/web/web/src/app/metalakes/metalake/rightContent/CreateTableDialog.js
@@ -72,7 +72,7 @@ import {
import Icon from '@/components/Icon'
// Import Redux hooks and actions
-import { useAppDispatch } from '@/lib/hooks/useStore'
+import { useAppDispatch, useAppSelector } from '@/lib/hooks/useStore'
import { createTable, updateTable } from '@/lib/store/metalakes'
// Import form validation libraries
@@ -85,7 +85,7 @@ import { groupBy } from 'lodash-es'
import { genUpdates } from '@/lib/utils'
import { nameRegex, nameRegexDesc, keyRegex } from '@/lib/utils/regex'
import { useSearchParams } from 'next/navigation'
-import { tableColumnTypes } from '@/lib/utils/initial'
+import { getRelationalColumnTypeMap, getParameterizedColumnType } from
'@/lib/utils/initial'
// Default form values
const defaultFormValues = {
@@ -138,6 +138,10 @@ const CreateTableDialog = props => {
const catalogType = searchParams.get('type')
const schemaName = searchParams.get('schema')
+ const store = useAppSelector(state => state.metalakes)
+ const currentCatalog = store.catalogs.find(ca => ca.name === catalog)
+ const columnTypes = getRelationalColumnTypeMap(currentCatalog?.provider)
+
// Component state
const [innerProps, setInnerProps] = useState([])
const [tableColumns, setTableColumns] = useState([{ name: '', type: '',
nullable: true, comment: '' }])
@@ -210,7 +214,8 @@ const CreateTableDialog = props => {
if (field === 'type') {
updatedColumns[index].typeSuffix = ''
updatedColumns[index].paramErrors = ''
- if (tableColumnTypes.find(type => type.key === value)?.params) {
+
+ if (getParameterizedColumnType(value)) {
updatedColumns[index].paramValues = []
}
}
@@ -222,7 +227,7 @@ const CreateTableDialog = props => {
const transformParamValues = index => {
let updatedColumns = [...tableColumns]
- const validateParams = tableColumnTypes.find(type => type.key ===
updatedColumns[index].type)?.validateParams
+ const validateParams =
getParameterizedColumnType(updatedColumns[index].type)?.validateParams
const paramValues = updatedColumns[index].paramValues.filter(param =>
param !== undefined).map(Number)
const validateResult = validateParams(paramValues)
@@ -592,9 +597,9 @@ const CreateTableDialog = props => {
data-refer={`column-type-${index}`}
renderValue={selected =>
<Box>{`${selected}${column.typeSuffix || ''}`}</Box>}
>
- {tableColumnTypes.map(type => (
- <MenuItem key={type.key} value={type.key}>
- {type.key}
+ {columnTypes.map(type => (
+ <MenuItem key={type} value={type}>
+ {type}
</MenuItem>
))}
</Select>
@@ -621,28 +626,26 @@ const CreateTableDialog = props => {
})
}
- return tableColumnTypes
- .find(t => t.key === column.type)
- ?.params?.map((param, paramIndex) => (
- <TextField
- key={paramIndex}
- size='small'
- type='number'
- sx={{ minWidth: 60 }}
-
value={column.paramValues?.[paramIndex] || ''}
- onChange={e => {
- const newParamValues =
[...(column.paramValues || [])]
- newParamValues[paramIndex] =
e.target.value
- handleColumnChange({ index, field:
'paramValues', value: newParamValues })
- }}
- placeholder={`${param}`}
-
data-refer={`column-param-${index}-${paramIndex}`}
- inputProps={{ min: 0 }}
- />
- ))
+ return
getParameterizedColumnType(column.type)?.params?.map((param, paramIndex) => (
+ <TextField
+ key={paramIndex}
+ size='small'
+ type='number'
+ sx={{ minWidth: 60 }}
+ value={column.paramValues?.[paramIndex]
|| ''}
+ onChange={e => {
+ const newParamValues =
[...(column.paramValues || [])]
+ newParamValues[paramIndex] =
e.target.value
+ handleColumnChange({ index, field:
'paramValues', value: newParamValues })
+ }}
+ placeholder={`${param}`}
+
data-refer={`column-param-${index}-${paramIndex}`}
+ inputProps={{ min: 0 }}
+ />
+ ))
})()}
{selectedColumnIndex !== index &&
- tableColumnTypes.find(type => type.key ===
column.type)?.params &&
+
getParameterizedColumnType(column.type)?.params &&
column.paramValues &&
transformParamValues(index)}
</Box>
diff --git a/web/web/src/lib/utils/initial.js b/web/web/src/lib/utils/initial.js
index 1ca2854da..6c599f9ee 100644
--- a/web/web/src/lib/utils/initial.js
+++ b/web/web/src/lib/utils/initial.js
@@ -347,37 +347,23 @@ export const providers = [
}
]
-export const tableColumnTypes = [
- { key: 'boolean' },
- { key: 'byte' },
- { key: 'short' },
- { key: 'integer' },
- { key: 'long' },
- { key: 'float' },
- { key: 'double' },
- {
- key: 'decimal',
- params: ['precision', 'scale'],
+const parameterizedColumnTypes = {
+ char: {
+ params: ['length'],
validateParams: params => {
- if (params.length !== 2) {
+ if (params.length !== 1) {
return {
valid: false,
- message: 'Please set precision and scale'
+ message: 'Please set length'
}
}
- const [param1, param2] = params
- if (param1 <= 0 || param1 > 38) {
- return {
- valid: false,
- message: 'The precision must be between 1 and 38'
- }
- }
+ const length = params[0]
- if (param2 < 0 || param2 > param1) {
+ if (length <= 0) {
return {
valid: false,
- message: 'The scale must be between 0 and the precision'
+ message: 'The length must be greater than 0'
}
}
@@ -386,28 +372,28 @@ export const tableColumnTypes = [
}
}
},
- { key: 'date' },
- { key: 'time' },
- { key: 'timestamp' },
- { key: 'timestamp_tz' },
- { key: 'string' },
- {
- key: 'char',
- params: ['length'],
+ decimal: {
+ params: ['precision', 'scale'],
validateParams: params => {
- if (params.length !== 1) {
+ if (params.length !== 2) {
return {
valid: false,
- message: 'Please set length'
+ message: 'Please set precision and scale'
}
}
- const length = params[0]
+ const [param1, param2] = params
+ if (param1 <= 0 || param1 > 38) {
+ return {
+ valid: false,
+ message: 'The precision must be between 1 and 38'
+ }
+ }
- if (length <= 0) {
+ if (param2 < 0 || param2 > param1) {
return {
valid: false,
- message: 'The length must be greater than 0'
+ message: 'The scale must be between 0 and the precision'
}
}
@@ -416,8 +402,7 @@ export const tableColumnTypes = [
}
}
},
- {
- key: 'varchar',
+ fixed: {
params: ['length'],
validateParams: params => {
if (params.length !== 1) {
@@ -441,10 +426,7 @@ export const tableColumnTypes = [
}
}
},
- { key: 'interval_day' },
- { key: 'interval_year' },
- {
- key: 'fixed',
+ varchar: {
params: ['length'],
validateParams: params => {
if (params.length !== 1) {
@@ -467,7 +449,131 @@ export const tableColumnTypes = [
valid: true
}
}
- },
- { key: 'uuid' },
- { key: 'binary' }
-]
+ }
+}
+
+export const getParameterizedColumnType = type => {
+ if (Object.keys(parameterizedColumnTypes).includes(type)) {
+ return parameterizedColumnTypes[type]
+ }
+}
+
+const relationalColumnTypeMap = {
+ 'lakehouse-iceberg': [
+ 'binary',
+ 'boolean',
+ 'date',
+ 'decimal',
+ 'double',
+ 'fixed',
+ 'float',
+ 'integer',
+ 'long',
+ 'string',
+ 'time',
+ 'timestamp',
+ 'timestamp_tz',
+ 'uuid'
+ ],
+
+ hive: [
+ 'binary',
+ 'boolean',
+ 'byte',
+ 'char',
+ 'date',
+ 'decimal',
+ 'double',
+ 'float',
+ 'integer',
+ 'interval_day',
+ 'interval_year',
+ 'long',
+ 'short',
+ 'string',
+ 'timestamp',
+ 'varchar'
+ ],
+
+ 'jdbc-mysql': [
+ 'binary',
+ 'byte',
+ 'byte unsigned',
+ 'char',
+ 'date',
+ 'decimal',
+ 'double',
+ 'float',
+ 'integer',
+ 'integer unsigned',
+ 'long',
+ 'long unsigned',
+ 'short',
+ 'short unsigned',
+ 'string',
+ 'time',
+ 'timestamp',
+ 'varchar'
+ ],
+ 'jdbc-postgresql': [
+ 'binary',
+ 'boolean',
+ 'char',
+ 'date',
+ 'decimal',
+ 'double',
+ 'float',
+ 'integer',
+ 'long',
+ 'short',
+ 'string',
+ 'time',
+ 'timestamp',
+ 'timestamp_tz',
+ 'varchar'
+ ],
+
+ 'jdbc-doris': [
+ 'boolean',
+ 'byte',
+ 'char',
+ 'date',
+ 'decimal',
+ 'double',
+ 'float',
+ 'integer',
+ 'long',
+ 'short',
+ 'string',
+ 'timestamp',
+ 'varchar'
+ ],
+
+ 'lakehouse-paimon': [
+ 'binary',
+ 'boolean',
+ 'byte',
+ 'char',
+ 'date',
+ 'decimal',
+ 'double',
+ 'fixed',
+ 'float',
+ 'integer',
+ 'long',
+ 'short',
+ 'string',
+ 'time',
+ 'timestamp',
+ 'timestamp_tz',
+ 'varchar'
+ ]
+}
+
+export const getRelationalColumnTypeMap = catalog => {
+ if (Object.keys(relationalColumnTypeMap).includes(catalog)) {
+ return relationalColumnTypeMap[catalog]
+ }
+
+ return []
+}