2023-01-17 18:22:31 +01:00
|
|
|
import {
|
|
|
|
generateMakeRequest,
|
|
|
|
MakeRequestResponse,
|
|
|
|
} from "../api/routes/public/tests/utils"
|
|
|
|
|
|
|
|
import * as setup from "../api/routes/tests/utilities"
|
2023-01-19 21:09:39 +01:00
|
|
|
import {
|
|
|
|
Datasource,
|
|
|
|
FieldType,
|
|
|
|
RelationshipTypes,
|
|
|
|
Row,
|
|
|
|
SourceName,
|
|
|
|
Table,
|
|
|
|
} from "@budibase/types"
|
2023-01-18 18:07:09 +01:00
|
|
|
import _ from "lodash"
|
2023-02-06 20:43:08 +01:00
|
|
|
import { generator } from "@budibase/backend-core/tests"
|
2023-02-02 11:43:18 +01:00
|
|
|
import { utils } from "@budibase/backend-core"
|
2023-02-06 21:12:08 +01:00
|
|
|
import { GenericContainer } from "testcontainers"
|
2023-01-17 18:22:31 +01:00
|
|
|
|
2023-01-20 12:48:11 +01:00
|
|
|
const config = setup.getConfig()!
|
2023-01-18 14:55:24 +01:00
|
|
|
|
2023-02-06 21:12:08 +01:00
|
|
|
jest.setTimeout(30000)
|
|
|
|
|
2023-02-06 15:54:49 +01:00
|
|
|
jest.unmock("pg")
|
2023-01-19 12:00:51 +01:00
|
|
|
|
2023-02-02 11:43:18 +01:00
|
|
|
describe("row api - postgres", () => {
|
2023-02-06 15:54:49 +01:00
|
|
|
let makeRequest: MakeRequestResponse,
|
2023-01-18 18:07:09 +01:00
|
|
|
postgresDatasource: Datasource,
|
2023-02-07 11:46:34 +01:00
|
|
|
primaryPostgresTable: Table,
|
2023-02-23 00:06:57 +01:00
|
|
|
o2mInfo: ForeignTableInfo,
|
|
|
|
m2oInfo: ForeignTableInfo,
|
|
|
|
m2mInfo: ForeignTableInfo
|
2023-01-18 18:07:09 +01:00
|
|
|
|
2023-02-06 20:43:08 +01:00
|
|
|
let host: string
|
|
|
|
let port: number
|
2023-02-02 11:43:18 +01:00
|
|
|
|
2023-02-06 15:54:49 +01:00
|
|
|
beforeAll(async () => {
|
2023-02-06 21:12:08 +01:00
|
|
|
const container = await new GenericContainer("postgres")
|
2023-02-06 20:43:08 +01:00
|
|
|
.withExposedPorts(5432)
|
|
|
|
.withEnv("POSTGRES_PASSWORD", "password")
|
|
|
|
.start()
|
|
|
|
|
2023-02-06 21:12:08 +01:00
|
|
|
host = container.getContainerIpAddress()
|
|
|
|
port = container.getMappedPort(5432)
|
2023-02-06 20:43:08 +01:00
|
|
|
|
2023-01-18 18:07:09 +01:00
|
|
|
await config.init()
|
2023-02-06 15:54:49 +01:00
|
|
|
const apiKey = await config.generateApiKey()
|
|
|
|
|
|
|
|
makeRequest = generateMakeRequest(apiKey, true)
|
|
|
|
})
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
2023-01-18 18:07:09 +01:00
|
|
|
postgresDatasource = await config.createDatasource({
|
2023-01-20 12:48:11 +01:00
|
|
|
datasource: {
|
|
|
|
type: "datasource",
|
|
|
|
source: SourceName.POSTGRES,
|
|
|
|
plus: true,
|
|
|
|
config: {
|
2023-02-02 11:43:18 +01:00
|
|
|
host,
|
|
|
|
port,
|
2023-01-20 12:48:11 +01:00
|
|
|
database: "postgres",
|
2023-02-06 15:54:49 +01:00
|
|
|
user: "postgres",
|
2023-02-07 11:12:42 +01:00
|
|
|
password: "password",
|
2023-01-20 12:48:11 +01:00
|
|
|
schema: "public",
|
|
|
|
ssl: false,
|
|
|
|
rejectUnauthorized: false,
|
|
|
|
ca: false,
|
|
|
|
},
|
2023-01-18 18:07:09 +01:00
|
|
|
},
|
|
|
|
})
|
2023-01-18 17:46:40 +01:00
|
|
|
|
2023-02-22 22:40:50 +01:00
|
|
|
async function createAuxTable(prefix: string) {
|
|
|
|
return await config.createTable({
|
|
|
|
name: `${prefix}_${generator.word({ length: 6 })}`,
|
|
|
|
type: "external",
|
|
|
|
primary: ["id"],
|
2023-02-23 10:39:16 +01:00
|
|
|
primaryDisplay: "title",
|
2023-02-22 22:40:50 +01:00
|
|
|
schema: {
|
|
|
|
id: {
|
|
|
|
name: "id",
|
|
|
|
type: FieldType.AUTO,
|
2023-02-23 10:39:16 +01:00
|
|
|
autocolumn: true,
|
2023-02-22 22:40:50 +01:00
|
|
|
constraints: {
|
|
|
|
presence: true,
|
|
|
|
},
|
2023-02-06 15:54:49 +01:00
|
|
|
},
|
2023-02-22 22:40:50 +01:00
|
|
|
title: {
|
|
|
|
name: "title",
|
|
|
|
type: FieldType.STRING,
|
|
|
|
constraints: {
|
|
|
|
presence: true,
|
|
|
|
},
|
2023-02-06 15:54:49 +01:00
|
|
|
},
|
|
|
|
},
|
2023-02-22 22:40:50 +01:00
|
|
|
sourceId: postgresDatasource._id,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
o2mInfo = {
|
|
|
|
table: await createAuxTable("o2m"),
|
|
|
|
fieldName: "oneToManyRelation",
|
2023-02-23 00:06:57 +01:00
|
|
|
relationshipType: RelationshipTypes.ONE_TO_MANY,
|
2023-02-22 22:40:50 +01:00
|
|
|
}
|
|
|
|
m2oInfo = {
|
|
|
|
table: await createAuxTable("m2o"),
|
|
|
|
fieldName: "manyToOneRelation",
|
2023-02-23 00:06:57 +01:00
|
|
|
relationshipType: RelationshipTypes.MANY_TO_ONE,
|
2023-02-22 22:40:50 +01:00
|
|
|
}
|
|
|
|
m2mInfo = {
|
|
|
|
table: await createAuxTable("m2m"),
|
|
|
|
fieldName: "manyToManyRelation",
|
2023-02-23 00:06:57 +01:00
|
|
|
relationshipType: RelationshipTypes.MANY_TO_MANY,
|
2023-02-22 22:40:50 +01:00
|
|
|
}
|
2023-01-18 18:07:09 +01:00
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
primaryPostgresTable = await config.createTable({
|
2023-02-22 22:40:50 +01:00
|
|
|
name: `p_${generator.word({ length: 6 })}`,
|
2023-02-06 15:54:49 +01:00
|
|
|
type: "external",
|
|
|
|
primary: ["id"],
|
2023-01-18 18:07:09 +01:00
|
|
|
schema: {
|
2023-02-06 15:54:49 +01:00
|
|
|
id: {
|
|
|
|
name: "id",
|
|
|
|
type: FieldType.AUTO,
|
2023-02-23 10:39:16 +01:00
|
|
|
autocolumn: true,
|
2023-02-06 15:54:49 +01:00
|
|
|
constraints: {
|
|
|
|
presence: true,
|
|
|
|
},
|
|
|
|
},
|
2023-01-18 18:07:09 +01:00
|
|
|
name: {
|
|
|
|
name: "name",
|
|
|
|
type: FieldType.STRING,
|
|
|
|
constraints: {
|
|
|
|
presence: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
description: {
|
|
|
|
name: "description",
|
|
|
|
type: FieldType.STRING,
|
|
|
|
},
|
|
|
|
value: {
|
|
|
|
name: "value",
|
|
|
|
type: FieldType.NUMBER,
|
2023-01-18 17:46:40 +01:00
|
|
|
},
|
2023-02-22 22:40:50 +01:00
|
|
|
oneToManyRelation: {
|
2023-01-19 21:09:39 +01:00
|
|
|
type: FieldType.LINK,
|
|
|
|
constraints: {
|
|
|
|
type: "array",
|
2023-02-06 15:54:49 +01:00
|
|
|
presence: false,
|
2023-01-19 21:09:39 +01:00
|
|
|
},
|
2023-02-22 22:40:50 +01:00
|
|
|
fieldName: o2mInfo.fieldName,
|
|
|
|
name: "oneToManyRelation",
|
2023-02-06 15:54:49 +01:00
|
|
|
relationshipType: RelationshipTypes.ONE_TO_MANY,
|
2023-02-22 22:40:50 +01:00
|
|
|
tableId: o2mInfo.table._id,
|
2023-02-23 10:39:16 +01:00
|
|
|
main: true,
|
2023-02-22 22:40:50 +01:00
|
|
|
},
|
|
|
|
manyToOneRelation: {
|
|
|
|
type: FieldType.LINK,
|
|
|
|
constraints: {
|
|
|
|
type: "array",
|
|
|
|
presence: false,
|
|
|
|
},
|
|
|
|
fieldName: m2oInfo.fieldName,
|
|
|
|
name: "manyToOneRelation",
|
|
|
|
relationshipType: RelationshipTypes.MANY_TO_ONE,
|
|
|
|
tableId: m2oInfo.table._id,
|
2023-02-23 10:39:16 +01:00
|
|
|
main: true,
|
2023-02-22 22:40:50 +01:00
|
|
|
},
|
|
|
|
manyToManyRelation: {
|
|
|
|
type: FieldType.LINK,
|
|
|
|
constraints: {
|
|
|
|
type: "array",
|
|
|
|
presence: false,
|
|
|
|
},
|
|
|
|
fieldName: m2mInfo.fieldName,
|
|
|
|
name: "manyToManyRelation",
|
|
|
|
relationshipType: RelationshipTypes.MANY_TO_MANY,
|
|
|
|
tableId: m2mInfo.table._id,
|
2023-02-23 10:39:16 +01:00
|
|
|
main: true,
|
2023-01-19 21:09:39 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
sourceId: postgresDatasource._id,
|
|
|
|
})
|
2023-01-18 17:46:40 +01:00
|
|
|
})
|
2023-01-17 18:22:31 +01:00
|
|
|
|
2023-02-22 22:40:50 +01:00
|
|
|
afterAll(config.end)
|
2023-01-18 18:07:09 +01:00
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
function generateRandomPrimaryRowData() {
|
2023-01-18 18:07:09 +01:00
|
|
|
return {
|
2023-02-02 11:43:18 +01:00
|
|
|
name: generator.name(),
|
|
|
|
description: generator.paragraph(),
|
2023-02-06 18:30:33 +01:00
|
|
|
value: generator.age(),
|
2023-01-18 18:07:09 +01:00
|
|
|
}
|
|
|
|
}
|
2023-01-17 18:22:31 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
type PrimaryRowData = {
|
|
|
|
name: string
|
|
|
|
description: string
|
|
|
|
value: number
|
|
|
|
}
|
|
|
|
|
2023-02-23 10:39:16 +01:00
|
|
|
type ForeignTableInfo = {
|
|
|
|
table: Table
|
|
|
|
fieldName: string
|
|
|
|
relationshipType: RelationshipTypes
|
|
|
|
}
|
|
|
|
|
|
|
|
type ForeignRowsInfo = {
|
|
|
|
row: Row
|
|
|
|
relationshipType: RelationshipTypes
|
|
|
|
}
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
async function createPrimaryRow(opts: {
|
2023-02-07 12:27:46 +01:00
|
|
|
rowData: PrimaryRowData
|
2023-02-23 00:06:57 +01:00
|
|
|
createForeignRows?: {
|
|
|
|
createOne2Many?: boolean
|
|
|
|
createMany2One?: number
|
|
|
|
createMany2Many?: number
|
|
|
|
}
|
2023-02-07 11:46:34 +01:00
|
|
|
}) {
|
2023-02-23 10:39:16 +01:00
|
|
|
let { rowData } = opts as any
|
2023-02-23 00:06:57 +01:00
|
|
|
let foreignRows: ForeignRowsInfo[] = []
|
2023-02-22 22:40:50 +01:00
|
|
|
|
2023-02-23 00:06:57 +01:00
|
|
|
async function createForeignRow(tableInfo: ForeignTableInfo) {
|
2023-02-23 10:39:16 +01:00
|
|
|
const foreignKey = `fk_${tableInfo.table.name}_${tableInfo.fieldName}`
|
|
|
|
|
2023-02-23 00:06:57 +01:00
|
|
|
const foreignRow = await config.createRow({
|
|
|
|
tableId: tableInfo.table._id,
|
2023-02-06 15:54:49 +01:00
|
|
|
title: generator.name(),
|
|
|
|
})
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
rowData = {
|
|
|
|
...rowData,
|
2023-02-23 00:06:57 +01:00
|
|
|
[foreignKey]: foreignRow.id,
|
2023-02-06 15:54:49 +01:00
|
|
|
}
|
2023-02-23 00:06:57 +01:00
|
|
|
foreignRows.push({
|
|
|
|
row: foreignRow,
|
2023-02-23 10:39:16 +01:00
|
|
|
|
2023-02-23 00:06:57 +01:00
|
|
|
relationshipType: tableInfo.relationshipType,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts?.createForeignRows?.createOne2Many) {
|
2023-02-23 10:39:16 +01:00
|
|
|
const foreignKey = `fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`
|
|
|
|
|
|
|
|
const foreignRow = await config.createRow({
|
|
|
|
tableId: o2mInfo.table._id,
|
|
|
|
title: generator.name(),
|
|
|
|
})
|
|
|
|
|
|
|
|
rowData = {
|
|
|
|
...rowData,
|
|
|
|
[foreignKey]: foreignRow.id,
|
|
|
|
}
|
|
|
|
foreignRows.push({
|
|
|
|
row: foreignRow,
|
|
|
|
relationshipType: o2mInfo.relationshipType,
|
|
|
|
})
|
2023-02-23 00:06:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < (opts?.createForeignRows?.createMany2One || 0); i++) {
|
2023-02-23 10:39:16 +01:00
|
|
|
const foreignRow = await config.createRow({
|
|
|
|
tableId: m2oInfo.table._id,
|
|
|
|
title: generator.name(),
|
|
|
|
})
|
|
|
|
|
|
|
|
rowData = {
|
|
|
|
...rowData,
|
|
|
|
[m2oInfo.fieldName]: rowData[m2oInfo.fieldName] || [],
|
|
|
|
}
|
|
|
|
rowData[m2oInfo.fieldName].push(foreignRow._id)
|
|
|
|
foreignRows.push({
|
|
|
|
row: foreignRow,
|
|
|
|
relationshipType: RelationshipTypes.MANY_TO_ONE,
|
|
|
|
})
|
2023-02-23 00:06:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < (opts?.createForeignRows?.createMany2Many || 0); i++) {
|
2023-02-23 10:50:18 +01:00
|
|
|
const foreignRow = await config.createRow({
|
|
|
|
tableId: m2mInfo.table._id,
|
|
|
|
title: generator.name(),
|
|
|
|
})
|
|
|
|
|
|
|
|
rowData = {
|
|
|
|
...rowData,
|
|
|
|
[m2mInfo.fieldName]: rowData[m2mInfo.fieldName] || [],
|
|
|
|
}
|
|
|
|
rowData[m2mInfo.fieldName].push(foreignRow._id)
|
|
|
|
foreignRows.push({
|
|
|
|
row: foreignRow,
|
|
|
|
relationshipType: RelationshipTypes.MANY_TO_MANY,
|
|
|
|
})
|
2023-02-06 15:54:49 +01:00
|
|
|
}
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
const row = await config.createRow({
|
|
|
|
tableId: primaryPostgresTable._id,
|
|
|
|
...rowData,
|
2023-01-19 12:35:00 +01:00
|
|
|
})
|
2023-02-07 11:46:34 +01:00
|
|
|
|
2023-02-23 00:06:57 +01:00
|
|
|
return { row, foreignRows }
|
2023-01-19 12:35:00 +01:00
|
|
|
}
|
|
|
|
|
2023-02-06 15:54:49 +01:00
|
|
|
async function createDefaultPgTable() {
|
|
|
|
return await config.createTable({
|
|
|
|
name: generator.word({ length: 10 }),
|
|
|
|
type: "external",
|
|
|
|
primary: ["id"],
|
|
|
|
schema: {
|
|
|
|
id: {
|
|
|
|
name: "id",
|
|
|
|
type: FieldType.AUTO,
|
|
|
|
constraints: {
|
|
|
|
presence: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
sourceId: postgresDatasource._id,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
async function populatePrimaryRows(
|
|
|
|
count: number,
|
2023-02-23 00:06:57 +01:00
|
|
|
opts?: {
|
|
|
|
createOne2Many?: boolean
|
|
|
|
createMany2One?: number
|
|
|
|
createMany2Many?: number
|
|
|
|
}
|
2023-02-07 12:27:46 +01:00
|
|
|
) {
|
2023-01-18 18:07:09 +01:00
|
|
|
return await Promise.all(
|
|
|
|
Array(count)
|
|
|
|
.fill({})
|
|
|
|
.map(async () => {
|
2023-02-07 11:46:34 +01:00
|
|
|
const rowData = generateRandomPrimaryRowData()
|
2023-01-18 18:07:09 +01:00
|
|
|
return {
|
|
|
|
rowData,
|
2023-02-07 11:46:34 +01:00
|
|
|
...(await createPrimaryRow({
|
|
|
|
rowData,
|
2023-02-22 22:40:50 +01:00
|
|
|
createForeignRows: opts,
|
2023-02-07 11:46:34 +01:00
|
|
|
})),
|
2023-01-18 18:07:09 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
)
|
2023-01-18 17:46:40 +01:00
|
|
|
}
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
it("validate table schema", async () => {
|
2023-01-19 17:21:37 +01:00
|
|
|
const res = await makeRequest(
|
|
|
|
"get",
|
2023-01-19 17:43:39 +01:00
|
|
|
`/api/datasources/${postgresDatasource._id}`
|
2023-01-19 17:21:37 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 17:43:39 +01:00
|
|
|
expect(res.body).toEqual({
|
|
|
|
config: {
|
|
|
|
ca: false,
|
|
|
|
database: "postgres",
|
2023-02-02 11:43:18 +01:00
|
|
|
host,
|
|
|
|
password: "--secret-value--",
|
|
|
|
port,
|
2023-01-19 17:43:39 +01:00
|
|
|
rejectUnauthorized: false,
|
|
|
|
schema: "public",
|
|
|
|
ssl: false,
|
2023-02-06 15:54:49 +01:00
|
|
|
user: "postgres",
|
2023-01-19 17:43:39 +01:00
|
|
|
},
|
|
|
|
plus: true,
|
|
|
|
source: "POSTGRES",
|
|
|
|
type: "datasource",
|
|
|
|
_id: expect.any(String),
|
|
|
|
_rev: expect.any(String),
|
|
|
|
createdAt: expect.any(String),
|
|
|
|
updatedAt: expect.any(String),
|
2023-02-06 15:54:49 +01:00
|
|
|
entities: expect.any(Object),
|
2023-01-19 17:43:39 +01:00
|
|
|
})
|
2023-01-19 17:21:37 +01:00
|
|
|
})
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
describe("POST /api/:tableId/rows", () => {
|
2023-01-19 18:23:48 +01:00
|
|
|
const createRow = (tableId: string | undefined, body: object) =>
|
|
|
|
makeRequest("post", `/api/${tableId}/rows`, body)
|
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("given than no row exists", () => {
|
|
|
|
it("adding a new one persists it", async () => {
|
|
|
|
const newRow = generateRandomPrimaryRowData()
|
2023-01-17 18:22:31 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
const res = await createRow(primaryPostgresTable._id, newRow)
|
2023-01-17 18:22:31 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.status).toBe(200)
|
2023-01-17 18:39:59 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
const persistedRows = await config.getRows(primaryPostgresTable._id!)
|
|
|
|
expect(persistedRows).toHaveLength(1)
|
2023-02-06 15:54:49 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
const expected = {
|
|
|
|
...res.body,
|
|
|
|
...newRow,
|
|
|
|
}
|
2023-02-06 15:54:49 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(persistedRows).toEqual([expect.objectContaining(expected)])
|
|
|
|
})
|
2023-01-18 13:26:26 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
it("multiple rows can be persisted", async () => {
|
|
|
|
const numberOfRows = 10
|
|
|
|
const newRows = Array(numberOfRows).fill(generateRandomPrimaryRowData())
|
2023-01-18 13:26:26 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
for (const newRow of newRows) {
|
|
|
|
const res = await createRow(primaryPostgresTable._id, newRow)
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
}
|
2023-01-18 13:26:26 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
const persistedRows = await config.getRows(primaryPostgresTable._id!)
|
|
|
|
expect(persistedRows).toHaveLength(numberOfRows)
|
|
|
|
expect(persistedRows).toEqual(
|
|
|
|
expect.arrayContaining(newRows.map(expect.objectContaining))
|
|
|
|
)
|
|
|
|
})
|
2023-01-18 13:26:26 +01:00
|
|
|
})
|
2023-01-17 18:22:31 +01:00
|
|
|
})
|
2023-01-18 17:46:40 +01:00
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
describe("PATCH /api/:tableId/rows", () => {
|
2023-01-19 18:23:48 +01:00
|
|
|
const updateRow = (tableId: string | undefined, body: Row) =>
|
|
|
|
makeRequest("patch", `/api/${tableId}/rows`, body)
|
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("given than a row exists", () => {
|
|
|
|
let row: Row
|
|
|
|
beforeEach(async () => {
|
2023-02-22 22:40:50 +01:00
|
|
|
let rowResponse = _.sample(await populatePrimaryRows(1))!
|
2023-02-07 12:27:46 +01:00
|
|
|
row = rowResponse.row
|
|
|
|
})
|
2023-01-18 18:11:52 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
it("updating it persists it", async () => {
|
|
|
|
const newName = generator.name()
|
|
|
|
const newValue = generator.age()
|
|
|
|
const updatedRow = {
|
|
|
|
...row,
|
|
|
|
name: newName,
|
|
|
|
value: newValue,
|
|
|
|
}
|
2023-01-18 18:11:52 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
const res = await updateRow(primaryPostgresTable._id, updatedRow)
|
2023-01-18 18:11:52 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.status).toBe(200)
|
|
|
|
expect(res.body).toEqual(updatedRow)
|
2023-01-18 18:11:52 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
const persistedRow = await config.getRow(
|
|
|
|
primaryPostgresTable._id!,
|
|
|
|
row.id
|
|
|
|
)
|
2023-01-18 18:11:52 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(persistedRow).toEqual(
|
|
|
|
expect.objectContaining({
|
|
|
|
id: row.id,
|
|
|
|
name: newName,
|
|
|
|
value: newValue,
|
|
|
|
})
|
|
|
|
)
|
|
|
|
})
|
2023-01-18 18:11:52 +01:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
describe("DELETE /api/:tableId/rows", () => {
|
2023-01-19 18:23:48 +01:00
|
|
|
const deleteRow = (
|
|
|
|
tableId: string | undefined,
|
|
|
|
body: Row | { rows: Row[] }
|
|
|
|
) => makeRequest("delete", `/api/${tableId}/rows`, body)
|
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("given than multiple row exist", () => {
|
2023-01-18 18:21:17 +01:00
|
|
|
const numberOfInitialRows = 5
|
2023-02-07 12:27:46 +01:00
|
|
|
let rows: Row[]
|
|
|
|
beforeEach(async () => {
|
|
|
|
rows = (await populatePrimaryRows(numberOfInitialRows)).map(x => x.row)
|
|
|
|
})
|
2023-01-18 18:21:17 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
it("delete request removes it", async () => {
|
|
|
|
const row = _.sample(rows)!
|
|
|
|
const res = await deleteRow(primaryPostgresTable._id, row)
|
2023-01-18 18:21:17 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.status).toBe(200)
|
2023-01-18 18:21:17 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
const persistedRows = await config.getRows(primaryPostgresTable._id!)
|
|
|
|
expect(persistedRows).toHaveLength(numberOfInitialRows - 1)
|
2023-01-18 18:21:17 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(row.id).toBeDefined()
|
|
|
|
expect(persistedRows).not.toContain(
|
|
|
|
expect.objectContaining({ _id: row.id })
|
|
|
|
)
|
|
|
|
})
|
2023-01-19 18:23:48 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
it("multiple rows can be removed at once", async () => {
|
|
|
|
let rowsToDelete = _.sampleSize(rows, 3)!
|
2023-01-19 18:28:42 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
const res = await deleteRow(primaryPostgresTable._id, {
|
|
|
|
rows: rowsToDelete,
|
|
|
|
})
|
2023-01-19 18:28:42 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 18:28:42 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
const persistedRows = await config.getRows(primaryPostgresTable._id!)
|
|
|
|
expect(persistedRows).toHaveLength(numberOfInitialRows - 3)
|
2023-01-19 18:28:42 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
for (const row of rowsToDelete) {
|
|
|
|
expect(persistedRows).not.toContain(
|
|
|
|
expect.objectContaining({ _id: row.id })
|
|
|
|
)
|
|
|
|
}
|
|
|
|
})
|
2023-01-19 18:28:42 +01:00
|
|
|
})
|
2023-01-18 18:21:17 +01:00
|
|
|
})
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
describe("GET /api/:tableId/rows/:rowId", () => {
|
2023-01-19 18:23:48 +01:00
|
|
|
const getRow = (tableId: string | undefined, rowId?: string | undefined) =>
|
|
|
|
makeRequest("get", `/api/${tableId}/rows/${rowId}`)
|
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("given than a table have a single row", () => {
|
|
|
|
let rowData: PrimaryRowData, row: Row
|
|
|
|
beforeEach(async () => {
|
|
|
|
const [createdRow] = await populatePrimaryRows(1)
|
|
|
|
rowData = createdRow.rowData
|
|
|
|
row = createdRow.row
|
|
|
|
})
|
2023-01-18 17:46:40 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
it("the row can be retrieved successfully", async () => {
|
|
|
|
const res = await getRow(primaryPostgresTable._id, row.id)
|
2023-01-18 17:46:40 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.status).toBe(200)
|
2023-01-18 17:46:40 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.body).toEqual(expect.objectContaining(rowData))
|
|
|
|
})
|
2023-01-18 17:46:40 +01:00
|
|
|
})
|
2023-01-18 17:48:18 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("given than a table have a multiple rows", () => {
|
|
|
|
let rows: { row: Row; rowData: PrimaryRowData }[]
|
2023-01-18 17:48:18 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
beforeEach(async () => {
|
2023-02-23 10:50:18 +01:00
|
|
|
rows = await populatePrimaryRows(5)
|
2023-02-07 12:27:46 +01:00
|
|
|
})
|
2023-01-18 17:48:18 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
it("a single row can be retrieved successfully", async () => {
|
|
|
|
const { rowData, row } = _.sample(rows)!
|
2023-01-18 17:48:18 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
const res = await getRow(primaryPostgresTable._id, row.id)
|
2023-01-19 21:09:39 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 21:09:39 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.body).toEqual(expect.objectContaining(rowData))
|
2023-01-19 21:09:39 +01:00
|
|
|
})
|
2023-02-07 12:27:46 +01:00
|
|
|
})
|
2023-01-19 21:09:39 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("given a row with relation data", () => {
|
|
|
|
let row: Row
|
2023-02-23 00:06:57 +01:00
|
|
|
let rowData: {
|
|
|
|
name: string
|
|
|
|
description: string
|
|
|
|
value: number
|
|
|
|
}
|
|
|
|
let foreignRows: ForeignRowsInfo[]
|
|
|
|
|
|
|
|
describe("with all relationship types", () => {
|
|
|
|
beforeEach(async () => {
|
|
|
|
let [createdRow] = await populatePrimaryRows(1, {
|
|
|
|
createOne2Many: true,
|
|
|
|
createMany2One: 3,
|
|
|
|
createMany2Many: 2,
|
|
|
|
})
|
|
|
|
row = createdRow.row
|
|
|
|
rowData = createdRow.rowData
|
|
|
|
foreignRows = createdRow.foreignRows
|
|
|
|
})
|
|
|
|
|
|
|
|
it("only one to many foreign keys are retrieved", async () => {
|
|
|
|
const res = await getRow(primaryPostgresTable._id, row.id)
|
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
|
|
|
|
const one2ManyForeignRows = foreignRows.filter(
|
|
|
|
x => x.relationshipType === RelationshipTypes.ONE_TO_MANY
|
|
|
|
)
|
|
|
|
expect(one2ManyForeignRows).toHaveLength(1)
|
|
|
|
|
|
|
|
expect(res.body).toEqual({
|
|
|
|
...rowData,
|
|
|
|
id: row.id,
|
|
|
|
tableId: row.tableId,
|
|
|
|
_id: expect.any(String),
|
|
|
|
_rev: expect.any(String),
|
2023-02-23 10:39:16 +01:00
|
|
|
[`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]:
|
|
|
|
one2ManyForeignRows[0].row.id,
|
2023-02-23 00:06:57 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
expect(res.body[o2mInfo.fieldName]).toBeUndefined()
|
2023-02-07 12:27:46 +01:00
|
|
|
})
|
|
|
|
})
|
2023-01-19 21:09:39 +01:00
|
|
|
|
2023-02-23 00:06:57 +01:00
|
|
|
describe("with only one to many", () => {
|
|
|
|
beforeEach(async () => {
|
|
|
|
let [createdRow] = await populatePrimaryRows(1, {
|
|
|
|
createOne2Many: true,
|
|
|
|
})
|
|
|
|
row = createdRow.row
|
|
|
|
rowData = createdRow.rowData
|
|
|
|
foreignRows = createdRow.foreignRows
|
|
|
|
})
|
2023-01-19 21:09:39 +01:00
|
|
|
|
2023-02-23 00:06:57 +01:00
|
|
|
it("only one to many foreign keys are retrieved", async () => {
|
|
|
|
const res = await getRow(primaryPostgresTable._id, row.id)
|
2023-02-07 12:27:46 +01:00
|
|
|
|
2023-02-23 00:06:57 +01:00
|
|
|
expect(res.status).toBe(200)
|
|
|
|
|
|
|
|
expect(foreignRows).toHaveLength(1)
|
|
|
|
|
|
|
|
expect(res.body).toEqual({
|
|
|
|
...rowData,
|
|
|
|
id: row.id,
|
|
|
|
tableId: row.tableId,
|
|
|
|
_id: expect.any(String),
|
|
|
|
_rev: expect.any(String),
|
2023-02-23 10:39:16 +01:00
|
|
|
[`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]:
|
|
|
|
foreignRows[0].row.id,
|
2023-02-23 00:06:57 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
expect(res.body[o2mInfo.fieldName]).toBeUndefined()
|
2023-02-07 12:27:46 +01:00
|
|
|
})
|
2023-02-23 00:06:57 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
describe("with only many to one", () => {
|
|
|
|
beforeEach(async () => {
|
|
|
|
let [createdRow] = await populatePrimaryRows(1, {
|
|
|
|
createMany2One: 3,
|
|
|
|
})
|
|
|
|
row = createdRow.row
|
|
|
|
rowData = createdRow.rowData
|
|
|
|
foreignRows = createdRow.foreignRows
|
|
|
|
})
|
|
|
|
|
|
|
|
it("only one to many foreign keys are retrieved", async () => {
|
|
|
|
const res = await getRow(primaryPostgresTable._id, row.id)
|
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
|
|
|
|
expect(foreignRows).toHaveLength(3)
|
|
|
|
|
|
|
|
expect(res.body).toEqual({
|
|
|
|
...rowData,
|
|
|
|
id: row.id,
|
|
|
|
tableId: row.tableId,
|
|
|
|
_id: expect.any(String),
|
|
|
|
_rev: expect.any(String),
|
|
|
|
})
|
2023-02-21 10:51:07 +01:00
|
|
|
|
2023-02-23 00:06:57 +01:00
|
|
|
expect(res.body[o2mInfo.fieldName]).toBeUndefined()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe("with only many to many", () => {
|
|
|
|
beforeEach(async () => {
|
|
|
|
let [createdRow] = await populatePrimaryRows(1, {
|
|
|
|
createMany2Many: 2,
|
|
|
|
})
|
|
|
|
row = createdRow.row
|
|
|
|
rowData = createdRow.rowData
|
|
|
|
foreignRows = createdRow.foreignRows
|
|
|
|
})
|
|
|
|
|
|
|
|
it("only one to many foreign keys are retrieved", async () => {
|
|
|
|
const res = await getRow(primaryPostgresTable._id, row.id)
|
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
|
|
|
|
expect(foreignRows).toHaveLength(2)
|
|
|
|
|
|
|
|
expect(res.body).toEqual({
|
|
|
|
...rowData,
|
|
|
|
id: row.id,
|
|
|
|
tableId: row.tableId,
|
|
|
|
_id: expect.any(String),
|
|
|
|
_rev: expect.any(String),
|
|
|
|
})
|
|
|
|
|
|
|
|
expect(res.body[o2mInfo.fieldName]).toBeUndefined()
|
|
|
|
})
|
2023-01-19 21:09:39 +01:00
|
|
|
})
|
|
|
|
})
|
2023-01-18 17:46:40 +01:00
|
|
|
})
|
2023-01-19 12:00:51 +01:00
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
describe("POST /api/:tableId/search", () => {
|
2023-01-19 12:44:48 +01:00
|
|
|
const search = (tableId: string | undefined, body?: object) =>
|
2023-01-19 18:23:48 +01:00
|
|
|
makeRequest("post", `/api/${tableId}/search`, body)
|
2023-01-19 12:44:48 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("search without parameters", () => {
|
|
|
|
describe("given than a table has no rows", () => {
|
|
|
|
it("search without query returns empty", async () => {
|
|
|
|
const res = await search(primaryPostgresTable._id)
|
2023-01-19 12:06:41 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 12:06:41 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.body).toEqual({
|
|
|
|
rows: [],
|
|
|
|
bookmark: null,
|
|
|
|
hasNextPage: false,
|
|
|
|
})
|
2023-02-06 15:54:49 +01:00
|
|
|
})
|
2023-01-19 12:20:20 +01:00
|
|
|
})
|
2023-01-19 12:06:41 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("given than a table has multiple rows", () => {
|
2023-01-19 12:20:20 +01:00
|
|
|
const rowsCount = 6
|
2023-02-07 12:27:46 +01:00
|
|
|
let rows: {
|
|
|
|
row: Row
|
|
|
|
rowData: PrimaryRowData
|
|
|
|
}[]
|
|
|
|
beforeEach(async () => {
|
|
|
|
rows = await populatePrimaryRows(rowsCount)
|
|
|
|
})
|
2023-01-19 12:00:51 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
it("search without query returns all of them", async () => {
|
|
|
|
const res = await search(primaryPostgresTable._id)
|
2023-01-19 12:00:51 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 12:00:51 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.body).toEqual({
|
|
|
|
rows: expect.arrayContaining(
|
|
|
|
rows.map(r => expect.objectContaining(r.rowData))
|
|
|
|
),
|
|
|
|
bookmark: null,
|
|
|
|
hasNextPage: false,
|
|
|
|
})
|
|
|
|
expect(res.body.rows).toHaveLength(rowsCount)
|
2023-01-19 18:23:48 +01:00
|
|
|
})
|
2023-01-19 12:20:20 +01:00
|
|
|
})
|
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("given than multiple tables have multiple rows", () => {
|
2023-01-19 12:20:20 +01:00
|
|
|
const rowsCount = 6
|
2023-02-07 12:27:46 +01:00
|
|
|
beforeEach(async () => {
|
|
|
|
const createRandomTableWithRows = async () =>
|
|
|
|
await config.createRow({
|
|
|
|
tableId: (await createDefaultPgTable())._id,
|
|
|
|
title: generator.name(),
|
|
|
|
})
|
2023-01-19 12:20:20 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
await createRandomTableWithRows()
|
|
|
|
await createRandomTableWithRows()
|
2023-02-07 11:46:34 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
await populatePrimaryRows(rowsCount)
|
2023-01-19 12:20:20 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
await createRandomTableWithRows()
|
|
|
|
})
|
|
|
|
it("search only return the requested ones", async () => {
|
|
|
|
const res = await search(primaryPostgresTable._id)
|
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 12:20:20 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.body.rows).toHaveLength(rowsCount)
|
|
|
|
})
|
2023-01-19 12:20:20 +01:00
|
|
|
})
|
2023-01-19 12:00:51 +01:00
|
|
|
})
|
2023-01-19 12:06:41 +01:00
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
it("Querying by a string field returns the rows with field containing or starting by that value", async () => {
|
2023-02-02 11:43:18 +01:00
|
|
|
const name = generator.name()
|
2023-01-19 12:20:20 +01:00
|
|
|
const rowsToFilter = [
|
|
|
|
...Array(2).fill({
|
|
|
|
name,
|
2023-02-02 11:43:18 +01:00
|
|
|
description: generator.paragraph(),
|
2023-02-06 18:30:33 +01:00
|
|
|
value: generator.age(),
|
2023-01-19 12:20:20 +01:00
|
|
|
}),
|
|
|
|
...Array(2).fill({
|
2023-02-02 11:43:18 +01:00
|
|
|
name: `${name}${utils.newid()}`,
|
|
|
|
description: generator.paragraph(),
|
2023-02-06 18:30:33 +01:00
|
|
|
value: generator.age(),
|
2023-01-19 12:20:20 +01:00
|
|
|
}),
|
|
|
|
]
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
await populatePrimaryRows(3)
|
2023-01-19 12:20:20 +01:00
|
|
|
for (const row of rowsToFilter) {
|
2023-02-07 11:46:34 +01:00
|
|
|
await createPrimaryRow({
|
|
|
|
rowData: row,
|
|
|
|
})
|
2023-01-19 12:20:20 +01:00
|
|
|
}
|
2023-02-07 11:46:34 +01:00
|
|
|
await populatePrimaryRows(1)
|
2023-01-19 12:06:41 +01:00
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
const res = await search(primaryPostgresTable._id, {
|
2023-01-19 12:44:48 +01:00
|
|
|
query: {
|
|
|
|
string: {
|
|
|
|
name,
|
2023-01-19 12:20:20 +01:00
|
|
|
},
|
2023-01-19 12:44:48 +01:00
|
|
|
},
|
|
|
|
})
|
2023-01-19 12:06:41 +01:00
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
|
2023-01-19 18:23:48 +01:00
|
|
|
expect(res.body).toEqual({
|
|
|
|
rows: expect.arrayContaining(rowsToFilter.map(expect.objectContaining)),
|
2023-02-06 15:54:49 +01:00
|
|
|
bookmark: null,
|
|
|
|
hasNextPage: false,
|
2023-01-19 18:23:48 +01:00
|
|
|
})
|
|
|
|
expect(res.body.rows).toHaveLength(4)
|
2023-01-19 12:06:41 +01:00
|
|
|
})
|
2023-01-19 12:35:00 +01:00
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
it("Querying respects the limit fields", async () => {
|
|
|
|
await populatePrimaryRows(6)
|
2023-01-19 12:35:00 +01:00
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
const res = await search(primaryPostgresTable._id, {
|
2023-01-19 12:44:48 +01:00
|
|
|
limit: 2,
|
|
|
|
})
|
2023-01-19 12:35:00 +01:00
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
|
|
|
|
2023-01-19 18:23:48 +01:00
|
|
|
expect(res.body.rows).toHaveLength(2)
|
2023-01-19 12:35:00 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
describe("sort", () => {
|
|
|
|
beforeEach(async () => {
|
2023-02-07 11:46:34 +01:00
|
|
|
const defaultValue = generateRandomPrimaryRowData()
|
2023-01-19 12:35:00 +01:00
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
await createPrimaryRow({
|
|
|
|
rowData: {
|
2023-01-19 12:35:00 +01:00
|
|
|
...defaultValue,
|
|
|
|
name: "d",
|
|
|
|
value: 3,
|
|
|
|
},
|
2023-02-07 11:46:34 +01:00
|
|
|
})
|
|
|
|
await createPrimaryRow({
|
|
|
|
rowData: { ...defaultValue, name: "aaa", value: 40 },
|
|
|
|
})
|
|
|
|
await createPrimaryRow({
|
|
|
|
rowData: { ...defaultValue, name: "ccccc", value: -5 },
|
|
|
|
})
|
|
|
|
await createPrimaryRow({
|
|
|
|
rowData: { ...defaultValue, name: "bb", value: 0 },
|
|
|
|
})
|
2023-01-19 12:35:00 +01:00
|
|
|
})
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
it("Querying respects the sort order when sorting ascending by a string value", async () => {
|
|
|
|
const res = await search(primaryPostgresTable._id, {
|
2023-01-19 18:23:48 +01:00
|
|
|
sort: "name",
|
|
|
|
sortOrder: "ascending",
|
|
|
|
sortType: "string",
|
2023-01-19 12:44:48 +01:00
|
|
|
})
|
2023-01-19 12:35:00 +01:00
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 18:23:48 +01:00
|
|
|
expect(res.body.rows).toEqual([
|
2023-01-19 12:35:00 +01:00
|
|
|
expect.objectContaining({ name: "aaa" }),
|
|
|
|
expect.objectContaining({ name: "bb" }),
|
|
|
|
expect.objectContaining({ name: "ccccc" }),
|
|
|
|
expect.objectContaining({ name: "d" }),
|
|
|
|
])
|
|
|
|
})
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
it("Querying respects the sort order when sorting descending by a string value", async () => {
|
|
|
|
const res = await search(primaryPostgresTable._id, {
|
2023-01-19 18:23:48 +01:00
|
|
|
sort: "name",
|
|
|
|
sortOrder: "descending",
|
|
|
|
sortType: "string",
|
2023-01-19 12:44:48 +01:00
|
|
|
})
|
2023-01-19 12:35:00 +01:00
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 18:23:48 +01:00
|
|
|
expect(res.body.rows).toEqual([
|
2023-01-19 12:35:00 +01:00
|
|
|
expect.objectContaining({ name: "d" }),
|
|
|
|
expect.objectContaining({ name: "ccccc" }),
|
|
|
|
expect.objectContaining({ name: "bb" }),
|
|
|
|
expect.objectContaining({ name: "aaa" }),
|
|
|
|
])
|
|
|
|
})
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
it("Querying respects the sort order when sorting ascending by a numeric value", async () => {
|
|
|
|
const res = await search(primaryPostgresTable._id, {
|
2023-01-19 18:23:48 +01:00
|
|
|
sort: "value",
|
|
|
|
sortOrder: "ascending",
|
|
|
|
sortType: "number",
|
2023-01-19 12:44:48 +01:00
|
|
|
})
|
2023-01-19 12:35:00 +01:00
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 18:23:48 +01:00
|
|
|
expect(res.body.rows).toEqual([
|
2023-01-19 12:35:00 +01:00
|
|
|
expect.objectContaining({ value: -5 }),
|
|
|
|
expect.objectContaining({ value: 0 }),
|
|
|
|
expect.objectContaining({ value: 3 }),
|
|
|
|
expect.objectContaining({ value: 40 }),
|
|
|
|
])
|
|
|
|
})
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
it("Querying respects the sort order when sorting descending by a numeric value", async () => {
|
|
|
|
const res = await search(primaryPostgresTable._id, {
|
2023-01-19 18:23:48 +01:00
|
|
|
sort: "value",
|
|
|
|
sortOrder: "descending",
|
|
|
|
sortType: "number",
|
2023-01-19 12:44:48 +01:00
|
|
|
})
|
2023-01-19 12:35:00 +01:00
|
|
|
|
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 18:23:48 +01:00
|
|
|
expect(res.body.rows).toEqual([
|
2023-01-19 12:35:00 +01:00
|
|
|
expect.objectContaining({ value: 40 }),
|
|
|
|
expect.objectContaining({ value: 3 }),
|
|
|
|
expect.objectContaining({ value: 0 }),
|
|
|
|
expect.objectContaining({ value: -5 }),
|
|
|
|
])
|
|
|
|
})
|
|
|
|
})
|
2023-01-19 12:00:51 +01:00
|
|
|
})
|
2023-01-19 12:44:48 +01:00
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
describe("GET /api/:tableId/:rowId/enrich", () => {
|
2023-01-19 21:09:39 +01:00
|
|
|
const getAll = (tableId: string | undefined, rowId: string | undefined) =>
|
|
|
|
makeRequest("get", `/api/${tableId}/${rowId}/enrich`)
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("given a row with relation data", () => {
|
2023-02-23 00:06:57 +01:00
|
|
|
let row: Row, rowData: PrimaryRowData, foreignRows: ForeignRowsInfo[]
|
2023-02-07 12:27:46 +01:00
|
|
|
|
2023-02-23 10:50:18 +01:00
|
|
|
describe("with all relationship types", () => {
|
2023-02-23 00:06:57 +01:00
|
|
|
beforeEach(async () => {
|
|
|
|
rowData = generateRandomPrimaryRowData()
|
|
|
|
const rowsInfo = await createPrimaryRow({
|
|
|
|
rowData,
|
2023-02-23 10:50:18 +01:00
|
|
|
createForeignRows: {
|
|
|
|
createOne2Many: true,
|
|
|
|
createMany2One: 3,
|
|
|
|
createMany2Many: 2,
|
|
|
|
},
|
2023-02-23 00:06:57 +01:00
|
|
|
})
|
2023-01-19 21:09:39 +01:00
|
|
|
|
2023-02-23 00:06:57 +01:00
|
|
|
row = rowsInfo.row
|
|
|
|
foreignRows = rowsInfo.foreignRows
|
|
|
|
})
|
2023-01-19 21:09:39 +01:00
|
|
|
|
2023-02-23 10:50:18 +01:00
|
|
|
it("enrich populates the foreign fields", async () => {
|
2023-02-23 00:06:57 +01:00
|
|
|
const res = await getAll(primaryPostgresTable._id, row.id)
|
2023-01-19 21:09:39 +01:00
|
|
|
|
2023-02-23 00:06:57 +01:00
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 21:09:39 +01:00
|
|
|
|
2023-02-23 10:50:18 +01:00
|
|
|
const foreignRowsByType = _.groupBy(
|
|
|
|
foreignRows,
|
|
|
|
x => x.relationshipType
|
|
|
|
)
|
2023-02-23 00:06:57 +01:00
|
|
|
expect(res.body).toEqual({
|
|
|
|
...rowData,
|
2023-02-23 10:39:16 +01:00
|
|
|
[`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]:
|
2023-02-23 10:50:18 +01:00
|
|
|
foreignRowsByType[RelationshipTypes.ONE_TO_MANY][0].row.id,
|
2023-02-23 00:06:57 +01:00
|
|
|
[o2mInfo.fieldName]: [
|
|
|
|
{
|
2023-02-23 10:50:18 +01:00
|
|
|
...foreignRowsByType[RelationshipTypes.ONE_TO_MANY][0].row,
|
2023-02-23 00:06:57 +01:00
|
|
|
_id: expect.any(String),
|
|
|
|
_rev: expect.any(String),
|
|
|
|
},
|
|
|
|
],
|
2023-02-23 10:39:16 +01:00
|
|
|
[m2oInfo.fieldName]: [
|
|
|
|
{
|
2023-02-23 10:50:18 +01:00
|
|
|
...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][0].row,
|
|
|
|
[`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][1].row,
|
2023-02-23 10:39:16 +01:00
|
|
|
[`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id,
|
|
|
|
},
|
|
|
|
{
|
2023-02-23 10:50:18 +01:00
|
|
|
...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][2].row,
|
2023-02-23 10:39:16 +01:00
|
|
|
[`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id,
|
|
|
|
},
|
|
|
|
],
|
2023-02-23 10:50:18 +01:00
|
|
|
[m2mInfo.fieldName]: [
|
|
|
|
{
|
|
|
|
...foreignRowsByType[RelationshipTypes.MANY_TO_MANY][0].row,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
...foreignRowsByType[RelationshipTypes.MANY_TO_MANY][1].row,
|
|
|
|
},
|
|
|
|
],
|
2023-02-23 10:39:16 +01:00
|
|
|
id: row.id,
|
|
|
|
tableId: row.tableId,
|
|
|
|
_id: expect.any(String),
|
|
|
|
_rev: expect.any(String),
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
2023-01-19 21:09:39 +01:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2023-02-07 11:46:34 +01:00
|
|
|
describe("GET /api/:tableId/rows", () => {
|
2023-01-19 17:46:05 +01:00
|
|
|
const getAll = (tableId: string | undefined) =>
|
|
|
|
makeRequest("get", `/api/${tableId}/rows`)
|
2023-01-19 12:44:48 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("given a table with no rows", () => {
|
|
|
|
it("get request returns empty", async () => {
|
|
|
|
const res = await getAll(primaryPostgresTable._id)
|
2023-01-19 12:44:48 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 12:44:48 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.body).toHaveLength(0)
|
|
|
|
})
|
2023-01-19 17:46:05 +01:00
|
|
|
})
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("given a table with multiple rows", () => {
|
2023-01-19 17:46:05 +01:00
|
|
|
const rowsCount = 6
|
2023-02-07 12:27:46 +01:00
|
|
|
let rows: {
|
|
|
|
row: Row
|
2023-02-23 00:06:57 +01:00
|
|
|
foreignRows: ForeignRowsInfo[]
|
2023-02-07 12:27:46 +01:00
|
|
|
rowData: PrimaryRowData
|
|
|
|
}[]
|
|
|
|
beforeEach(async () => {
|
|
|
|
rows = await populatePrimaryRows(rowsCount)
|
|
|
|
})
|
2023-01-19 12:44:48 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
it("get request returns all of them", async () => {
|
|
|
|
const res = await getAll(primaryPostgresTable._id)
|
2023-01-19 12:44:48 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.status).toBe(200)
|
2023-01-19 12:44:48 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.body).toHaveLength(rowsCount)
|
|
|
|
expect(res.body).toEqual(
|
|
|
|
expect.arrayContaining(
|
|
|
|
rows.map(r => expect.objectContaining(r.rowData))
|
|
|
|
)
|
2023-01-19 17:46:05 +01:00
|
|
|
)
|
2023-02-07 12:27:46 +01:00
|
|
|
})
|
2023-01-19 17:46:05 +01:00
|
|
|
})
|
2023-01-19 12:44:48 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
describe("given multiple tables with multiple rows", () => {
|
2023-01-19 17:46:05 +01:00
|
|
|
const rowsCount = 6
|
2023-01-19 12:44:48 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
beforeEach(async () => {
|
|
|
|
const createRandomTableWithRows = async () =>
|
|
|
|
await config.createRow({
|
|
|
|
tableId: (await createDefaultPgTable())._id,
|
|
|
|
title: generator.name(),
|
|
|
|
})
|
2023-01-19 12:44:48 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
await createRandomTableWithRows()
|
|
|
|
await populatePrimaryRows(rowsCount)
|
|
|
|
await createRandomTableWithRows()
|
|
|
|
})
|
|
|
|
|
|
|
|
it("get returns the requested ones", async () => {
|
|
|
|
const res = await getAll(primaryPostgresTable._id)
|
2023-01-19 12:44:48 +01:00
|
|
|
|
2023-02-07 12:27:46 +01:00
|
|
|
expect(res.status).toBe(200)
|
|
|
|
|
|
|
|
expect(res.body).toHaveLength(rowsCount)
|
|
|
|
})
|
2023-01-19 17:46:05 +01:00
|
|
|
})
|
|
|
|
})
|
2023-01-17 18:22:31 +01:00
|
|
|
})
|