mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 01:12:56 +03:00
suggest column default values (#2352)
This commit is contained in:
parent
00e911e3cd
commit
93a7c2c734
@ -62,6 +62,7 @@ export const passMTRenameTable = () => {
|
||||
};
|
||||
|
||||
export const passMTRenameColumn = () => {
|
||||
cy.wait(10000);
|
||||
cy.get(getElementFromAlias('modify-table-edit-column-0')).click();
|
||||
cy.get(getElementFromAlias('edit-col-name'))
|
||||
.clear()
|
||||
|
45
console/package-lock.json
generated
45
console/package-lock.json
generated
@ -12669,6 +12669,26 @@
|
||||
"integrity": "sha1-wStu/cIkfBDae4dw0YUICnsEcVY=",
|
||||
"dev": true
|
||||
},
|
||||
"react-autosuggest": {
|
||||
"version": "9.4.3",
|
||||
"resolved": "https://registry.npmjs.org/react-autosuggest/-/react-autosuggest-9.4.3.tgz",
|
||||
"integrity": "sha512-wFbp5QpgFQRfw9cwKvcgLR8theikOUkv8PFsuLYqI2PUgVlx186Cz8MYt5bLxculi+jxGGUUVt+h0esaBZZouw==",
|
||||
"requires": {
|
||||
"prop-types": "^15.5.10",
|
||||
"react-autowhatever": "^10.1.2",
|
||||
"shallow-equal": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"react-autowhatever": {
|
||||
"version": "10.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-autowhatever/-/react-autowhatever-10.2.0.tgz",
|
||||
"integrity": "sha512-dqHH4uqiJldPMbL8hl/i2HV4E8FMTDEdVlOIbRqYnJi0kTpWseF9fJslk/KS9pGDnm80JkYzVI+nzFjnOG/u+g==",
|
||||
"requires": {
|
||||
"prop-types": "^15.5.8",
|
||||
"react-themeable": "^1.1.0",
|
||||
"section-iterator": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"react-base16-styling": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.5.3.tgz",
|
||||
@ -12953,6 +12973,21 @@
|
||||
"prop-types": "^15.5.0"
|
||||
}
|
||||
},
|
||||
"react-themeable": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-themeable/-/react-themeable-1.1.0.tgz",
|
||||
"integrity": "sha1-fURm3ZsrX6dQWHJ4JenxUro3mg4=",
|
||||
"requires": {
|
||||
"object-assign": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"object-assign": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
|
||||
"integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-toggle": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-toggle/-/react-toggle-4.0.2.tgz",
|
||||
@ -14185,6 +14220,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"section-iterator": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/section-iterator/-/section-iterator-2.0.0.tgz",
|
||||
"integrity": "sha1-v0RNev7rlK1Dw5rS+yYVFifMuio="
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz",
|
||||
@ -14304,6 +14344,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"shallow-equal": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.1.0.tgz",
|
||||
"integrity": "sha512-0SW1nWo1hnabO62SEeHsl8nmTVVEzguVWZCj5gaQrgWAxz/BaCja4OWdJBWLVPDxdtE/WU7c98uUCCXyPHSCvw=="
|
||||
},
|
||||
"shallowequal": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
|
||||
|
@ -79,6 +79,7 @@
|
||||
"query-string": "^6.1.0",
|
||||
"react": "16.8.2",
|
||||
"react-ace": "^6.1.1",
|
||||
"react-autosuggest": "^9.4.3",
|
||||
"react-bootstrap": "^0.32.1",
|
||||
"react-copy-to-clipboard": "^5.0.0",
|
||||
"react-dom": "16.8.2",
|
||||
|
@ -0,0 +1,65 @@
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Autosuggest from 'react-autosuggest';
|
||||
|
||||
const CustomInputAutoSuggest = props => {
|
||||
const [suggestions, setSuggestions] = useState([]);
|
||||
|
||||
const { options, theme = require('./Theme.scss') } = props;
|
||||
|
||||
const getSuggestions = value => {
|
||||
const inputValue = value.trim().toLowerCase();
|
||||
const inputLength = inputValue.length;
|
||||
const filterResults = () => {
|
||||
return options.map(option => {
|
||||
return {
|
||||
title: option.title,
|
||||
suggestions: option.suggestions.filter(
|
||||
op => op.value.toLowerCase().slice(0, inputLength) === inputValue
|
||||
),
|
||||
};
|
||||
});
|
||||
};
|
||||
return inputLength === 0 ? [...options] : filterResults();
|
||||
};
|
||||
const onSuggestionsFetchRequested = ob => {
|
||||
const { value } = ob;
|
||||
setSuggestions(getSuggestions(value));
|
||||
};
|
||||
const getSuggestionValue = suggestion => suggestion.value;
|
||||
const onSuggestionsClearRequested = () => {
|
||||
setSuggestions([]);
|
||||
};
|
||||
const renderSuggestion = suggestion => <div>{suggestion.value}</div>;
|
||||
|
||||
/* Don't render the section when there are no suggestions in it */
|
||||
const renderSectionTitle = section => {
|
||||
return section.suggestions.length > 0 ? section.title : null;
|
||||
};
|
||||
|
||||
const getSectionSuggestions = section => {
|
||||
return section.suggestions;
|
||||
};
|
||||
|
||||
return (
|
||||
<Autosuggest
|
||||
suggestions={suggestions}
|
||||
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
|
||||
onSuggestionsClearRequested={onSuggestionsClearRequested}
|
||||
getSuggestionValue={getSuggestionValue}
|
||||
renderSuggestion={renderSuggestion}
|
||||
inputProps={{ ...props }}
|
||||
theme={theme}
|
||||
multiSection
|
||||
renderSectionTitle={renderSectionTitle}
|
||||
shouldRenderSuggestions={() => true}
|
||||
getSectionSuggestions={getSectionSuggestions}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
CustomInputAutoSuggest.propTypes = {
|
||||
options: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
export default CustomInputAutoSuggest;
|
@ -0,0 +1,11 @@
|
||||
@import '../Theme.scss';
|
||||
|
||||
.suggestionsContainerOpen {
|
||||
top: 30px;
|
||||
width: 280px;
|
||||
left: 5px;
|
||||
}
|
||||
|
||||
.suggestion {
|
||||
padding: 6px 12px;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
@import '../Theme.scss';
|
||||
|
||||
.suggestionsContainerOpen {
|
||||
top: 30px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.suggestion {
|
||||
padding: 6px 12px;
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
$suggestion-width: 280px;
|
||||
$set-top: 34px;
|
||||
$suggestion-padding: 6px 12px;
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
}
|
||||
.input {
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.inputFocussed {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.inputOpen {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.suggestionsContainer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.suggestionsContainerOpen {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: $set-top;
|
||||
min-width: 100%;
|
||||
width: $suggestion-width;
|
||||
border: 1px solid #aaa;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.suggestionsList {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.suggestion {
|
||||
cursor: pointer;
|
||||
word-break: break-word;
|
||||
// padding: $suggestion-padding;
|
||||
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
cursor: default;
|
||||
display: block;
|
||||
font-size: inherit;
|
||||
padding: 8px 12px;
|
||||
width: 100%;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
box-sizing: border-box;
|
||||
|
||||
&:hover {
|
||||
background-color: #DEEBFF;
|
||||
}
|
||||
}
|
||||
|
||||
.suggestionHighlighted {
|
||||
background-color: #DEEBFF;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
color: #999;
|
||||
cursor: default;
|
||||
display: block;
|
||||
font-size: 75%;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.25em;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
text-transform: uppercase;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sectionContainer {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.sectionContainerFirst {
|
||||
margin-top: 10px;
|
||||
}
|
@ -38,6 +38,7 @@ const SearchableSelectBox = ({
|
||||
value,
|
||||
bsClass,
|
||||
styleOverrides,
|
||||
placeholder,
|
||||
filterOption,
|
||||
}) => {
|
||||
/* Select element style customization */
|
||||
@ -68,7 +69,7 @@ const SearchableSelectBox = ({
|
||||
isSearchable
|
||||
components={{ Option: CustomOption }}
|
||||
classNamePrefix={`${bsClass}`}
|
||||
placeholder="column_type"
|
||||
placeholder={placeholder}
|
||||
options={options}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
|
@ -9,6 +9,8 @@ import {
|
||||
import { UPDATE_MIGRATION_STATUS_ERROR } from '../../../Main/Actions';
|
||||
import { setTable } from '../DataActions.js';
|
||||
|
||||
import { isPostgresFunction } from '../utils';
|
||||
|
||||
const SET_DEFAULTS = 'AddTable/SET_DEFAULTS';
|
||||
const SET_TABLENAME = 'AddTable/SET_TABLENAME';
|
||||
const SET_TABLECOMMENT = 'AddTable/SET_TABLECOMMENT';
|
||||
@ -121,7 +123,14 @@ const createTableSql = () => {
|
||||
) {
|
||||
if (currentCols[i].type === 'text') {
|
||||
// if a column type is text and if it has a default value, add a single quote by default
|
||||
tableColumns += " DEFAULT '" + currentCols[i].default.value + "'";
|
||||
const checkIfFunctionFormat = isPostgresFunction(
|
||||
currentCols[i].default.value
|
||||
);
|
||||
if (!checkIfFunctionFormat) {
|
||||
tableColumns += " DEFAULT '" + currentCols[i].default.value + "'";
|
||||
} else {
|
||||
tableColumns += ' DEFAULT ' + currentCols[i].default.value;
|
||||
}
|
||||
} else {
|
||||
if (currentCols[i].type === 'uuid') {
|
||||
isUUIDDefault = true;
|
||||
|
@ -29,7 +29,7 @@ import {
|
||||
setUniqueKeys,
|
||||
} from './AddActions';
|
||||
|
||||
import { fetchColumnTypes, RESET_COLUMN_TYPE_LIST } from '../DataActions';
|
||||
import { fetchColumnTypeInfo, RESET_COLUMN_TYPE_INFO } from '../DataActions';
|
||||
import { setDefaults, setPk, createTableSql } from './AddActions';
|
||||
import { validationError, resetValidation } from './AddActions';
|
||||
|
||||
@ -71,12 +71,12 @@ class AddTable extends Component {
|
||||
this.setColDefaultValue = this.setColDefaultValue.bind(this);
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.dispatch(fetchColumnTypes());
|
||||
this.props.dispatch(fetchColumnTypeInfo());
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.props.dispatch(setDefaults());
|
||||
this.props.dispatch({
|
||||
type: RESET_COLUMN_TYPE_LIST,
|
||||
type: RESET_COLUMN_TYPE_INFO,
|
||||
});
|
||||
}
|
||||
onTableNameChange = e => {
|
||||
@ -123,9 +123,9 @@ class AddTable extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
setColDefaultValue = (i, isNullableChecked, e) => {
|
||||
setColDefaultValue = (i, isNullableChecked, value) => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(setColDefault(e.target.value, i, isNullableChecked));
|
||||
dispatch(setColDefault(value, i, isNullableChecked));
|
||||
};
|
||||
|
||||
columnValidation() {
|
||||
@ -285,6 +285,8 @@ class AddTable extends Component {
|
||||
internalError,
|
||||
dataTypes,
|
||||
schemaList,
|
||||
columnDefaultFunctions,
|
||||
columnTypeCasts,
|
||||
} = this.props;
|
||||
const styles = require('../../../Common/TableCommon/Table.scss');
|
||||
const getCreateBtnText = () => {
|
||||
@ -322,6 +324,8 @@ class AddTable extends Component {
|
||||
<TableColumns
|
||||
uniqueKeys={uniqueKeys}
|
||||
dataTypes={dataTypes}
|
||||
columnDefaultFunctions={columnDefaultFunctions}
|
||||
columnTypeCasts={columnTypeCasts}
|
||||
columns={columns}
|
||||
onRemoveColumn={this.onRemoveColumn}
|
||||
onColumnChange={this.onColumnNameChange}
|
||||
@ -435,6 +439,8 @@ const mapStateToProps = state => ({
|
||||
allSchemas: state.tables.allSchemas,
|
||||
currentSchema: state.tables.currentSchema,
|
||||
dataTypes: state.tables.columnDataTypes,
|
||||
columnDefaultFunctions: state.tables.columnDefaultFunctions,
|
||||
columnTypeCasts: state.tables.columnTypeCasts,
|
||||
columnDataTypeFetchErr: state.tables.columnDataTypeFetchErr,
|
||||
schemaList: state.tables.schemaList,
|
||||
});
|
||||
|
@ -3,11 +3,9 @@ import PropTypes from 'prop-types';
|
||||
|
||||
import SearchableSelectBox from '../../../Common/SearchableSelect/SearchableSelect';
|
||||
import { commonDataTypes } from '../utils';
|
||||
import {
|
||||
getDataOptions,
|
||||
getPlaceholder,
|
||||
getDefaultValue,
|
||||
} from '../Common/utils';
|
||||
import { getDataOptions, inferDefaultValues } from '../Common/utils';
|
||||
|
||||
import TableColumnDefault from './TableColumnDefault';
|
||||
|
||||
/* Custom style object for searchable select box */
|
||||
const customSelectBoxStyles = {
|
||||
@ -17,6 +15,9 @@ const customSelectBoxStyles = {
|
||||
singleValue: {
|
||||
color: '#555555',
|
||||
},
|
||||
valueContainer: {
|
||||
padding: '0px 12px',
|
||||
},
|
||||
};
|
||||
|
||||
const TableColumn = props => {
|
||||
@ -32,6 +33,8 @@ const TableColumn = props => {
|
||||
onColNullableChange,
|
||||
onColUniqueChange,
|
||||
dataTypes: restTypes,
|
||||
columnDefaultFunctions,
|
||||
columnTypeCasts,
|
||||
uniqueKeys,
|
||||
} = props;
|
||||
|
||||
@ -56,6 +59,7 @@ const TableColumn = props => {
|
||||
restTypes,
|
||||
i
|
||||
);
|
||||
|
||||
const getRemoveIcon = colLen => {
|
||||
let removeIcon;
|
||||
if (i + 1 === colLen) {
|
||||
@ -71,6 +75,16 @@ const TableColumn = props => {
|
||||
return removeIcon;
|
||||
};
|
||||
|
||||
/* Collect list of relevant default values if the type doesn't have any default values
|
||||
* */
|
||||
const getInferredDefaultValues = () =>
|
||||
inferDefaultValues(columnDefaultFunctions, columnTypeCasts)(column.type);
|
||||
|
||||
const defaultFunctions =
|
||||
column.type in columnDefaultFunctions
|
||||
? columnDefaultFunctions[column.type]
|
||||
: getInferredDefaultValues();
|
||||
|
||||
return (
|
||||
<div key={i} className={`${styles.display_flex} form-group`}>
|
||||
<input
|
||||
@ -92,8 +106,19 @@ const TableColumn = props => {
|
||||
bsClass={`col-type-${i} add_table_column_selector`}
|
||||
styleOverrides={customSelectBoxStyles}
|
||||
filterOption={'prefix'}
|
||||
placeholder="column_type"
|
||||
/>
|
||||
</span>
|
||||
<span className={`${styles.inputDefault} ${styles.defaultWidth}`}>
|
||||
<TableColumnDefault
|
||||
onChange={setColDefaultValue}
|
||||
colIndex={i}
|
||||
testId={`col-default-${i}`}
|
||||
column={column}
|
||||
colDefaultFunctions={defaultFunctions}
|
||||
/>
|
||||
</span>
|
||||
{/*
|
||||
<input
|
||||
placeholder={getPlaceholder(column)}
|
||||
type="text"
|
||||
@ -107,7 +132,8 @@ const TableColumn = props => {
|
||||
column.nullable || false
|
||||
)}
|
||||
data-test={`col-default-${i}`}
|
||||
/>{' '}
|
||||
/>
|
||||
*/}{' '}
|
||||
<input
|
||||
className={`${styles.inputCheckbox} form-control `}
|
||||
checked={column.nullable}
|
||||
|
@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import CustomInputAutoSuggest from '../../../Common/CustomInputAutoSuggest/CustomInputAutoSuggest';
|
||||
import {
|
||||
getPlaceholder,
|
||||
getDefaultValue,
|
||||
getDefaultFunctionsOptions,
|
||||
} from '../Common/utils';
|
||||
|
||||
const TableColumnDefault = ({
|
||||
column,
|
||||
colDefaultFunctions,
|
||||
onChange,
|
||||
testId,
|
||||
colIndex: i,
|
||||
}) => {
|
||||
// const styles = require('../../../Common/TableCommon/Table.scss');
|
||||
const handleColDefaultValueChange = (e, data) => {
|
||||
const { newValue } = data;
|
||||
onChange(i, column.nullable || false, newValue);
|
||||
};
|
||||
|
||||
const renderTableColumnDefaultHtml = () => {
|
||||
const dfVal = getDefaultValue(column);
|
||||
|
||||
/* Collect direct default functions and the indirect default functions */
|
||||
const defaultValues = getDefaultFunctionsOptions(colDefaultFunctions, i);
|
||||
|
||||
return (
|
||||
<CustomInputAutoSuggest
|
||||
options={defaultValues}
|
||||
onChange={handleColDefaultValueChange}
|
||||
value={dfVal}
|
||||
className={`col-default-value-${i} add_table_default_value_selector form-control`}
|
||||
placeholder={getPlaceholder(column)}
|
||||
id={`col-default-value-${i}`}
|
||||
data-test={testId}
|
||||
/>
|
||||
);
|
||||
};
|
||||
return renderTableColumnDefaultHtml();
|
||||
};
|
||||
|
||||
export default TableColumnDefault;
|
@ -1,8 +1,14 @@
|
||||
import { aggCategory, pgCategoryCode } from './PgInfo';
|
||||
|
||||
const commonlyUsedFunctions = ['now', 'gen_random_uuid', 'random'];
|
||||
|
||||
const getParanthesized = name => {
|
||||
return `${name}()`;
|
||||
};
|
||||
|
||||
const splitDbRow = row => {
|
||||
/* Splits comma seperated type names
|
||||
* Splits comma seperated type display names
|
||||
* Splits comma seperated type user friendly type names
|
||||
* Splits comma seperated type descriptions
|
||||
* */
|
||||
return {
|
||||
@ -59,6 +65,39 @@ const getDataTypeInfo = (row, categoryInfo, colId, cached = {}) => {
|
||||
return { typInfo: currTypeObj, typValueMap: columnTypeValueMap };
|
||||
};
|
||||
|
||||
const getDefaultFunctionsOptions = (funcs, identifier) => {
|
||||
const defaultValues = [
|
||||
{
|
||||
title: 'All Functions',
|
||||
suggestions: [],
|
||||
},
|
||||
];
|
||||
funcs.forEach((f, i) => {
|
||||
const funcVal = getParanthesized(f);
|
||||
const suggestionObj = {
|
||||
value: funcVal,
|
||||
label: funcVal,
|
||||
description: funcVal,
|
||||
key: i,
|
||||
colIdentifier: identifier,
|
||||
title: 'All Functions',
|
||||
};
|
||||
if (commonlyUsedFunctions.indexOf(f) !== -1) {
|
||||
if (defaultValues.length === 1) {
|
||||
defaultValues.push({
|
||||
title: 'Frequently Used Functions',
|
||||
suggestions: [],
|
||||
});
|
||||
}
|
||||
defaultValues[1].suggestions.push(suggestionObj);
|
||||
} else {
|
||||
defaultValues[0].suggestions.push(suggestionObj);
|
||||
}
|
||||
});
|
||||
/* Reversing the array just so that if frequently used types were present, they come first */
|
||||
return defaultValues.reverse();
|
||||
};
|
||||
|
||||
/*
|
||||
* Input arguments:
|
||||
* dataTypes -> Frequently used types
|
||||
@ -136,10 +175,41 @@ const getDefaultValue = column => {
|
||||
return ('default' in column && column.default.value) || '';
|
||||
};
|
||||
|
||||
const getRecommendedTypeCasts = (dataType, typeCasts) => {
|
||||
return (dataType in typeCasts && typeCasts[dataType][3].split(',')) || [];
|
||||
};
|
||||
|
||||
const inferDefaultValues = (defaultFuncs, typeCasts) => {
|
||||
let defaultValues = [];
|
||||
const visitedType = {};
|
||||
/* Current type is the type for which default values needs to be computed
|
||||
* Algorithm:
|
||||
* Look for the types which the current type can be casted to
|
||||
* Try to find the default values for the right type and accumulate it to an array
|
||||
* */
|
||||
const computeDefaultValues = currentType => {
|
||||
visitedType[currentType] = true;
|
||||
/* Retrieve the recommended type casts for the current type */
|
||||
const validRightCasts = getRecommendedTypeCasts(currentType, typeCasts);
|
||||
validRightCasts.forEach(v => {
|
||||
if (!visitedType[v]) {
|
||||
if (v in defaultFuncs) {
|
||||
visitedType[v] = true;
|
||||
defaultValues = [...defaultValues, ...defaultFuncs[v]];
|
||||
}
|
||||
}
|
||||
});
|
||||
return defaultValues;
|
||||
};
|
||||
return computeDefaultValues;
|
||||
};
|
||||
|
||||
export {
|
||||
getDataOptions,
|
||||
getPlaceholder,
|
||||
getDefaultValue,
|
||||
getDataTypeInfo,
|
||||
getAllDataTypeMap,
|
||||
getDefaultFunctionsOptions,
|
||||
inferDefaultValues,
|
||||
};
|
||||
|
@ -29,7 +29,10 @@ import {
|
||||
fetchTrackedTableListQuery,
|
||||
mergeLoadSchemaData,
|
||||
} from './utils';
|
||||
import { fetchColumnTypesQuery } from './utils';
|
||||
|
||||
import { fetchColumnTypesQuery, fetchColumnDefaultFunctions } from './utils';
|
||||
|
||||
import { fetchColumnCastsQuery, convertArrayToJson } from './TableModify/utils';
|
||||
|
||||
import { SERVER_CONSOLE_MODE } from '../../../constants';
|
||||
|
||||
@ -47,9 +50,9 @@ const UPDATE_REMOTE_SCHEMA_MANUAL_REL = 'Data/UPDATE_SCHEMA_MANUAL_REL';
|
||||
const SET_CONSISTENT_SCHEMA = 'Data/SET_CONSISTENT_SCHEMA';
|
||||
const SET_CONSISTENT_FUNCTIONS = 'Data/SET_CONSISTENT_FUNCTIONS';
|
||||
|
||||
const FETCH_COLUMN_TYPE_LIST = 'Data/FETCH_COLUMN_TYPE_LIST';
|
||||
const FETCH_COLUMN_TYPE_LIST_FAIL = 'Data/FETCH_COLUMN_TYPE_LIST_FAIL';
|
||||
const RESET_COLUMN_TYPE_LIST = 'Data/RESET_COLUMN_TYPE_LIST';
|
||||
const FETCH_COLUMN_TYPE_INFO = 'Data/FETCH_COLUMN_TYPE_INFO';
|
||||
const FETCH_COLUMN_TYPE_INFO_FAIL = 'Data/FETCH_COLUMN_TYPE_INFO_FAIL';
|
||||
const RESET_COLUMN_TYPE_INFO = 'Data/RESET_COLUMN_TYPE_INFO';
|
||||
|
||||
const MAKE_REQUEST = 'ModifyTable/MAKE_REQUEST';
|
||||
const REQUEST_SUCCESS = 'ModifyTable/REQUEST_SUCCESS';
|
||||
@ -535,15 +538,39 @@ const makeMigrationCall = (
|
||||
);
|
||||
};
|
||||
|
||||
const fetchColumnTypes = () => {
|
||||
const getBulkColumnInfoFetchQuery = schema => {
|
||||
const fetchColumnTypes = {
|
||||
type: 'run_sql',
|
||||
args: {
|
||||
sql: fetchColumnTypesQuery,
|
||||
},
|
||||
};
|
||||
const fetchTypeDefaultValues = {
|
||||
type: 'run_sql',
|
||||
args: {
|
||||
sql: fetchColumnDefaultFunctions(schema),
|
||||
},
|
||||
};
|
||||
|
||||
const fetchValidTypeCasts = {
|
||||
type: 'run_sql',
|
||||
args: {
|
||||
sql: fetchColumnCastsQuery,
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
type: 'bulk',
|
||||
args: [fetchColumnTypes, fetchTypeDefaultValues, fetchValidTypeCasts],
|
||||
};
|
||||
};
|
||||
|
||||
const fetchColumnTypeInfo = () => {
|
||||
return (dispatch, getState) => {
|
||||
const url = Endpoints.getSchema;
|
||||
const reqQuery = {
|
||||
type: 'run_sql',
|
||||
args: {
|
||||
sql: fetchColumnTypesQuery,
|
||||
},
|
||||
};
|
||||
const currState = getState();
|
||||
const { currentSchema } = currState.tables;
|
||||
const reqQuery = getBulkColumnInfoFetchQuery(currentSchema);
|
||||
const options = {
|
||||
credentials: globalCookiePolicy,
|
||||
method: 'POST',
|
||||
@ -552,9 +579,20 @@ const fetchColumnTypes = () => {
|
||||
};
|
||||
return dispatch(requestAction(url, options)).then(
|
||||
data => {
|
||||
const resultData = data[1].result.slice(1);
|
||||
const typeFuncsMap = {};
|
||||
|
||||
resultData.forEach(r => {
|
||||
typeFuncsMap[r[1]] = r[0].split(',');
|
||||
});
|
||||
const columnDataTypeInfo = {
|
||||
columnDataTypes: data[0].result.slice(1),
|
||||
columnTypeDefaultValues: typeFuncsMap,
|
||||
columnTypeCasts: convertArrayToJson(data[2].result.slice(1)),
|
||||
};
|
||||
return dispatch({
|
||||
type: FETCH_COLUMN_TYPE_LIST,
|
||||
data: data.result.slice(1),
|
||||
type: FETCH_COLUMN_TYPE_INFO,
|
||||
data: columnDataTypeInfo,
|
||||
});
|
||||
},
|
||||
error => {
|
||||
@ -567,7 +605,7 @@ const fetchColumnTypes = () => {
|
||||
)
|
||||
);
|
||||
return dispatch({
|
||||
type: FETCH_COLUMN_TYPE_LIST_FAIL,
|
||||
type: FETCH_COLUMN_TYPE_INFO_FAIL,
|
||||
data: error,
|
||||
});
|
||||
}
|
||||
@ -680,24 +718,30 @@ const dataReducer = (state = defaultState, action) => {
|
||||
},
|
||||
},
|
||||
};
|
||||
case FETCH_COLUMN_TYPE_LIST:
|
||||
case FETCH_COLUMN_TYPE_INFO:
|
||||
return {
|
||||
...state,
|
||||
columnDataTypes: action.data,
|
||||
columnDataTypeFetchErr: defaultState.columnDataTypeFetchErr,
|
||||
columnDataTypes: action.data.columnDataTypes,
|
||||
columnDefaultFunctions: action.data.columnTypeDefaultValues,
|
||||
columnDataTypeInfoErr: null,
|
||||
columnTypeCasts: action.data.columnTypeCasts,
|
||||
};
|
||||
|
||||
case FETCH_COLUMN_TYPE_LIST_FAIL:
|
||||
case FETCH_COLUMN_TYPE_INFO_FAIL:
|
||||
return {
|
||||
...state,
|
||||
columnDataTypes: [],
|
||||
columnDataTypeFetchErr: action.data,
|
||||
columnDefaultFunctions: {},
|
||||
columnTypeCasts: {},
|
||||
columnDataTypeInfoErr: action.data,
|
||||
};
|
||||
case RESET_COLUMN_TYPE_LIST:
|
||||
case RESET_COLUMN_TYPE_INFO:
|
||||
return {
|
||||
...state,
|
||||
columnDataTypes: [...defaultState.columnDataTypes],
|
||||
columnDataTypeFetchErr: defaultState.columnDataTypeFetchErr,
|
||||
columnDefaultFunctions: { ...defaultState.columnDefaultFunctions },
|
||||
columnTypeCasts: { ...defaultState.columnTypeCasts },
|
||||
columnDataTypeInfoErr: defaultState.columnDataTypeInfoErr,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
@ -727,7 +771,7 @@ export {
|
||||
LOAD_SCHEMA,
|
||||
setConsistentSchema,
|
||||
setConsistentFunctions,
|
||||
fetchColumnTypes,
|
||||
RESET_COLUMN_TYPE_LIST,
|
||||
fetchColumnTypeInfo,
|
||||
RESET_COLUMN_TYPE_INFO,
|
||||
setUntrackedRelations,
|
||||
};
|
||||
|
@ -136,7 +136,9 @@ const defaultModifyState = {
|
||||
|
||||
const defaultState = {
|
||||
columnDataTypes: [], // To store list of column types supported by postgres
|
||||
columnDataTypeFetchErr: null,
|
||||
columnDataTypeInfoErr: null,
|
||||
columnDefaultFunctions: {},
|
||||
columnTypeCasts: {},
|
||||
currentTable: null,
|
||||
view: { ...defaultViewState },
|
||||
modify: { ...defaultModifyState },
|
||||
|
@ -129,7 +129,8 @@ class InsertItem extends Component {
|
||||
type: 'text',
|
||||
};
|
||||
|
||||
const colType = col.data_type;
|
||||
// const colType = col.data_type;
|
||||
const colType = col.udt_name;
|
||||
const placeHolder = hasDefault
|
||||
? col.column_default
|
||||
: getPlaceholder(colType);
|
||||
|
@ -4,8 +4,13 @@ import gqlPattern, { gqlColumnErrorNotif } from '../Common/GraphQLValidation';
|
||||
import { commonDataTypes } from '../utils';
|
||||
|
||||
import SearchableSelectBox from '../../../Common/SearchableSelect/SearchableSelect';
|
||||
import CustomInputAutoSuggest from '../../../Common/CustomInputAutoSuggest/CustomInputAutoSuggest';
|
||||
|
||||
import { getDataOptions } from '../Common/utils';
|
||||
import {
|
||||
getDataOptions,
|
||||
getDefaultFunctionsOptions,
|
||||
inferDefaultValues,
|
||||
} from '../Common/utils';
|
||||
|
||||
import Button from '../../../Common/Button/Button';
|
||||
import { addColSql } from '../TableModify/ModifyActions';
|
||||
@ -90,15 +95,22 @@ const useColumnEditor = (dispatch, tableName) => {
|
||||
},
|
||||
colDefault: {
|
||||
value: colDefault,
|
||||
onChange: e => {
|
||||
setColumnState({ ...columnState, colDefault: e.target.value });
|
||||
onChange: (e, data) => {
|
||||
const { newValue } = data;
|
||||
setColumnState({ ...columnState, colDefault: newValue });
|
||||
},
|
||||
},
|
||||
onSubmit,
|
||||
};
|
||||
};
|
||||
|
||||
const ColumnCreator = ({ dispatch, tableName, dataTypes: restTypes = [] }) => {
|
||||
const ColumnCreator = ({
|
||||
dispatch,
|
||||
tableName,
|
||||
dataTypes: restTypes = [],
|
||||
validTypeCasts,
|
||||
columnDefaultFunctions,
|
||||
}) => {
|
||||
const {
|
||||
colName,
|
||||
colType,
|
||||
@ -108,6 +120,37 @@ const ColumnCreator = ({ dispatch, tableName, dataTypes: restTypes = [] }) => {
|
||||
onSubmit,
|
||||
} = useColumnEditor(dispatch, tableName);
|
||||
|
||||
let defaultOptions = [];
|
||||
|
||||
const getInferredDefaultValues = () =>
|
||||
inferDefaultValues(columnDefaultFunctions, validTypeCasts)(colType.value);
|
||||
|
||||
const colDefaultFunctions =
|
||||
colType.value in columnDefaultFunctions
|
||||
? columnDefaultFunctions[colType.value]
|
||||
: getInferredDefaultValues();
|
||||
|
||||
if (colDefaultFunctions && colDefaultFunctions.length > 0) {
|
||||
defaultOptions = getDefaultFunctionsOptions(colDefaultFunctions, 0);
|
||||
}
|
||||
|
||||
const getDefaultInput = () => {
|
||||
const theme = require('../../../Common/CustomInputAutoSuggest/CustomThemes/AddColumnDefault.scss');
|
||||
|
||||
return (
|
||||
<CustomInputAutoSuggest
|
||||
placeholder="default value"
|
||||
options={defaultOptions}
|
||||
className={`${styles.input}
|
||||
${styles.defaultInput}
|
||||
input-sm form-control`}
|
||||
{...colDefault}
|
||||
data-test="default-value"
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const { columnDataTypes, columnTypeValueMap } = getDataOptions(
|
||||
commonDataTypes,
|
||||
restTypes,
|
||||
@ -153,6 +196,7 @@ const ColumnCreator = ({ dispatch, tableName, dataTypes: restTypes = [] }) => {
|
||||
bsClass={`col-type-${0} modify_select`}
|
||||
styleOverrides={customSelectBoxStyles}
|
||||
filterOption={'prefix'}
|
||||
placeholder="column_type"
|
||||
/>
|
||||
</span>
|
||||
<input
|
||||
@ -170,7 +214,8 @@ const ColumnCreator = ({ dispatch, tableName, dataTypes: restTypes = [] }) => {
|
||||
data-test="unique-checkbox"
|
||||
/>
|
||||
<label className={styles.nullLabel}>Unique</label>
|
||||
|
||||
{getDefaultInput()}
|
||||
{/*
|
||||
<input
|
||||
placeholder="default value"
|
||||
type="text"
|
||||
@ -180,6 +225,7 @@ const ColumnCreator = ({ dispatch, tableName, dataTypes: restTypes = [] }) => {
|
||||
{...colDefault}
|
||||
data-test="default-value"
|
||||
/>
|
||||
*/}
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import SearchableSelectBox from '../../../Common/SearchableSelect/SearchableSelect';
|
||||
import CustomInputAutoSuggest from '../../../Common/CustomInputAutoSuggest/CustomInputAutoSuggest';
|
||||
|
||||
import { getValidAlterOptions } from './utils';
|
||||
|
||||
@ -12,6 +13,7 @@ const ColumnEditor = ({
|
||||
selectedProperties,
|
||||
editColumn,
|
||||
alterTypeOptions,
|
||||
defaultOptions,
|
||||
}) => {
|
||||
const colName = columnProperties.name;
|
||||
|
||||
@ -62,8 +64,9 @@ const ColumnEditor = ({
|
||||
const updateColumnType = selected => {
|
||||
dispatch(editColumn(colName, 'type', selected.value));
|
||||
};
|
||||
const updateColumnDef = e => {
|
||||
dispatch(editColumn(colName, 'default', e.target.value));
|
||||
const updateColumnDef = (e, data) => {
|
||||
const { newValue } = data;
|
||||
dispatch(editColumn(colName, 'default', newValue));
|
||||
};
|
||||
const updateColumnComment = e => {
|
||||
dispatch(editColumn(colName, 'comment', e.target.value));
|
||||
@ -75,6 +78,23 @@ const ColumnEditor = ({
|
||||
dispatch(editColumn(colName, 'isUnique', e.target.value === 'true'));
|
||||
};
|
||||
|
||||
const getDefaultInput = () => {
|
||||
const theme = require('../../../Common/CustomInputAutoSuggest/CustomThemes/EditColumnDefault.scss');
|
||||
|
||||
return (
|
||||
<CustomInputAutoSuggest
|
||||
options={defaultOptions}
|
||||
className="input-sm form-control"
|
||||
value={selectedProperties[colName].default || ''}
|
||||
onChange={updateColumnDef}
|
||||
type="text"
|
||||
disabled={columnProperties.pkConstraint}
|
||||
data-test="edit-col-default"
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${styles.colEditor} container-fluid`}>
|
||||
<form className="form-horizontal" onSubmit={onSubmit}>
|
||||
@ -100,6 +120,7 @@ const ColumnEditor = ({
|
||||
bsClass={`col-type-${0} modify_select`}
|
||||
styleOverrides={customSelectBoxStyles}
|
||||
filterOption={'prefix'}
|
||||
placeholder="column_type"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -136,6 +157,8 @@ const ColumnEditor = ({
|
||||
<div className={`${styles.display_flex} form-group`}>
|
||||
<label className="col-xs-2">Default</label>
|
||||
<div className="col-xs-6">
|
||||
{getDefaultInput()}
|
||||
{/*
|
||||
<input
|
||||
className="input-sm form-control"
|
||||
value={selectedProperties[colName].default || ''}
|
||||
@ -144,6 +167,7 @@ const ColumnEditor = ({
|
||||
disabled={columnProperties.pkConstraint}
|
||||
data-test="edit-col-default"
|
||||
/>
|
||||
*/}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`${styles.display_flex} form-group`}>
|
||||
|
@ -12,6 +12,11 @@ import {
|
||||
import { ordinalColSort } from '../utils';
|
||||
import { defaultDataTypeToCast } from '../constants';
|
||||
|
||||
import {
|
||||
getDefaultFunctionsOptions,
|
||||
inferDefaultValues,
|
||||
} from '../Common/utils';
|
||||
|
||||
import styles from './ModifyTable.scss';
|
||||
|
||||
const ColumnEditorList = ({
|
||||
@ -21,6 +26,7 @@ const ColumnEditorList = ({
|
||||
dispatch,
|
||||
validTypeCasts,
|
||||
dataTypeIndexMap,
|
||||
columnDefaultFunctions,
|
||||
}) => {
|
||||
const tableName = tableSchema.table_name;
|
||||
|
||||
@ -131,21 +137,55 @@ const ColumnEditorList = ({
|
||||
);
|
||||
};
|
||||
|
||||
/* If the dataTypeIndexMap is not loaded, then just load the current type information
|
||||
* */
|
||||
|
||||
const getValidTypeCasts = udtName => {
|
||||
const lowerUdtName = udtName.toLowerCase();
|
||||
if (lowerUdtName in validTypeCasts) {
|
||||
return validTypeCasts[lowerUdtName];
|
||||
}
|
||||
return [
|
||||
...dataTypeIndexMap[lowerUdtName],
|
||||
...dataTypeIndexMap[defaultDataTypeToCast],
|
||||
];
|
||||
if (dataTypeIndexMap && Object.keys(dataTypeIndexMap).length > 0) {
|
||||
return [
|
||||
...dataTypeIndexMap[lowerUdtName],
|
||||
...dataTypeIndexMap[defaultDataTypeToCast],
|
||||
];
|
||||
}
|
||||
return [lowerUdtName, lowerUdtName, ''];
|
||||
};
|
||||
|
||||
const getValidDefaultTypes = udtName => {
|
||||
const lowerUdtName = udtName.toLowerCase();
|
||||
let defaultOptions = [];
|
||||
if (lowerUdtName in columnDefaultFunctions) {
|
||||
defaultOptions = columnDefaultFunctions[lowerUdtName];
|
||||
} else {
|
||||
defaultOptions = inferDefaultValues(
|
||||
columnDefaultFunctions,
|
||||
validTypeCasts
|
||||
)(lowerUdtName);
|
||||
}
|
||||
|
||||
return getDefaultFunctionsOptions(defaultOptions);
|
||||
};
|
||||
|
||||
/*
|
||||
* Alter type options contains a list of items and its valid castable types
|
||||
* [
|
||||
* "Data type",
|
||||
* "User friendly name of the data type",
|
||||
* "Description of the data type",
|
||||
* "Comma seperated castable data types",
|
||||
* "Comma seperated user friendly names of the castable data types",
|
||||
* "Colon seperated user friendly description of the castable data types"
|
||||
* ]
|
||||
* */
|
||||
|
||||
const colEditorExpanded = () => {
|
||||
return (
|
||||
<ColumnEditor
|
||||
alterTypeOptions={getValidTypeCasts(col.udt_name)}
|
||||
defaultOptions={getValidDefaultTypes(col.udt_name)}
|
||||
column={col}
|
||||
onSubmit={onSubmit}
|
||||
onDelete={safeOnDelete}
|
||||
|
@ -25,6 +25,8 @@ import {
|
||||
getUniqueConstraintName,
|
||||
} from '../Common/ReusableComponents/utils';
|
||||
|
||||
import { isPostgresFunction } from '../utils';
|
||||
|
||||
import {
|
||||
fetchColumnCastsQuery,
|
||||
convertArrayToJson,
|
||||
@ -881,7 +883,9 @@ const addColSql = (
|
||||
callback
|
||||
) => {
|
||||
let defWithQuotes = "''";
|
||||
if (colType === 'text' && colDefault !== '') {
|
||||
|
||||
const checkIfFunctionFormat = isPostgresFunction(colDefault);
|
||||
if (colType === 'text' && colDefault !== '' && !checkIfFunctionFormat) {
|
||||
defWithQuotes = "'" + colDefault + "'";
|
||||
} else {
|
||||
defWithQuotes = colDefault;
|
||||
@ -1167,9 +1171,10 @@ const saveColumnChangesSql = (colName, column) => {
|
||||
const comment = columnEdit.comment || '';
|
||||
const newName = columnEdit.name;
|
||||
const currentSchema = columnEdit.schemaName;
|
||||
const checkIfFunctionFormat = isPostgresFunction(def);
|
||||
// ALTER TABLE <table> ALTER COLUMN <column> TYPE <column_type>;
|
||||
let defWithQuotes;
|
||||
if (colType === 'text') {
|
||||
if (colType === 'text' && !checkIfFunctionFormat) {
|
||||
defWithQuotes = `'${def}'`;
|
||||
} else {
|
||||
defWithQuotes = def;
|
||||
|
@ -8,13 +8,12 @@ import {
|
||||
deleteTableSql,
|
||||
untrackTableSql,
|
||||
RESET,
|
||||
fetchColumnCasts,
|
||||
setUniqueKeys,
|
||||
} from '../TableModify/ModifyActions';
|
||||
import {
|
||||
setTable,
|
||||
fetchColumnTypes,
|
||||
RESET_COLUMN_TYPE_LIST,
|
||||
fetchColumnTypeInfo,
|
||||
RESET_COLUMN_TYPE_INFO,
|
||||
} from '../DataActions';
|
||||
import Button from '../../../Common/Button/Button';
|
||||
import ColumnEditorList from './ColumnEditorList';
|
||||
@ -31,12 +30,11 @@ class ModifyTable extends React.Component {
|
||||
const { dispatch } = this.props;
|
||||
dispatch({ type: RESET });
|
||||
dispatch(setTable(this.props.tableName));
|
||||
dispatch(fetchColumnTypes());
|
||||
dispatch(fetchColumnCasts());
|
||||
dispatch(fetchColumnTypeInfo());
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.props.dispatch({
|
||||
type: RESET_COLUMN_TYPE_LIST,
|
||||
type: RESET_COLUMN_TYPE_INFO,
|
||||
});
|
||||
}
|
||||
render() {
|
||||
@ -53,6 +51,7 @@ class ModifyTable extends React.Component {
|
||||
dataTypes,
|
||||
validTypeCasts,
|
||||
uniqueKeyModify,
|
||||
columnDefaultFunctions,
|
||||
schemaList,
|
||||
} = this.props;
|
||||
|
||||
@ -135,6 +134,7 @@ class ModifyTable extends React.Component {
|
||||
columnEdit={columnEdit}
|
||||
dispatch={dispatch}
|
||||
currentSchema={currentSchema}
|
||||
columnDefaultFunctions={columnDefaultFunctions}
|
||||
/>
|
||||
<hr />
|
||||
<h4 className={styles.subheading_text}>Add a new column</h4>
|
||||
@ -142,6 +142,8 @@ class ModifyTable extends React.Component {
|
||||
dispatch={dispatch}
|
||||
tableName={tableName}
|
||||
dataTypes={dataTypes}
|
||||
validTypeCasts={validTypeCasts}
|
||||
columnDefaultFunctions={columnDefaultFunctions}
|
||||
/>
|
||||
<hr />
|
||||
<h4 className={styles.subheading_text}>Primary Key</h4>
|
||||
@ -212,7 +214,8 @@ const mapStateToProps = (state, ownProps) => ({
|
||||
pkModify: state.tables.modify.pkModify,
|
||||
fkModify: state.tables.modify.fkModify,
|
||||
dataTypes: state.tables.columnDataTypes,
|
||||
validTypeCasts: state.tables.modify.alterColumnOptions,
|
||||
columnDefaultFunctions: state.tables.columnDefaultFunctions,
|
||||
validTypeCasts: state.tables.columnTypeCasts,
|
||||
columnDataTypeFetchErr: state.tables.columnDataTypeFetchErr,
|
||||
schemaList: state.tables.schemaList,
|
||||
...state.tables.modify,
|
||||
|
@ -14,22 +14,31 @@ const getValidAlterOptions = (alterTypeOptions, colName) => {
|
||||
colName,
|
||||
0
|
||||
);
|
||||
|
||||
const {
|
||||
typInfo: validOptions,
|
||||
typValueMap: validOptionsMap,
|
||||
} = getDataTypeInfo(alterTypeOptions.slice(3, 6), colName, 0);
|
||||
|
||||
const _allInfo = [...currentInfo, ...validOptions];
|
||||
|
||||
const _allOptionsMap = {
|
||||
...validOptionsMap,
|
||||
/*
|
||||
* alterTypeOptions can also only contain only three elements
|
||||
*/
|
||||
let allInfo = [...currentInfo];
|
||||
let allOptionsMap = {
|
||||
...currentMap,
|
||||
};
|
||||
|
||||
if (alterTypeOptions.length > 3) {
|
||||
const {
|
||||
typInfo: validOptions,
|
||||
typValueMap: validOptionsMap,
|
||||
} = getDataTypeInfo(alterTypeOptions.slice(3, 6), colName, 0);
|
||||
|
||||
allInfo = allInfo.concat(validOptions);
|
||||
// const allInfo = [...currentInfo, ...validOptions];
|
||||
allOptionsMap = {
|
||||
...validOptionsMap,
|
||||
...currentMap,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
alterOptions: _allInfo,
|
||||
alterOptionsValueMap: _allOptionsMap,
|
||||
alterOptions: allInfo,
|
||||
alterOptionsValueMap: allOptionsMap,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -91,17 +91,17 @@ const ManualRelationshipSelector = ({
|
||||
disabled={!relAdd.relType || !relAdd.relName}
|
||||
>
|
||||
{// default unselected option
|
||||
relAdd.rSchema === '' && (
|
||||
<option value={''} disabled>
|
||||
{'-- reference schema --'}
|
||||
</option>
|
||||
)}
|
||||
relAdd.rSchema === '' && (
|
||||
<option value={''} disabled>
|
||||
{'-- reference schema --'}
|
||||
</option>
|
||||
)}
|
||||
{// all reference schema options
|
||||
schemaList.map((rs, j) => (
|
||||
<option key={j} value={rs}>
|
||||
{rs}
|
||||
</option>
|
||||
))}
|
||||
schemaList.map((rs, j) => (
|
||||
<option key={j} value={rs}>
|
||||
{rs}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
|
@ -587,3 +587,29 @@ WHERE (t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHER
|
||||
AND t.typname != 'unknown'
|
||||
AND t.typcategory != 'P'
|
||||
GROUP BY t.typcategory;`;
|
||||
|
||||
export const fetchColumnDefaultFunctions = (schema = 'public') => `
|
||||
SELECT string_agg(pgp.proname, ','),
|
||||
t.typname as "Type"
|
||||
from pg_proc pgp
|
||||
JOIN pg_type t
|
||||
ON pgp.prorettype = t.oid
|
||||
JOIN pg_namespace pgn
|
||||
ON pgn.oid = pgp.pronamespace
|
||||
WHERE (t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid))
|
||||
AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)
|
||||
AND pg_catalog.pg_type_is_visible(t.oid)
|
||||
AND t.typname != 'unknown'
|
||||
AND t.typcategory != 'P'
|
||||
AND (array_length(pgp.proargtypes, 1) = 0)
|
||||
AND ( pgn.nspname = '${schema}' OR pgn.nspname = 'pg_catalog' )
|
||||
AND pgp.proretset=false
|
||||
AND pgp.prokind='f'
|
||||
GROUP BY t.typname
|
||||
ORDER BY t.typname ASC;
|
||||
`;
|
||||
|
||||
const postgresFunctionTester = /.*\(\)$/gm;
|
||||
|
||||
export const isPostgresFunction = str =>
|
||||
new RegExp(postgresFunctionTester).test(str);
|
||||
|
@ -473,7 +473,7 @@ export const metadataReducer = (state = defaultState, action) => {
|
||||
...state,
|
||||
allowedQueries: [
|
||||
...state.allowedQueries.map(q =>
|
||||
q.name === action.data.queryName ? action.data.newQuery : q
|
||||
(q.name === action.data.queryName ? action.data.newQuery : q)
|
||||
),
|
||||
],
|
||||
};
|
||||
|
2
console/src/theme/bootstrap.overrides.scss
vendored
2
console/src/theme/bootstrap.overrides.scss
vendored
@ -13,7 +13,7 @@
|
||||
max-height: 30px !important;
|
||||
}
|
||||
|
||||
.add_table_column_selector__control {
|
||||
.add_table_column_selector__control, .add_table_default_value_selector__control {
|
||||
min-height: 34px !important;
|
||||
max-height: 34px !important;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user