WIP - basic override of foreign keys.
This commit is contained in:
parent
e25c6d4f3f
commit
fd4403037d
|
@ -1,6 +1,6 @@
|
|||
const { makeExternalQuery } = require("./utils")
|
||||
const { DataSourceOperation, SortDirection } = require("../../../constants")
|
||||
const { getExternalTable } = require("../table/utils")
|
||||
const { DataSourceOperation, SortDirection, FieldTypes, RelationshipTypes } = require("../../../constants")
|
||||
const { getAllExternalTables } = require("../table/utils")
|
||||
const {
|
||||
breakExternalTableId,
|
||||
generateRowIdField,
|
||||
|
@ -35,17 +35,56 @@ function generateIdForRow(row, table) {
|
|||
return generateRowIdField(idParts)
|
||||
}
|
||||
|
||||
function outputProcessing(rows, table) {
|
||||
function updateRelationshipColumns(rows, row, relationships, allTables) {
|
||||
const columns = {}
|
||||
for (let relationship of relationships) {
|
||||
const linkedTable = allTables[relationship.tableName]
|
||||
if (!linkedTable) {
|
||||
continue
|
||||
}
|
||||
const display = linkedTable.primaryDisplay
|
||||
const related = {}
|
||||
if (display && row[display]) {
|
||||
related.primaryDisplay = row[display]
|
||||
}
|
||||
related._id = row[relationship.to]
|
||||
columns[relationship.from] = related
|
||||
}
|
||||
for (let [column, related] of Object.entries(columns)) {
|
||||
if (!Array.isArray(rows[row._id][column])) {
|
||||
rows[row._id][column] = []
|
||||
}
|
||||
rows[row._id][column].push(related)
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
function outputProcessing(rows, table, relationships, allTables) {
|
||||
// if no rows this is what is returned? Might be PG only
|
||||
if (rows[0].read === true) {
|
||||
return []
|
||||
}
|
||||
let finalRows = {}
|
||||
for (let row of rows) {
|
||||
row._id = generateIdForRow(row, table)
|
||||
row.tableId = table._id
|
||||
row._rev = "rev"
|
||||
// this is a relationship of some sort
|
||||
if (finalRows[row._id]) {
|
||||
finalRows = updateRelationshipColumns(finalRows, row, relationships, allTables)
|
||||
continue
|
||||
}
|
||||
return rows
|
||||
const thisRow = {}
|
||||
// filter the row down to what is actually the row (not joined)
|
||||
for (let fieldName of Object.keys(table.schema)) {
|
||||
thisRow[fieldName] = row[fieldName]
|
||||
}
|
||||
thisRow._id = row._id
|
||||
thisRow.tableId = table._id
|
||||
thisRow._rev = "rev"
|
||||
finalRows[thisRow._id] = thisRow
|
||||
// do this at end once its been added to the final rows
|
||||
finalRows = updateRelationshipColumns(finalRows, row, relationships, allTables)
|
||||
}
|
||||
return Object.values(finalRows)
|
||||
}
|
||||
|
||||
function buildFilters(id, filters, table) {
|
||||
|
@ -83,6 +122,26 @@ function buildFilters(id, filters, table) {
|
|||
}
|
||||
}
|
||||
|
||||
function buildRelationships(table) {
|
||||
const relationships = []
|
||||
for (let [fieldName, field] of Object.entries(table.schema)) {
|
||||
if (field.type !== FieldTypes.LINK) {
|
||||
continue
|
||||
}
|
||||
// TODO: through field
|
||||
if (field.relationshipType === RelationshipTypes.MANY_TO_MANY) {
|
||||
continue
|
||||
}
|
||||
const broken = breakExternalTableId(field.tableId)
|
||||
relationships.push({
|
||||
from: fieldName,
|
||||
to: field.fieldName,
|
||||
tableName: broken.tableName,
|
||||
})
|
||||
}
|
||||
return relationships
|
||||
}
|
||||
|
||||
async function handleRequest(
|
||||
appId,
|
||||
operation,
|
||||
|
@ -90,12 +149,14 @@ async function handleRequest(
|
|||
{ id, row, filters, sort, paginate } = {}
|
||||
) {
|
||||
let { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||
const table = await getExternalTable(appId, datasourceId, tableName)
|
||||
const tables = await getAllExternalTables(appId, datasourceId)
|
||||
const table = tables[tableName]
|
||||
if (!table) {
|
||||
throw `Unable to process query, table "${tableName}" not defined.`
|
||||
}
|
||||
// clean up row on ingress using schema
|
||||
filters = buildFilters(id, filters, table)
|
||||
const relationships = buildRelationships(table)
|
||||
row = inputProcessing(row, table)
|
||||
if (
|
||||
operation === DataSourceOperation.DELETE &&
|
||||
|
@ -116,6 +177,7 @@ async function handleRequest(
|
|||
filters,
|
||||
sort,
|
||||
paginate,
|
||||
relationships,
|
||||
body: row,
|
||||
// pass an id filter into extra, purely for mysql/returning
|
||||
extra: {
|
||||
|
@ -126,9 +188,9 @@ async function handleRequest(
|
|||
const response = await makeExternalQuery(appId, json)
|
||||
// we searched for rows in someway
|
||||
if (operation === DataSourceOperation.READ && Array.isArray(response)) {
|
||||
return outputProcessing(response, table)
|
||||
return outputProcessing(response, table, relationships, tables)
|
||||
} else {
|
||||
row = outputProcessing(response, table)[0]
|
||||
row = outputProcessing(response, table, relationships, tables)[0]
|
||||
return { row, table }
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +332,4 @@ exports.validate = async () => {
|
|||
return { valid: true }
|
||||
}
|
||||
|
||||
exports.fetchEnrichedRow = async () => {
|
||||
// TODO: How does this work
|
||||
throw "Not Implemented"
|
||||
}
|
||||
exports.fetchEnrichedRow = async () => {}
|
||||
|
|
|
@ -204,15 +204,18 @@ class TableSaveFunctions {
|
|||
}
|
||||
}
|
||||
|
||||
exports.getExternalTable = async (appId, datasourceId, tableName) => {
|
||||
exports.getAllExternalTables = async (appId, datasourceId) => {
|
||||
const db = new CouchDB(appId)
|
||||
const datasource = await db.get(datasourceId)
|
||||
if (!datasource || !datasource.entities) {
|
||||
throw "Datasource is not configured fully."
|
||||
}
|
||||
return Object.values(datasource.entities).find(
|
||||
entity => entity.name === tableName
|
||||
)
|
||||
return datasource.entities
|
||||
}
|
||||
|
||||
exports.getExternalTable = async (appId, datasourceId, tableName) => {
|
||||
const entities = await exports.getAllExternalTables(appId, datasourceId)
|
||||
return entities[tableName]
|
||||
}
|
||||
|
||||
exports.TableSaveFunctions = TableSaveFunctions
|
||||
|
|
|
@ -55,6 +55,25 @@ function addFilters(query, filters) {
|
|||
return query
|
||||
}
|
||||
|
||||
function addRelationships(query, fromTable, relationships) {
|
||||
if (!relationships) {
|
||||
return query
|
||||
}
|
||||
for (let relationship of relationships) {
|
||||
const from = `${fromTable}.${relationship.from}`
|
||||
const to = `${relationship.tableName}.${relationship.to}`
|
||||
if (!relationship.through) {
|
||||
query = query.innerJoin(relationship.tableName, from, to)
|
||||
} else {
|
||||
const through = relationship
|
||||
query = query
|
||||
.innerJoin(through.tableName, from, through.from)
|
||||
.innerJoin(relationship.tableName, to, through.to)
|
||||
}
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
function buildCreate(knex, json, opts) {
|
||||
const { endpoint, body } = json
|
||||
let query = knex(endpoint.entityId)
|
||||
|
@ -67,8 +86,9 @@ function buildCreate(knex, json, opts) {
|
|||
}
|
||||
|
||||
function buildRead(knex, json, limit) {
|
||||
let { endpoint, resource, filters, sort, paginate } = json
|
||||
let query = knex(endpoint.entityId)
|
||||
let { endpoint, resource, filters, sort, paginate, relationships } = json
|
||||
const tableName = endpoint.entityId
|
||||
let query = knex(tableName)
|
||||
// select all if not specified
|
||||
if (!resource) {
|
||||
resource = { fields: [] }
|
||||
|
@ -81,6 +101,8 @@ function buildRead(knex, json, limit) {
|
|||
}
|
||||
// handle where
|
||||
query = addFilters(query, filters)
|
||||
// handle join
|
||||
query = addRelationships(query, tableName, relationships)
|
||||
// handle sorting
|
||||
if (sort) {
|
||||
for (let [key, value] of Object.entries(sort)) {
|
||||
|
|
|
@ -153,6 +153,20 @@ class PostgresIntegration extends Sql {
|
|||
name: columnName,
|
||||
type: convertType(column.data_type, TYPE_MAP),
|
||||
}
|
||||
|
||||
// // TODO: hack for testing
|
||||
// if (tableName === "persons") {
|
||||
// tables[tableName].primaryDisplay = "firstname"
|
||||
// }
|
||||
// if (columnName.toLowerCase() === "personid" && tableName === "tasks") {
|
||||
// tables[tableName].schema[columnName] = {
|
||||
// name: columnName,
|
||||
// type: "link",
|
||||
// tableId: buildExternalTableId(datasourceId, "persons"),
|
||||
// relationshipType: "one-to-many",
|
||||
// fieldName: "personid",
|
||||
// }
|
||||
// }
|
||||
}
|
||||
this.tables = tables
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue