1
0
Fork 0
mirror of synced 2024-07-09 08:16:34 +12:00

primary and secondary index fields

This commit is contained in:
Martin McKeaveney 2021-02-09 18:49:12 +00:00
parent 05353c7666
commit 9c7a373fb0
8 changed files with 105 additions and 61 deletions

View file

@ -232,7 +232,7 @@ export const getBackendUiStore = () => {
return state return state
}) })
}, },
saveField: ({ originalName, field, primaryDisplay = false }) => { saveField: ({ originalName, field, primaryDisplay = false, indexes }) => {
store.update(state => { store.update(state => {
// delete the original if renaming // delete the original if renaming
// need to handle if the column had no name, empty string // need to handle if the column had no name, empty string
@ -249,6 +249,10 @@ export const getBackendUiStore = () => {
state.draftTable.primaryDisplay = field.name state.draftTable.primaryDisplay = field.name
} }
if (indexes) {
state.draftTable.indexes = indexes
}
state.draftTable.schema[field.name] = cloneDeep(field) state.draftTable.schema[field.name] = cloneDeep(field)
store.actions.tables.save(state.draftTable) store.actions.tables.save(state.draftTable)
return state return state

View file

@ -1,5 +1,12 @@
<script> <script>
import { Input, Button, TextButton, Select, Toggle } from "@budibase/bbui" import {
Input,
Button,
Label,
TextButton,
Select,
Toggle,
} from "@budibase/bbui"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { backendUiStore } from "builderStore" import { backendUiStore } from "builderStore"
import { TableNames, UNEDITABLE_USER_FIELDS } from "constants" import { TableNames, UNEDITABLE_USER_FIELDS } from "constants"
@ -24,6 +31,7 @@
let primaryDisplay = let primaryDisplay =
$backendUiStore.selectedTable.primaryDisplay == null || $backendUiStore.selectedTable.primaryDisplay == null ||
$backendUiStore.selectedTable.primaryDisplay === field.name $backendUiStore.selectedTable.primaryDisplay === field.name
let indexes = [...($backendUiStore.selectedTable.indexes || [])]
let confirmDeleteDialog let confirmDeleteDialog
let deletion let deletion
@ -41,6 +49,7 @@
originalName, originalName,
field, field,
primaryDisplay, primaryDisplay,
indexes,
}) })
return state return state
}) })
@ -79,8 +88,24 @@
} }
} }
function onChangeSearchable() { function onChangePrimaryIndex(e) {
const enabled = e.target.checked
if (enabled) {
indexes[0] = field.name
} else {
indexes.shift()
indexes = indexes
}
}
function onChangeSecondaryIndex(e) {
const enabled = e.target.checked
if (enabled) {
indexes[1] = field.name
} else {
indexes.pop()
indexes = indexes
}
} }
function confirmDelete() { function confirmDelete() {
@ -124,10 +149,20 @@
on:change={onChangePrimaryDisplay} on:change={onChangePrimaryDisplay}
thin thin
text="Use as table display column" /> text="Use as table display column" />
<Label gray small>Search Indexes</Label>
<Toggle <Toggle
bind:checked={field.searchable} checked={indexes[0] === field.name}
disabled={indexes[1] === field.name}
on:change={onChangePrimaryIndex}
thin thin
text="Index for Search" /> text="Primary" />
<Toggle
checked={indexes[1] === field.name}
disabled={!indexes[0] || indexes[0] === field.name}
on:change={onChangeSecondaryIndex}
thin
text="Secondary" />
{/if} {/if}
{#if field.type === 'string'} {#if field.type === 'string'}

View file

@ -229,27 +229,8 @@ exports.fetchView = async function(ctx) {
} }
} }
exports.createIndex = async function(ctx) {
const appId = "app_1987903cf3604d459969c80cf17651a0"
const db = new CouchDB(appId)
const indexes = await db.getIndexes()
// ctx.body = await db.get("_design/search_ddoc")
ctx.body = await db.createIndex({
index: {
fields: ctx.request.body.fields,
name: "other_search_index",
ddoc: "search_ddoc",
type: "json",
},
})
// ctx.body = await db.getIndexes()
}
exports.search = async function(ctx) { exports.search = async function(ctx) {
// const appId = ctx.user.appId const appId = ctx.user.appId
const appId = "app_1987903cf3604d459969c80cf17651a0"
const db = new CouchDB(appId) const db = new CouchDB(appId)
@ -260,20 +241,10 @@ exports.search = async function(ctx) {
query.tableId = ctx.params.tableId query.tableId = ctx.params.tableId
// Paginating
// if (cursor) {
// if (backwards) {
// query._id = { $lte: cursor }
// } else {
// query._id = { $gte: cursor }
// }
// }
const response = await db.find({ const response = await db.find({
selector: query, selector: query,
limit: pageSize, limit: pageSize,
skip: pageSize * page, skip: pageSize * page,
// sort: ["_id"],
}) })
const rows = response.docs const rows = response.docs
@ -285,7 +256,6 @@ exports.search = async function(ctx) {
} }
} }
// ctx.body = response
ctx.body = await linkRows.attachLinkInfo(appId, rows) ctx.body = await linkRows.attachLinkInfo(appId, rows)
} }

View file

@ -7,6 +7,7 @@ const {
generateTableID, generateTableID,
generateRowID, generateRowID,
} = require("../../db/utils") } = require("../../db/utils")
const { isEqual } = require("lodash/fp")
async function checkForColumnUpdates(db, oldTable, updatedTable) { async function checkForColumnUpdates(db, oldTable, updatedTable) {
let updatedRows let updatedRows
@ -38,18 +39,6 @@ async function checkForColumnUpdates(db, oldTable, updatedTable) {
return updatedRows return updatedRows
} }
async function updateSearchIndex(fields) {
console.log("Updating stuff")
const resp = await db.createIndex({
index: {
fields,
name: "search_index",
ddoc: "search_ddoc",
type: "json",
},
})
}
exports.fetch = async function(ctx) { exports.fetch = async function(ctx) {
const db = new CouchDB(ctx.user.appId) const db = new CouchDB(ctx.user.appId)
const body = await db.allDocs( const body = await db.allDocs(
@ -140,6 +129,46 @@ exports.save = async function(ctx) {
const result = await db.post(tableToSave) const result = await db.post(tableToSave)
tableToSave._rev = result.rev tableToSave._rev = result.rev
// create relevant search indexes
if (tableToSave.indexes && tableToSave.indexes.length > 0) {
const currentIndexes = await db.getIndexes()
const indexName = `search:${result.id}`
const existingIndex = currentIndexes.indexes.find(
existing => existing.name === indexName
)
if (existingIndex) {
const currentFields = existingIndex.def.fields.map(
field => Object.keys(field)[0]
)
// if index fields have changed, delete the original index
if (!isEqual(currentFields, tableToSave.indexes)) {
await db.deleteIndex(existingIndex)
// create/recreate the index with fields
await db.createIndex({
index: {
fields: tableToSave.indexes,
name: indexName,
ddoc: "search_ddoc",
type: "json",
},
})
}
} else {
// create/recreate the index with fields
await db.createIndex({
index: {
fields: tableToSave.indexes,
name: indexName,
ddoc: "search_ddoc",
type: "json",
},
})
}
}
ctx.eventEmitter && ctx.eventEmitter &&
ctx.eventEmitter.emitTable(`table:save`, appId, tableToSave) ctx.eventEmitter.emitTable(`table:save`, appId, tableToSave)

View file

@ -31,14 +31,9 @@ router
usage, usage,
rowController.save rowController.save
) )
.post(
"/api/createindex",
// authorized(PermissionTypes.TABLE, PermissionLevels.READ),
rowController.createIndex
)
.post( .post(
"/api/:tableId/rows/search", "/api/:tableId/rows/search",
// authorized(PermissionTypes.TABLE, PermissionLevels.READ), authorized(PermissionTypes.TABLE, PermissionLevels.READ),
rowController.search rowController.search
) )
.patch( .patch(

View file

@ -14,7 +14,15 @@ const selfhost = require("./selfhost")
const app = new Koa() const app = new Koa()
// set up top level koa middleware // set up top level koa middleware
app.use(koaBody({ multipart: true })) app.use(
koaBody({
multipart: true,
formLimit: "10mb",
jsonLimit: "10mb",
textLimit: "10mb",
enableTypes: ["json", "form", "text"],
})
)
app.use( app.use(
logger({ logger({

View file

@ -41,9 +41,7 @@
<div class="root" use:styleable={$component.styles}> <div class="root" use:styleable={$component.styles}>
<div class="content"> <div class="content">
{#if logo} {#if logo}
<div class="logo-container"> <div class="logo-container"><img src={logo} alt="logo" /></div>
<img src={logo} alt="logo" />
</div>
{/if} {/if}
{#if title} {#if title}

View file

@ -28,8 +28,13 @@
let page = 0 let page = 0
$: fetchData(table, page) $: fetchData(table, page)
$: searchable = [...(table.indexes || []), ...columns]
// omit empty strings // omit empty strings
$: parsedSearch = Object.keys(search).reduce((acc, next) => search[next] === "" ? acc : { ...acc, [next]: search[next] }, {}) $: parsedSearch = Object.keys(search).reduce(
(acc, next) =>
search[next] === "" ? acc : { ...acc, [next]: search[next] },
{}
)
async function fetchData(table, page) { async function fetchData(table, page) {
if (!isEmpty(table)) { if (!isEmpty(table)) {
@ -40,8 +45,8 @@
search: parsedSearch, search: parsedSearch,
pagination: { pagination: {
pageSize, pageSize,
page page,
} },
}) })
} }
loaded = true loaded = true