Some type updates.
This commit is contained in:
parent
965725d022
commit
1402716f5c
|
@ -109,8 +109,10 @@ function generateSchema(
|
||||||
const { tableName } = breakExternalTableId(column.tableId)
|
const { tableName } = breakExternalTableId(column.tableId)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const relatedTable = tables[tableName]
|
const relatedTable = tables[tableName]
|
||||||
if (!relatedTable) {
|
if (!relatedTable || !relatedTable.primary) {
|
||||||
throw new Error("Referenced table doesn't exist")
|
throw new Error(
|
||||||
|
"Referenced table doesn't exist or has no primary keys"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
const relatedPrimary = relatedTable.primary[0]
|
const relatedPrimary = relatedTable.primary[0]
|
||||||
const externalType = relatedTable.schema[relatedPrimary].externalType
|
const externalType = relatedTable.schema[relatedPrimary].externalType
|
||||||
|
|
|
@ -55,10 +55,7 @@ export function buildExternalTableId(datasourceId: string, tableName: string) {
|
||||||
return `${datasourceId}${DOUBLE_SEPARATOR}${tableName}`
|
return `${datasourceId}${DOUBLE_SEPARATOR}${tableName}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function breakExternalTableId(tableId: string | undefined) {
|
export function breakExternalTableId(tableId: string) {
|
||||||
if (!tableId) {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
const parts = tableId.split(DOUBLE_SEPARATOR)
|
const parts = tableId.split(DOUBLE_SEPARATOR)
|
||||||
let datasourceId = parts.shift()
|
let datasourceId = parts.shift()
|
||||||
// if they need joined
|
// if they need joined
|
||||||
|
@ -67,6 +64,9 @@ export function breakExternalTableId(tableId: string | undefined) {
|
||||||
if (tableName.includes(ENCODED_SPACE)) {
|
if (tableName.includes(ENCODED_SPACE)) {
|
||||||
tableName = decodeURIComponent(tableName)
|
tableName = decodeURIComponent(tableName)
|
||||||
}
|
}
|
||||||
|
if (!datasourceId || !tableName) {
|
||||||
|
throw new Error("Unable to get datasource/table name from table ID")
|
||||||
|
}
|
||||||
return { datasourceId, tableName }
|
return { datasourceId, tableName }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,8 +126,8 @@ function getEndpoint(tableId: string | undefined, operation: string) {
|
||||||
}
|
}
|
||||||
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
return {
|
return {
|
||||||
datasourceId: datasourceId!,
|
datasourceId: datasourceId,
|
||||||
entityId: tableName!,
|
entityId: tableName,
|
||||||
operation: operation as Operation,
|
operation: operation as Operation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ export class ExternalRequest<T extends Operation> {
|
||||||
const { tableName } = breakExternalTableId(definition.tableId)
|
const { tableName } = breakExternalTableId(definition.tableId)
|
||||||
return {
|
return {
|
||||||
original: name,
|
original: name,
|
||||||
updated: tableName!,
|
updated: tableName,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -267,12 +267,10 @@ export class ExternalRequest<T extends Operation> {
|
||||||
|
|
||||||
getTable(tableId: string | undefined): Table | undefined {
|
getTable(tableId: string | undefined): Table | undefined {
|
||||||
if (!tableId) {
|
if (!tableId) {
|
||||||
throw "Table ID is unknown, cannot find table"
|
throw new Error("Table ID is unknown, cannot find table")
|
||||||
}
|
}
|
||||||
const { tableName } = breakExternalTableId(tableId)
|
const { tableName } = breakExternalTableId(tableId)
|
||||||
if (tableName) {
|
return this.tables[tableName]
|
||||||
return this.tables[tableName]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// seeds the object with table and datasource information
|
// seeds the object with table and datasource information
|
||||||
|
@ -323,9 +321,7 @@ export class ExternalRequest<T extends Operation> {
|
||||||
if (field.type === FieldType.NUMBER && !isNaN(parseFloat(row[key]))) {
|
if (field.type === FieldType.NUMBER && !isNaN(parseFloat(row[key]))) {
|
||||||
newRow[key] = parseFloat(row[key])
|
newRow[key] = parseFloat(row[key])
|
||||||
} else if (field.type === FieldType.LINK) {
|
} else if (field.type === FieldType.LINK) {
|
||||||
const { tableName: linkTableName } = breakExternalTableId(
|
const { tableName: linkTableName } = breakExternalTableId(field.tableId)
|
||||||
field?.tableId
|
|
||||||
)
|
|
||||||
// table has to exist for many to many
|
// table has to exist for many to many
|
||||||
if (!linkTableName || !this.tables[linkTableName]) {
|
if (!linkTableName || !this.tables[linkTableName]) {
|
||||||
continue
|
continue
|
||||||
|
@ -406,9 +402,6 @@ export class ExternalRequest<T extends Operation> {
|
||||||
[key: string]: { rows: Row[]; isMany: boolean; tableId: string }
|
[key: string]: { rows: Row[]; isMany: boolean; tableId: string }
|
||||||
} = {}
|
} = {}
|
||||||
const { tableName } = breakExternalTableId(tableId)
|
const { tableName } = breakExternalTableId(tableId)
|
||||||
if (!tableName) {
|
|
||||||
return related
|
|
||||||
}
|
|
||||||
const table = this.tables[tableName]
|
const table = this.tables[tableName]
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const primaryKey = table.primary[0]
|
const primaryKey = table.primary[0]
|
||||||
|
@ -602,17 +595,19 @@ export class ExternalRequest<T extends Operation> {
|
||||||
|
|
||||||
async run(config: RunConfig): Promise<ExternalRequestReturnType<T>> {
|
async run(config: RunConfig): Promise<ExternalRequestReturnType<T>> {
|
||||||
const { operation, tableId } = this
|
const { operation, tableId } = this
|
||||||
let { datasourceId, tableName } = breakExternalTableId(tableId)
|
if (!tableId) {
|
||||||
if (!tableName) {
|
throw new Error("Unable to run without a table ID")
|
||||||
throw "Unable to run without a table name"
|
|
||||||
}
|
}
|
||||||
|
let { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
if (!this.datasource) {
|
if (!this.datasource) {
|
||||||
await this.retrieveMetadata(datasourceId!)
|
await this.retrieveMetadata(datasourceId)
|
||||||
}
|
}
|
||||||
const table = this.tables[tableName]
|
const table = this.tables[tableName]
|
||||||
let isSql = isSQL(this.datasource!)
|
let isSql = isSQL(this.datasource!)
|
||||||
if (!table) {
|
if (!table) {
|
||||||
throw `Unable to process query, table "${tableName}" not defined.`
|
throw new Error(
|
||||||
|
`Unable to process query, table "${tableName}" not defined.`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// look for specific components of config which may not be considered acceptable
|
// look for specific components of config which may not be considered acceptable
|
||||||
let { id, row, filters, sort, paginate, rows } = cleanupConfig(
|
let { id, row, filters, sort, paginate, rows } = cleanupConfig(
|
||||||
|
|
|
@ -136,10 +136,7 @@ export async function fetchEnrichedRow(ctx: UserCtx) {
|
||||||
const id = ctx.params.rowId
|
const id = ctx.params.rowId
|
||||||
const tableId = utils.getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
const datasource: Datasource = await sdk.datasources.get(datasourceId!)
|
const datasource: Datasource = await sdk.datasources.get(datasourceId)
|
||||||
if (!tableName) {
|
|
||||||
ctx.throw(400, "Unable to find table.")
|
|
||||||
}
|
|
||||||
if (!datasource || !datasource.entities) {
|
if (!datasource || !datasource.entities) {
|
||||||
ctx.throw(400, "Datasource has not been configured for plus API.")
|
ctx.throw(400, "Datasource has not been configured for plus API.")
|
||||||
}
|
}
|
||||||
|
@ -163,7 +160,7 @@ export async function fetchEnrichedRow(ctx: UserCtx) {
|
||||||
}
|
}
|
||||||
const links = row[fieldName]
|
const links = row[fieldName]
|
||||||
const linkedTableId = field.tableId
|
const linkedTableId = field.tableId
|
||||||
const linkedTableName = breakExternalTableId(linkedTableId).tableName!
|
const linkedTableName = breakExternalTableId(linkedTableId).tableName
|
||||||
const linkedTable = tables[linkedTableName]
|
const linkedTable = tables[linkedTableName]
|
||||||
// don't support composite keys right now
|
// don't support composite keys right now
|
||||||
const linkedIds = links.map((link: Row) => breakRowIdField(link._id!)[0])
|
const linkedIds = links.map((link: Row) => breakRowIdField(link._id!)[0])
|
||||||
|
|
|
@ -2,6 +2,8 @@ import {
|
||||||
DatasourcePlusQueryResponse,
|
DatasourcePlusQueryResponse,
|
||||||
DSPlusOperation,
|
DSPlusOperation,
|
||||||
FieldType,
|
FieldType,
|
||||||
|
isManyToOne,
|
||||||
|
isOneToMany,
|
||||||
ManyToManyRelationshipFieldMetadata,
|
ManyToManyRelationshipFieldMetadata,
|
||||||
RelationshipFieldMetadata,
|
RelationshipFieldMetadata,
|
||||||
RelationshipsJson,
|
RelationshipsJson,
|
||||||
|
@ -93,12 +95,12 @@ export function buildExternalRelationships(
|
||||||
): RelationshipsJson[] {
|
): RelationshipsJson[] {
|
||||||
const relationships = []
|
const relationships = []
|
||||||
for (let [fieldName, field] of Object.entries(table.schema)) {
|
for (let [fieldName, field] of Object.entries(table.schema)) {
|
||||||
if (field.type !== FieldType.LINK) {
|
if (field.type !== FieldType.LINK || !field.tableId) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const { tableName: linkTableName } = breakExternalTableId(field.tableId)
|
const { tableName: linkTableName } = breakExternalTableId(field.tableId)
|
||||||
// no table to link to, this is not a valid relationships
|
// no table to link to, this is not a valid relationships
|
||||||
if (!linkTableName || !tables[linkTableName]) {
|
if (!tables[linkTableName]) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const linkTable = tables[linkTableName]
|
const linkTable = tables[linkTableName]
|
||||||
|
@ -110,7 +112,7 @@ export function buildExternalRelationships(
|
||||||
// need to specify where to put this back into
|
// need to specify where to put this back into
|
||||||
column: fieldName,
|
column: fieldName,
|
||||||
}
|
}
|
||||||
if (isManyToMany(field)) {
|
if (isManyToMany(field) && field.through) {
|
||||||
const { tableName: throughTableName } = breakExternalTableId(
|
const { tableName: throughTableName } = breakExternalTableId(
|
||||||
field.through
|
field.through
|
||||||
)
|
)
|
||||||
|
@ -120,7 +122,7 @@ export function buildExternalRelationships(
|
||||||
definition.to = field.throughFrom || linkTable.primary[0]
|
definition.to = field.throughFrom || linkTable.primary[0]
|
||||||
definition.fromPrimary = table.primary[0]
|
definition.fromPrimary = table.primary[0]
|
||||||
definition.toPrimary = linkTable.primary[0]
|
definition.toPrimary = linkTable.primary[0]
|
||||||
} else {
|
} else if (isManyToOne(field) || isOneToMany(field)) {
|
||||||
// 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
|
||||||
definition.from = field.foreignKey || table.primary[0]
|
definition.from = field.foreignKey || table.primary[0]
|
||||||
definition.to = field.fieldName
|
definition.to = field.fieldName
|
||||||
|
@ -180,16 +182,18 @@ export function buildSqlFieldList(
|
||||||
}
|
}
|
||||||
let fields = extractRealFields(table)
|
let fields = extractRealFields(table)
|
||||||
for (let field of Object.values(table.schema)) {
|
for (let field of Object.values(table.schema)) {
|
||||||
if (field.type !== FieldType.LINK || !opts?.relationships) {
|
if (
|
||||||
|
field.type !== FieldType.LINK ||
|
||||||
|
!opts?.relationships ||
|
||||||
|
!field.tableId
|
||||||
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const { tableName: linkTableName } = breakExternalTableId(field.tableId)
|
const { tableName: linkTableName } = breakExternalTableId(field.tableId)
|
||||||
if (linkTableName) {
|
const linkTable = tables[linkTableName]
|
||||||
const linkTable = tables[linkTableName]
|
if (linkTable) {
|
||||||
if (linkTable) {
|
const linkedFields = extractRealFields(linkTable, fields)
|
||||||
const linkedFields = extractRealFields(linkTable, fields)
|
fields = fields.concat(linkedFields)
|
||||||
fields = fields.concat(linkedFields)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fields
|
return fields
|
||||||
|
|
|
@ -18,8 +18,8 @@ import { builderSocket } from "../../../websockets"
|
||||||
import { inputProcessing } from "../../../utilities/rowProcessor"
|
import { inputProcessing } from "../../../utilities/rowProcessor"
|
||||||
|
|
||||||
function getDatasourceId(table: Table) {
|
function getDatasourceId(table: Table) {
|
||||||
if (!table) {
|
if (!table || !table._id) {
|
||||||
throw "No table supplied"
|
throw new Error("No table/table ID supplied")
|
||||||
}
|
}
|
||||||
if (table.sourceId) {
|
if (table.sourceId) {
|
||||||
return table.sourceId
|
return table.sourceId
|
||||||
|
|
|
@ -145,6 +145,10 @@ export async function exportRows(
|
||||||
delimiter,
|
delimiter,
|
||||||
customHeaders,
|
customHeaders,
|
||||||
} = options
|
} = options
|
||||||
|
|
||||||
|
if (!tableId) {
|
||||||
|
throw new HTTPError("No table ID for search provided.", 400)
|
||||||
|
}
|
||||||
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
|
|
||||||
let requestQuery: SearchFilters = {}
|
let requestQuery: SearchFilters = {}
|
||||||
|
@ -167,7 +171,7 @@ export async function exportRows(
|
||||||
requestQuery = query || {}
|
requestQuery = query || {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const datasource = await sdk.datasources.get(datasourceId!)
|
const datasource = await sdk.datasources.get(datasourceId)
|
||||||
const table = await sdk.tables.getTable(tableId)
|
const table = await sdk.tables.getTable(tableId)
|
||||||
if (!datasource || !datasource.entities) {
|
if (!datasource || !datasource.entities) {
|
||||||
throw new HTTPError("Datasource has not been configured for plus API.", 400)
|
throw new HTTPError("Datasource has not been configured for plus API.", 400)
|
||||||
|
@ -180,10 +184,6 @@ export async function exportRows(
|
||||||
let rows: Row[] = []
|
let rows: Row[] = []
|
||||||
let headers
|
let headers
|
||||||
|
|
||||||
if (!tableName) {
|
|
||||||
throw new HTTPError("Could not find table name.", 400)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter data to only specified columns if required
|
// Filter data to only specified columns if required
|
||||||
if (columns && columns.length) {
|
if (columns && columns.length) {
|
||||||
for (let i = 0; i < result.rows.length; i++) {
|
for (let i = 0; i < result.rows.length; i++) {
|
||||||
|
|
|
@ -90,10 +90,10 @@ export async function getExternalTable(
|
||||||
export async function getTable(tableId: string): Promise<Table> {
|
export async function getTable(tableId: string): Promise<Table> {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
let output: Table
|
let output: Table
|
||||||
if (isExternalTableID(tableId)) {
|
if (tableId && isExternalTableID(tableId)) {
|
||||||
let { datasourceId, tableName } = breakExternalTableId(tableId)
|
let { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
const datasource = await datasources.get(datasourceId!)
|
const datasource = await datasources.get(datasourceId)
|
||||||
const table = await getExternalTable(datasourceId!, tableName!)
|
const table = await getExternalTable(datasourceId, tableName)
|
||||||
output = { ...table, sql: isSQL(datasource) }
|
output = { ...table, sql: isSQL(datasource) }
|
||||||
} else {
|
} else {
|
||||||
output = await db.get<Table>(tableId)
|
output = await db.get<Table>(tableId)
|
||||||
|
|
|
@ -10,9 +10,9 @@ export async function get(viewId: string): Promise<ViewV2> {
|
||||||
const { tableId } = utils.extractViewInfoFromID(viewId)
|
const { tableId } = utils.extractViewInfoFromID(viewId)
|
||||||
|
|
||||||
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
const ds = await sdk.datasources.get(datasourceId!)
|
const ds = await sdk.datasources.get(datasourceId)
|
||||||
|
|
||||||
const table = ds.entities![tableName!]
|
const table = ds.entities![tableName]
|
||||||
const views = Object.values(table.views!).filter(isV2)
|
const views = Object.values(table.views!).filter(isV2)
|
||||||
const found = views.find(v => v.id === viewId)
|
const found = views.find(v => v.id === viewId)
|
||||||
if (!found) {
|
if (!found) {
|
||||||
|
@ -25,9 +25,9 @@ export async function getEnriched(viewId: string): Promise<ViewV2Enriched> {
|
||||||
const { tableId } = utils.extractViewInfoFromID(viewId)
|
const { tableId } = utils.extractViewInfoFromID(viewId)
|
||||||
|
|
||||||
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
const ds = await sdk.datasources.get(datasourceId!)
|
const ds = await sdk.datasources.get(datasourceId)
|
||||||
|
|
||||||
const table = ds.entities![tableName!]
|
const table = ds.entities![tableName]
|
||||||
const views = Object.values(table.views!).filter(isV2)
|
const views = Object.values(table.views!).filter(isV2)
|
||||||
const found = views.find(v => v.id === viewId)
|
const found = views.find(v => v.id === viewId)
|
||||||
if (!found) {
|
if (!found) {
|
||||||
|
@ -49,9 +49,9 @@ export async function create(
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
|
|
||||||
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
const ds = await sdk.datasources.get(datasourceId!)
|
const ds = await sdk.datasources.get(datasourceId)
|
||||||
ds.entities![tableName!].views ??= {}
|
ds.entities![tableName].views ??= {}
|
||||||
ds.entities![tableName!].views![view.name] = view
|
ds.entities![tableName].views![view.name] = view
|
||||||
await db.put(ds)
|
await db.put(ds)
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
@ -60,9 +60,9 @@ export async function update(tableId: string, view: ViewV2): Promise<ViewV2> {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
|
|
||||||
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
const ds = await sdk.datasources.get(datasourceId!)
|
const ds = await sdk.datasources.get(datasourceId)
|
||||||
ds.entities![tableName!].views ??= {}
|
ds.entities![tableName].views ??= {}
|
||||||
const views = ds.entities![tableName!].views!
|
const views = ds.entities![tableName].views!
|
||||||
|
|
||||||
const existingView = Object.values(views).find(
|
const existingView = Object.values(views).find(
|
||||||
v => isV2(v) && v.id === view.id
|
v => isV2(v) && v.id === view.id
|
||||||
|
@ -87,9 +87,9 @@ export async function remove(viewId: string): Promise<ViewV2> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { datasourceId, tableName } = breakExternalTableId(view.tableId)
|
const { datasourceId, tableName } = breakExternalTableId(view.tableId)
|
||||||
const ds = await sdk.datasources.get(datasourceId!)
|
const ds = await sdk.datasources.get(datasourceId)
|
||||||
|
|
||||||
delete ds.entities![tableName!].views![view?.name]
|
delete ds.entities![tableName].views![view?.name]
|
||||||
await db.put(ds)
|
await db.put(ds)
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue