Browse Source

Feat : UIDT impmporovements (#2026)

* wip: rating cell ui implementation

Signed-off-by: Pranav C <pranavxc@gmail.com>

* wip: migration for meta column data field

Signed-off-by: Pranav C <pranavxc@gmail.com>

* wip: rating column options

Signed-off-by: Pranav C <pranavxc@gmail.com>

* feat: rating cell creation and mapping metadata

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor:  change default type to int for rating

Signed-off-by: Pranav C <pranavxc@gmail.com>

* feat: add email cell

Signed-off-by: Pranav C <pranavxc@gmail.com>

* feat: accept invalid values for columns if validation disabled

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: remove additional options

Signed-off-by: Pranav C <pranavxc@gmail.com>

* feat: checkbox customization

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: move validate checkbox to advance option

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: add tick icon in checkbox

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: start rating max value from 1

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: minor ui corrections

Signed-off-by: Pranav C <pranavxc@gmail.com>

* fix: load rating component in gallery view

Signed-off-by: Pranav C <pranavxc@gmail.com>

* fix: use default icon and color if meta missing(checkbox and rating)

re #2036

Signed-off-by: Pranav C <pranavxc@gmail.com>

* fix: cache column with parsed metadata

re #2038

Signed-off-by: Pranav C <pranavxc@gmail.com>

* fix: convert old rating column to number type

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: migration filename correction

Signed-off-by: Pranav C <pranavxc@gmail.com>

* refactor: component name

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2071/head
Pranav C 2 years ago committed by GitHub
parent
commit
8d33fa9b96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      packages/nc-gui/components/project/spreadsheet/components/Cell.vue
  2. 38
      packages/nc-gui/components/project/spreadsheet/components/EditColumn.vue
  3. 19
      packages/nc-gui/components/project/spreadsheet/components/EditableCell.vue
  4. 22
      packages/nc-gui/components/project/spreadsheet/components/cell/EmailCell.vue
  5. 14
      packages/nc-gui/components/project/spreadsheet/components/cell/UrlCell.vue
  6. 98
      packages/nc-gui/components/project/spreadsheet/components/editColumn/RatingOptions.vue
  7. 95
      packages/nc-gui/components/project/spreadsheet/components/editColumn/checkboxOptions.vue
  8. 36
      packages/nc-gui/components/project/spreadsheet/components/editableCell/BooleanCell.vue
  9. 9
      packages/nc-gui/components/project/spreadsheet/components/editableCell/EditableUrlCell.vue
  10. 71
      packages/nc-gui/components/project/spreadsheet/components/editableCell/RatingCell.vue
  11. 6
      packages/nc-gui/components/project/spreadsheet/mixins/cell.js
  12. 70
      packages/nc-gui/components/project/spreadsheet/views/GridView.vue
  13. 84
      packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts
  14. 74
      packages/nocodb-sdk/src/lib/sqlUi/MysqlUi.ts
  15. 36
      packages/nocodb-sdk/src/lib/sqlUi/OracleUi.ts
  16. 97
      packages/nocodb-sdk/src/lib/sqlUi/PgUi.ts
  17. 94
      packages/nocodb-sdk/src/lib/sqlUi/SqliteUi.ts
  18. 3
      packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSqlv2.ts
  19. 40
      packages/nocodb/src/lib/noco-models/Column.ts
  20. 6
      packages/nocodb/src/lib/noco/common/XcMigrationSourcev2.ts
  21. 38
      packages/nocodb/src/lib/noco/migrationsv2/nc_015_add_meta_col_in_column_table.ts
  22. 4
      packages/nocodb/src/lib/noco/upgrader/jobs/ncProjectUpgraderV2_0090000.ts

11
packages/nc-gui/components/project/spreadsheet/components/Cell.vue

@ -11,11 +11,14 @@
<!-- <enum-list-editable-cell @click.stop="$emit('enableedit')" v-else-if="isEnum && selected" :value="value" :column="column"></enum-list-editable-cell>-->
<enum-cell v-else-if="isEnum" :value="value" :column="column" @click.stop="$emit('enableedit')" />
<url-cell v-else-if="isURL" :value="value" />
<email-cell v-else-if="isEmail" :value="value" />
<json-cell v-else-if="isJSON" :value="value" />
<date-cell v-else-if="isDate" :value="value" />
<date-time-cell v-else-if="isDateTime" :value="value" />
<time-cell v-else-if="isTime" :value="value" />
<boolean-cell v-else-if="isBoolean" :value="value" />
<boolean-cell v-else-if="isBoolean" :value="value" read-only />
<rating-cell v-else-if="isRating" :value="value" read-only />
<span v-else :class="{'long-text-cell' : isTextArea}" :title="title">{{ value }}</span>
</template>
@ -30,12 +33,14 @@ import SetListCell from '~/components/project/spreadsheet/components/cell/SetLis
import EnumCell from '~/components/project/spreadsheet/components/cell/EnumCell'
import EditableAttachmentCell from '~/components/project/spreadsheet/components/editableCell/EditableAttachmentCell'
import BooleanCell from '~/components/project/spreadsheet/components/cell/BooleanCell'
import EmailCell from '~/components/project/spreadsheet/components/cell/EmailCell'
import RatingCell from '~/components/project/spreadsheet/components/editableCell/RatingCell'
export default {
name: 'TableCell',
components: { TimeCell, DateTimeCell, DateCell, JsonCell, UrlCell, EditableAttachmentCell, EnumCell, SetListCell, BooleanCell },
components: { RatingCell, EmailCell, TimeCell, DateTimeCell, DateCell, JsonCell, UrlCell, EditableAttachmentCell, EnumCell, SetListCell, BooleanCell },
mixins: [cell],
props: ['value', 'dbAlias', 'isLocked', 'selected'],
props: ['value', 'dbAlias', 'isLocked', 'selected', 'column'],
computed: {
title() {
if (typeof this.value === 'string') { return this.value }

38
packages/nc-gui/components/project/spreadsheet/components/EditColumn.vue

@ -137,6 +137,21 @@
@input="newColumn.altered = newColumn.altered || 2"
/>
</v-col>
<v-col v-else-if="isRating" cols="12">
<rating-options
v-model="newColumn.meta"
:column="newColumn"
:meta="meta"
/>
</v-col>
<v-col v-else-if="isCheckbox" cols="12">
<checkbox-options
v-model="newColumn.meta"
:column="newColumn"
:meta="meta"
/>
</v-col>
<v-col
v-if="accordion"
cols="12"
@ -160,6 +175,10 @@
<v-col v-show="advanceOptions || !accordion" cols="12">
<v-row>
<v-col v-if="newColumn.meta && columnToValidate.includes(newColumn.uidt)" cols="12" class="pt-0 pb-0">
<v-checkbox v-model="newColumn.meta.validate" dense hide-details :label="`Accept only valid ${newColumn.uidt}`" class="mt-0" />
</v-col>
<template v-if="newColumn.uidt !== 'Formula'">
<v-col v-if="isLookup" cols="12">
<lookup-options
@ -526,10 +545,15 @@ import RelationOptions from '~/components/project/spreadsheet/components/editCol
import DlgLabelSubmitCancel from '~/components/utils/DlgLabelSubmitCancel'
import LinkedToAnotherOptions from '~/components/project/spreadsheet/components/editColumn/LinkedToAnotherOptions'
import { validateColumnName } from '~/helpers'
import RatingOptions from '~/components/project/spreadsheet/components/editColumn/RatingOptions'
import CheckboxOptions from '~/components/project/spreadsheet/components/editColumn/checkboxOptions'
const columnToValidate = [UITypes.Email, UITypes.URL, UITypes.PhoneNumber]
export default {
name: 'EditColumn',
components: {
CheckboxOptions,
RatingOptions,
RollupOptions,
FormulaOptions,
LookupOptions,
@ -548,6 +572,7 @@ export default {
value: Boolean
},
data: () => ({
columnToValidate,
valid: false,
relationDeleteDlg: false,
newColumn: {},
@ -594,6 +619,12 @@ export default {
isLookup() {
return this.newColumn && this.newColumn.uidt === 'Lookup'
},
isRating() {
return this.newColumn && this.newColumn.uidt === UITypes.Rating
},
isCheckbox() {
return this.newColumn && this.newColumn.uidt === UITypes.Checkbox
},
isRollup() {
return this.newColumn && this.newColumn.uidt === 'Rollup'
},
@ -734,6 +765,7 @@ export default {
const colProp = this.sqlUi.getDataTypeForUiType(this.newColumn)
this.newColumn = {
...this.newColumn,
meta: null,
rqd: false,
pk: false,
ai: false,
@ -759,6 +791,12 @@ export default {
this.newColumn.dtxp = this.column.dtxp
}
if (columnToValidate.includes(this.newColumn.uidt)) {
this.newColumn.meta = {
validate: this.newColumn.meta && this.newColumn.meta.validate
}
}
this.newColumn.altered = this.newColumn.altered || 2
},
focusInput() {

19
packages/nc-gui/components/project/spreadsheet/components/EditableCell.vue

@ -23,9 +23,22 @@
v-on="$listeners"
/>
<rating-cell
v-if="isRating"
v-model="localState"
:active="active"
:is-form="isForm"
:column="column"
:is-public-grid="isPublic && !isForm"
:is-public-form="isPublic && isForm"
:is-locked="isLocked"
v-on="$listeners"
/>
<boolean-cell
v-else-if="isBoolean"
v-model="localState"
:column="column"
:is-form="isForm"
v-on="parentListeners"
/>
@ -132,10 +145,12 @@ import EditableAttachmentCell from '~/components/project/spreadsheet/components/
import EnumCell from '~/components/project/spreadsheet/components/cell/EnumCell'
import SetListEditableCell from '~/components/project/spreadsheet/components/editableCell/SetListEditableCell'
import SetListCell from '~/components/project/spreadsheet/components/cell/SetListCell'
import RatingCell from '~/components/project/spreadsheet/components/editableCell/RatingCell'
export default {
name: 'EditableCell',
components: {
RatingCell,
JsonEditableCell,
EditableUrlCell,
SetListCell,
@ -182,7 +197,7 @@ export default {
if (val !== this.value) {
this.changed = true
this.$emit('input', val)
if (this.isAttachment || this.isEnum || this.isBoolean || this.isSet || this.isTime || this.isDateTime || this.isDate) {
if (this.isAttachment || this.isEnum || this.isBoolean || this.isRating || this.isSet || this.isTime || this.isDateTime || this.isDate) {
this.syncData()
} else if (!this.isCurrency) {
this.syncDataDebounce(this)
@ -213,7 +228,7 @@ export default {
// this.$refs.input.focus();
},
beforeDestroy() {
if (this.changed && !(this.isAttachment || this.isEnum || this.isBoolean || this.isSet || this.isTime || this.isDateTime)) {
if (this.changed && !(this.isAttachment || this.isEnum || this.isBoolean || this.isRating || this.isSet || this.isTime || this.isDateTime)) {
this.changed = false
this.$emit('change')
}

22
packages/nc-gui/components/project/spreadsheet/components/cell/EmailCell.vue

@ -0,0 +1,22 @@
<template>
<a v-if="isEmail" :href="`mailto:${value}`" target="_blank">{{ value }}</a>
<span v-else>{{ value }}</span>
</template>
<script>
import { isEmail } from '~/helpers'
export default {
name: 'EmailCell',
props: ['value'],
computed: {
isEmail() {
return isEmail(this.value || '')
}
}
}
</script>
<style scoped>
</style>

14
packages/nc-gui/components/project/spreadsheet/components/cell/UrlCell.vue

@ -1,12 +1,20 @@
<template>
<a v-if="value" :href="value" target="_blank">{{ value }}</a>
<span v-else />
<a v-if="isValid" :href="value" target="_blank">{{ value }}</a>
<span v-else>{{ value }}</span>
</template>
<script>
import { isValidURL } from '~/helpers'
export default {
name: 'UrlCell',
props: ['value']
props: ['value'],
computed: {
isValid() {
return this.value && isValidURL(this.value)
}
}
}
</script>

98
packages/nc-gui/components/project/spreadsheet/components/editColumn/RatingOptions.vue

@ -0,0 +1,98 @@
<template>
<div>
<div class="nc-rating-wrapper ui-type">
<v-select
v-model="colMeta.icon"
label="Icon"
:items="icons"
dense
outlined
class="caption"
:item-value="v=>v"
:value-comparator="(a,b) => a && b && a.full === b.full && a.empty === b.empty"
>
<template #item="{ item }">
<v-icon small :color="colMeta.color">
{{ item.full }}
</v-icon>
<v-icon class="ml-2" small :color="colMeta.color">
{{ item.empty }}
</v-icon>
</template>
<template #selection="{ item }">
<v-icon small :color="colMeta.color">
{{ item.full }}
</v-icon>
<v-icon class="ml-2" small :color="colMeta.color">
{{ item.empty }}
</v-icon>
</template>
</v-select>
<v-select
v-model="colMeta.max"
label="Max"
:items="[1,2,3,4,5,6,7,8,9,10]"
dense
outlined
class="caption"
/>
</div>
<v-color-picker
v-model="colMeta.color"
class="mx-auto"
hide-inputs
/>
</div>
</template>
<script>
export default {
name: 'RatingOptions',
props: ['column', 'meta', 'value'],
data: () => ({
colMeta: {
icon: {
full: 'mdi-star',
empty: 'mdi-star-outline'
},
color: '#fcb401',
max: 5
},
icons: [{
full: 'mdi-star',
empty: 'mdi-star-outline'
}, {
full: 'mdi-heart',
empty: 'mdi-heart-outline'
}, {
full: 'mdi-moon-full',
empty: 'mdi-moon-new'
}, {
full: 'mdi-thumb-up',
empty: 'mdi-thumb-up-outline'
}, {
full: 'mdi-flag',
empty: 'mdi-flag-outline'
}]
}),
watch: {
value() {
this.colMeta = this.value || {}
},
colMeta(v) {
this.$emit('input', v)
}
},
created() {
this.colMeta = this.value || { ...this.colMeta }
}
}
</script>
<style scoped lang="scss">
.nc-rating-wrapper {
display: flex;
gap: 16px
}
</style>

95
packages/nc-gui/components/project/spreadsheet/components/editColumn/checkboxOptions.vue

@ -0,0 +1,95 @@
<template>
<div>
<div class="nc-rating-wrapper ui-type">
<v-select
v-model="colMeta.icon"
label="Icon"
:items="icons"
dense
outlined
class="caption"
:item-value="v=>v"
:value-comparator="(a,b) => a && b && a.checked === b.checked && a.unchecked === b.unchecked"
>
<template #item="{ item }">
<v-icon small :color="colMeta.color">
{{ item.checked }}
</v-icon>
<v-icon class="ml-2" small :color="colMeta.color">
{{ item.unchecked }}
</v-icon>
</template>
<template #selection="{ item }">
<v-icon small :color="colMeta.color">
{{ item.checked }}
</v-icon>
<v-icon class="ml-2" small :color="colMeta.color">
{{ item.unchecked }}
</v-icon>
</template>
</v-select>
</div>
<v-color-picker
v-model="colMeta.color"
class="mx-auto"
hide-inputs
/>
</div>
</template>
<script>
export default {
name: 'CheckboxOptions',
props: ['column', 'meta', 'value'],
data: () => ({
colMeta: {
icon: {
checked: 'mdi-check-bold',
unchecked: 'mdi-crop-square'
},
color: '#777'
},
icons: [{
checked: 'mdi-check-bold',
unchecked: 'mdi-crop-square'
}, {
checked: 'mdi-check-circle-outline',
unchecked: 'mdi-checkbox-blank-circle-outline'
}, {
checked: 'mdi-star',
unchecked: 'mdi-star-outline'
}, {
checked: 'mdi-heart',
unchecked: 'mdi-heart-outline'
}, {
checked: 'mdi-moon-full',
unchecked: 'mdi-moon-new'
}, {
checked: 'mdi-thumb-up',
unchecked: 'mdi-thumb-up-outline'
}, {
checked: 'mdi-flag',
unchecked: 'mdi-flag-outline'
}]
}),
watch: {
value() {
this.colMeta = this.value || {}
},
colMeta(v) {
this.$emit('input', v)
}
},
created() {
this.colMeta = this.value || { ...this.colMeta }
}
}
</script>
<style scoped lang="scss">
.nc-rating-wrapper {
display: flex;
gap: 16px
}
</style>

36
packages/nc-gui/components/project/spreadsheet/components/editableCell/BooleanCell.vue

@ -1,6 +1,8 @@
<template>
<div class="d-flex align-center " :class="{'justify-center':!isForm}">
<input v-model="localState" type="checkbox" v-on="parentListeners">
<div class="d-flex align-center " :class="{'justify-center':!isForm,'nc-cell-hover-show': !localState}">
<v-icon small :color="checkboxMeta.color" @click="toggle">
{{ localState ? checkedIcon :uncheckedIcon }}
</v-icon>
</div>
</template>
@ -8,10 +10,19 @@
export default {
name: 'BooleanCell',
props: {
column: Object,
value: [String, Number, Boolean],
isForm: Boolean
isForm: Boolean,
readOnly: Boolean
},
computed: {
checkedIcon() {
return (this.checkboxMeta && this.checkboxMeta.icon && this.checkboxMeta.icon.checked) || 'mdi-check-bold'
},
uncheckedIcon() {
return (this.checkboxMeta && this.checkboxMeta.icon && this.checkboxMeta.icon.unchecked) || 'mdi-crop-square'
},
localState: {
get() {
return this.value
@ -20,14 +31,27 @@ export default {
this.$emit('input', val)
}
},
parentListeners() {
const $listeners = {}
return $listeners
},
checkboxMeta() {
return {
icon: {
checked: 'mdi-check-circle-outline',
unchecked: 'mdi-checkbox-blank-circle-outline'
},
color: 'primary',
...(this.column && this.column.meta
? this.column.meta
: {})
}
}
},
mounted() {
this.$el.focus()
methods: {
toggle() {
this.localState = !this.localState
}
}
}
</script>

9
packages/nc-gui/components/project/spreadsheet/components/editableCell/EditableUrlCell.vue

@ -8,7 +8,8 @@ import { isValidURL } from '@/helpers'
export default {
name: 'EditableUrlCell',
props: {
value: String
value: String,
column: Object
},
computed: {
localState: {
@ -16,7 +17,11 @@ export default {
return this.value
},
set(val) {
if (isValidURL(val)) { this.$emit('input', val) }
if (!(
this.column &&
this.column.meta &&
this.column.meta.validate
) || isValidURL(val)) { this.$emit('input', val) }
}
},
parentListeners() {

71
packages/nc-gui/components/project/spreadsheet/components/editableCell/RatingCell.vue

@ -0,0 +1,71 @@
<template>
<div class="d-100 h-100" :class="{'nc-cell-hover-show': localState == 0 || !localState}">
<v-rating
v-model="localState"
:length="ratingMeta.max"
dense
x-small
:disabled="readOnly"
clearable
>
<template #item="{isFilled, click}">
<v-icon v-if="isFilled" :size="15" :color="ratingMeta.color" @click="click">
{{ fullIcon }}
</v-icon>
<v-icon
v-else
:color="ratingMeta.color"
:size="15"
class="nc-cell-hover-show"
@click="click"
>
{{ emptyIcon }}
</v-icon>
</template>
</v-rating>
</div>
</template>
<script>
export default {
name: 'RatingCell',
props: {
column: Object,
value: [String, Number],
readOnly: Boolean
},
computed: {
fullIcon() {
return (this.ratingMeta && this.ratingMeta.icon && this.ratingMeta.icon.full) || 'mdi-star'
},
emptyIcon() {
return (this.ratingMeta && this.ratingMeta.icon && this.ratingMeta.icon.empty) || 'mdi-star-outline'
},
localState: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
},
ratingMeta() {
return {
icon: {
full: 'mdi-star',
empty: 'mdi-star-outline'
},
color: '#fcb401',
max: 5,
...(this.column && this.column.meta
? this.column.meta
: {})
}
}
}
}
</script>
<style scoped>
</style>

6
packages/nc-gui/components/project/spreadsheet/mixins/cell.js

@ -56,9 +56,15 @@ export default {
isURL() {
return this.uiDatatype === 'URL'
},
isEmail() {
return this.uiDatatype === UITypes.Email
},
isAttachment() {
return this.uiDatatype === 'Attachment'
},
isRating() {
return this.uiDatatype === UITypes.Rating
},
isCurrency() {
return this.column.uidt == 'Currency'
}

70
packages/nc-gui/components/project/spreadsheet/views/GridView.vue

@ -139,7 +139,7 @@
v-show="!rowMeta || !rowMeta.selected"
class="ml-2 grey--text"
:class="{ 'row-no': !isPublicView }"
>{{ row + 1 }}</span>
>{{ row + 1 }}</span>
<template v-if="!isPublicView">
<v-checkbox
@ -632,31 +632,30 @@ export default {
break
// delete
case 46:
{
if (this.editEnabled.col != null && this.editEnabled.row != null) {
return
}
const rowObj = this.data[this.selected.row].row
const columnObj = this.availableColumns[this.selected.col]
case 46: {
if (this.editEnabled.col != null && this.editEnabled.row != null) {
return
}
if (
// this.isRequired(columnObj, rowObj, true) ||
columnObj.virtual
) {
return
}
const rowObj = this.data[this.selected.row].row
const columnObj = this.availableColumns[this.selected.col]
this.$set(rowObj, columnObj.title, null)
// update/save cell value
this.onCellValueChange(
this.selected.col,
this.selected.row,
columnObj,
true
)
if (
// this.isRequired(columnObj, rowObj, true) ||
columnObj.virtual
) {
return
}
this.$set(rowObj, columnObj.title, null)
// update/save cell value
this.onCellValueChange(
this.selected.col,
this.selected.row,
columnObj,
true
)
}
break
// left
case 37:
@ -735,11 +734,11 @@ export default {
onClickOutside() {
if (
(this.meta.columns &&
this.meta.columns[this.selected.col] &&
this.meta.columns[this.selected.col].virtual) ||
this.meta.columns[this.selected.col] &&
this.meta.columns[this.selected.col].virtual) ||
(this.availableColumns &&
this.availableColumns[this.editEnabled.col] &&
this.availableColumns[this.editEnabled.col].uidt === 'JSON')
this.availableColumns[this.editEnabled.col] &&
this.availableColumns[this.editEnabled.col].uidt === 'JSON')
) {
return
}
@ -820,6 +819,7 @@ export default {
(column && column.uidt === UITypes.DateTime) ||
(column && column.uidt === UITypes.Date) ||
(column && column.uidt === UITypes.Time) ||
(column && column.uidt === UITypes.Rating) ||
(this.sqlUi &&
column.dt &&
this.sqlUi.getAbstractType(column) === 'boolean')
@ -930,7 +930,7 @@ export default {
}
.search-field.v-text-field.v-text-field--solo.v-input--dense
> .v-input__control {
> .v-input__control {
min-height: auto;
}
@ -1163,4 +1163,18 @@ td:first-child {
.has-many-icon {
transform: rotate(90deg);
}
::v-deep {
tr {
.nc-cell-hover-show {
opacity: 0;
transition: .3s opacity;
}
&:hover .nc-cell-hover-show {
opacity: .7;
}
}
}
</style>

84
packages/nocodb-sdk/src/lib/sqlUi/MssqlUi.ts

@ -1,4 +1,4 @@
import UITypes from "../UITypes";
import UITypes from '../UITypes';
const dbTypes = [
'bigint',
@ -35,15 +35,15 @@ const dbTypes = [
'uniqueidentifier',
'varbinary',
'xml',
'varchar'
'varchar',
];
export class MssqlUi {
static getNewTableColumns() {
return [
{
column_name: 'id',
title: 'Id',
column_name: 'id',
title: 'Id',
dt: 'int',
dtx: 'integer',
ct: 'int(11)',
@ -62,11 +62,11 @@ export class MssqlUi {
altered: 1,
uidt: 'ID',
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'title',
title: 'Title',
column_name: 'title',
title: 'Title',
dt: 'varchar',
dtx: 'specificType',
ct: 'varchar(45)',
@ -85,11 +85,11 @@ export class MssqlUi {
altered: 1,
uidt: 'SingleLineText',
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'created_at',
title: 'CreatedAt',
column_name: 'created_at',
title: 'CreatedAt',
dt: 'datetime',
dtx: 'specificType',
ct: 'varchar(45)',
@ -108,11 +108,11 @@ export class MssqlUi {
altered: 1,
uidt: UITypes.DateTime,
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'updated_at',
title: 'UpdatedAt',
column_name: 'updated_at',
title: 'UpdatedAt',
dt: 'datetime',
dtx: 'specificType',
ct: 'varchar(45)',
@ -131,8 +131,8 @@ export class MssqlUi {
altered: 1,
uidt: UITypes.DateTime,
uip: '',
uicn: ''
}
uicn: '',
},
];
}
@ -157,7 +157,7 @@ export class MssqlUi {
altered: 1,
uidt: 'SingleLineText',
uip: '',
uicn: ''
uicn: '',
};
}
@ -741,13 +741,15 @@ export class MssqlUi {
}
static extractFunctionName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg);
return match && match[1];
}
static extractProcedureName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg);
return match && match[1];
}
@ -808,7 +810,7 @@ export class MssqlUi {
const column = {
dp: null,
tn,
column_name: keys[i],
column_name: keys[i],
cno: keys[i],
np: 10,
ns: 0,
@ -827,7 +829,7 @@ export class MssqlUi {
dtx: 'specificType',
dtxp: null,
dtxs: 0,
altered: 1
altered: 1,
};
switch (typeof json[keys[i]]) {
@ -835,13 +837,13 @@ export class MssqlUi {
if (Number.isInteger(json[keys[i]])) {
if (MssqlUi.isValidTimestamp(keys[i], json[keys[i]])) {
Object.assign(column, {
dt: 'timestamp'
dt: 'timestamp',
});
} else {
Object.assign(column, {
dt: 'int',
np: 10,
ns: 0
ns: 0,
});
}
} else {
@ -850,25 +852,25 @@ export class MssqlUi {
np: 10,
ns: 2,
dtxp: '11',
dtxs: 2
dtxs: 2,
});
}
break;
case 'string':
if (MssqlUi.isValidDate(json[keys[i]])) {
Object.assign(column, {
dt: 'datetime'
dt: 'datetime',
});
} else if (json[keys[i]].length <= 255) {
Object.assign(column, {
dt: 'varchar',
np: 255,
ns: 0,
dtxp: '255'
dtxp: '255',
});
} else {
Object.assign(column, {
dt: 'text'
dt: 'text',
});
}
break;
@ -876,7 +878,7 @@ export class MssqlUi {
Object.assign(column, {
dt: 'bit',
np: null,
ns: 0
ns: 0,
});
break;
case 'object':
@ -884,7 +886,7 @@ export class MssqlUi {
dt: 'varchar',
np: 255,
ns: 0,
dtxp: '255'
dtxp: '255',
});
break;
default:
@ -1043,9 +1045,7 @@ export class MssqlUi {
}
}
static getDataTypeForUiType(
col
): {
static getDataTypeForUiType(col): {
readonly dt: string;
readonly [key: string]: any;
} {
@ -1098,7 +1098,7 @@ export class MssqlUi {
colProp.validate = {
func: ['isMobilePhone'],
args: [''],
msg: ['Validation failed : isMobilePhone']
msg: ['Validation failed : isMobilePhone'],
};
break;
case 'Email':
@ -1106,7 +1106,7 @@ export class MssqlUi {
colProp.validate = {
func: ['isEmail'],
args: [''],
msg: ['Validation failed : isEmail']
msg: ['Validation failed : isEmail'],
};
break;
case 'URL':
@ -1114,7 +1114,7 @@ export class MssqlUi {
colProp.validate = {
func: ['isURL'],
args: [''],
msg: ['Validation failed : isURL']
msg: ['Validation failed : isURL'],
};
break;
case 'Number':
@ -1128,7 +1128,7 @@ export class MssqlUi {
colProp.validate = {
func: ['isCurrency'],
args: [''],
msg: ['Validation failed : isCurrency']
msg: ['Validation failed : isCurrency'],
};
break;
case 'Percent':
@ -1138,7 +1138,7 @@ export class MssqlUi {
colProp.dt = 'int';
break;
case 'Rating':
colProp.dt = 'float';
colProp.dt = 'int';
break;
case 'Formula':
colProp.dt = 'varchar';
@ -1224,7 +1224,7 @@ export class MssqlUi {
'numeric',
'real',
'smallint',
'tinyint'
'tinyint',
];
case 'Decimal':
@ -1240,7 +1240,7 @@ export class MssqlUi {
'numeric',
'real',
'smallint',
'tinyint'
'tinyint',
];
case 'Percent':
@ -1253,7 +1253,7 @@ export class MssqlUi {
'numeric',
'real',
'smallint',
'tinyint'
'tinyint',
];
case 'Duration':
@ -1266,7 +1266,7 @@ export class MssqlUi {
'numeric',
'real',
'smallint',
'tinyint'
'tinyint',
];
case 'Rating':
@ -1279,7 +1279,7 @@ export class MssqlUi {
'numeric',
'real',
'smallint',
'tinyint'
'tinyint',
];
case 'Formula':
@ -1302,7 +1302,7 @@ export class MssqlUi {
case 'LastModifiedTime':
return [
'datetimeoffset',
'datetime2'
'datetime2',
// 'datetime'
];

74
packages/nocodb-sdk/src/lib/sqlUi/MysqlUi.ts

@ -1,4 +1,4 @@
import UITypes from "../UITypes";
import UITypes from '../UITypes';
const dbTypes = [
'int',
@ -39,7 +39,7 @@ const dbTypes = [
'multipoint',
'multilinestring',
'multipolygon',
'json'
'json',
];
export class MysqlUi {
@ -66,7 +66,7 @@ export class MysqlUi {
altered: 1,
uidt: 'ID',
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'title',
@ -89,7 +89,7 @@ export class MysqlUi {
altered: 1,
uidt: 'SingleLineText',
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'created_at',
@ -112,7 +112,7 @@ export class MysqlUi {
altered: 1,
uidt: UITypes.DateTime,
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'updated_at',
@ -135,8 +135,8 @@ export class MysqlUi {
altered: 1,
uidt: UITypes.DateTime,
uip: '',
uicn: ''
}
uicn: '',
},
];
}
@ -161,7 +161,7 @@ export class MysqlUi {
altered: 1,
uidt: 'SingleLineText',
uip: '',
uicn: ''
uicn: '',
};
}
@ -659,13 +659,15 @@ export class MysqlUi {
}
static extractFunctionName(query) {
const reg = /^\s*CREATE\s+.*?(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:`?[\w\d_]+`?\.)?`?([\w_\d]+)`?/i;
const reg =
/^\s*CREATE\s+.*?(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:`?[\w\d_]+`?\.)?`?([\w_\d]+)`?/i;
const match = query.match(reg);
return match && match[1];
}
static extractProcedureName(query) {
const reg = /^\s*CREATE.*?\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const reg =
/^\s*CREATE.*?\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg);
return match && match[1];
}
@ -677,14 +679,14 @@ export class MysqlUi {
// set headers before settings result
for (let i = 0; i < keys.length; i++) {
const text = keys[i];
headers.push({text, value: text, sortable: false});
headers.push({ text, value: text, sortable: false });
}
} else {
const keys = Object.keys(result);
for (let i = 0; i < keys.length; i++) {
const text = keys[i];
if (typeof text !== 'function') {
headers.push({text, value: text, sortable: false});
headers.push({ text, value: text, sortable: false });
}
}
result = [result];
@ -750,7 +752,7 @@ export class MysqlUi {
dtx: 'specificType',
dtxp: null,
dtxs: 0,
altered: 1
altered: 1,
};
switch (typeof json[keys[i]]) {
@ -758,13 +760,13 @@ export class MysqlUi {
if (Number.isInteger(json[keys[i]])) {
if (MysqlUi.isValidTimestamp(keys[i], json[keys[i]])) {
Object.assign(column, {
dt: 'timestamp'
dt: 'timestamp',
});
} else {
Object.assign(column, {
dt: 'int',
np: 10,
ns: 0
ns: 0,
});
}
} else {
@ -773,25 +775,25 @@ export class MysqlUi {
np: 10,
ns: 2,
dtxp: '11',
dtxs: 2
dtxs: 2,
});
}
break;
case 'string':
if (MysqlUi.isValidDate(json[keys[i]])) {
Object.assign(column, {
dt: 'datetime'
dt: 'datetime',
});
} else if (json[keys[i]].length <= 255) {
Object.assign(column, {
dt: 'varchar',
np: 255,
ns: 0,
dtxp: '255'
dtxp: '255',
});
} else {
Object.assign(column, {
dt: 'text'
dt: 'text',
});
}
break;
@ -799,14 +801,14 @@ export class MysqlUi {
Object.assign(column, {
dt: 'boolean',
np: 3,
ns: 0
ns: 0,
});
break;
case 'object':
Object.assign(column, {
dt: 'json',
np: 3,
ns: 0
ns: 0,
});
break;
default:
@ -991,7 +993,7 @@ export class MysqlUi {
colProp.validate = {
func: ['isMobilePhone'],
args: [''],
msg: ['Validation failed : isMobilePhone ({cn})']
msg: ['Validation failed : isMobilePhone ({cn})'],
};
break;
case 'Email':
@ -999,7 +1001,7 @@ export class MysqlUi {
colProp.validate = {
func: ['isEmail'],
args: [''],
msg: ['Validation failed : isEmail ({cn})']
msg: ['Validation failed : isEmail ({cn})'],
};
break;
case 'URL':
@ -1007,7 +1009,7 @@ export class MysqlUi {
colProp.validate = {
func: ['isURL'],
args: [''],
msg: ['Validation failed : isURL ({cn})']
msg: ['Validation failed : isURL ({cn})'],
};
break;
case 'Number':
@ -1021,7 +1023,7 @@ export class MysqlUi {
colProp.validate = {
func: ['isCurrency'],
args: [''],
msg: ['Validation failed : isCurrency']
msg: ['Validation failed : isCurrency'],
};
break;
case 'Percent':
@ -1031,7 +1033,7 @@ export class MysqlUi {
colProp.dt = 'int';
break;
case 'Rating':
colProp.dt = 'float';
colProp.dt = 'int';
break;
case 'Formula':
colProp.dt = 'varchar';
@ -1089,7 +1091,7 @@ export class MysqlUi {
'text',
'tinytext',
'mediumtext',
'longtext'
'longtext',
];
case 'Attachment':
@ -1101,7 +1103,7 @@ export class MysqlUi {
'text',
'tinytext',
'mediumtext',
'longtext'
'longtext',
];
case 'JSON':
@ -1116,7 +1118,7 @@ export class MysqlUi {
'bit',
'boolean',
'serial',
'tinyint'
'tinyint',
];
case 'MultiSelect':
@ -1148,7 +1150,7 @@ export class MysqlUi {
'float',
'decimal',
'double',
'serial'
'serial',
];
case 'Decimal':
@ -1164,7 +1166,7 @@ export class MysqlUi {
'smallint',
'mediumint',
'bigint',
'bit'
'bit',
];
case 'Percent':
@ -1177,7 +1179,7 @@ export class MysqlUi {
'smallint',
'mediumint',
'bigint',
'bit'
'bit',
];
case 'Duration':
@ -1190,7 +1192,7 @@ export class MysqlUi {
'smallint',
'mediumint',
'bigint',
'bit'
'bit',
];
case 'Rating':
@ -1203,7 +1205,7 @@ export class MysqlUi {
'smallint',
'mediumint',
'bigint',
'bit'
'bit',
];
case 'Formula':
@ -1214,7 +1216,7 @@ export class MysqlUi {
'text',
'tinytext',
'mediumtext',
'longtext'
'longtext',
];
case 'Rollup':
@ -1248,7 +1250,7 @@ export class MysqlUi {
'polygon',
'multipoint',
'multilinestring',
'multipolygon'
'multipolygon',
];
case 'Button':

36
packages/nocodb-sdk/src/lib/sqlUi/OracleUi.ts

@ -22,7 +22,7 @@ export class OracleUi {
altered: 1,
uidt: 'ID',
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'title',
@ -45,8 +45,8 @@ export class OracleUi {
altered: 1,
uidt: 'SingleLineText',
uip: '',
uicn: ''
}
uicn: '',
},
// {
// column_name: "created_at",
// dt: "timestamp",
@ -107,7 +107,7 @@ export class OracleUi {
altered: 1,
uidt: 'SingleLineText',
uip: '',
uicn: ''
uicn: '',
};
}
@ -435,13 +435,15 @@ export class OracleUi {
}
static extractFunctionName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg);
return match && match[1];
}
static extractProcedureName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg);
return match && match[1];
}
@ -522,7 +524,7 @@ export class OracleUi {
dtx: 'specificType',
dtxp: '11',
dtxs: 0,
altered: 1
altered: 1,
});
} else {
columns.push({
@ -548,7 +550,7 @@ export class OracleUi {
dtx: 'specificType',
dtxp: '11',
dtxs: 2,
altered: 1
altered: 1,
});
}
@ -579,7 +581,7 @@ export class OracleUi {
dtx: 'specificType',
dtxp: '45',
dtxs: 0,
altered: 1
altered: 1,
});
} else {
columns.push({
@ -605,7 +607,7 @@ export class OracleUi {
dtx: 'specificType',
dtxp: null,
dtxs: 0,
altered: 1
altered: 1,
});
}
@ -635,7 +637,7 @@ export class OracleUi {
dtx: 'specificType',
dtxp: '1',
dtxs: 0,
altered: 1
altered: 1,
});
break;
@ -663,7 +665,7 @@ export class OracleUi {
dtx: 'specificType',
dtxp: null,
dtxs: 0,
altered: 1
altered: 1,
});
break;
@ -839,7 +841,7 @@ export class OracleUi {
colProp.validate = {
func: ['isMobilePhone'],
args: [''],
msg: ['Validation failed : isMobilePhone']
msg: ['Validation failed : isMobilePhone'],
};
break;
case 'Email':
@ -847,7 +849,7 @@ export class OracleUi {
colProp.validate = {
func: ['isEmail'],
args: [''],
msg: ['Validation failed : isEmail']
msg: ['Validation failed : isEmail'],
};
break;
case 'URL':
@ -855,7 +857,7 @@ export class OracleUi {
colProp.validate = {
func: ['isURL'],
args: [''],
msg: ['Validation failed : isURL']
msg: ['Validation failed : isURL'],
};
break;
case 'Number':
@ -869,7 +871,7 @@ export class OracleUi {
colProp.validate = {
func: ['isCurrency'],
args: [''],
msg: ['Validation failed : isCurrency']
msg: ['Validation failed : isCurrency'],
};
break;
case 'Percent':
@ -879,7 +881,7 @@ export class OracleUi {
colProp.dt = 'integer';
break;
case 'Rating':
colProp.dt = 'float';
colProp.dt = 'integer';
break;
case 'Formula':
colProp.dt = 'varchar';

97
packages/nocodb-sdk/src/lib/sqlUi/PgUi.ts

@ -1,4 +1,4 @@
import UITypes from "../UITypes";
import UITypes from '../UITypes';
const dbTypes = [
'int',
@ -98,15 +98,15 @@ const dbTypes = [
'unknown',
'void',
'xid',
'xml'
'xml',
];
export class PgUi {
static getNewTableColumns() {
return [
{
column_name: 'id',
title: 'Id',
column_name: 'id',
title: 'Id',
dt: 'int4',
dtx: 'integer',
ct: 'int(11)',
@ -125,11 +125,11 @@ export class PgUi {
altered: 1,
uidt: 'ID',
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'title',
title: 'Title',
column_name: 'title',
title: 'Title',
dt: 'character varying',
dtx: 'specificType',
ct: 'varchar(45)',
@ -148,11 +148,11 @@ export class PgUi {
altered: 1,
uidt: 'SingleLineText',
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'created_at',
title: 'CreatedAt',
column_name: 'created_at',
title: 'CreatedAt',
dt: 'timestamp',
dtx: 'specificType',
ct: 'varchar(45)',
@ -171,11 +171,11 @@ export class PgUi {
altered: 1,
uidt: UITypes.DateTime,
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'updated_at',
title: 'UpdatedAt',
column_name: 'updated_at',
title: 'UpdatedAt',
dt: 'timestamp',
dtx: 'specificType',
ct: 'varchar(45)',
@ -195,8 +195,8 @@ export class PgUi {
altered: 1,
uidt: UITypes.DateTime,
uip: '',
uicn: ''
}
uicn: '',
},
];
}
@ -221,7 +221,7 @@ export class PgUi {
altered: 1,
uidt: 'SingleLineText',
uip: '',
uicn: ''
uicn: '',
};
}
@ -1160,13 +1160,15 @@ export class PgUi {
}
static extractFunctionName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg);
return match && match[1];
}
static extractProcedureName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg);
return match && match[1];
}
@ -1176,8 +1178,8 @@ export class PgUi {
headers.push({ text: 'Row count', value: 'rowCount', sortable: false });
result = [
{
rowCount: result.rowCount
}
rowCount: result.rowCount,
},
];
} else {
result = result.rows;
@ -1232,7 +1234,7 @@ export class PgUi {
const column = {
dp: null,
tn,
column_name: keys[i],
column_name: keys[i],
cno: keys[i],
np: 10,
ns: 0,
@ -1251,7 +1253,7 @@ export class PgUi {
dtx: 'specificType',
dtxp: null,
dtxs: 0,
altered: 1
altered: 1,
};
switch (typeof json[keys[i]]) {
@ -1259,13 +1261,13 @@ export class PgUi {
if (Number.isInteger(json[keys[i]])) {
if (PgUi.isValidTimestamp(keys[i], json[keys[i]])) {
Object.assign(column, {
dt: 'timestamp'
dt: 'timestamp',
});
} else {
Object.assign(column, {
dt: 'int',
np: 10,
ns: 0
ns: 0,
});
}
} else {
@ -1274,25 +1276,25 @@ export class PgUi {
np: null,
ns: null,
dtxp: null,
dtxs: null
dtxs: null,
});
}
break;
case 'string':
if (PgUi.isValidDate(json[keys[i]])) {
Object.assign(column, {
dt: 'date'
dt: 'date',
});
} else if (json[keys[i]].length <= 255) {
Object.assign(column, {
dt: 'character varying',
np: null,
ns: 0,
dtxp: null
dtxp: null,
});
} else {
Object.assign(column, {
dt: 'text'
dt: 'text',
});
}
break;
@ -1300,14 +1302,14 @@ export class PgUi {
Object.assign(column, {
dt: 'boolean',
np: 3,
ns: 0
ns: 0,
});
break;
case 'object':
Object.assign(column, {
dt: 'json',
np: 3,
ns: 0
ns: 0,
});
break;
default:
@ -1521,7 +1523,6 @@ export class PgUi {
case 'longblob':
return 'blob';
case 'enum':
return 'enum';
case 'set':
return 'set';
@ -1616,7 +1617,7 @@ export class PgUi {
colProp.validate = {
func: ['isMobilePhone'],
args: [''],
msg: ['Validation failed : isMobilePhone']
msg: ['Validation failed : isMobilePhone'],
};
break;
case 'Email':
@ -1624,7 +1625,7 @@ export class PgUi {
colProp.validate = {
func: ['isEmail'],
args: [''],
msg: ['Validation failed : isEmail']
msg: ['Validation failed : isEmail'],
};
break;
case 'URL':
@ -1632,7 +1633,7 @@ export class PgUi {
colProp.validate = {
func: ['isURL'],
args: [''],
msg: ['Validation failed : isURL']
msg: ['Validation failed : isURL'],
};
break;
case 'Number':
@ -1646,7 +1647,7 @@ export class PgUi {
colProp.validate = {
func: ['isCurrency'],
args: [''],
msg: ['Validation failed : isCurrency']
msg: ['Validation failed : isCurrency'],
};
break;
case 'Percent':
@ -1656,7 +1657,7 @@ export class PgUi {
colProp.dt = 'int8';
break;
case 'Rating':
colProp.dt = 'float8';
colProp.dt = 'smallint';
break;
case 'Formula':
colProp.dt = 'character varying';
@ -1732,7 +1733,7 @@ export class PgUi {
'int8range',
'serial',
'serial2',
'serial8'
'serial8',
];
case 'MultiSelect':
@ -1753,7 +1754,7 @@ export class PgUi {
'timestamptz',
'timestamp with time zone',
'timetz',
'time with time zone'
'time with time zone',
];
case 'PhoneNumber':
@ -1780,7 +1781,7 @@ export class PgUi {
'float8',
'smallint',
'smallserial',
'numeric'
'numeric',
];
case 'Decimal':
@ -1802,7 +1803,7 @@ export class PgUi {
'money',
'float4',
'float8',
'numeric'
'numeric',
];
case 'Percent':
@ -1822,7 +1823,7 @@ export class PgUi {
'float8',
'smallint',
'smallserial',
'numeric'
'numeric',
];
case 'Duration':
@ -1842,7 +1843,7 @@ export class PgUi {
'float8',
'smallint',
'smallserial',
'numeric'
'numeric',
];
case 'Rating':
@ -1862,7 +1863,7 @@ export class PgUi {
'float8',
'smallint',
'smallserial',
'numeric'
'numeric',
];
case 'Formula':
@ -1884,7 +1885,7 @@ export class PgUi {
'serial2',
'serial8',
'smallint',
'smallserial'
'smallserial',
];
case 'Lookup':
@ -1896,7 +1897,7 @@ export class PgUi {
'timestamp',
'timestamp without time zone',
'timestamptz',
'timestamp with time zone'
'timestamp with time zone',
];
case 'DateTime':
@ -1906,7 +1907,7 @@ export class PgUi {
'timestamp',
'timestamp without time zone',
'timestamptz',
'timestamp with time zone'
'timestamp with time zone',
];
case 'AutoNumber':
@ -1922,7 +1923,7 @@ export class PgUi {
'serial2',
'serial8',
'smallint',
'smallserial'
'smallserial',
];
case 'Barcode':
@ -1937,7 +1938,7 @@ export class PgUi {
'line',
'lseg',
'path',
'circle'
'circle',
];
case 'Button':

94
packages/nocodb-sdk/src/lib/sqlUi/SqliteUi.ts

@ -1,4 +1,4 @@
import UITypes from "../UITypes";
import UITypes from '../UITypes';
const dbTypes = [
'int',
@ -22,15 +22,15 @@ const dbTypes = [
'datetime',
'text',
'varchar',
'timestamp'
'timestamp',
];
export class SqliteUi {
static getNewTableColumns() {
return [
{
column_name: 'id',
title: 'Id',
column_name: 'id',
title: 'Id',
dt: 'integer',
dtx: 'integer',
ct: 'int(11)',
@ -49,11 +49,11 @@ export class SqliteUi {
altered: 1,
uidt: 'ID',
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'title',
title: 'Title',
column_name: 'title',
title: 'Title',
dt: 'varchar',
dtx: 'specificType',
ct: 'varchar',
@ -72,11 +72,11 @@ export class SqliteUi {
altered: 1,
uidt: 'SingleLineText',
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'created_at',
title: 'CreatedAt',
column_name: 'created_at',
title: 'CreatedAt',
dt: 'datetime',
dtx: 'specificType',
ct: 'varchar',
@ -95,11 +95,11 @@ export class SqliteUi {
altered: 1,
uidt: UITypes.DateTime,
uip: '',
uicn: ''
uicn: '',
},
{
column_name: 'updated_at',
title: 'UpdatedAt',
column_name: 'updated_at',
title: 'UpdatedAt',
dt: 'datetime',
dtx: 'specificType',
ct: 'varchar',
@ -118,8 +118,8 @@ export class SqliteUi {
altered: 1,
uidt: UITypes.DateTime,
uip: '',
uicn: ''
}
uicn: '',
},
];
}
@ -144,7 +144,7 @@ export class SqliteUi {
altered: 1,
uidt: 'SingleLineText',
uip: '',
uicn: ''
uicn: '',
};
}
@ -498,13 +498,15 @@ export class SqliteUi {
}
static extractFunctionName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*FUNCTION\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg);
return match && match[1];
}
static extractProcedureName(query) {
const reg = /^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const reg =
/^\s*CREATE\s+(?:OR\s+REPLACE\s*)?\s*PROCEDURE\s+(?:[\w\d_]+\.)?([\w_\d]+)/i;
const match = query.match(reg);
return match && match[1];
}
@ -565,7 +567,7 @@ export class SqliteUi {
const column = {
dp: null,
tn,
column_name: keys[i],
column_name: keys[i],
cno: keys[i],
np: null,
ns: null,
@ -584,7 +586,7 @@ export class SqliteUi {
dtx: 'specificType',
dtxp: null,
dtxs: 0,
altered: 1
altered: 1,
};
switch (typeof json[keys[i]]) {
@ -592,16 +594,16 @@ export class SqliteUi {
if (Number.isInteger(json[keys[i]])) {
if (SqliteUi.isValidTimestamp(keys[i], json[keys[i]])) {
Object.assign(column, {
dt: 'timestamp'
dt: 'timestamp',
});
} else {
Object.assign(column, {
dt: 'integer'
dt: 'integer',
});
}
} else {
Object.assign(column, {
dt: 'real'
dt: 'real',
});
}
break;
@ -613,24 +615,24 @@ export class SqliteUi {
// } else
if (json[keys[i]].length <= 255) {
Object.assign(column, {
dt: 'varchar'
dt: 'varchar',
});
} else {
Object.assign(column, {
dt: 'text'
dt: 'text',
});
}
break;
case 'boolean':
Object.assign(column, {
dt: 'integer'
dt: 'integer',
});
break;
case 'object':
Object.assign(column, {
dt: 'text',
np: null,
dtxp: null
dtxp: null,
});
break;
default:
@ -807,7 +809,7 @@ export class SqliteUi {
colProp.validate = {
func: ['isMobilePhone'],
args: [''],
msg: ['Validation failed : isMobilePhone']
msg: ['Validation failed : isMobilePhone'],
};
break;
case 'Email':
@ -815,7 +817,7 @@ export class SqliteUi {
colProp.validate = {
func: ['isEmail'],
args: [''],
msg: ['Validation failed : isEmail']
msg: ['Validation failed : isEmail'],
};
break;
case 'URL':
@ -823,7 +825,7 @@ export class SqliteUi {
colProp.validate = {
func: ['isURL'],
args: [''],
msg: ['Validation failed : isURL']
msg: ['Validation failed : isURL'],
};
break;
case 'Number':
@ -837,7 +839,7 @@ export class SqliteUi {
colProp.validate = {
func: ['isCurrency'],
args: [''],
msg: ['Validation failed : isCurrency']
msg: ['Validation failed : isCurrency'],
};
break;
case 'Percent':
@ -847,7 +849,7 @@ export class SqliteUi {
colProp.dt = 'integer';
break;
case 'Rating':
colProp.dt = 'float';
colProp.dt = 'integer';
break;
case 'Formula':
colProp.dt = 'varchar';
@ -911,7 +913,7 @@ export class SqliteUi {
'bigint',
'int2',
'int8',
'boolean'
'boolean',
];
case 'MultiSelect':
@ -929,7 +931,7 @@ export class SqliteUi {
'mediumint',
'bigint',
'int2',
'int8'
'int8',
];
case 'Time':
@ -941,7 +943,7 @@ export class SqliteUi {
'mediumint',
'bigint',
'int2',
'int8'
'int8',
];
case 'PhoneNumber':
@ -965,7 +967,7 @@ export class SqliteUi {
'real',
'double',
'double precision',
'float'
'float',
];
case 'Decimal':
@ -985,7 +987,7 @@ export class SqliteUi {
'bigint',
'int2',
'int8',
'numeric'
'numeric',
];
case 'Percent':
@ -1002,7 +1004,7 @@ export class SqliteUi {
'bigint',
'int2',
'int8',
'numeric'
'numeric',
];
case 'Duration':
@ -1014,15 +1016,11 @@ export class SqliteUi {
'mediumint',
'bigint',
'int2',
'int8'
'int8',
];
case 'Rating':
return [
'real',
'double',
'double precision',
'float',
'int',
'integer',
'tinyint',
@ -1031,7 +1029,11 @@ export class SqliteUi {
'bigint',
'int2',
'int8',
'numeric'
'numeric',
'real',
'double',
'double precision',
'float',
];
case 'Formula':
@ -1049,7 +1051,7 @@ export class SqliteUi {
'mediumint',
'bigint',
'int2',
'int8'
'int8',
];
case 'Lookup':
@ -1072,7 +1074,7 @@ export class SqliteUi {
'mediumint',
'bigint',
'int2',
'int8'
'int8',
];
case 'Barcode':

3
packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSqlv2.ts

@ -1776,6 +1776,9 @@ class BaseModelSqlv2 {
// let cols = Object.keys(this.columns);
for (let i = 0; i < this.model.columns.length; ++i) {
const column = this.model.columns[i];
// skip validation if `validate` is undefined or false
if (!column?.meta?.validate) continue;
const validate = column.getValidators();
const cn = column.column_name;
if (!validate) continue;

40
packages/nocodb/src/lib/noco-models/Column.ts

@ -56,6 +56,7 @@ export default class Column<T = any> implements ColumnType {
public order: number;
public validate: any;
public meta: any;
constructor(data: Partial<ColumnType | Column>) {
Object.assign(this, data);
@ -106,7 +107,11 @@ export default class Column<T = any> implements ColumnType {
order: column.order,
project_id: column.project_id,
base_id: column.base_id,
system: column.system
system: column.system,
meta:
column.meta && typeof column.meta === 'object'
? JSON.stringify(column.meta)
: column.meta
};
if (column.validate) {
@ -375,6 +380,17 @@ export default class Column<T = any> implements ColumnType {
order: 'asc'
}
});
columnsList.forEach(column => {
if (column.meta && typeof column.meta === 'string') {
try {
column.meta = JSON.parse(column.meta);
} catch {
column.meta = {};
}
}
});
await NocoCache.setList(CacheScope.COLUMN, [fk_model_id], columnsList);
}
columnsList.sort(
@ -452,6 +468,11 @@ export default class Column<T = any> implements ColumnType {
MetaTable.COLUMNS,
colId
);
try {
colData.meta = JSON.parse(colData.meta);
} catch {
colData.meta = {};
}
await NocoCache.set(`${CacheScope.COLUMN}:${colId}`, colData);
}
if (colData) {
@ -783,7 +804,8 @@ export default class Column<T = any> implements ColumnType {
au: column.au,
pv: column.pv,
system: column.system,
validate: null
validate: null,
meta: column.meta
};
if (column.validate) {
@ -801,7 +823,19 @@ export default class Column<T = any> implements ColumnType {
await NocoCache.set(key, o);
}
// set meta
await ncMeta.metaUpdate(null, null, MetaTable.COLUMNS, updateObj, colId);
await ncMeta.metaUpdate(
null,
null,
MetaTable.COLUMNS,
{
...updateObj,
meta:
updateObj.meta && typeof updateObj.meta === 'object'
? JSON.stringify(updateObj.meta)
: updateObj.meta
},
colId
);
await this.insertColOption(column, colId, ncMeta);
}

6
packages/nocodb/src/lib/noco/common/XcMigrationSourcev2.ts

@ -2,6 +2,7 @@ import * as nc_011 from '../migrationsv2/nc_011';
import * as nc_012_alter_column_data_types from '../migrationsv2/nc_012_alter_column_data_types';
import * as nc_013_sync_source from '../migrationsv2/nc_013_sync_source';
import * as nc_014_alter_column_data_types from '../migrationsv2/nc_014_alter_column_data_types';
import * as nc_015_add_meta_col_in_column_table from '../migrationsv2/nc_015_add_meta_col_in_column_table';
// Create a custom migration source class
export default class XcMigrationSourcev2 {
@ -14,7 +15,8 @@ export default class XcMigrationSourcev2 {
'nc_011',
'nc_012_alter_column_data_types',
'nc_013_sync_source',
'nc_014_alter_column_data_types'
'nc_014_alter_column_data_types',
'nc_015_add_meta_col_in_column_table'
]);
}
@ -32,6 +34,8 @@ export default class XcMigrationSourcev2 {
return nc_013_sync_source;
case 'nc_014_alter_column_data_types':
return nc_014_alter_column_data_types;
case 'nc_015_add_meta_col_in_column_table':
return nc_015_add_meta_col_in_column_table;
}
}
}

38
packages/nocodb/src/lib/noco/migrationsv2/nc_015_add_meta_col_in_column_table.ts

@ -0,0 +1,38 @@
import Knex from 'knex';
import { MetaTable } from '../../utils/globals';
const up = async (knex: Knex) => {
await knex.schema.alterTable(MetaTable.COLUMNS, table => {
table.text('meta');
});
};
const down = async knex => {
await knex.schema.alterTable(MetaTable.COLUMNS, table => {
table.dropColumn('meta');
});
};
export { up, down };
/**
* @copyright Copyright (c) 2022, Xgene Cloud Ltd
*
* @author Wing-Kam Wong <wingkwong.code@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

4
packages/nocodb/src/lib/noco/upgrader/jobs/ncProjectUpgraderV2_0090000.ts

@ -436,6 +436,10 @@ async function migrateProjectModels(
columnMeta.uidt = UITypes.ForeignKey;
}
if (columnMeta.uidt === UITypes.Rating) {
columnMeta.uidt = UITypes.Number;
}
const column = await Column.insert(
{
...columnMeta,

Loading…
Cancel
Save