metrics for view joins and grouped filters
This commit is contained in:
parent
9ef6cbd566
commit
3332f2fa22
|
@ -13,8 +13,8 @@ const EXCLUDED_EVENTS: Event[] = [
|
||||||
Event.ROLE_UPDATED,
|
Event.ROLE_UPDATED,
|
||||||
Event.DATASOURCE_UPDATED,
|
Event.DATASOURCE_UPDATED,
|
||||||
Event.QUERY_UPDATED,
|
Event.QUERY_UPDATED,
|
||||||
Event.TABLE_UPDATED,
|
// Event.TABLE_UPDATED,
|
||||||
Event.VIEW_UPDATED,
|
// Event.VIEW_UPDATED,
|
||||||
Event.VIEW_FILTER_UPDATED,
|
Event.VIEW_FILTER_UPDATED,
|
||||||
Event.VIEW_CALCULATION_UPDATED,
|
Event.VIEW_CALCULATION_UPDATED,
|
||||||
Event.AUTOMATION_TRIGGER_UPDATED,
|
Event.AUTOMATION_TRIGGER_UPDATED,
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { publishEvent } from "../events"
|
import { publishEvent } from "../events"
|
||||||
import {
|
import {
|
||||||
Event,
|
Event,
|
||||||
TableExportFormat,
|
FieldType,
|
||||||
Table,
|
Table,
|
||||||
TableCreatedEvent,
|
TableCreatedEvent,
|
||||||
TableUpdatedEvent,
|
|
||||||
TableDeletedEvent,
|
TableDeletedEvent,
|
||||||
TableExportedEvent,
|
TableExportedEvent,
|
||||||
|
TableExportFormat,
|
||||||
TableImportedEvent,
|
TableImportedEvent,
|
||||||
|
TableUpdatedEvent,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
|
||||||
async function created(table: Table, timestamp?: string | number) {
|
async function created(table: Table, timestamp?: string | number) {
|
||||||
|
@ -20,14 +21,34 @@ async function created(table: Table, timestamp?: string | number) {
|
||||||
await publishEvent(Event.TABLE_CREATED, properties, timestamp)
|
await publishEvent(Event.TABLE_CREATED, properties, timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updated(table: Table) {
|
async function updated(oldTable: Table, newTable: Table) {
|
||||||
|
// only publish the event if it has fields we are interested in
|
||||||
|
let defaultValues, aiColumn
|
||||||
|
|
||||||
|
// check that new fields have been added
|
||||||
|
for (const key in newTable.schema) {
|
||||||
|
if (!oldTable.schema[key]) {
|
||||||
|
const newColumn = newTable.schema[key]
|
||||||
|
if ("default" in newColumn) {
|
||||||
|
defaultValues = true
|
||||||
|
}
|
||||||
|
if (newColumn.type === FieldType.AI) {
|
||||||
|
aiColumn = newColumn.operation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const properties: TableUpdatedEvent = {
|
const properties: TableUpdatedEvent = {
|
||||||
tableId: table._id as string,
|
tableId: newTable._id as string,
|
||||||
|
defaultValues,
|
||||||
|
aiColumn,
|
||||||
audited: {
|
audited: {
|
||||||
name: table.name,
|
name: newTable.name,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
await publishEvent(Event.TABLE_UPDATED, properties)
|
if (defaultValues || aiColumn) {
|
||||||
|
await publishEvent(Event.TABLE_UPDATED, properties)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleted(table: Table) {
|
async function deleted(table: Table) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
ViewFilterDeletedEvent,
|
ViewFilterDeletedEvent,
|
||||||
ViewFilterUpdatedEvent,
|
ViewFilterUpdatedEvent,
|
||||||
ViewUpdatedEvent,
|
ViewUpdatedEvent,
|
||||||
|
View,
|
||||||
ViewV2,
|
ViewV2,
|
||||||
ViewCalculation,
|
ViewCalculation,
|
||||||
Table,
|
Table,
|
||||||
|
@ -19,17 +20,27 @@ import {
|
||||||
|
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
async function created(view: Partial<ViewV2>, timestamp?: string | number) {
|
async function created(view: ViewV2, timestamp?: string | number) {
|
||||||
const properties: ViewCreatedEvent = {
|
const properties: ViewCreatedEvent = {
|
||||||
name: view.name,
|
name: view.name,
|
||||||
type: view.type,
|
type: view.type,
|
||||||
|
tableId: view.tableId,
|
||||||
}
|
}
|
||||||
await publishEvent(Event.VIEW_CREATED, properties, timestamp)
|
await publishEvent(Event.VIEW_CREATED, properties, timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updated(view: View) {
|
async function updated(newView: ViewV2) {
|
||||||
|
// // check whether any of the fields are different
|
||||||
|
let viewJoins = 0
|
||||||
|
for (const key in newView.schema) {
|
||||||
|
if (newView.schema[key]?.columns) {
|
||||||
|
viewJoins += Object.keys(newView.schema[key]?.columns).length
|
||||||
|
}
|
||||||
|
}
|
||||||
const properties: ViewUpdatedEvent = {
|
const properties: ViewUpdatedEvent = {
|
||||||
tableId: view.tableId,
|
tableId: newView.tableId,
|
||||||
|
groupedFilters: newView.queryUI?.groups?.length || 0,
|
||||||
|
viewJoins,
|
||||||
}
|
}
|
||||||
await publishEvent(Event.VIEW_UPDATED, properties)
|
await publishEvent(Event.VIEW_UPDATED, properties)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,13 +45,13 @@ export async function updateTable(
|
||||||
inputs.created = true
|
inputs.created = true
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const { datasource, table } = await sdk.tables.external.save(
|
const { datasource, oldTable, table } = await sdk.tables.external.save(
|
||||||
datasourceId!,
|
datasourceId!,
|
||||||
inputs,
|
inputs,
|
||||||
{ tableId, renaming }
|
{ tableId, renaming }
|
||||||
)
|
)
|
||||||
builderSocket?.emitDatasourceUpdate(ctx, datasource)
|
builderSocket?.emitDatasourceUpdate(ctx, datasource)
|
||||||
return table
|
return { table, oldTable }
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (err instanceof Error) {
|
if (err instanceof Error) {
|
||||||
ctx.throw(400, err.message)
|
ctx.throw(400, err.message)
|
||||||
|
|
|
@ -119,8 +119,15 @@ export async function save(ctx: UserCtx<SaveTableRequest, SaveTableResponse>) {
|
||||||
await events.table.created(savedTable)
|
await events.table.created(savedTable)
|
||||||
} else {
|
} else {
|
||||||
const api = pickApi({ table })
|
const api = pickApi({ table })
|
||||||
savedTable = await api.updateTable(ctx, renaming)
|
const { table: updatedTable, oldTable } = await api.updateTable(
|
||||||
await events.table.updated(savedTable)
|
ctx,
|
||||||
|
renaming
|
||||||
|
)
|
||||||
|
savedTable = updatedTable
|
||||||
|
|
||||||
|
if (oldTable) {
|
||||||
|
await events.table.updated(oldTable, savedTable)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (renaming) {
|
if (renaming) {
|
||||||
await sdk.views.renameLinkedViews(savedTable, renaming)
|
await sdk.views.renameLinkedViews(savedTable, renaming)
|
||||||
|
|
|
@ -30,14 +30,14 @@ export async function updateTable(
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { table } = await sdk.tables.internal.save(tableToSave, {
|
const { table, oldTable } = await sdk.tables.internal.save(tableToSave, {
|
||||||
userId: ctx.user._id,
|
userId: ctx.user._id,
|
||||||
rowsToImport: rows,
|
rowsToImport: rows,
|
||||||
tableId: ctx.request.body._id,
|
tableId: ctx.request.body._id,
|
||||||
renaming,
|
renaming,
|
||||||
})
|
})
|
||||||
|
|
||||||
return table
|
return { table, oldTable }
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (err instanceof Error) {
|
if (err instanceof Error) {
|
||||||
ctx.throw(400, err.message)
|
ctx.throw(400, err.message)
|
||||||
|
|
|
@ -60,35 +60,31 @@ export async function save(ctx: Ctx) {
|
||||||
existingTable.views[viewName] = existingTable.views[originalName]
|
existingTable.views[viewName] = existingTable.views[originalName]
|
||||||
}
|
}
|
||||||
await db.put(table)
|
await db.put(table)
|
||||||
await handleViewEvents(
|
|
||||||
existingTable.views[viewName] as View,
|
|
||||||
table.views[viewName]
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx.body = table.views[viewName]
|
ctx.body = table.views[viewName]
|
||||||
builderSocket?.emitTableUpdate(ctx, table)
|
builderSocket?.emitTableUpdate(ctx, table)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function calculationEvents(existingView: View, newView: View) {
|
// export async function calculationEvents(existingView: View, newView: View) {
|
||||||
const existingCalculation = existingView && existingView.calculation
|
// const existingCalculation = existingView && existingView.calculation
|
||||||
const newCalculation = newView && newView.calculation
|
// const newCalculation = newView && newView.calculation
|
||||||
|
//
|
||||||
if (existingCalculation && !newCalculation) {
|
// if (existingCalculation && !newCalculation) {
|
||||||
await events.view.calculationDeleted(existingView)
|
// await events.view.calculationDeleted(existingView)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (!existingCalculation && newCalculation) {
|
// if (!existingCalculation && newCalculation) {
|
||||||
await events.view.calculationCreated(newView)
|
// await events.view.calculationCreated(newView)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (
|
// if (
|
||||||
existingCalculation &&
|
// existingCalculation &&
|
||||||
newCalculation &&
|
// newCalculation &&
|
||||||
existingCalculation !== newCalculation
|
// existingCalculation !== newCalculation
|
||||||
) {
|
// ) {
|
||||||
await events.view.calculationUpdated(newView)
|
// await events.view.calculationUpdated(newView)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export async function filterEvents(existingView: View, newView: View) {
|
export async function filterEvents(existingView: View, newView: View) {
|
||||||
const hasExistingFilters = !!(
|
const hasExistingFilters = !!(
|
||||||
|
@ -115,16 +111,6 @@ export async function filterEvents(existingView: View, newView: View) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleViewEvents(existingView: View, newView: View) {
|
|
||||||
if (!existingView) {
|
|
||||||
await events.view.created(newView)
|
|
||||||
} else {
|
|
||||||
await events.view.updated(newView)
|
|
||||||
}
|
|
||||||
await calculationEvents(existingView, newView)
|
|
||||||
await filterEvents(existingView, newView)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function destroy(ctx: Ctx) {
|
export async function destroy(ctx: Ctx) {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
const viewName = decodeURIComponent(ctx.params.viewName)
|
const viewName = decodeURIComponent(ctx.params.viewName)
|
||||||
|
|
|
@ -151,7 +151,7 @@ export async function create(ctx: Ctx<CreateViewRequest, ViewResponse>) {
|
||||||
}
|
}
|
||||||
const result = await sdk.views.create(tableId, parsedView)
|
const result = await sdk.views.create(tableId, parsedView)
|
||||||
|
|
||||||
await events.view.created(view)
|
await events.view.created(result)
|
||||||
|
|
||||||
ctx.status = 201
|
ctx.status = 201
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
|
@ -190,10 +190,11 @@ export async function update(ctx: Ctx<UpdateViewRequest, ViewResponse>) {
|
||||||
primaryDisplay: view.primaryDisplay,
|
primaryDisplay: view.primaryDisplay,
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await sdk.views.update(tableId, parsedView)
|
const { view: result } = await sdk.views.update(tableId, parsedView)
|
||||||
ctx.body = {
|
|
||||||
data: result,
|
await events.view.updated(result)
|
||||||
}
|
|
||||||
|
ctx.body = { data: result }
|
||||||
|
|
||||||
const table = await sdk.tables.getTable(tableId)
|
const table = await sdk.tables.getTable(tableId)
|
||||||
builderSocket?.emitTableUpdate(ctx, table)
|
builderSocket?.emitTableUpdate(ctx, table)
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const backfill = async (appDb: Database, timestamp: string | number) => {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
await events.view.created(view, timestamp)
|
// await events.view.created(view, timestamp)
|
||||||
|
|
||||||
if (view.calculation) {
|
if (view.calculation) {
|
||||||
await events.view.calculationCreated(view, timestamp)
|
await events.view.calculationCreated(view, timestamp)
|
||||||
|
|
|
@ -282,7 +282,7 @@ export async function save(
|
||||||
tableToSave.sql = true
|
tableToSave.sql = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return { datasource: updatedDatasource, table: tableToSave }
|
return { datasource: updatedDatasource, table: tableToSave, oldTable }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function destroy(datasourceId: string, table: Table) {
|
export async function destroy(datasourceId: string, table: Table) {
|
||||||
|
|
|
@ -171,7 +171,7 @@ export async function save(
|
||||||
}
|
}
|
||||||
// has to run after, make sure it has _id
|
// has to run after, make sure it has _id
|
||||||
await runStaticFormulaChecks(table, { oldTable, deletion: false })
|
await runStaticFormulaChecks(table, { oldTable, deletion: false })
|
||||||
return { table }
|
return { table, oldTable }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function destroy(table: Table) {
|
export async function destroy(table: Table) {
|
||||||
|
|
|
@ -63,7 +63,7 @@ export async function create(
|
||||||
export async function update(
|
export async function update(
|
||||||
tableId: string,
|
tableId: string,
|
||||||
view: Readonly<ViewV2>
|
view: Readonly<ViewV2>
|
||||||
): Promise<ViewV2> {
|
): Promise<{ view: ViewV2; existingView: ViewV2 }> {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
|
|
||||||
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
|
@ -87,7 +87,7 @@ export async function update(
|
||||||
delete views[existingView.name]
|
delete views[existingView.name]
|
||||||
views[view.name] = view
|
views[view.name] = view
|
||||||
await db.put(ds)
|
await db.put(ds)
|
||||||
return view
|
return { view, existingView }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function remove(viewId: string): Promise<ViewV2> {
|
export async function remove(viewId: string): Promise<ViewV2> {
|
||||||
|
|
|
@ -315,7 +315,10 @@ export async function create(
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update(tableId: string, view: ViewV2): Promise<ViewV2> {
|
export async function update(
|
||||||
|
tableId: string,
|
||||||
|
view: ViewV2
|
||||||
|
): Promise<{ view: ViewV2; existingView: ViewV2 }> {
|
||||||
await guardViewSchema(tableId, view)
|
await guardViewSchema(tableId, view)
|
||||||
|
|
||||||
return pickApi(tableId).update(tableId, view)
|
return pickApi(tableId).update(tableId, view)
|
||||||
|
|
|
@ -54,7 +54,7 @@ export async function create(
|
||||||
export async function update(
|
export async function update(
|
||||||
tableId: string,
|
tableId: string,
|
||||||
view: Readonly<ViewV2>
|
view: Readonly<ViewV2>
|
||||||
): Promise<ViewV2> {
|
): Promise<{ view: ViewV2; existingView: ViewV2 }> {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
const table = await sdk.tables.getTable(tableId)
|
const table = await sdk.tables.getTable(tableId)
|
||||||
table.views ??= {}
|
table.views ??= {}
|
||||||
|
@ -76,7 +76,7 @@ export async function update(
|
||||||
delete table.views[existingView.name]
|
delete table.views[existingView.name]
|
||||||
table.views[view.name] = view
|
table.views[view.name] = view
|
||||||
await db.put(table)
|
await db.put(table)
|
||||||
return view
|
return { view, existingView }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function remove(viewId: string): Promise<ViewV2> {
|
export async function remove(viewId: string): Promise<ViewV2> {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { BaseEvent, TableExportFormat } from "./event"
|
import { BaseEvent, TableExportFormat } from "./event"
|
||||||
|
import { AIOperationEnum } from "../ai"
|
||||||
|
|
||||||
export interface TableCreatedEvent extends BaseEvent {
|
export interface TableCreatedEvent extends BaseEvent {
|
||||||
tableId: string
|
tableId: string
|
||||||
|
@ -9,6 +10,8 @@ export interface TableCreatedEvent extends BaseEvent {
|
||||||
|
|
||||||
export interface TableUpdatedEvent extends BaseEvent {
|
export interface TableUpdatedEvent extends BaseEvent {
|
||||||
tableId: string
|
tableId: string
|
||||||
|
defaultValues: boolean | undefined
|
||||||
|
aiColumn: AIOperationEnum | undefined
|
||||||
audited: {
|
audited: {
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import { ViewCalculation, ViewV2Schema, ViewV2Type } from "../../documents"
|
import { ViewCalculation, ViewV2Type } from "../../documents"
|
||||||
import { BaseEvent, TableExportFormat } from "./event"
|
import { BaseEvent, TableExportFormat } from "./event"
|
||||||
import { LegacyFilter, SortOrder, SortType, UISearchFilter } from "../../api"
|
|
||||||
import { SearchFilters } from "../search"
|
|
||||||
|
|
||||||
export interface ViewCreatedEvent extends BaseEvent {
|
export interface ViewCreatedEvent extends BaseEvent {
|
||||||
name: string
|
name: string
|
||||||
type?: ViewV2Type
|
type?: ViewV2Type
|
||||||
|
tableId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ViewUpdatedEvent extends BaseEvent {
|
export interface ViewUpdatedEvent extends BaseEvent {
|
||||||
tableId: string
|
tableId: string
|
||||||
|
groupedFilters: number
|
||||||
|
viewJoins: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ViewDeletedEvent extends BaseEvent {
|
export interface ViewDeletedEvent extends BaseEvent {
|
||||||
|
|
Loading…
Reference in New Issue