mirror of https://github.com/nocodb/nocodb
Pranav C
3 years ago
10 changed files with 524 additions and 33 deletions
@ -0,0 +1,205 @@
|
||||
<template> |
||||
<div> |
||||
<v-container fluid class="wrapper"> |
||||
<v-row> |
||||
<v-col cols="6"> |
||||
<v-autocomplete |
||||
ref="input" |
||||
v-model="rollup.table" |
||||
outlined |
||||
class="caption" |
||||
hide-details="auto" |
||||
label="Child Table" |
||||
:full-width="false" |
||||
:items="refTables" |
||||
item-text="_rltn" |
||||
:item-value="v => v" |
||||
:rules="[v => !!v || 'Required']" |
||||
dense |
||||
> |
||||
<template #item="{item}"> |
||||
<span class="caption"><span class="font-weight-bold"> {{ |
||||
item._rltn |
||||
}}</span> <small>({{ relationNames[item.type] }}) |
||||
</small></span> |
||||
</template> |
||||
</v-autocomplete> |
||||
</v-col> |
||||
<v-col cols="6"> |
||||
<v-autocomplete |
||||
ref="input" |
||||
v-model="rollup.column" |
||||
outlined |
||||
class="caption" |
||||
hide-details="auto" |
||||
label="Child column" |
||||
:full-width="false" |
||||
:items="columnList" |
||||
item-text="_rlcn" |
||||
dense |
||||
:loading="loadingColumns" |
||||
:item-value="v => v" |
||||
:rules="[v => !!v || 'Required']" |
||||
/> |
||||
</v-col> |
||||
<v-col cols="12"> |
||||
<v-autocomplete |
||||
ref="aggrInput" |
||||
v-model="rollup.fn" |
||||
outlined |
||||
class="caption" |
||||
hide-details="auto" |
||||
label="Aggregate function" |
||||
:full-width="false" |
||||
:items="aggrFunctionsList" |
||||
dense |
||||
:loading="loadingColumns" |
||||
:rules="[v => !!v || 'Required']" |
||||
/> |
||||
</v-col> |
||||
</v-row> |
||||
</v-container> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
export default { |
||||
name: 'RollupOptions', |
||||
props: ['nodes', 'column', 'meta', 'isSQLite', 'alias'], |
||||
data: () => ({ |
||||
rollup: {}, |
||||
loadingColumns: false, |
||||
relationNames: { |
||||
mm: 'Many To Many', |
||||
hm: 'Has Many' |
||||
// bt: 'Belongs To' |
||||
}, |
||||
aggrFunctionsList: [ |
||||
{ text: 'count', value: 'count' }, |
||||
{ text: 'min', value: 'min' }, |
||||
{ text: 'max', value: 'max' }, |
||||
{ text: 'avg', value: 'avg' }, |
||||
{ text: 'min', value: 'min' }, |
||||
{ text: 'sum', value: 'sum' }, |
||||
{ text: 'countDistinct', value: 'countDistinct' }, |
||||
{ text: 'sumDistinct', value: 'sumDistinct' }, |
||||
{ text: 'avgDistinct', value: 'avgDistinct' } |
||||
] |
||||
}), |
||||
computed: { |
||||
refTables() { |
||||
return this.meta |
||||
? [ |
||||
// ...(this.meta.belongsTo || []).map(({ rtn, _rtn, rcn, tn, cn }) => ({ |
||||
// type: 'bt', |
||||
// rtn, |
||||
// _rtn, |
||||
// rcn, |
||||
// tn, |
||||
// cn, |
||||
// ltn: rtn, |
||||
// _ltn: _rtn |
||||
// })), |
||||
...(this.meta.hasMany || []).map(({ |
||||
tn, |
||||
_tn, |
||||
cn, |
||||
rcn, |
||||
rtn |
||||
}) => ({ |
||||
type: 'hm', |
||||
tn, |
||||
_tn, |
||||
cn, |
||||
rcn, |
||||
rtn, |
||||
rltn: tn, |
||||
_rltn: _tn |
||||
})), |
||||
...(this.meta.manyToMany || []).map(({ vtn, _vtn, vrcn, vcn, rtn, _rtn, rcn, tn, cn }) => ({ |
||||
type: 'mm', |
||||
tn, |
||||
cn, |
||||
vtn, |
||||
_vtn, |
||||
vrcn, |
||||
rcn, |
||||
rtn, |
||||
vcn, |
||||
_rtn, |
||||
rltn: rtn, |
||||
_rltn: _rtn |
||||
})) |
||||
] |
||||
: [] |
||||
}, |
||||
columnList() { |
||||
return (( |
||||
this.rollup && |
||||
this.rollup.table && |
||||
this.$store.state.meta.metas && |
||||
this.$store.state.meta.metas[this.rollup.table.rltn] && |
||||
this.$store.state.meta.metas[this.rollup.table.rltn].columns |
||||
) || []).map(({ cn, _cn }) => ({ |
||||
rlcn: cn, |
||||
_rlcn: _cn |
||||
})) |
||||
} |
||||
}, |
||||
methods: { |
||||
async onTableChange() { |
||||
this.loadingColumns = true |
||||
if (this.rollup.table) { |
||||
try { |
||||
await this.$store.dispatch('meta/ActLoadMeta', { |
||||
dbAlias: this.nodes.dbAlias, |
||||
env: this.nodes.env, |
||||
tn: this.rollup.table.ltn |
||||
}) |
||||
} catch (e) { |
||||
// ignore |
||||
} |
||||
} |
||||
|
||||
this.loadingColumns = false |
||||
}, |
||||
async save() { |
||||
try { |
||||
await this.$store.dispatch('meta/ActLoadMeta', { |
||||
dbAlias: this.nodes.dbAlias, |
||||
env: this.nodes.env, |
||||
tn: this.meta.tn, |
||||
force: true |
||||
}) |
||||
const meta = JSON.parse(JSON.stringify(this.$store.state.meta.metas[this.meta.tn])) |
||||
|
||||
meta.v.push({ |
||||
_cn: this.alias, |
||||
rollup: { |
||||
...this.rollup.table, |
||||
...this.rollup.column, |
||||
fn: this.rollup.fn |
||||
} |
||||
}) |
||||
|
||||
await this.$store.dispatch('sqlMgr/ActSqlOp', [{ |
||||
env: this.nodes.env, |
||||
dbAlias: this.nodes.dbAlias |
||||
}, 'xcModelSet', { |
||||
tn: this.nodes.tn, |
||||
meta |
||||
}]) |
||||
|
||||
return this.$emit('saved', this.alias) |
||||
} catch (e) { |
||||
this.$toast.error(e.message).goAway(3000) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
|
||||
</style> |
@ -0,0 +1,166 @@
|
||||
<template> |
||||
<span> |
||||
{{ row[column._cn] }} |
||||
</span> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
export default { |
||||
name: 'RollupCell', |
||||
components: { }, |
||||
props: { |
||||
meta: [Object], |
||||
column: [Object], |
||||
nodes: [Object], |
||||
row: [Object] |
||||
}, |
||||
data: () => ({ |
||||
lookupListModal: false |
||||
}), |
||||
computed: { |
||||
// todo : optimize |
||||
lookupApi() { |
||||
return this.column && this.$ncApis.get({ |
||||
env: this.nodes.env, |
||||
dbAlias: this.nodes.dbAlias, |
||||
table: this.column.lk.ltn |
||||
}) |
||||
}, |
||||
lookUpMeta() { |
||||
return this.$store.state.meta.metas[this.column.lk.ltn] |
||||
}, |
||||
assocMeta() { |
||||
return this.column.lk.type === 'mm' && this.$store.state.meta.metas[this.column.lk.vtn] |
||||
}, |
||||
lookUpColumnAlias() { |
||||
if (!this.lookUpMeta || !this.column.lk.lcn) { |
||||
return |
||||
} |
||||
return (this.$store.state.meta.metas[this.column.lk.ltn].columns.find(cl => cl.cn === this.column.lk.lcn) || {})._cn |
||||
}, |
||||
lookUpColumn() { |
||||
if (!this.lookUpMeta || !this.column.lk.lcn) { |
||||
return |
||||
} |
||||
return (this.$store.state.meta.metas[this.column.lk.ltn].columns.find(cl => cl.cn === this.column.lk.lcn) || {}) |
||||
}, |
||||
localValueObj() { |
||||
if (!this.column || !this.row) { |
||||
return null |
||||
} |
||||
switch (this.column.lk.type) { |
||||
case 'mm': |
||||
return this.row[`${this.column.lk._ltn}MMList`] |
||||
case 'hm': |
||||
return this.row[`${this.column.lk._ltn}List`] |
||||
case 'bt': |
||||
return this.row[`${this.column.lk._ltn}Read`] |
||||
default: |
||||
return null |
||||
} |
||||
}, |
||||
localValue() { |
||||
if (!this.localValueObj || !this.lookUpColumnAlias) { |
||||
return null |
||||
} |
||||
if (Array.isArray(this.localValueObj)) { |
||||
return this.localValueObj.map(o => o[this.lookUpColumnAlias]) |
||||
} |
||||
return [this.localValueObj[this.lookUpColumnAlias]] |
||||
}, |
||||
queryParams() { |
||||
switch (this.column.lk.type) { |
||||
case 'bt': |
||||
return { where: `(${this.lookUpMeta.columns.find(c => c.cn === this.column.lk.rcn)._cn},eq,${this.row[this.meta.columns.find(c => c.cn === this.column.lk.cn)._cn]})` } |
||||
case 'hm': |
||||
return { where: `(${this.lookUpMeta.columns.find(c => c.cn === this.column.lk.cn)._cn},eq,${this.row[this.meta.columns.find(c => c.cn === this.column.lk.rcn)._cn]})` } |
||||
case 'mm': |
||||
return this.assocMeta |
||||
? { |
||||
conditionGraph: { |
||||
[this.assocMeta.tn]: { |
||||
relationType: 'hm', |
||||
[this.assocMeta.columns.find(c => c.cn === this.column.lk.vcn).cn]: { |
||||
eq: this.row[this.meta.columns.find(c => c.cn === this.column.lk.cn)._cn] |
||||
} |
||||
} |
||||
} |
||||
} |
||||
: {} |
||||
default: |
||||
return {} |
||||
} |
||||
} |
||||
}, |
||||
created() { |
||||
this.loadLookupMeta() |
||||
}, |
||||
methods: { |
||||
async loadLookupMeta() { |
||||
if (!this.lookUpMeta) { |
||||
await this.$store.dispatch('meta/ActLoadMeta', { |
||||
env: this.nodes.env, |
||||
dbAlias: this.nodes.dbAlias, |
||||
tn: this.column.lk.ltn |
||||
}) |
||||
} |
||||
if (this.column.lk.type === 'mm' && !this.assocMeta) { |
||||
await this.$store.dispatch('meta/ActLoadMeta', { |
||||
env: this.nodes.env, |
||||
dbAlias: this.nodes.dbAlias, |
||||
tn: this.column.lk.vtn |
||||
}) |
||||
} |
||||
}, |
||||
showLookupListModal() { |
||||
this.lookupListModal = true |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped lang="scss"> |
||||
.chips-wrapper { |
||||
.chips { |
||||
max-width: 100%; |
||||
|
||||
&.lookup-items { |
||||
flex-wrap: wrap; |
||||
row-gap: 3px; |
||||
gap: 3px; |
||||
margin: 3px 0; |
||||
} |
||||
} |
||||
|
||||
&.active { |
||||
.chips { |
||||
max-width: calc(100% - 44px); |
||||
} |
||||
} |
||||
} |
||||
</style> |
||||
<!-- |
||||
/** |
||||
* @copyright Copyright (c) 2021, Xgene Cloud Ltd |
||||
* |
||||
* @author Naveen MR <oof1lab@gmail.com> |
||||
* @author Pranav C Balan <pranavxc@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/>. |
||||
* |
||||
*/ |
||||
--> |
@ -0,0 +1,25 @@
|
||||
import Knex from "knex"; |
||||
|
||||
export default function ({knex, rollup,}: { knex: Knex, rollup: any }) { |
||||
switch (rollup.type) { |
||||
case 'hm': |
||||
|
||||
return knex(rollup.rltn) |
||||
[rollup.fn]?.(knex.ref(`${rollup.rltn}.${rollup.rlcn}`)) |
||||
.where( |
||||
knex.ref(`${rollup.tn}.${rollup.cn}`), '=', knex.ref(`${rollup.rtn}.${rollup.rcn}`) |
||||
) |
||||
break; |
||||
case 'mm': |
||||
|
||||
return knex(rollup.rltn) |
||||
[rollup.fn]?.(knex.ref(`${rollup.rltn}.${rollup.rlcn}`)) |
||||
.innerJoin(rollup.vtn, knex.ref(`${rollup.vtn}.${rollup.vrcn}`), '=', knex.ref(`${rollup.rtn}.${rollup.rcn}`)) |
||||
.where(knex.ref(`${rollup.vtn}.${rollup.vcn}`), '=', knex.ref(`${rollup.tn}.${rollup.cn}`)) |
||||
|
||||
|
||||
default: |
||||
throw Error(`Unsupported relation type '${rollup.type}'`) |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue