mirror of https://github.com/Budibase/budibase.git
3 changed files with 301 additions and 88 deletions
@ -0,0 +1,192 @@ |
|||
import { writable, derived, get } from "svelte/store" |
|||
import * as API from "builderStore/api" |
|||
import { buildLuceneQuery } from "../../../client/src/utils/lucene" |
|||
|
|||
const defaultOptions = { |
|||
tableId: null, |
|||
filter: null, |
|||
limit: 10, |
|||
sortColumn: null, |
|||
sortOrder: "ascending", |
|||
paginate: true, |
|||
schema: null, |
|||
} |
|||
|
|||
export const fetchTableData = opts => { |
|||
// Save option set so we can override it later rather than relying on params
|
|||
let options = { |
|||
...defaultOptions, |
|||
...opts, |
|||
} |
|||
|
|||
// Local non-observable state
|
|||
let query |
|||
let sortType |
|||
|
|||
// Local observable state
|
|||
const store = writable({ |
|||
rows: [], |
|||
schema: null, |
|||
loading: false, |
|||
loaded: false, |
|||
bookmarks: [], |
|||
pageNumber: 0, |
|||
}) |
|||
|
|||
// Derive certain properties to return
|
|||
const derivedStore = derived(store, $store => { |
|||
return { |
|||
...$store, |
|||
hasNextPage: $store.bookmarks[$store.pageNumber + 1] != null, |
|||
hasPrevPage: $store.pageNumber > 0, |
|||
} |
|||
}) |
|||
|
|||
const fetchPage = async bookmark => { |
|||
const { tableId, limit, sortColumn, sortOrder, paginate } = options |
|||
store.update($store => ({ ...$store, loading: true })) |
|||
const res = await API.post(`/api/${options.tableId}/search`, { |
|||
tableId, |
|||
query, |
|||
limit, |
|||
sort: sortColumn, |
|||
sortOrder: sortOrder?.toLowerCase() ?? "ascending", |
|||
sortType, |
|||
paginate, |
|||
bookmark, |
|||
}) |
|||
store.update($store => ({ ...$store, loading: false, loaded: true })) |
|||
return await res.json() |
|||
} |
|||
|
|||
// Fetches a fresh set of results from the server
|
|||
const fetchData = async () => { |
|||
const { tableId, schema, sortColumn, filter } = options |
|||
|
|||
// Ensure table ID exists
|
|||
if (!tableId) { |
|||
return |
|||
} |
|||
|
|||
// Get and enrich schema.
|
|||
// Ensure there are "name" properties for all fields and that field schema
|
|||
// are objects
|
|||
let enrichedSchema = schema |
|||
if (!enrichedSchema) { |
|||
const definition = await API.get(`/api/tables/${tableId}`) |
|||
enrichedSchema = definition?.schema ?? null |
|||
} |
|||
if (enrichedSchema) { |
|||
Object.entries(schema).forEach(([fieldName, fieldSchema]) => { |
|||
if (typeof fieldSchema === "string") { |
|||
enrichedSchema[fieldName] = { |
|||
type: fieldSchema, |
|||
name: fieldName, |
|||
} |
|||
} else { |
|||
enrichedSchema[fieldName] = { |
|||
...fieldSchema, |
|||
name: fieldName, |
|||
} |
|||
} |
|||
}) |
|||
|
|||
// Save fixed schema so we can provide it later
|
|||
options.schema = enrichedSchema |
|||
} |
|||
|
|||
// Ensure schema exists
|
|||
if (!schema) { |
|||
return |
|||
} |
|||
store.update($store => ({ ...$store, schema })) |
|||
|
|||
// Work out what sort type to use
|
|||
if (!sortColumn || !schema[sortColumn]) { |
|||
sortType = "string" |
|||
} |
|||
const type = schema?.[sortColumn]?.type |
|||
sortType = type === "number" ? "number" : "string" |
|||
|
|||
// Build the lucene query
|
|||
query = buildLuceneQuery(filter) |
|||
|
|||
// Actually fetch data
|
|||
const page = await fetchPage() |
|||
store.update($store => ({ |
|||
...$store, |
|||
loading: false, |
|||
loaded: true, |
|||
pageNumber: 0, |
|||
rows: page.rows, |
|||
bookmarks: page.hasNextPage ? [null, page.bookmark] : [null], |
|||
})) |
|||
} |
|||
|
|||
// Fetches the next page of data
|
|||
const nextPage = async () => { |
|||
const state = get(derivedStore) |
|||
if (!options.paginate || !state.hasNextPage) { |
|||
return |
|||
} |
|||
|
|||
// Fetch next page
|
|||
const page = await fetchPage(state.bookmarks[state.pageNumber + 1]) |
|||
|
|||
// Update state
|
|||
store.update($store => { |
|||
let { bookmarks, pageNumber } = $store |
|||
if (page.hasNextPage) { |
|||
bookmarks[pageNumber + 2] = page.bookmark |
|||
} |
|||
return { |
|||
...$store, |
|||
pageNumber: pageNumber + 1, |
|||
rows: page.rows, |
|||
bookmarks, |
|||
} |
|||
}) |
|||
} |
|||
|
|||
// Fetches the previous page of data
|
|||
const prevPage = async () => { |
|||
const state = get(derivedStore) |
|||
if (!options.paginate || !state.hasPrevPage) { |
|||
return |
|||
} |
|||
|
|||
// Fetch previous page
|
|||
const page = await fetchPage(state.bookmarks[state.pageNumber - 1]) |
|||
|
|||
// Update state
|
|||
store.update($store => { |
|||
return { |
|||
...$store, |
|||
pageNumber: $store.pageNumber - 1, |
|||
rows: page.rows, |
|||
} |
|||
}) |
|||
} |
|||
|
|||
// Resets the data set and updates options
|
|||
const update = async newOptions => { |
|||
if (newOptions) { |
|||
options = { |
|||
...options, |
|||
...newOptions, |
|||
} |
|||
} |
|||
await fetchData() |
|||
} |
|||
|
|||
// Initially fetch data but don't bother waiting for the result
|
|||
fetchData() |
|||
|
|||
// Return our derived store which will be updated over time
|
|||
return { |
|||
subscribe: derivedStore.subscribe, |
|||
nextPage, |
|||
prevPage, |
|||
update, |
|||
} |
|||
} |
|||
Loading…
Reference in new issue