diff --git a/hosting/couchdb/build-target-paths.sh b/hosting/couchdb/build-target-paths.sh index 67e1765ca8..34227011f4 100644 --- a/hosting/couchdb/build-target-paths.sh +++ b/hosting/couchdb/build-target-paths.sh @@ -2,8 +2,8 @@ echo ${TARGETBUILD} > /buildtarget.txt if [[ "${TARGETBUILD}" = "aas" ]]; then - # Azure AppService uses /home for persisent data & SSH on port 2222 - DATA_DIR=/home + # Azure AppService uses /home for persistent data & SSH on port 2222 + DATA_DIR="${DATA_DIR:-/home}" WEBSITES_ENABLE_APP_SERVICE_STORAGE=true mkdir -p $DATA_DIR/{search,minio,couch} mkdir -p $DATA_DIR/couch/{dbs,views} diff --git a/hosting/scripts/build-target-paths.sh b/hosting/scripts/build-target-paths.sh index 67e1765ca8..34227011f4 100644 --- a/hosting/scripts/build-target-paths.sh +++ b/hosting/scripts/build-target-paths.sh @@ -2,8 +2,8 @@ echo ${TARGETBUILD} > /buildtarget.txt if [[ "${TARGETBUILD}" = "aas" ]]; then - # Azure AppService uses /home for persisent data & SSH on port 2222 - DATA_DIR=/home + # Azure AppService uses /home for persistent data & SSH on port 2222 + DATA_DIR="${DATA_DIR:-/home}" WEBSITES_ENABLE_APP_SERVICE_STORAGE=true mkdir -p $DATA_DIR/{search,minio,couch} mkdir -p $DATA_DIR/couch/{dbs,views} diff --git a/hosting/single/runner.sh b/hosting/single/runner.sh index 9dc7aa25d8..87201c95c0 100644 --- a/hosting/single/runner.sh +++ b/hosting/single/runner.sh @@ -22,7 +22,7 @@ declare -a DOCKER_VARS=("APP_PORT" "APPS_URL" "ARCHITECTURE" "BUDIBASE_ENVIRONME # Azure App Service customisations if [[ "${TARGETBUILD}" = "aas" ]]; then - DATA_DIR=/home + DATA_DIR="${DATA_DIR:-/home}" WEBSITES_ENABLE_APP_SERVICE_STORAGE=true /etc/init.d/ssh start else diff --git a/lerna.json b/lerna.json index 25ec556c56..5605642877 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.13.3", + "version": "2.13.5", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/src/constants/db.ts b/packages/backend-core/src/constants/db.ts index b33b4835a9..bb944556af 100644 --- a/packages/backend-core/src/constants/db.ts +++ b/packages/backend-core/src/constants/db.ts @@ -28,7 +28,7 @@ export enum ViewName { APP_BACKUP_BY_TRIGGER = "by_trigger", } -export const DeprecatedViews = { +export const DeprecatedViews: Record = { [ViewName.USER_BY_EMAIL]: [ // removed due to inaccuracy in view doc filter logic "by_email", diff --git a/packages/backend-core/src/db/views.ts b/packages/backend-core/src/db/views.ts index fbcdbde5fc..5d9c5b74d3 100644 --- a/packages/backend-core/src/db/views.ts +++ b/packages/backend-core/src/db/views.ts @@ -12,12 +12,14 @@ import { Database, DatabaseQueryOpts, Document, + DesignDocument, + DBView, } from "@budibase/types" import env from "../environment" const DESIGN_DB = "_design/database" -function DesignDoc() { +function DesignDoc(): DesignDocument { return { _id: DESIGN_DB, // view collation information, read before writing any complex views: @@ -26,20 +28,14 @@ function DesignDoc() { } } -interface DesignDocument { - views: any -} - async function removeDeprecated(db: Database, viewName: ViewName) { - // @ts-ignore if (!DeprecatedViews[viewName]) { return } try { const designDoc = await db.get(DESIGN_DB) - // @ts-ignore for (let deprecatedNames of DeprecatedViews[viewName]) { - delete designDoc.views[deprecatedNames] + delete designDoc.views?.[deprecatedNames] } await db.put(designDoc) } catch (err) { @@ -48,18 +44,18 @@ async function removeDeprecated(db: Database, viewName: ViewName) { } export async function createView( - db: any, + db: Database, viewJs: string, viewName: string ): Promise { let designDoc try { - designDoc = (await db.get(DESIGN_DB)) as DesignDocument + designDoc = await db.get(DESIGN_DB) } catch (err) { // no design doc, make one designDoc = DesignDoc() } - const view = { + const view: DBView = { map: viewJs, } designDoc.views = { diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItemHeader.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItemHeader.svelte index 0c7ac3d27d..3c9e1a13b1 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItemHeader.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItemHeader.svelte @@ -13,13 +13,13 @@ export let idx export let addLooping export let deleteStep - + export let enableNaming = true let validRegex = /^[A-Za-z0-9_\s]+$/ let typing = false const dispatch = createEventDispatcher() - $: stepNames = $selectedAutomation.definition.stepNames + $: stepNames = $selectedAutomation?.definition.stepNames $: automationName = stepNames?.[block.id] || block?.name || "" $: automationNameError = getAutomationNameError(automationName) $: status = updateStatus(testResult, isTrigger) @@ -32,7 +32,7 @@ )?.[0] } } - $: loopBlock = $selectedAutomation.definition.steps.find( + $: loopBlock = $selectedAutomation?.definition.steps.find( x => x.blockToLoop === block?.id ) @@ -126,24 +126,33 @@ Step {idx} {/if} - { - automationName = e.target.value.trim() - }} - on:click={startTyping} - on:blur={async () => { - typing = false - if (automationNameError) { - automationName = stepNames[block.id] || block?.name - } else { - await saveName() - } - }} - /> + + {#if enableNaming} + { + automationName = e.target.value.trim() + }} + on:click={startTyping} + on:blur={async () => { + typing = false + if (automationNameError) { + automationName = stepNames[block.id] || block?.name + } else { + await saveName() + } + }} + /> + {:else} +
+ {automationName} +
+ {/if}
@@ -178,9 +187,11 @@ {/if} - - - + {#if !isHeaderTrigger} + + + + {/if} {/if} {#if !showTestStatus} {#if block.stepId !== ActionStepID.LOOP} (openBlocks[block.id] = !openBlocks[block.id])} isTrigger={idx === 0} diff --git a/packages/builder/src/pages/builder/app/[application]/settings/automation-history/_components/HistoryDetailsPanel.svelte b/packages/builder/src/pages/builder/app/[application]/settings/automation-history/_components/HistoryDetailsPanel.svelte index 5b9c925130..cde76fa1c0 100644 --- a/packages/builder/src/pages/builder/app/[application]/settings/automation-history/_components/HistoryDetailsPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/settings/automation-history/_components/HistoryDetailsPanel.svelte @@ -56,7 +56,7 @@ {/if} {#key history}
- +
{/key} diff --git a/packages/server/src/api/controllers/layout.ts b/packages/server/src/api/controllers/layout.ts index 2a359592c7..69e4ad91ed 100644 --- a/packages/server/src/api/controllers/layout.ts +++ b/packages/server/src/api/controllers/layout.ts @@ -1,7 +1,7 @@ import { EMPTY_LAYOUT } from "../../constants/layouts" import { generateLayoutID, getScreenParams } from "../../db/utils" import { events, context } from "@budibase/backend-core" -import { BBContext } from "@budibase/types" +import { BBContext, Layout } from "@budibase/types" export async function save(ctx: BBContext) { const db = context.getAppDB() @@ -30,7 +30,7 @@ export async function destroy(ctx: BBContext) { layoutRev = ctx.params.layoutRev const layoutsUsedByScreens = ( - await db.allDocs( + await db.allDocs( getScreenParams(null, { include_docs: true, }) diff --git a/packages/server/src/api/controllers/table/utils.ts b/packages/server/src/api/controllers/table/utils.ts index da1573715c..ee295ff7af 100644 --- a/packages/server/src/api/controllers/table/utils.ts +++ b/packages/server/src/api/controllers/table/utils.ts @@ -333,29 +333,33 @@ export async function checkForViewUpdates( columnRename?: RenameColumn ) { const views = await getViews() - const tableViews = views.filter(view => view.meta.tableId === table._id) + const tableViews = views.filter(view => view.meta?.tableId === table._id) // Check each table view to see if impacted by this table action for (let view of tableViews) { let needsUpdated = false + const viewMetadata = view.meta as any + if (!viewMetadata) { + continue + } // First check for renames, otherwise check for deletions if (columnRename) { // Update calculation field if required - if (view.meta.field === columnRename.old) { - view.meta.field = columnRename.updated + if (viewMetadata.field === columnRename.old) { + viewMetadata.field = columnRename.updated needsUpdated = true } // Update group by field if required - if (view.meta.groupBy === columnRename.old) { - view.meta.groupBy = columnRename.updated + if (viewMetadata.groupBy === columnRename.old) { + viewMetadata.groupBy = columnRename.updated needsUpdated = true } // Update filters if required - if (view.meta.filters) { - view.meta.filters.forEach((filter: any) => { + if (viewMetadata.filters) { + viewMetadata.filters.forEach((filter: any) => { if (filter.key === columnRename.old) { filter.key = columnRename.updated needsUpdated = true @@ -365,26 +369,26 @@ export async function checkForViewUpdates( } else if (deletedColumns) { deletedColumns.forEach((column: string) => { // Remove calculation statement if required - if (view.meta.field === column) { - delete view.meta.field - delete view.meta.calculation - delete view.meta.groupBy + if (viewMetadata.field === column) { + delete viewMetadata.field + delete viewMetadata.calculation + delete viewMetadata.groupBy needsUpdated = true } // Remove group by field if required - if (view.meta.groupBy === column) { - delete view.meta.groupBy + if (viewMetadata.groupBy === column) { + delete viewMetadata.groupBy needsUpdated = true } // Remove filters referencing deleted field if required - if (view.meta.filters && view.meta.filters.length) { - const initialLength = view.meta.filters.length - view.meta.filters = view.meta.filters.filter((filter: any) => { + if (viewMetadata.filters && viewMetadata.filters.length) { + const initialLength = viewMetadata.filters.length + viewMetadata.filters = viewMetadata.filters.filter((filter: any) => { return filter.key !== column }) - if (initialLength !== view.meta.filters.length) { + if (initialLength !== viewMetadata.filters.length) { needsUpdated = true } } @@ -397,15 +401,16 @@ export async function checkForViewUpdates( (field: any) => field.name == view.groupBy ) const newViewTemplate = viewTemplate( - view.meta, + viewMetadata, groupByField?.type === FieldTypes.ARRAY ) - await saveView(null, view.name, newViewTemplate) - if (!newViewTemplate.meta.schema) { - newViewTemplate.meta.schema = table.schema + const viewName = view.name! + await saveView(null, viewName, newViewTemplate) + if (!newViewTemplate.meta?.schema) { + newViewTemplate.meta!.schema = table.schema } - if (table.views?.[view.name]) { - table.views[view.name] = newViewTemplate.meta as View + if (table.views?.[viewName]) { + table.views[viewName] = newViewTemplate.meta as View } } } diff --git a/packages/server/src/api/controllers/view/utils.ts b/packages/server/src/api/controllers/view/utils.ts index 9ffa091a8c..7f9ae1a9bc 100644 --- a/packages/server/src/api/controllers/view/utils.ts +++ b/packages/server/src/api/controllers/view/utils.ts @@ -8,13 +8,13 @@ import { import env from "../../../environment" import { context } from "@budibase/backend-core" import viewBuilder from "./viewBuilder" -import { Database } from "@budibase/types" +import { Database, DBView, DesignDocument, InMemoryView } from "@budibase/types" export async function getView(viewName: string) { const db = context.getAppDB() if (env.SELF_HOSTED) { - const designDoc = await db.get("_design/database") - return designDoc.views[viewName] + const designDoc = await db.get("_design/database") + return designDoc.views?.[viewName] } else { // This is a table view, don't read the view from the DB if (viewName.startsWith(DocumentType.TABLE + SEPARATOR)) { @@ -22,7 +22,7 @@ export async function getView(viewName: string) { } try { - const viewDoc = await db.get(generateMemoryViewID(viewName)) + const viewDoc = await db.get(generateMemoryViewID(viewName)) return viewDoc.view } catch (err: any) { // Return null when PouchDB doesn't found the view @@ -35,25 +35,28 @@ export async function getView(viewName: string) { } } -export async function getViews() { +export async function getViews(): Promise { const db = context.getAppDB() - const response = [] + const response: DBView[] = [] if (env.SELF_HOSTED) { - const designDoc = await db.get("_design/database") - for (let name of Object.keys(designDoc.views)) { + const designDoc = await db.get("_design/database") + for (let name of Object.keys(designDoc.views || {})) { // Only return custom views, not built ins const viewNames = Object.values(ViewName) as string[] if (viewNames.indexOf(name) !== -1) { continue } - response.push({ - name, - ...designDoc.views[name], - }) + const view = designDoc.views?.[name] + if (view) { + response.push({ + name, + ...view, + }) + } } } else { const views = ( - await db.allDocs( + await db.allDocs( getMemoryViewParams({ include_docs: true, }) @@ -72,11 +75,11 @@ export async function getViews() { export async function saveView( originalName: string | null, viewName: string, - viewTemplate: any + viewTemplate: DBView ) { const db = context.getAppDB() if (env.SELF_HOSTED) { - const designDoc = await db.get("_design/database") + const designDoc = await db.get("_design/database") designDoc.views = { ...designDoc.views, [viewName]: viewTemplate, @@ -89,17 +92,17 @@ export async function saveView( } else { const id = generateMemoryViewID(viewName) const originalId = originalName ? generateMemoryViewID(originalName) : null - const viewDoc: any = { + const viewDoc: InMemoryView = { _id: id, view: viewTemplate, name: viewName, - tableId: viewTemplate.meta.tableId, + tableId: viewTemplate.meta!.tableId, } try { - const old = await db.get(id) + const old = await db.get(id) if (originalId) { - const originalDoc = await db.get(originalId) - await db.remove(originalDoc._id, originalDoc._rev) + const originalDoc = await db.get(originalId) + await db.remove(originalDoc._id!, originalDoc._rev) } if (old && old._rev) { viewDoc._rev = old._rev @@ -114,52 +117,65 @@ export async function saveView( export async function deleteView(viewName: string) { const db = context.getAppDB() if (env.SELF_HOSTED) { - const designDoc = await db.get("_design/database") - const view = designDoc.views[viewName] - delete designDoc.views[viewName] + const designDoc = await db.get("_design/database") + const view = designDoc.views?.[viewName] + delete designDoc.views?.[viewName] await db.put(designDoc) return view } else { const id = generateMemoryViewID(viewName) - const viewDoc = await db.get(id) - await db.remove(viewDoc._id, viewDoc._rev) + const viewDoc = await db.get(id) + await db.remove(viewDoc._id!, viewDoc._rev) return viewDoc.view } } export async function migrateToInMemoryView(db: Database, viewName: string) { // delete the view initially - const designDoc = await db.get("_design/database") + const designDoc = await db.get("_design/database") + const meta = designDoc.views?.[viewName].meta + if (!meta) { + throw new Error("Unable to migrate view - no metadata") + } // run the view back through the view builder to update it - const view = viewBuilder(designDoc.views[viewName].meta) - delete designDoc.views[viewName] + const view = viewBuilder(meta) + delete designDoc.views?.[viewName] await db.put(designDoc) - await exports.saveView(db, null, viewName, view) + await saveView(null, viewName, view) } export async function migrateToDesignView(db: Database, viewName: string) { - let view = await db.get(generateMemoryViewID(viewName)) - const designDoc = await db.get("_design/database") - designDoc.views[viewName] = viewBuilder(view.view.meta) + let view = await db.get(generateMemoryViewID(viewName)) + const designDoc = await db.get("_design/database") + const meta = view.view.meta + if (!meta) { + throw new Error("Unable to migrate view - no metadata") + } + if (!designDoc.views) { + designDoc.views = {} + } + designDoc.views[viewName] = viewBuilder(meta) await db.put(designDoc) - await db.remove(view._id, view._rev) + await db.remove(view._id!, view._rev) } export async function getFromDesignDoc(db: Database, viewName: string) { - const designDoc = await db.get("_design/database") - let view = designDoc.views[viewName] + const designDoc = await db.get("_design/database") + let view = designDoc.views?.[viewName] if (view == null) { throw { status: 404, message: "Unable to get view" } } return view } -export async function getFromMemoryDoc(db: Database, viewName: string) { - let view = await db.get(generateMemoryViewID(viewName)) +export async function getFromMemoryDoc( + db: Database, + viewName: string +): Promise { + let view = await db.get(generateMemoryViewID(viewName)) if (view) { - view = view.view + return view.view } else { throw { status: 404, message: "Unable to get view" } } - return view } diff --git a/packages/server/src/api/controllers/view/viewBuilder.ts b/packages/server/src/api/controllers/view/viewBuilder.ts index cbe7e72d04..3df9df6657 100644 --- a/packages/server/src/api/controllers/view/viewBuilder.ts +++ b/packages/server/src/api/controllers/view/viewBuilder.ts @@ -1,13 +1,4 @@ -import { ViewFilter } from "@budibase/types" - -type ViewTemplateOpts = { - field: string - tableId: string - groupBy: string - filters: ViewFilter[] - calculation: string - groupByMulti: boolean -} +import { ViewFilter, ViewTemplateOpts, DBView } from "@budibase/types" const TOKEN_MAP: Record = { EQUALS: "===", @@ -146,7 +137,7 @@ function parseEmitExpression(field: string, groupBy: string) { export default function ( { field, tableId, groupBy, filters = [], calculation }: ViewTemplateOpts, groupByMulti?: boolean -) { +): DBView { // first filter can't have a conjunction if (filters && filters.length > 0 && filters[0].conjunction) { delete filters[0].conjunction diff --git a/packages/server/src/api/controllers/view/views.ts b/packages/server/src/api/controllers/view/views.ts index 86deff09ef..d311565524 100644 --- a/packages/server/src/api/controllers/view/views.ts +++ b/packages/server/src/api/controllers/view/views.ts @@ -47,8 +47,11 @@ export async function save(ctx: Ctx) { // add views to table document if (!table.views) table.views = {} - if (!view.meta.schema) { - view.meta.schema = table.schema + if (!view.meta?.schema) { + view.meta = { + ...view.meta!, + schema: table.schema, + } } table.views[viewName] = { ...view.meta, name: viewName } if (originalName) { @@ -125,10 +128,13 @@ export async function destroy(ctx: Ctx) { const db = context.getAppDB() const viewName = decodeURIComponent(ctx.params.viewName) const view = await deleteView(viewName) + if (!view || !view.meta) { + ctx.throw(400, "Unable to delete view - no metadata/view not found.") + } const table = await sdk.tables.getTable(view.meta.tableId) delete table.views![viewName] await db.put(table) - await events.view.deleted(view) + await events.view.deleted(view as View) ctx.body = view builderSocket?.emitTableUpdate(ctx, table) @@ -147,7 +153,7 @@ export async function exportView(ctx: Ctx) { ) } - if (view) { + if (view && view.meta) { ctx.params.viewName = viewName // Fetch view rows ctx.query = { diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 48f7ab4f09..c426d59f4e 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -32,6 +32,7 @@ import { structures, } from "@budibase/backend-core/tests" import _ from "lodash" +import * as uuid from "uuid" const timestamp = new Date("2023-01-26T11:48:57.597Z").toISOString() tk.freeze(timestamp) @@ -68,7 +69,7 @@ describe.each([ const generateTableConfig: () => SaveTableRequest = () => { return { - name: generator.word(), + name: uuid.v4(), type: "table", primary: ["id"], primaryDisplay: "name", @@ -481,7 +482,7 @@ describe.each([ }) const createViewResponse = await config.createView({ - name: generator.word(), + name: uuid.v4(), schema: { Country: { visible: true, @@ -816,7 +817,8 @@ describe.each([ RelationshipType.ONE_TO_MANY, ["link"], { - name: generator.word(), + // Making sure that the combined table name + column name is within postgres limits + name: uuid.v4().replace(/-/g, "").substring(0, 16), type: "table", primary: ["id"], primaryDisplay: "id", @@ -949,7 +951,7 @@ describe.each([ describe("view 2.0", () => { async function userTable(): Promise { return { - name: `users_${generator.word()}`, + name: `users_${uuid.v4()}`, sourceId: INTERNAL_TABLE_SOURCE_ID, sourceType: TableSourceType.INTERNAL, type: "table", @@ -1133,7 +1135,7 @@ describe.each([ const viewSchema = { age: { visible: true }, name: { visible: true } } async function userTable(): Promise
{ return { - name: `users_${generator.word()}`, + name: `users_${uuid.v4()}`, sourceId: INTERNAL_TABLE_SOURCE_ID, sourceType: TableSourceType.INTERNAL, type: "table", @@ -1630,7 +1632,7 @@ describe.each([ }), (tableId: string) => config.api.row.save(tableId, { - name: generator.word(), + name: uuid.v4(), description: generator.paragraph(), tableId, }), diff --git a/packages/server/src/db/inMemoryView.ts b/packages/server/src/db/inMemoryView.ts index 4e9301f4ee..724bc725ce 100644 --- a/packages/server/src/db/inMemoryView.ts +++ b/packages/server/src/db/inMemoryView.ts @@ -1,5 +1,5 @@ import newid from "./newid" -import { Row, View, Document } from "@budibase/types" +import { Row, Document, DBView } from "@budibase/types" // bypass the main application db config // use in memory pouchdb directly @@ -7,7 +7,7 @@ import { db as dbCore } from "@budibase/backend-core" const Pouch = dbCore.getPouch({ inMemory: true }) export async function runView( - view: View, + view: DBView, calculation: string, group: boolean, data: Row[] diff --git a/packages/server/src/sdk/app/rows/search/internal.ts b/packages/server/src/sdk/app/rows/search/internal.ts index e31bda1a15..87a33c0ba0 100644 --- a/packages/server/src/sdk/app/rows/search/internal.ts +++ b/packages/server/src/sdk/app/rows/search/internal.ts @@ -185,8 +185,8 @@ export async function fetchView( group: !!group, }) } else { - const tableId = viewInfo.meta.tableId - const data = await fetchRaw(tableId) + const tableId = viewInfo.meta!.tableId + const data = await fetchRaw(tableId!) response = await inMemoryViews.runView( viewInfo, calculation as string, @@ -200,7 +200,7 @@ export async function fetchView( response.rows = response.rows.map(row => row.doc) let table: Table try { - table = await sdk.tables.getTable(viewInfo.meta.tableId) + table = await sdk.tables.getTable(viewInfo.meta!.tableId) } catch (err) { throw new Error("Unable to retrieve view table.") } diff --git a/packages/types/src/documents/app/layout.ts b/packages/types/src/documents/app/layout.ts index db046e3d92..06542f680d 100644 --- a/packages/types/src/documents/app/layout.ts +++ b/packages/types/src/documents/app/layout.ts @@ -2,4 +2,5 @@ import { Document } from "../document" export interface Layout extends Document { props: any + layoutId?: string } diff --git a/packages/types/src/documents/app/view.ts b/packages/types/src/documents/app/view.ts index 0d79e2c505..b5a22ec592 100644 --- a/packages/types/src/documents/app/view.ts +++ b/packages/types/src/documents/app/view.ts @@ -1,5 +1,24 @@ import { SearchFilter, SortOrder, SortType } from "../../api" import { UIFieldMetadata } from "./table" +import { Document } from "../document" +import { DBView } from "../../sdk" + +export type ViewTemplateOpts = { + field: string + tableId: string + groupBy: string + filters: ViewFilter[] + schema: any + calculation: string + groupByMulti?: boolean +} + +export interface InMemoryView extends Document { + view: DBView + name: string + tableId: string + groupBy?: string +} export interface View { name?: string @@ -10,7 +29,7 @@ export interface View { calculation?: ViewCalculation map?: string reduce?: any - meta?: Record + meta?: ViewTemplateOpts } export interface ViewV2 { diff --git a/packages/types/src/sdk/db.ts b/packages/types/src/sdk/db.ts index 12c53a9561..26807d99ce 100644 --- a/packages/types/src/sdk/db.ts +++ b/packages/types/src/sdk/db.ts @@ -1,5 +1,5 @@ import Nano from "@budibase/nano" -import { AllDocsResponse, AnyDocument, Document } from "../" +import { AllDocsResponse, AnyDocument, Document, ViewTemplateOpts } from "../" import { Writable } from "stream" export enum SearchIndex { @@ -20,6 +20,37 @@ export enum SortOption { DESCENDING = "desc", } +export type IndexAnalyzer = { + name: string + default?: string + fields?: Record +} + +export type DBView = { + name?: string + map: string + reduce?: string + meta?: ViewTemplateOpts + groupBy?: string +} + +export interface DesignDocument extends Document { + // we use this static reference for all design documents + _id: "_design/database" + language?: string + // CouchDB views + views?: { + [viewName: string]: DBView + } + // Lucene indexes + indexes?: { + [indexName: string]: { + index: string + analyzer?: string | IndexAnalyzer + } + } +} + export type CouchFindOptions = { selector: PouchDB.Find.Selector fields?: string[]