Some type updates.

This commit is contained in:
mike12345567 2024-06-24 13:10:30 +01:00
parent 965725d022
commit 1402716f5c
9 changed files with 60 additions and 62 deletions

View File

@ -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

View File

@ -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 }
} }

View File

@ -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(

View File

@ -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])

View File

@ -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

View File

@ -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

View File

@ -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++) {

View File

@ -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)

View File

@ -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
} }