(core) control the distribution of attachment metadata

Summary:
for users who don't automatically have deep rights
to the document, provide them with attachment metadata only
for rows they have access to. This is a little tricky to
do efficiently. We provide attachment metadata when an
individual table is fetched, rather than on initial document
load, so we don't block that load on a full document scan.
We provide attachment metadata to a client when we see that
we are shipping rows mentioning particular attachments,
without making any effort to keep track of the metadata they
already have.

Test Plan: updated tests

Reviewers: dsagal, jarek

Reviewed By: dsagal, jarek

Differential Revision: https://phab.getgrist.com/D3722
This commit is contained in:
Paul Fitzpatrick
2022-12-21 11:40:00 -05:00
parent 6dce083484
commit 472a9a186e
14 changed files with 429 additions and 169 deletions

View File

@@ -2,7 +2,8 @@
* TableData maintains a single table's data.
*/
import {ActionDispatcher} from 'app/common/ActionDispatcher';
import {BulkColValues, CellValue, ColInfo, ColInfoWithId, ColValues, DocAction,
import {
BulkAddRecord, BulkColValues, CellValue, ColInfo, ColInfoWithId, ColValues, DocAction,
isSchemaAction, ReplaceTableData, RowRecord, TableDataAction} from 'app/common/DocActions';
import {getDefaultForType} from 'app/common/gristTypes';
import {arrayRemove, arraySplice, getDistinctValues} from 'app/common/gutil';
@@ -250,16 +251,40 @@ export class TableData extends ActionDispatcher implements SkippableRows {
/**
* Return data in TableDataAction form ['TableData', tableId, [...rowIds], {...}]
* Optionally takes a list of row ids to return data from. If a row id is
* not actually present in the table, a row of nulls will be returned for it.
*/
public getTableDataAction(): TableDataAction {
const rowIds = this.getRowIds();
public getTableDataAction(desiredRowIds?: number[]): TableDataAction {
const rowIds = desiredRowIds || this.getRowIds();
let bulkColValues: {[colId: string]: CellValue[]};
if (desiredRowIds) {
const len = rowIds.length;
bulkColValues = {};
for (const colId of this.getColIds()) { bulkColValues[colId] = Array(len); }
for (let i = 0; i < len; i++) {
const index = this._rowMap.get(rowIds[i]);
for (const {colId, values} of this._colArray) {
const value = (index === undefined) ? null : values[index];
bulkColValues[colId][i] = value;
}
}
} else {
bulkColValues = fromPairs(
this.getColIds()
.filter(colId => colId !== 'id')
.map(colId => [colId, this.getColValues(colId)! as CellValue[]]));
}
return ['TableData',
this.tableId,
rowIds as number[],
fromPairs(
this.getColIds()
.filter(colId => colId !== 'id')
.map(colId => [colId, this.getColValues(colId)! as CellValue[]]))];
bulkColValues];
}
public getBulkAddRecord(desiredRowIds?: number[]): BulkAddRecord {
const tableData = this.getTableDataAction(desiredRowIds?.sort((a, b) => a - b));
return [
'BulkAddRecord', tableData[1], tableData[2], tableData[3],
];
}
/**
@@ -357,6 +382,13 @@ export class TableData extends ActionDispatcher implements SkippableRows {
// ---- The following methods implement ActionDispatcher interface ----
protected onAddRecord(action: DocAction, tableId: string, rowId: number, colValues: ColValues): void {
if (this._rowMap.get(rowId) !== undefined) {
// If adding a record that already exists, act like an update.
// We rely on this behavior for distributing attachment
// metadata.
this.onUpdateRecord(action, tableId, rowId, colValues);
return;
}
const index: number = this._rowIdCol.length;
this._rowMap.set(rowId, index);
this._rowIdCol[index] = rowId;
@@ -366,14 +398,28 @@ export class TableData extends ActionDispatcher implements SkippableRows {
}
protected onBulkAddRecord(action: DocAction, tableId: string, rowIds: number[], colValues: BulkColValues): void {
const index: number = this._rowIdCol.length;
let destIndex: number = this._rowIdCol.length;
for (let i = 0; i < rowIds.length; i++) {
this._rowMap.set(rowIds[i], index + i);
this._rowIdCol[index + i] = rowIds[i];
}
for (const {colId, defl, values} of this._colArray) {
for (let i = 0; i < rowIds.length; i++) {
values[index + i] = colValues.hasOwnProperty(colId) ? colValues[colId][i] : defl;
const srcIndex = this._rowMap.get(rowIds[i]);
if (srcIndex !== undefined) {
// If adding a record that already exists, act like an update.
// We rely on this behavior for distributing attachment
// metadata.
for (const colId in colValues) {
if (colValues.hasOwnProperty(colId)) {
const colData = this._columns.get(colId);
if (colData) {
colData.values[srcIndex] = colValues[colId][i];
}
}
}
} else {
this._rowMap.set(rowIds[i], destIndex);
this._rowIdCol[destIndex] = rowIds[i];
for (const {colId, defl, values} of this._colArray) {
values[destIndex] = colValues.hasOwnProperty(colId) ? colValues[colId][i] : defl;
}
destIndex++;
}
}
}