Merge branch 'master' into fix/csv-importing-file-refresh
This commit is contained in:
commit
981e2ca89d
|
@ -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) {
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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"],
|
||||||
},
|
},
|
||||||
|
|
|
@ -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"] }])
|
||||||
|
|
|
@ -398,6 +398,7 @@ describe.each([
|
||||||
name: "auto",
|
name: "auto",
|
||||||
autocolumn: true,
|
autocolumn: true,
|
||||||
type: FieldType.AUTO,
|
type: FieldType.AUTO,
|
||||||
|
subtype: AutoFieldSubType.AUTO_ID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
|
|
|
@ -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 = {
|
||||||
}
|
|
||||||
|
|
||||||
const schema: FieldSchema = {
|
|
||||||
type: foundType,
|
type: foundType,
|
||||||
externalType,
|
externalType,
|
||||||
autocolumn,
|
autocolumn,
|
||||||
name,
|
name,
|
||||||
constraints,
|
constraints: {
|
||||||
|
presence,
|
||||||
|
inclusion: options!,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} 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)
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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[]
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue