mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
243 lines
6.5 KiB
243 lines
6.5 KiB
import type { ColumnType, ViewType } from 'nocodb-sdk' |
|
import type { ExtensionManifest, ExtensionType } from '#imports' |
|
|
|
const [useProvideExtensionHelper, useExtensionHelper] = useInjectionState( |
|
(extension: Ref<ExtensionType>, extensionManifest: ComputedRef<ExtensionManifest | undefined>, activeError: Ref<any>) => { |
|
const { $api } = useNuxtApp() |
|
|
|
const basesStore = useBases() |
|
|
|
const { activeProjectId: baseId } = storeToRefs(basesStore) |
|
|
|
const tableStore = useTablesStore() |
|
|
|
const { activeTables: tables } = storeToRefs(tableStore) |
|
|
|
const viewStore = useViewsStore() |
|
|
|
const { viewsByTable } = storeToRefs(viewStore) |
|
|
|
const { getMeta } = useMetas() |
|
|
|
const { eventBus } = useSmartsheetStoreOrThrow() |
|
|
|
const fullscreen = ref(false) |
|
|
|
const showExpandBtn = ref(true) |
|
|
|
const fullscreenModalSize = ref<keyof typeof modalSizes>(extensionManifest.value?.config?.modalSize || 'lg') |
|
|
|
const collapsed = computed({ |
|
get: () => extension.value?.meta?.collapsed ?? false, |
|
set: (value) => { |
|
extension.value?.setMeta('collapsed', value) |
|
}, |
|
}) |
|
|
|
const getViewsForTable = async (tableId: string) => { |
|
if (viewsByTable.value.has(tableId)) { |
|
return viewsByTable.value.get(tableId) as ViewType[] |
|
} |
|
|
|
await viewStore.loadViews({ tableId, ignoreLoading: true }) |
|
return viewsByTable.value.get(tableId) as ViewType[] |
|
} |
|
|
|
const getData = async (params: { |
|
tableId: string |
|
viewId?: string |
|
eachPage: (records: Record<string, any>[], nextPage: () => void) => Promise<void> | void |
|
done: () => Promise<void> | void |
|
}) => { |
|
const { tableId, viewId, eachPage, done } = params |
|
|
|
let page = 1 |
|
|
|
const nextPage = async () => { |
|
const { list: records, pageInfo } = await $api.dbViewRow.list( |
|
'noco', |
|
baseId.value!, |
|
tableId, |
|
viewId as string, |
|
{ |
|
offset: (page - 1) * 100, |
|
limit: 100, |
|
} as any, |
|
) |
|
|
|
if (pageInfo?.isLastPage) { |
|
await eachPage(records, () => {}) |
|
await done() |
|
} else { |
|
page++ |
|
await eachPage(records, nextPage) |
|
} |
|
} |
|
|
|
await nextPage() |
|
} |
|
|
|
const getTableMeta = async (tableId: string) => { |
|
return getMeta(tableId) |
|
} |
|
|
|
const insertData = async (params: { tableId: string; data: Record<string, any> }) => { |
|
const { tableId, data } = params |
|
|
|
const chunks = [] |
|
|
|
let inserted = 0 |
|
|
|
// chunk data into 100 records |
|
for (let i = 0; i < data.length; i += 100) { |
|
chunks.push(data.slice(i, i + 100)) |
|
} |
|
|
|
for (const chunk of chunks) { |
|
inserted += chunk.length |
|
await $api.dbDataTableRow.create(tableId, chunk) |
|
} |
|
|
|
return { |
|
inserted, |
|
} |
|
} |
|
|
|
const updateData = async (params: { tableId: string; data: Record<string, any> }) => { |
|
const { tableId, data } = params |
|
|
|
const chunks = [] |
|
|
|
let updated = 0 |
|
|
|
// chunk data into 100 records |
|
for (let i = 0; i < data.length; i += 100) { |
|
chunks.push(data.slice(i, i + 100)) |
|
} |
|
|
|
for (const chunk of chunks) { |
|
updated += chunk.length |
|
await $api.dbDataTableRow.update(tableId, chunk) |
|
} |
|
|
|
return { |
|
updated, |
|
} |
|
} |
|
|
|
const upsertData = async (params: { |
|
tableId: string |
|
data: Record<string, any> |
|
upsertField: ColumnType |
|
importType: 'insert' | 'update' | 'insertAndUpdate' |
|
}) => { |
|
const { tableId, data, upsertField } = params |
|
|
|
const chunkSize = 100 |
|
|
|
const tableMeta = await getMeta(tableId) |
|
|
|
if (!tableMeta?.columns) throw new Error('Table not found') |
|
|
|
const chunks = [] |
|
|
|
for (let i = 0; i < data.length; i += chunkSize) { |
|
chunks.push(data.slice(i, i + chunkSize)) |
|
} |
|
|
|
const insert = [] |
|
const update = [] |
|
|
|
let insertCounter = 0 |
|
let updateCounter = 0 |
|
|
|
for (const chunk of chunks) { |
|
// select chunk of data to determine if it's an insert or update |
|
const { list } = await $api.dbDataTableRow.list(tableId, { |
|
where: `(${upsertField.title},in,${chunk.map((record: Record<string, any>) => record[upsertField.title!]).join(',')})`, |
|
limit: chunkSize, |
|
}) |
|
|
|
if (params.importType !== 'update') { |
|
insert.push( |
|
...chunk.filter( |
|
(record: Record<string, any>) => |
|
!list.some((r: Record<string, any>) => `${r[upsertField.title!]}` === `${record[upsertField.title!]}`), |
|
), |
|
) |
|
} |
|
|
|
if (params.importType !== 'insert') { |
|
update.push( |
|
...chunk |
|
.filter((record: Record<string, any>) => |
|
list.some((r: Record<string, any>) => `${r[upsertField.title!]}` === `${record[upsertField.title!]}`), |
|
) |
|
.map((record: Record<string, any>) => { |
|
const existingRecord = list.find( |
|
(r: Record<string, any>) => `${r[upsertField.title!]}` === `${record[upsertField.title!]}`, |
|
) |
|
return { |
|
...rowPkData(existingRecord!, tableMeta.columns!), |
|
...record, |
|
} |
|
}), |
|
) |
|
} |
|
} |
|
|
|
if (insert.length) { |
|
insertCounter += insert.length |
|
while (insert.length) { |
|
await $api.dbDataTableRow.create(tableId, insert.splice(0, chunkSize)) |
|
} |
|
} |
|
|
|
if (update.length) { |
|
updateCounter += update.length |
|
while (update.length) { |
|
await $api.dbDataTableRow.update(tableId, update.splice(0, chunkSize)) |
|
} |
|
} |
|
|
|
return { inserted: insertCounter, updated: updateCounter } |
|
} |
|
|
|
const reloadData = () => { |
|
eventBus.emit(SmartsheetStoreEvents.DATA_RELOAD) |
|
} |
|
|
|
const reloadMeta = () => { |
|
eventBus.emit(SmartsheetStoreEvents.FIELD_RELOAD) |
|
} |
|
|
|
return { |
|
$api, |
|
fullscreen, |
|
collapsed, |
|
extension, |
|
extensionManifest, |
|
activeError, |
|
tables, |
|
showExpandBtn, |
|
fullscreenModalSize, |
|
getViewsForTable, |
|
getData, |
|
getTableMeta, |
|
insertData, |
|
updateData, |
|
upsertData, |
|
reloadData, |
|
reloadMeta, |
|
} |
|
}, |
|
'extension-helper', |
|
) |
|
|
|
export { useProvideExtensionHelper } |
|
|
|
export function useExtensionHelperOrThrow() { |
|
const extensionStore = useExtensionHelper() |
|
if (extensionStore == null) throw new Error('Please call `useProvideExtensionHelper` on the appropriate parent component') |
|
return extensionStore |
|
}
|
|
|