Browse Source

chore: sync with develop & resolve conflicts

test/percent
Wing-Kam Wong 2 years ago
parent
commit
c01e60e92a
  1. 2
      packages/nc-gui/components/ProjectTabs.vue
  2. 120
      packages/nc-gui/components/ProjectTreeView.vue
  3. 1
      packages/nc-gui/components/project/Table.vue
  4. 24
      packages/nc-gui/components/project/spreadsheet/components/ColumnFilter.vue
  5. 13
      packages/nc-gui/components/project/spreadsheet/components/EditColumn.vue
  6. 1
      packages/nc-gui/components/project/spreadsheet/components/EditableCell.vue
  7. 38
      packages/nc-gui/components/project/spreadsheet/components/editColumn/DateOptions.vue
  8. 11
      packages/nc-gui/components/project/spreadsheet/components/editableCell/DatePickerCell.vue
  9. 2
      packages/nc-gui/components/project/spreadsheet/components/editableCell/EditableAttachmentCell.vue
  10. 20
      packages/nc-gui/components/project/spreadsheet/components/virtualCell/LookupCell.vue
  11. 9
      packages/nc-gui/helpers/dateFormatHelper.js
  12. 2
      packages/nc-gui/helpers/rightClickOptions.js
  13. 12
      packages/nc-gui/helpers/rolePermissionsEE.js
  14. 36
      packages/noco-docs-prev/package-lock.json
  15. 38
      packages/noco-docs/package-lock.json
  16. 123
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts
  17. 2
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts
  18. 3
      packages/nocodb/src/lib/meta/api/userApi/userApis.ts

2
packages/nc-gui/components/ProjectTabs.vue

@ -207,7 +207,7 @@
style="height: 100%"
>
<project-settings
v-if="_isUIAllowed('settings')"
v-if="_isUIAllowed('projectSettings')"
class="backgroundColor"
:nodes="tab._nodes"
style="height: 100%"

120
packages/nc-gui/components/ProjectTreeView.vue

@ -409,9 +409,18 @@
</span>
</v-list-item-title>
</v-list-item>
<v-list-item v-if="_isUIAllowed('table-delete')" dense @click="checkAndDeleteTable(child)">
<v-list-item-icon>
<v-icon x-small>
mdi-delete-outline
</v-icon>
</v-list-item-icon>
<v-list-item-title>
<span classs="caption">Delete</span>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<!-- <v-icon @click.stop="" x-small>mdi-delete-outline</v-icon>-->
</div>
</template>
@ -769,6 +778,13 @@
:heading="selectedNodeForDelete.heading"
type="error"
/>
<dlgLabelSubmitCancel
v-if="dialogDeleteTable.dialogShow"
type="error"
:actions-mtd="deleteTable"
:dialog-show="dialogDeleteTable.dialogShow"
:heading="`${dialogDeleteTable.heading} ${dialogDeleteTable.tableName}`"
/>
<quick-import
ref="quickImport"
v-model="quickImportDialog"
@ -783,6 +799,7 @@
/* eslint-disable */
import {mapMutations, mapGetters, mapActions} from "vuex";
import { UITypes } from 'nocodb-sdk'
import rightClickOptions from "../helpers/rightClickOptions";
import rightClickOptionsSub from "../helpers/rightClickOptionsSub";
@ -904,6 +921,12 @@ export default {
cookie: null,
defaultValue: null,
},
dialogDeleteTable: {
dialogShow: false,
heading: 'Click Submit to Delete the Table:',
nodes: {},
id: '',
},
selectedNodeForDelete: {
dialog: false,
item: null,
@ -1073,7 +1096,69 @@ export default {
openLink(link) {
window.open(link, "_blank");
},
async checkAndDeleteTable(table, action = 'showDialog') {
this.dialogDeleteTable.tableName = table.title
this.dialogDeleteTable.nodes = table._nodes
this.dialogDeleteTable.id = table.id
await this.deleteTable(action)
this.$e('c:table:delete')
},
async deleteTable(action = '') {
if (action === 'showDialog') {
this.dialogDeleteTable.dialogShow = true
} else if (action === 'hideDialog') {
this.dialogDeleteTable.dialogShow = false
} else {
try {
const nodes = this.dialogDeleteTable.nodes;
const id = this.dialogDeleteTable.id
const meta = await this.$store.dispatch('meta/ActLoadMeta', { id })
const relationColumns = meta.columns.filter(c => c.uidt === UITypes.LinkToAnotherRecord)
if (relationColumns.length) {
const refColMsgs = await Promise.all(relationColumns.map(async(c, i) => {
const refMeta = await this.$store.dispatch('meta/ActLoadMeta', { id: c.colOptions.fk_related_model_id })
return `${i + 1}. ${c.title} is a LinkToAnotherRecord of ${(refMeta && refMeta.title) || c.title}`
}))
this.$toast.info(`<div style="padding:10px 4px">Unable to delete tables because of the following.
<br><br>${refColMsgs.join('<br>')}<br><br>
Delete them & try again</div>
`).goAway(10000)
this.dialogDeleteTable.dialogShow = false
return
}
await this.$api.dbTable.delete(id)
this.removeTableTab({
env: nodes.env,
dbAlias: nodes.dbAlias,
table_name: nodes.table_name
})
await this.loadTablesFromParentTreeNode({
_nodes: {
...nodes
}
})
this.$store.commit('meta/MutMeta', {
key: nodes.table_name,
value: null
})
this.$store.commit('meta/MutMeta', {
key: id,
value: null
})
this.$toast.info(`Deleted table ${nodes.title} successfully`).goAway(3000)
} catch (e) {
const msg = await this._extractSdkResponseErrorMsg(e)
this.$toast.error(msg).goAway(3000)
}
this.dialogDeleteTable.dialogShow = false
this.$e('a:table:delete')
}
},
/* settingsTabAdd() {
const tabIndex = this.tabs.findIndex(el => el.key === `projectSettings`);
if (tabIndex !== -1) {
@ -1189,6 +1274,7 @@ export default {
"project/loadProceduresFromParentTreeNode",
removeTabsByName: "tabs/removeTabsByName",
clearProjects: "project/clearProjects",
removeTableTab: 'tabs/removeTableTab',
}),
async addTab(item, open, leaf) {
// console.log("addtab item", item, open, leaf);
@ -1792,7 +1878,7 @@ export default {
this.selectedNodeForDelete = {
dialog: true,
item: item,
heading: `Click Submit to Delete The ${item._nodes.type}`,
heading: `Click Submit to Delete The ${item._nodes.type}: ${item.name}`,
};
} else if (action === "hideDialog") {
this.selectedNodeForDelete = {
@ -1803,34 +1889,8 @@ export default {
} else {
item = this.selectedNodeForDelete.item;
if (item._nodes.type === "table") {
const result = await this.$store.dispatch("sqlMgr/ActSqlOp", [
{
env: item._nodes.env,
dbAlias: item._nodes.dbAlias,
},
"columnList",
{
table_name: item._nodes.table_name,
},
]);
await this.sqlMgr.sqlOpPlus(
{
env: item._nodes.env,
dbAlias: item._nodes.dbAlias,
},
"tableDelete",
{
table_name: item._nodes.table_name,
columns: columns.data.list,
}
);
await this.loadTablesFromParentTreeNode({
_nodes: {
...item._nodes,
},
});
this.$toast.success("Table deleted successfully").goAway(3000);
await this.checkAndDeleteTable(item, '')
} else if (item._nodes.type === "view") {
const view = await this.$store.dispatch("sqlMgr/ActSqlOp", [
{

1
packages/nc-gui/components/project/Table.vue

@ -143,6 +143,7 @@ export default {
key: this.deleteId,
value: null
})
this.$toast.info(`Deleted table ${this.nodes.title} successfully`).goAway(3000)
} catch (e) {
const msg = await this._extractSdkResponseErrorMsg(e)
this.$toast.error(msg).goAway(3000)

24
packages/nc-gui/components/project/spreadsheet/components/ColumnFilter.vue

@ -108,6 +108,7 @@
class="flex-shrink-1 flex-grow-0 caption nc-filter-operation-select"
:items="filterComparisonOp(filter)"
:placeholder="$t('labels.operation')"
v-show="filter && filter.fk_column_id"
solo
flat
style="max-width: 120px"
@ -142,6 +143,7 @@
v-else
:key="i + '_7'"
v-model="filter.value"
v-show="filter && filter.fk_column_id"
solo
flat
hide-details
@ -324,13 +326,23 @@ export default {
if (
f &&
f.fk_column_id &&
this.columnsById[f.fk_column_id] &&
this.columnsById[f.fk_column_id].uidt ===
UITypes.LinkToAnotherRecord &&
this.columnsById[f.fk_column_id].uidt === UITypes.Lookup
this.columnsById[f.fk_column_id]
) {
return !['notempty', 'empty', 'notnull', 'null'].includes(op.value)
}
const uidt = this.columnsById[f.fk_column_id].uidt
if (uidt === UITypes.Lookup) {
// TODO: handle it later
return !['notempty', 'empty', 'notnull', 'null'].includes(op.value)
} else if (uidt === UITypes.LinkToAnotherRecord) {
const type = this.columnsById[f.fk_column_id].colOptions.type
if (type === 'hm' || type === 'mm') {
// exclude notnull & null
return !['notnull', 'null'].includes(op.value)
} else if (type === 'bt') {
// exclude notempty & empty
return !['notempty', 'empty'].includes(op.value)
}
}
}
return true
})
},

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

@ -145,7 +145,13 @@
there are multiple values associated with a cell
</v-alert>
</v-col>
<v-col v-if="isDate" cols="12">
<date-options
v-model="newColumn.meta"
:column="newColumn"
:meta="meta"
/>
</v-col>
<v-col v-if="isSelect" cols="12">
<custom-select-options
v-model="newColumn.dtxp"
@ -590,6 +596,7 @@ import RatingOptions from '~/components/project/spreadsheet/components/editColum
import CheckboxOptions from '~/components/project/spreadsheet/components/editColumn/CheckboxOptions'
import CurrencyOptions from '@/components/project/spreadsheet/components/editColumn/CurrencyOptions'
import DurationOptions from '@/components/project/spreadsheet/components/editColumn/DurationOptions'
import DateOptions from '@/components/project/spreadsheet/components/editColumn/DateOptions'
import PercentOptions from '@/components/project/spreadsheet/components/editColumn/PercentOptions'
const columnToValidate = [UITypes.Email, UITypes.URL, UITypes.PhoneNumber]
@ -608,6 +615,7 @@ export default {
CustomSelectOptions,
CurrencyOptions,
DurationOptions,
DateOptions,
PercentOptions
},
props: {
@ -705,6 +713,9 @@ export default {
},
isCurrency() {
return this.newColumn && this.newColumn.uidt === UITypes.Currency
},
isDate() {
return this.newColumn && this.newColumn.uidt === UITypes.Date
}
},
watch: {

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

@ -78,6 +78,7 @@
<date-picker-cell
v-else-if="isDate"
v-model="localState"
:column="column"
v-on="parentListeners"
/>

38
packages/nc-gui/components/project/spreadsheet/components/editColumn/DateOptions.vue

@ -0,0 +1,38 @@
<template>
<v-autocomplete
v-model="colMeta.date_format"
label="Date Format"
class="caption nc-column-name-input"
:rules="[isValidDateFormat]"
:items="dateFormatList"
dense
outlined
/>
</template>
<script>
import { dateFormat, validateDateFormat } from '~/helpers/dateFormatHelper'
export default {
name: 'DateOptions',
props: ['column', 'meta', 'value'],
data: () => ({
colMeta: {
date_format: 'YYYY-MM-DD'
},
dateFormatList: dateFormat,
isValidDateFormat: (value) => {
return validateDateFormat(value) || 'Invalid Date Format'
}
}),
watch: {
value() {
this.colMeta = this.value || {}
},
colMeta(v) {
this.$emit('input', v)
}
},
created() {
this.colMeta = this.value ? { ...this.value } : { ...this.colMeta }
}
}
</script>

11
packages/nc-gui/components/project/spreadsheet/components/editableCell/DatePickerCell.vue

@ -18,6 +18,7 @@ import dayjs from 'dayjs'
export default {
name: 'DatePickerCell',
props: {
column: Object,
value: [String, Date]
},
computed: {
@ -35,10 +36,18 @@ export default {
},
date() {
if (!this.value || this.localState) {
return this.localState
return this.localState ? dayjs(this.localState).format(this.datepickerMeta.date_format || 'YYYY-MM-DD') : this.localState
}
return 'Invalid Date'
},
datepickerMeta() {
return {
date_format: 'YYYY-MM-DD',
...(this.column && this.column.meta
? this.column.meta
: {})
}
},
parentListeners() {
const $listeners = {}

2
packages/nc-gui/components/project/spreadsheet/components/editableCell/EditableAttachmentCell.vue

@ -1,6 +1,6 @@
<template>
<div
class="main h-100"
class="main d-100 h-100"
@dragover.prevent="dragOver = true"
@dragenter.prevent="dragOver = true"
@dragexit="dragOver = false"

20
packages/nc-gui/components/project/spreadsheet/components/virtualCell/LookupCell.vue

@ -36,13 +36,25 @@
/>
</template>
<template v-else>
<template v-if="localValue">
<template v-if="lookupColumnMeta['uidt'] === UITypes.Attachment">
<table-cell
v-for="(v,i) in localValue"
:key="i"
:is-locked="true"
:column="lookupColumnMeta"
:meta="lookupTableMeta"
:db-alias="nodes.dbAlias"
:value="v"
:sql-ui="sqlUi"
/>
</template>
<template v-else-if="localValue">
<item-chip
v-for="(value,i) in localValue"
v-for="(v,i) in localValue"
:key="i"
style="margin: 1.5px"
:active="active"
:value="value"
:value="v"
:readonly="true"
>
<table-cell
@ -51,7 +63,7 @@
:column="lookupColumnMeta"
:meta="lookupTableMeta"
:db-alias="nodes.dbAlias"
:value="value"
:value="v"
:sql-ui="sqlUi"
/>
</item-chip>

9
packages/nc-gui/helpers/dateFormatHelper.js

@ -0,0 +1,9 @@
export const dateFormat = [
'DD-MM-YYYY', 'MM-DD-YYYY', 'YYYY-MM-DD',
'DD/MM/YYYY', 'MM/DD/YYYY', 'YYYY/MM/DD',
'DD MM YYYY', 'MM DD YYYY', 'YYYY MM DD'
]
export function validateDateFormat(v) {
return dateFormat.includes(v)
}

2
packages/nc-gui/helpers/rightClickOptions.js

@ -61,7 +61,7 @@ export default {
},
table: {
'Table Rename': 'ENV_DB_TABLES_RENAME',
// "Table Delete": "ENV_DB_TABLES_DELETE",
"Table Delete": "ENV_DB_TABLES_DELETE",
// d1: null,
// "Send to SQL Editor": {
// 'Copy To Clipboard': {

12
packages/nc-gui/helpers/rolePermissionsEE.js

@ -15,20 +15,24 @@ export default {
gridColUpdate: true,
filterSync: true,
csvImport: true,
apiDocs: true
apiDocs: true,
projectSettings: true
},
commenter: {
smartSheet: true,
column: true,
rowComments: true
rowComments: true,
projectSettings: true
},
viewer: {
smartSheet: true,
column: true
column: true,
projectSettings: true
},
user: {
projectCreate: true,
projectActions: true
projectActions: true,
projectSettings: true
}
}
/**

36
packages/noco-docs-prev/package-lock.json generated

@ -7023,7 +7023,7 @@
"node_modules/filter-obj": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
"integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs=",
"integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
"engines": {
"node": ">=0.10.0"
}
@ -11010,9 +11010,9 @@
}
},
"node_modules/parse-path": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz",
"integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.4.tgz",
"integrity": "sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw==",
"dependencies": {
"is-ssh": "^1.3.0",
"protocols": "^1.4.0",
@ -11040,19 +11040,19 @@
"node_modules/parse-path/node_modules/strict-uri-encode": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=",
"integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
"engines": {
"node": ">=4"
}
},
"node_modules/parse-url": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.0.tgz",
"integrity": "sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==",
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.2.tgz",
"integrity": "sha512-uCSjOvD3T+6B/sPWhR+QowAZcU/o4bjPrVBQBGFxcDF6J6FraCGIaDBsdoQawiaaAVdHvtqBe3w3vKlfBKySOQ==",
"dependencies": {
"is-ssh": "^1.3.0",
"normalize-url": "^6.1.0",
"parse-path": "^4.0.0",
"parse-path": "^4.0.4",
"protocols": "^1.4.0"
}
},
@ -22364,7 +22364,7 @@
"filter-obj": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
"integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs="
"integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ=="
},
"finalhandler": {
"version": "1.1.2",
@ -25385,9 +25385,9 @@
}
},
"parse-path": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz",
"integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.4.tgz",
"integrity": "sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw==",
"requires": {
"is-ssh": "^1.3.0",
"protocols": "^1.4.0",
@ -25409,18 +25409,18 @@
"strict-uri-encode": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
"integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ=="
}
}
},
"parse-url": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.0.tgz",
"integrity": "sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==",
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.2.tgz",
"integrity": "sha512-uCSjOvD3T+6B/sPWhR+QowAZcU/o4bjPrVBQBGFxcDF6J6FraCGIaDBsdoQawiaaAVdHvtqBe3w3vKlfBKySOQ==",
"requires": {
"is-ssh": "^1.3.0",
"normalize-url": "^6.1.0",
"parse-path": "^4.0.0",
"parse-path": "^4.0.4",
"protocols": "^1.4.0"
}
},

38
packages/noco-docs/package-lock.json generated

@ -8570,17 +8570,28 @@
"json-parse-better-errors": "^1.0.1"
}
},
"parse-path": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz",
"integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==",
"parse-url": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.2.tgz",
"integrity": "sha512-uCSjOvD3T+6B/sPWhR+QowAZcU/o4bjPrVBQBGFxcDF6J6FraCGIaDBsdoQawiaaAVdHvtqBe3w3vKlfBKySOQ==",
"requires": {
"is-ssh": "^1.3.0",
"protocols": "^1.4.0",
"qs": "^6.9.4",
"query-string": "^6.13.8"
"normalize-url": "^6.1.0",
"parse-path": "^4.0.4",
"protocols": "^1.4.0"
},
"dependencies": {
"parse-path": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.4.tgz",
"integrity": "sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw==",
"requires": {
"is-ssh": "^1.3.0",
"protocols": "^1.4.0",
"qs": "^6.9.4",
"query-string": "^6.13.8"
}
},
"query-string": {
"version": "6.14.1",
"resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz",
@ -8595,21 +8606,10 @@
"strict-uri-encode": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
"integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ=="
}
}
},
"parse-url": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/parse-url/-/parse-url-6.0.0.tgz",
"integrity": "sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==",
"requires": {
"is-ssh": "^1.3.0",
"normalize-url": "^6.1.0",
"parse-path": "^4.0.0",
"protocols": "^1.4.0"
}
},
"parse5": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",

123
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts

@ -50,11 +50,11 @@ const parseConditionV2 = async (
}
if (Array.isArray(_filter)) {
const qbs = await Promise.all(
_filter.map(child => parseConditionV2(child, knex, aliasCount))
_filter.map((child) => parseConditionV2(child, knex, aliasCount))
);
return qbP => {
qbP.where(qb => {
return (qbP) => {
qbP.where((qb) => {
for (const [i, qb1] of Object.entries(qbs)) {
qb[getLogicalOpMethod(_filter[i])](qb1);
}
@ -64,11 +64,11 @@ const parseConditionV2 = async (
const children = await filter.getChildren();
const qbs = await Promise.all(
(children || []).map(child => parseConditionV2(child, knex, aliasCount))
(children || []).map((child) => parseConditionV2(child, knex, aliasCount))
);
return qbP => {
qbP[getLogicalOpMethod(filter)](qb => {
return (qbP) => {
qbP[getLogicalOpMethod(filter)]((qb) => {
for (const [i, qb1] of Object.entries(qbs)) {
qb[getLogicalOpMethod(children[i])](qb1);
}
@ -78,7 +78,8 @@ const parseConditionV2 = async (
const column = await filter.getColumn();
if (!column) return () => {};
if (column.uidt === UITypes.LinkToAnotherRecord) {
const colOptions = (await column.getColOptions()) as LinkToAnotherRecordColumn;
const colOptions =
(await column.getColOptions()) as LinkToAnotherRecordColumn;
const childColumn = await colOptions.getChildColumn();
const parentColumn = await colOptions.getParentColumn();
const childModel = await childColumn.getModel();
@ -86,6 +87,28 @@ const parseConditionV2 = async (
const parentModel = await parentColumn.getModel();
await parentModel.getColumns();
if (colOptions.type === RelationTypes.HAS_MANY) {
if (
filter.comparison_op === 'empty' ||
filter.comparison_op === 'notempty'
) {
const selectHmCount = knex(childModel.table_name)
.count(childColumn.column_name)
.where(
childColumn.column_name,
knex.raw('??.??', [
alias || parentModel.table_name,
parentColumn.column_name,
])
);
return (qb) => {
if (filter.comparison_op === 'empty') {
qb.where(knex.raw('0'), selectHmCount);
} else {
qb.whereNot(knex.raw('0'), selectHmCount);
}
};
}
const selectQb = knex(childModel.table_name).select(
childColumn.column_name
);
@ -97,7 +120,7 @@ const parseConditionV2 = async (
? negatedMapping[filter.comparison_op]
: {}),
fk_model_id: childModel.id,
fk_column_id: childModel?.primaryValue?.id
fk_column_id: childModel?.primaryValue?.id,
}),
knex,
aliasCount
@ -110,6 +133,17 @@ const parseConditionV2 = async (
else qbP.whereIn(parentColumn.column_name, selectQb);
};
} else if (colOptions.type === RelationTypes.BELONGS_TO) {
if (filter.comparison_op === 'null') {
return (qb) => {
qb.whereNull(childColumn.column_name);
};
}
if (filter.comparison_op === 'notnull') {
return (qb) => {
qb.whereNotNull(childColumn.column_name);
};
}
const selectQb = knex(parentModel.table_name).select(
parentColumn.column_name
);
@ -121,7 +155,7 @@ const parseConditionV2 = async (
? negatedMapping[filter.comparison_op]
: {}),
fk_model_id: parentModel.id,
fk_column_id: parentModel?.primaryValue?.id
fk_column_id: parentModel?.primaryValue?.id,
}),
knex,
aliasCount
@ -138,6 +172,29 @@ const parseConditionV2 = async (
const mmParentColumn = await colOptions.getMMParentColumn();
const mmChildColumn = await colOptions.getMMChildColumn();
if (
filter.comparison_op === 'empty' ||
filter.comparison_op === 'notempty'
) {
const selectMmCount = knex(mmModel.table_name)
.count(mmChildColumn.column_name)
.where(
mmChildColumn.column_name,
knex.raw('??.??', [
alias || childModel.table_name,
childColumn.column_name,
])
);
return (qb) => {
if (filter.comparison_op === 'empty') {
qb.where(knex.raw('0'), selectMmCount);
} else {
qb.whereNot(knex.raw('0'), selectMmCount);
}
};
}
const selectQb = knex(mmModel.table_name)
.select(mmChildColumn.column_name)
.join(
@ -153,7 +210,7 @@ const parseConditionV2 = async (
? negatedMapping[filter.comparison_op]
: {}),
fk_model_id: parentModel.id,
fk_column_id: parentModel?.primaryValue?.id
fk_column_id: parentModel?.primaryValue?.id,
}),
knex,
aliasCount
@ -167,7 +224,7 @@ const parseConditionV2 = async (
};
}
return _qb => {};
return (_qb) => {};
} else if (column.uidt === UITypes.Lookup) {
return await generateLookupCondition(column, filter, knex, aliasCount);
} else if (column.uidt === UITypes.Rollup && !customWhereClause) {
@ -175,7 +232,7 @@ const parseConditionV2 = async (
await genRollupSelectv2({
knex,
alias,
columnOptions: (await column.getColOptions()) as RollupColumn
columnOptions: (await column.getColOptions()) as RollupColumn,
})
).builder;
return parseConditionV2(
@ -213,7 +270,7 @@ const parseConditionV2 = async (
);
let val = customWhereClause ? customWhereClause : filter.value;
return qb => {
return (qb) => {
switch (filter.comparison_op) {
case 'eq':
qb = qb.where(field, val);
@ -229,11 +286,15 @@ const parseConditionV2 = async (
} else {
val = `%${val}%`;
}
qb = qb.where(
field,
qb?.client?.config?.client === 'pg' ? 'ilike' : 'like',
val
);
if (qb?.client?.config?.client === 'pg') {
qb = qb.whereRaw('??::text ilike ?', [field, val]);
} else {
qb = qb.where(
field,
'like',
val
);
}
break;
case 'nlike':
if (column.uidt === UITypes.Formula) {
@ -321,7 +382,7 @@ const parseConditionV2 = async (
const negatedMapping = {
nlike: { comparison_op: 'like' },
neq: { comparison_op: 'eq' }
neq: { comparison_op: 'eq' },
};
function getAlias(aliasCount: { count: number }) {
@ -337,9 +398,8 @@ async function generateLookupCondition(
): Promise<any> {
const colOptions = await col.getColOptions<LookupColumn>();
const relationColumn = await colOptions.getRelationColumn();
const relationColumnOptions = await relationColumn.getColOptions<
LinkToAnotherRecordColumn
>();
const relationColumnOptions =
await relationColumn.getColOptions<LinkToAnotherRecordColumn>();
// const relationModel = await relationColumn.getModel();
const lookupColumn = await colOptions.getLookupColumn();
const alias = getAlias(aliasCount);
@ -362,7 +422,7 @@ async function generateLookupCondition(
...filter,
...(filter.comparison_op in negatedMapping
? negatedMapping[filter.comparison_op]
: {})
: {}),
},
lookupColumn,
qb,
@ -385,7 +445,7 @@ async function generateLookupCondition(
...filter,
...(filter.comparison_op in negatedMapping
? negatedMapping[filter.comparison_op]
: {})
: {}),
},
lookupColumn,
qb,
@ -419,7 +479,7 @@ async function generateLookupCondition(
...filter,
...(filter.comparison_op in negatedMapping
? negatedMapping[filter.comparison_op]
: {})
: {}),
},
lookupColumn,
qb,
@ -455,9 +515,8 @@ async function nestedConditionJoin(
await lookupColumn.getColOptions<LookupColumn>()
).getRelationColumn()
: lookupColumn;
const relationColOptions = await relationColumn.getColOptions<
LinkToAnotherRecordColumn
>();
const relationColOptions =
await relationColumn.getColOptions<LinkToAnotherRecordColumn>();
const relAlias = `__nc${aliasCount.count++}`;
const childColumn = await relationColOptions.getChildColumn();
@ -528,7 +587,7 @@ async function nestedConditionJoin(
new Filter({
...filter,
fk_model_id: childModel.id,
fk_column_id: childModel.primaryValue?.id
fk_column_id: childModel.primaryValue?.id,
}),
knex,
aliasCount,
@ -544,7 +603,7 @@ async function nestedConditionJoin(
new Filter({
...filter,
fk_model_id: parentModel.id,
fk_column_id: parentModel?.primaryValue?.id
fk_column_id: parentModel?.primaryValue?.id,
}),
knex,
aliasCount,
@ -560,7 +619,7 @@ async function nestedConditionJoin(
new Filter({
...filter,
fk_model_id: parentModel.id,
fk_column_id: parentModel.primaryValue?.id
fk_column_id: parentModel.primaryValue?.id,
}),
knex,
aliasCount,
@ -577,7 +636,7 @@ async function nestedConditionJoin(
new Filter({
...filter,
fk_model_id: (await lookupColumn.getModel()).id,
fk_column_id: lookupColumn?.id
fk_column_id: lookupColumn?.id,
}),
knex,
aliasCount,

2
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts

@ -1,9 +1,11 @@
export function sanitize(v) {
if (typeof v !== 'string') return v;
return v?.replace(/([^\\]|^)(\?+)/g, (_, m1, m2) => {
return `${m1}${m2.split('?').join('\\?')}`;
});
}
export function unsanitize(v) {
if (typeof v !== 'string') return v;
return v?.replace(/\\[?]/g, '?');
}

3
packages/nocodb/src/lib/meta/api/userApi/userApis.ts

@ -366,9 +366,6 @@ async function tokenValidate(req, res): Promise<any> {
if (user.reset_password_expires < new Date()) {
NcError.badRequest('Password reset url expired');
}
if (!user.token_version) {
NcError.badRequest('Token Expired. Please login again.');
}
res.json(true);
}

Loading…
Cancel
Save