Handle relationships properly
This commit is contained in:
parent
d8462ba961
commit
bbf7142bd7
|
@ -56,10 +56,10 @@ export const getQueryableFields = async (
|
|||
fields: string[],
|
||||
table: Table
|
||||
): Promise<string[]> => {
|
||||
const handledTables = new Set<string>([table._id!])
|
||||
const extractTableFields = async (
|
||||
table: Table,
|
||||
allowedFields: string[]
|
||||
allowedFields: string[],
|
||||
fromTables: string[]
|
||||
): Promise<string[]> => {
|
||||
const result = []
|
||||
for (const field of Object.keys(table.schema).filter(
|
||||
|
@ -67,15 +67,15 @@ export const getQueryableFields = async (
|
|||
)) {
|
||||
const subSchema = table.schema[field]
|
||||
if (subSchema.type === FieldType.LINK) {
|
||||
if (handledTables.has(`${table._id}_${subSchema.tableId}`)) {
|
||||
if (fromTables.includes(subSchema.tableId)) {
|
||||
// avoid circular loops
|
||||
continue
|
||||
}
|
||||
handledTables.add(`${table._id}_${subSchema.tableId}`)
|
||||
const relatedTable = await sdk.tables.getTable(subSchema.tableId)
|
||||
const relatedFields = await extractTableFields(
|
||||
relatedTable,
|
||||
Object.keys(relatedTable.schema)
|
||||
Object.keys(relatedTable.schema),
|
||||
[...fromTables, subSchema.tableId]
|
||||
)
|
||||
|
||||
result.push(
|
||||
|
@ -96,7 +96,7 @@ export const getQueryableFields = async (
|
|||
"_id", // Querying by _id is always allowed, even if it's never part of the schema
|
||||
]
|
||||
|
||||
result.push(...(await extractTableFields(table, fields)))
|
||||
result.push(...(await extractTableFields(table, fields, [table._id!])))
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -195,26 +195,26 @@ describe("query utils", () => {
|
|||
})
|
||||
|
||||
it("returns table schema fields and _id", async () => {
|
||||
const table: Table = {
|
||||
const table: Table = await config.api.table.save({
|
||||
...structures.basicTable(),
|
||||
schema: {
|
||||
name: { name: "name", type: FieldType.STRING },
|
||||
age: { name: "age", type: FieldType.NUMBER },
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const result = await getQueryableFields(Object.keys(table.schema), table)
|
||||
expect(result).toEqual(["_id", "name", "age"])
|
||||
})
|
||||
|
||||
it("excludes hidden fields", async () => {
|
||||
const table: Table = {
|
||||
const table: Table = await config.api.table.save({
|
||||
...structures.basicTable(),
|
||||
schema: {
|
||||
name: { name: "name", type: FieldType.STRING },
|
||||
age: { name: "age", type: FieldType.NUMBER, visible: false },
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const result = await getQueryableFields(Object.keys(table.schema), table)
|
||||
expect(result).toEqual(["_id", "name"])
|
||||
|
@ -230,7 +230,7 @@ describe("query utils", () => {
|
|||
},
|
||||
})
|
||||
|
||||
const table: Table = {
|
||||
const table: Table = await config.api.table.save({
|
||||
...structures.basicTable(),
|
||||
schema: {
|
||||
name: { name: "name", type: FieldType.STRING },
|
||||
|
@ -242,7 +242,7 @@ describe("query utils", () => {
|
|||
fieldName: "table",
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const result = await config.doInContext(config.appId, () => {
|
||||
return getQueryableFields(Object.keys(table.schema), table)
|
||||
|
@ -267,7 +267,7 @@ describe("query utils", () => {
|
|||
},
|
||||
})
|
||||
|
||||
const table: Table = {
|
||||
const table: Table = await config.api.table.save({
|
||||
...structures.basicTable(),
|
||||
schema: {
|
||||
name: { name: "name", type: FieldType.STRING },
|
||||
|
@ -279,7 +279,7 @@ describe("query utils", () => {
|
|||
fieldName: "table",
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const result = await config.doInContext(config.appId, () => {
|
||||
return getQueryableFields(Object.keys(table.schema), table)
|
||||
|
@ -297,7 +297,7 @@ describe("query utils", () => {
|
|||
},
|
||||
})
|
||||
|
||||
const table: Table = {
|
||||
const table: Table = await config.api.table.save({
|
||||
...structures.basicTable(),
|
||||
schema: {
|
||||
name: { name: "name", type: FieldType.STRING },
|
||||
|
@ -310,7 +310,7 @@ describe("query utils", () => {
|
|||
visible: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const result = await config.doInContext(config.appId, () => {
|
||||
return getQueryableFields(Object.keys(table.schema), table)
|
||||
|
@ -318,61 +318,82 @@ describe("query utils", () => {
|
|||
expect(result).toEqual(["_id", "name"])
|
||||
})
|
||||
|
||||
it("includes nested relationship fields", async () => {
|
||||
const aux1: Table = await config.api.table.save({
|
||||
describe("nested relationship", () => {
|
||||
let table: Table, aux1: Table, aux2: Table
|
||||
|
||||
beforeAll(async () => {
|
||||
aux1 = await config.api.table.save({
|
||||
...structures.basicTable(),
|
||||
name: "aux1Table",
|
||||
schema: {
|
||||
name: { name: "name", type: FieldType.STRING },
|
||||
},
|
||||
})
|
||||
const aux2: Table = await config.api.table.save({
|
||||
aux2 = await config.api.table.save({
|
||||
...structures.basicTable(),
|
||||
name: "aux2Table",
|
||||
schema: {
|
||||
title: { name: "title", type: FieldType.STRING },
|
||||
aux1_1: {
|
||||
name: "aux1_1",
|
||||
type: FieldType.LINK,
|
||||
tableId: aux1._id!,
|
||||
relationshipType: RelationshipType.ONE_TO_MANY,
|
||||
fieldName: "aux2_1",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
table = await config.api.table.save({
|
||||
...structures.basicTable(),
|
||||
schema: {
|
||||
name: { name: "name", type: FieldType.STRING },
|
||||
aux1: {
|
||||
name: "aux1",
|
||||
type: FieldType.LINK,
|
||||
tableId: aux1._id!,
|
||||
relationshipType: RelationshipType.ONE_TO_MANY,
|
||||
fieldName: "aux2",
|
||||
fieldName: "table",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const table: Table = {
|
||||
...structures.basicTable(),
|
||||
schema: {
|
||||
name: { name: "name", type: FieldType.STRING },
|
||||
aux: {
|
||||
name: "aux",
|
||||
aux2: {
|
||||
name: "aux2",
|
||||
type: FieldType.LINK,
|
||||
tableId: aux2._id!,
|
||||
relationshipType: RelationshipType.ONE_TO_MANY,
|
||||
fieldName: "table",
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it("includes nested relationship fields from main table", async () => {
|
||||
const result = await config.doInContext(config.appId, () => {
|
||||
return getQueryableFields(Object.keys(table.schema), table)
|
||||
})
|
||||
expect(result).toEqual([
|
||||
"_id",
|
||||
"name",
|
||||
// Aux primitive props
|
||||
"aux.title",
|
||||
// deep 1 aux1 primitive props
|
||||
"aux1.name",
|
||||
"aux1Table.name",
|
||||
|
||||
// deep 2 aux1 primitive props
|
||||
"aux1.aux2_1.title",
|
||||
"aux1Table.aux2_1.title",
|
||||
"aux1.aux2Table.title",
|
||||
"aux1Table.aux2Table.title",
|
||||
|
||||
// deep 1 aux2 primitive props
|
||||
"aux2.title",
|
||||
"aux2Table.title",
|
||||
|
||||
// Aux deep 1 primitive props
|
||||
"aux.aux1.name",
|
||||
"aux2Table.aux1.name",
|
||||
|
||||
// Aux deep 2 primitive props
|
||||
"aux.aux1Table.name",
|
||||
// deep 2 aux2 primitive props
|
||||
"aux2.aux1_1.name",
|
||||
"aux2Table.aux1_1.name",
|
||||
"aux2.aux1Table.name",
|
||||
"aux2Table.aux1Table.name",
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue