Merge branch 'master' into fix/csv-importing-file-refresh

This commit is contained in:
Adria Navarro 2024-07-31 12:11:03 +02:00 committed by GitHub
commit 981e2ca89d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 111 additions and 36 deletions

View File

@ -14,16 +14,20 @@ import { events, HTTPError } from "@budibase/backend-core"
import { import {
BulkImportRequest, BulkImportRequest,
BulkImportResponse, BulkImportResponse,
CsvToJsonRequest,
CsvToJsonResponse,
FetchTablesResponse, FetchTablesResponse,
MigrateRequest, MigrateRequest,
MigrateResponse, MigrateResponse,
Row,
SaveTableRequest, SaveTableRequest,
SaveTableResponse, SaveTableResponse,
Table, Table,
TableResponse, TableResponse,
TableSourceType, TableSourceType,
UserCtx, UserCtx,
ValidateNewTableImportRequest,
ValidateTableImportRequest,
ValidateTableImportResponse,
} from "@budibase/types" } from "@budibase/types"
import sdk from "../../../sdk" import sdk from "../../../sdk"
import { jsonFromCsvString } from "../../../utilities/csv" import { jsonFromCsvString } from "../../../utilities/csv"
@ -144,7 +148,9 @@ export async function bulkImport(
ctx.body = { message: `Bulk rows created.` } ctx.body = { message: `Bulk rows created.` }
} }
export async function csvToJson(ctx: UserCtx) { export async function csvToJson(
ctx: UserCtx<CsvToJsonRequest, CsvToJsonResponse>
) {
const { csvString } = ctx.request.body const { csvString } = ctx.request.body
const result = await jsonFromCsvString(csvString) const result = await jsonFromCsvString(csvString)
@ -153,8 +159,10 @@ export async function csvToJson(ctx: UserCtx) {
ctx.body = result ctx.body = result
} }
export async function validateNewTableImport(ctx: UserCtx) { export async function validateNewTableImport(
const { rows, schema }: { rows: unknown; schema: unknown } = ctx.request.body ctx: UserCtx<ValidateNewTableImportRequest, ValidateTableImportResponse>
) {
const { rows, schema } = ctx.request.body
if (isRows(rows) && isSchema(schema)) { if (isRows(rows) && isSchema(schema)) {
ctx.status = 200 ctx.status = 200
@ -164,8 +172,10 @@ export async function validateNewTableImport(ctx: UserCtx) {
} }
} }
export async function validateExistingTableImport(ctx: UserCtx) { export async function validateExistingTableImport(
const { rows, tableId }: { rows: Row[]; tableId?: string } = ctx.request.body ctx: UserCtx<ValidateTableImportRequest, ValidateTableImportResponse>
) {
const { rows, tableId } = ctx.request.body
let schema = null let schema = null
if (tableId) { if (tableId) {

View File

@ -15,6 +15,7 @@ import {
Table, Table,
TableSchema, TableSchema,
SupportedSqlTypes, SupportedSqlTypes,
JsonFieldSubType,
} from "@budibase/types" } from "@budibase/types"
import { DatabaseName, getDatasource } from "../../../integrations/tests/utils" import { DatabaseName, getDatasource } from "../../../integrations/tests/utils"
import { tableForDatasource } from "../../../tests/utilities/structures" import { tableForDatasource } from "../../../tests/utilities/structures"
@ -288,7 +289,10 @@ describe("/datasources", () => {
name: "options", name: "options",
type: FieldType.OPTIONS, type: FieldType.OPTIONS,
constraints: { constraints: {
presence: { allowEmpty: false }, presence: {
allowEmpty: false,
},
inclusion: [],
}, },
}, },
[FieldType.NUMBER]: { [FieldType.NUMBER]: {
@ -302,6 +306,10 @@ describe("/datasources", () => {
[FieldType.ARRAY]: { [FieldType.ARRAY]: {
name: "array", name: "array",
type: FieldType.ARRAY, type: FieldType.ARRAY,
constraints: {
type: JsonFieldSubType.ARRAY,
inclusion: [],
},
}, },
[FieldType.DATETIME]: { [FieldType.DATETIME]: {
name: "datetime", name: "datetime",

View File

@ -32,6 +32,7 @@ import {
TableSourceType, TableSourceType,
UpdatedRowEventEmitter, UpdatedRowEventEmitter,
TableSchema, TableSchema,
JsonFieldSubType,
} from "@budibase/types" } from "@budibase/types"
import { generator, mocks } from "@budibase/backend-core/tests" import { generator, mocks } from "@budibase/backend-core/tests"
import _, { merge } from "lodash" import _, { merge } from "lodash"
@ -102,7 +103,7 @@ describe.each([
): SaveTableRequest { ): SaveTableRequest {
const defaultSchema: TableSchema = { const defaultSchema: TableSchema = {
id: { id: {
type: FieldType.AUTO, type: FieldType.NUMBER,
name: "id", name: "id",
autocolumn: true, autocolumn: true,
constraints: { constraints: {
@ -384,7 +385,7 @@ describe.each([
const arrayField: FieldSchema = { const arrayField: FieldSchema = {
type: FieldType.ARRAY, type: FieldType.ARRAY,
constraints: { constraints: {
type: "array", type: JsonFieldSubType.ARRAY,
presence: false, presence: false,
inclusion: ["One", "Two", "Three"], inclusion: ["One", "Two", "Three"],
}, },

View File

@ -20,6 +20,7 @@ import {
Datasource, Datasource,
EmptyFilterOption, EmptyFilterOption,
FieldType, FieldType,
JsonFieldSubType,
RelationshipType, RelationshipType,
Row, Row,
RowSearchParams, RowSearchParams,
@ -1494,7 +1495,10 @@ describe.each([
numbers: { numbers: {
name: "numbers", name: "numbers",
type: FieldType.ARRAY, type: FieldType.ARRAY,
constraints: { inclusion: ["one", "two", "three"] }, constraints: {
type: JsonFieldSubType.ARRAY,
inclusion: ["one", "two", "three"],
},
}, },
}) })
await createRows([{ numbers: ["one", "two"] }, { numbers: ["three"] }]) await createRows([{ numbers: ["one", "two"] }, { numbers: ["three"] }])

View File

@ -398,6 +398,7 @@ describe.each([
name: "auto", name: "auto",
autocolumn: true, autocolumn: true,
type: FieldType.AUTO, type: FieldType.AUTO,
subtype: AutoFieldSubType.AUTO_ID,
}, },
}, },
}, },

View File

@ -56,7 +56,7 @@ describe.each([
primary: ["id"], primary: ["id"],
schema: { schema: {
id: { id: {
type: FieldType.AUTO, type: FieldType.NUMBER,
name: "id", name: "id",
autocolumn: true, autocolumn: true,
constraints: { constraints: {
@ -241,7 +241,7 @@ describe.each([
schema: { schema: {
id: { id: {
name: "id", name: "id",
type: FieldType.AUTO, type: FieldType.NUMBER,
autocolumn: true, autocolumn: true,
visible: true, visible: true,
}, },
@ -1555,7 +1555,7 @@ describe.each([
schema: { schema: {
id: { id: {
name: "id", name: "id",
type: FieldType.AUTO, type: FieldType.NUMBER,
autocolumn: true, autocolumn: true,
}, },
name: { name: {

View File

@ -17,6 +17,7 @@ import {
AutoFieldSubType, AutoFieldSubType,
Datasource, Datasource,
FieldType, FieldType,
JsonFieldSubType,
RelationshipType, RelationshipType,
Row, Row,
SourceName, SourceName,
@ -131,7 +132,7 @@ export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = {
"Item Tags": { "Item Tags": {
type: FieldType.ARRAY, type: FieldType.ARRAY,
constraints: { constraints: {
type: FieldType.ARRAY, type: JsonFieldSubType.ARRAY,
presence: { presence: {
allowEmpty: false, allowEmpty: false,
}, },
@ -153,7 +154,7 @@ export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = {
Status: { Status: {
type: FieldType.ARRAY, type: FieldType.ARRAY,
constraints: { constraints: {
type: FieldType.ARRAY, type: JsonFieldSubType.ARRAY,
presence: { presence: {
allowEmpty: false, allowEmpty: false,
}, },
@ -291,7 +292,7 @@ export const DEFAULT_EMPLOYEE_TABLE_SCHEMA: Table = {
"Employee Level": { "Employee Level": {
type: FieldType.ARRAY, type: FieldType.ARRAY,
constraints: { constraints: {
type: FieldType.ARRAY, type: JsonFieldSubType.ARRAY,
presence: false, presence: false,
inclusion: ["Manager", "Junior", "Senior", "Apprentice", "Contractor"], inclusion: ["Manager", "Junior", "Senior", "Apprentice", "Contractor"],
}, },
@ -535,7 +536,7 @@ export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = {
"Expense Tags": { "Expense Tags": {
type: FieldType.ARRAY, type: FieldType.ARRAY,
constraints: { constraints: {
type: FieldType.ARRAY, type: JsonFieldSubType.ARRAY,
presence: { presence: {
allowEmpty: false, allowEmpty: false,
}, },

View File

@ -150,22 +150,28 @@ export function generateColumnDefinition(config: {
}).internal }).internal
} }
const constraints: { let schema: FieldSchema
presence: boolean
inclusion?: string[]
} = {
presence,
}
if (foundType === FieldType.OPTIONS) { if (foundType === FieldType.OPTIONS) {
constraints.inclusion = options schema = {
} type: foundType,
externalType,
const schema: FieldSchema = { autocolumn,
type: foundType, name,
externalType, constraints: {
autocolumn, presence,
name, inclusion: options!,
constraints, },
}
} else {
schema = {
type: foundType,
externalType,
autocolumn,
name,
constraints: {
presence,
},
}
} }
if (schema.type === FieldType.DATETIME) { if (schema.type === FieldType.DATETIME) {
schema.dateOnly = SQL_DATE_ONLY_TYPES.includes(lowerCaseType) schema.dateOnly = SQL_DATE_ONLY_TYPES.includes(lowerCaseType)

View File

@ -55,7 +55,7 @@ describe.each([
schema: { schema: {
id: { id: {
name: "id", name: "id",
type: FieldType.AUTO, type: FieldType.NUMBER,
autocolumn: true, autocolumn: true,
}, },
name: { name: {

View File

@ -37,7 +37,7 @@ export interface PaginatedSearchRowResponse
PaginationResponse {} PaginationResponse {}
export interface ExportRowsRequest { export interface ExportRowsRequest {
rows: string[] rows?: string[]
columns?: string[] columns?: string[]
query?: SearchFilters query?: SearchFilters
sort?: string sort?: string

View File

@ -1,4 +1,4 @@
import { Row, Table, TableRequest, View } from "../../../documents" import { Row, Table, TableRequest, TableSchema, View } from "../../../documents"
import { ViewV2Enriched } from "../../../sdk" import { ViewV2Enriched } from "../../../sdk"
export type TableViewsResponse = { [key: string]: View | ViewV2Enriched } export type TableViewsResponse = { [key: string]: View | ViewV2Enriched }
@ -32,3 +32,28 @@ export interface MigrateRequest {
export interface MigrateResponse { export interface MigrateResponse {
message: string message: string
} }
export interface ValidateNewTableImportRequest {
rows: Row[]
schema: TableSchema
}
export interface ValidateTableImportRequest {
tableId?: string
rows: Row[]
}
export interface ValidateTableImportResponse {
schemaValidation: {
[field: string]: boolean
}
allValid: boolean
invalidColumns: Array<string>
errors: Record<string, string>
}
export interface CsvToJsonRequest {
csvString: string
}
export type CsvToJsonResponse = any[]

View File

@ -64,7 +64,7 @@ export interface AutoColumnFieldMetadata
extends Omit<BaseFieldSchema, "subtype"> { extends Omit<BaseFieldSchema, "subtype"> {
type: FieldType.AUTO type: FieldType.AUTO
autocolumn: true autocolumn: true
subtype?: AutoFieldSubType subtype: AutoFieldSubType
lastID?: number lastID?: number
// if the column was turned to an auto-column for SQL, explains why (primary, foreign etc) // if the column was turned to an auto-column for SQL, explains why (primary, foreign etc)
autoReason?: AutoReason autoReason?: AutoReason
@ -157,6 +157,21 @@ export interface FieldConstraints {
} }
} }
export interface OptionsFieldMetadata extends BaseFieldSchema {
type: FieldType.OPTIONS
constraints: FieldConstraints & {
inclusion: string[]
}
}
export interface ArrayFieldMetadata extends BaseFieldSchema {
type: FieldType.ARRAY
constraints: FieldConstraints & {
type: JsonFieldSubType.ARRAY
inclusion: string[]
}
}
interface BaseFieldSchema extends UIFieldMetadata { interface BaseFieldSchema extends UIFieldMetadata {
type: FieldType type: FieldType
name: string name: string
@ -182,6 +197,8 @@ interface OtherFieldMetadata extends BaseFieldSchema {
| FieldType.BB_REFERENCE_SINGLE | FieldType.BB_REFERENCE_SINGLE
| FieldType.ATTACHMENTS | FieldType.ATTACHMENTS
| FieldType.STRING | FieldType.STRING
| FieldType.ARRAY
| FieldType.OPTIONS
> >
} }
@ -198,6 +215,8 @@ export type FieldSchema =
| JsonFieldMetadata | JsonFieldMetadata
| AttachmentFieldMetadata | AttachmentFieldMetadata
| BBReferenceSingleFieldMetadata | BBReferenceSingleFieldMetadata
| ArrayFieldMetadata
| OptionsFieldMetadata
export interface TableSchema { export interface TableSchema {
[key: string]: FieldSchema [key: string]: FieldSchema