Fix relationship types
This commit is contained in:
parent
c8ffa98844
commit
21e2d7ddbe
|
@ -5,8 +5,11 @@ import {
|
||||||
FieldType,
|
FieldType,
|
||||||
FilterType,
|
FilterType,
|
||||||
IncludeRelationship,
|
IncludeRelationship,
|
||||||
|
ManyToManyRelationshipFieldMetadata,
|
||||||
|
OneToManyRelationshipFieldMetadata,
|
||||||
Operation,
|
Operation,
|
||||||
PaginationJson,
|
PaginationJson,
|
||||||
|
RelationshipFieldMetadata,
|
||||||
RelationshipsJson,
|
RelationshipsJson,
|
||||||
RelationshipType,
|
RelationshipType,
|
||||||
Row,
|
Row,
|
||||||
|
@ -254,12 +257,20 @@ function fixArrayTypes(row: Row, table: Table) {
|
||||||
return row
|
return row
|
||||||
}
|
}
|
||||||
|
|
||||||
function isOneSide(field: FieldSchema) {
|
function isOneSide(
|
||||||
|
field: RelationshipFieldMetadata
|
||||||
|
): field is OneToManyRelationshipFieldMetadata {
|
||||||
return (
|
return (
|
||||||
field.relationshipType && field.relationshipType.split("-")[0] === "one"
|
field.relationshipType && field.relationshipType.split("-")[0] === "one"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isManyToMany(
|
||||||
|
field: RelationshipFieldMetadata
|
||||||
|
): field is ManyToManyRelationshipFieldMetadata {
|
||||||
|
return !!(field as ManyToManyRelationshipFieldMetadata).through
|
||||||
|
}
|
||||||
|
|
||||||
function isEditableColumn(column: FieldSchema) {
|
function isEditableColumn(column: FieldSchema) {
|
||||||
const isExternalAutoColumn =
|
const isExternalAutoColumn =
|
||||||
column.autocolumn &&
|
column.autocolumn &&
|
||||||
|
@ -352,11 +363,11 @@ export class ExternalRequest<T extends Operation> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// many to many
|
// many to many
|
||||||
else if (field.through) {
|
else if (isManyToMany(field)) {
|
||||||
// we're not inserting a doc, will be a bunch of update calls
|
// we're not inserting a doc, will be a bunch of update calls
|
||||||
const otherKey: string = field.throughFrom || linkTablePrimary
|
const otherKey: string = field.throughFrom || linkTablePrimary
|
||||||
const thisKey: string = field.throughTo || tablePrimary
|
const thisKey: string = field.throughTo || tablePrimary
|
||||||
row[key].forEach((relationship: any) => {
|
for (const relationship of row[key]) {
|
||||||
manyRelationships.push({
|
manyRelationships.push({
|
||||||
tableId: field.through || field.tableId,
|
tableId: field.through || field.tableId,
|
||||||
isUpdate: false,
|
isUpdate: false,
|
||||||
|
@ -365,14 +376,14 @@ export class ExternalRequest<T extends Operation> {
|
||||||
// leave the ID for enrichment later
|
// leave the ID for enrichment later
|
||||||
[thisKey]: `{{ literal ${tablePrimary} }}`,
|
[thisKey]: `{{ literal ${tablePrimary} }}`,
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
// many to one
|
// many to one
|
||||||
else {
|
else {
|
||||||
const thisKey: string = "id"
|
const thisKey: string = "id"
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const otherKey: string = field.fieldName
|
const otherKey: string = field.fieldName
|
||||||
row[key].forEach((relationship: any) => {
|
for (const relationship of row[key]) {
|
||||||
manyRelationships.push({
|
manyRelationships.push({
|
||||||
tableId: field.tableId,
|
tableId: field.tableId,
|
||||||
isUpdate: true,
|
isUpdate: true,
|
||||||
|
@ -381,7 +392,7 @@ export class ExternalRequest<T extends Operation> {
|
||||||
// leave the ID for enrichment later
|
// leave the ID for enrichment later
|
||||||
[otherKey]: `{{ literal ${tablePrimary} }}`,
|
[otherKey]: `{{ literal ${tablePrimary} }}`,
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// we return the relationships that may need to be created in the through table
|
// we return the relationships that may need to be created in the through table
|
||||||
|
@ -551,20 +562,24 @@ export class ExternalRequest<T extends Operation> {
|
||||||
}
|
}
|
||||||
const definition: any = {
|
const definition: any = {
|
||||||
// if no foreign key specified then use the name of the field in other table
|
// if no foreign key specified then use the name of the field in other table
|
||||||
from: field.foreignKey || table.primary[0],
|
from: (field as any).foreignKey || table.primary[0],
|
||||||
to: field.fieldName,
|
to: field.fieldName,
|
||||||
tableName: linkTableName,
|
tableName: linkTableName,
|
||||||
// need to specify where to put this back into
|
// need to specify where to put this back into
|
||||||
column: fieldName,
|
column: fieldName,
|
||||||
}
|
}
|
||||||
if (field.through) {
|
if ((field as ManyToManyRelationshipFieldMetadata).through) {
|
||||||
const { tableName: throughTableName } = breakExternalTableId(
|
const { tableName: throughTableName } = breakExternalTableId(
|
||||||
field.through
|
(field as ManyToManyRelationshipFieldMetadata).through
|
||||||
)
|
)
|
||||||
definition.through = throughTableName
|
definition.through = throughTableName
|
||||||
// don't support composite keys for relationships
|
// don't support composite keys for relationships
|
||||||
definition.from = field.throughTo || table.primary[0]
|
definition.from =
|
||||||
definition.to = field.throughFrom || linkTable.primary[0]
|
(field as ManyToManyRelationshipFieldMetadata).throughTo ||
|
||||||
|
table.primary[0]
|
||||||
|
definition.to =
|
||||||
|
(field as ManyToManyRelationshipFieldMetadata).throughFrom ||
|
||||||
|
linkTable.primary[0]
|
||||||
definition.fromPrimary = table.primary[0]
|
definition.fromPrimary = table.primary[0]
|
||||||
definition.toPrimary = linkTable.primary[0]
|
definition.toPrimary = linkTable.primary[0]
|
||||||
}
|
}
|
||||||
|
@ -597,12 +612,15 @@ export class ExternalRequest<T extends Operation> {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const isMany = field.relationshipType === RelationshipType.MANY_TO_MANY
|
const isMany = field.relationshipType === RelationshipType.MANY_TO_MANY
|
||||||
const tableId = isMany ? field.through : field.tableId
|
const tableId = isMany
|
||||||
|
? (field as ManyToManyRelationshipFieldMetadata).through
|
||||||
|
: field.tableId
|
||||||
const { tableName: relatedTableName } = breakExternalTableId(tableId)
|
const { tableName: relatedTableName } = breakExternalTableId(tableId)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const linkPrimaryKey = this.tables[relatedTableName].primary[0]
|
const linkPrimaryKey = this.tables[relatedTableName].primary[0]
|
||||||
const manyKey = field.throughTo || primaryKey
|
const manyKey =
|
||||||
const lookupField = isMany ? primaryKey : field.foreignKey
|
(field as ManyToManyRelationshipFieldMetadata).throughTo || primaryKey
|
||||||
|
const lookupField = isMany ? primaryKey : (field as any).foreignKey
|
||||||
const fieldName = isMany ? manyKey : field.fieldName
|
const fieldName = isMany ? manyKey : field.fieldName
|
||||||
if (!lookupField || !row[lookupField]) {
|
if (!lookupField || !row[lookupField]) {
|
||||||
continue
|
continue
|
||||||
|
@ -617,7 +635,10 @@ export class ExternalRequest<T extends Operation> {
|
||||||
})
|
})
|
||||||
// this is the response from knex if no rows found
|
// this is the response from knex if no rows found
|
||||||
const rows = !response[0].read ? response : []
|
const rows = !response[0].read ? response : []
|
||||||
const storeTo = isMany ? field.throughFrom || linkPrimaryKey : fieldName
|
const storeTo = isMany
|
||||||
|
? (field as ManyToManyRelationshipFieldMetadata).throughFrom ||
|
||||||
|
linkPrimaryKey
|
||||||
|
: fieldName
|
||||||
related[storeTo] = { rows, isMany, tableId }
|
related[storeTo] = { rows, isMany, tableId }
|
||||||
}
|
}
|
||||||
return related
|
return related
|
||||||
|
|
|
@ -306,7 +306,8 @@ class OracleIntegration extends Sql implements DatasourcePlus {
|
||||||
presence: false,
|
presence: false,
|
||||||
},
|
},
|
||||||
...this.internalConvertType(oracleColumn),
|
...this.internalConvertType(oracleColumn),
|
||||||
}
|
} as any // TODO
|
||||||
|
|
||||||
table.schema[columnName] = fieldSchema
|
table.schema[columnName] = fieldSchema
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,13 @@ import { ObjectStoreBuckets } from "../../constants"
|
||||||
import { context, db as dbCore, objectStore } from "@budibase/backend-core"
|
import { context, db as dbCore, objectStore } from "@budibase/backend-core"
|
||||||
import { InternalTables } from "../../db/utils"
|
import { InternalTables } from "../../db/utils"
|
||||||
import { TYPE_TRANSFORM_MAP } from "./map"
|
import { TYPE_TRANSFORM_MAP } from "./map"
|
||||||
import { FieldSubtype, Row, RowAttachment, Table } from "@budibase/types"
|
import {
|
||||||
|
AutoColumnFieldMetadata,
|
||||||
|
FieldSubtype,
|
||||||
|
Row,
|
||||||
|
RowAttachment,
|
||||||
|
Table,
|
||||||
|
} from "@budibase/types"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import {
|
import {
|
||||||
processInputBBReferences,
|
processInputBBReferences,
|
||||||
|
@ -71,7 +77,7 @@ export function processAutoColumn(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (!schema.subtype) {
|
if (!schema.subtype) {
|
||||||
schema = fixAutoColumnSubType(schema)
|
schema = fixAutoColumnSubType(schema as AutoColumnFieldMetadata)
|
||||||
}
|
}
|
||||||
switch (schema.subtype) {
|
switch (schema.subtype) {
|
||||||
case AutoFieldSubTypes.CREATED_BY:
|
case AutoFieldSubTypes.CREATED_BY:
|
||||||
|
@ -94,8 +100,12 @@ export function processAutoColumn(
|
||||||
break
|
break
|
||||||
case AutoFieldSubTypes.AUTO_ID:
|
case AutoFieldSubTypes.AUTO_ID:
|
||||||
if (creating) {
|
if (creating) {
|
||||||
schema.lastID = !schema.lastID ? BASE_AUTO_ID : schema.lastID + 1
|
const safeSchema = schema as AutoColumnFieldMetadata
|
||||||
row[key] = schema.lastID
|
|
||||||
|
safeSchema.lastID = !safeSchema.lastID
|
||||||
|
? BASE_AUTO_ID
|
||||||
|
: safeSchema.lastID + 1
|
||||||
|
row[key] = safeSchema.lastID
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,22 +15,33 @@ export interface UIFieldMetadata {
|
||||||
icon?: string
|
icon?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ManyToManyRelationshipFieldMetadata {
|
interface BaseRelationshipFieldMetadata extends BaseFieldSchema {
|
||||||
|
type: FieldType.LINK
|
||||||
|
main?: boolean
|
||||||
|
fieldName?: string
|
||||||
|
tableId: string
|
||||||
|
}
|
||||||
|
export interface ManyToManyRelationshipFieldMetadata
|
||||||
|
extends BaseRelationshipFieldMetadata {
|
||||||
relationshipType: RelationshipType.MANY_TO_MANY
|
relationshipType: RelationshipType.MANY_TO_MANY
|
||||||
through: string
|
through: string
|
||||||
throughFrom: string
|
throughFrom: string
|
||||||
throughTo: string
|
throughTo: string
|
||||||
}
|
}
|
||||||
interface OneSidedRelationshipFieldMetadata {
|
export interface OneToManyRelationshipFieldMetadata
|
||||||
relationshipType: RelationshipType.ONE_TO_MANY | RelationshipType.MANY_TO_ONE
|
extends BaseRelationshipFieldMetadata {
|
||||||
|
relationshipType: RelationshipType.ONE_TO_MANY
|
||||||
foreignKey: string
|
foreignKey: string
|
||||||
}
|
}
|
||||||
export type RelationshipFieldMetadata = BaseFieldSchema & {
|
export interface ManyToOneRelationshipFieldMetadata
|
||||||
type: FieldType.LINK
|
extends BaseRelationshipFieldMetadata {
|
||||||
main?: boolean
|
relationshipType: RelationshipType.MANY_TO_ONE
|
||||||
fieldName?: string
|
foreignKey: string
|
||||||
tableId: string
|
}
|
||||||
} & (ManyToManyRelationshipFieldMetadata | OneSidedRelationshipFieldMetadata)
|
export type RelationshipFieldMetadata =
|
||||||
|
| ManyToManyRelationshipFieldMetadata
|
||||||
|
| OneToManyRelationshipFieldMetadata
|
||||||
|
| ManyToOneRelationshipFieldMetadata
|
||||||
|
|
||||||
export interface AutoColumnFieldMetadata extends BaseFieldSchema {
|
export interface AutoColumnFieldMetadata extends BaseFieldSchema {
|
||||||
type: FieldType.AUTO
|
type: FieldType.AUTO
|
||||||
|
@ -106,6 +117,7 @@ interface BaseFieldSchema extends UIFieldMetadata {
|
||||||
externalType?: string
|
externalType?: string
|
||||||
constraints?: FieldConstraints
|
constraints?: FieldConstraints
|
||||||
autocolumn?: boolean
|
autocolumn?: boolean
|
||||||
|
autoReason?: AutoReason
|
||||||
subtype?: string
|
subtype?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +125,6 @@ interface OtherFieldMetadata extends BaseFieldSchema {
|
||||||
type: Exclude<
|
type: Exclude<
|
||||||
FieldType,
|
FieldType,
|
||||||
| FieldType.DATETIME
|
| FieldType.DATETIME
|
||||||
| FieldType.DATETIME
|
|
||||||
| FieldType.LINK
|
| FieldType.LINK
|
||||||
| FieldType.AUTO
|
| FieldType.AUTO
|
||||||
| FieldType.STRING
|
| FieldType.STRING
|
||||||
|
|
Loading…
Reference in New Issue