mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +00:00 
			
		
		
		
	(core) Use GristObjCode in CellValue
Summary: Makes type checking a bit stronger Test Plan: it just has to compile Reviewers: jarek Reviewed By: jarek Differential Revision: https://phab.getgrist.com/D3065
This commit is contained in:
		
							parent
							
								
									62db263d1f
								
							
						
					
					
						commit
						a64fb105e3
					
				@ -8,7 +8,7 @@ import { TableData } from 'app/client/models/TableData';
 | 
			
		||||
import { createEmptyTableDelta, getTableIdAfter, getTableIdBefore, TableDelta } from 'app/common/ActionSummary';
 | 
			
		||||
import { DisposableWithEvents } from 'app/common/DisposableWithEvents';
 | 
			
		||||
import { CellVersions, UserAction } from 'app/common/DocActions';
 | 
			
		||||
import { GristObjCode } from "app/common/gristTypes";
 | 
			
		||||
import { GristObjCode } from 'app/plugin/GristData';
 | 
			
		||||
import { CellDelta } from 'app/common/TabularDiff';
 | 
			
		||||
import { DocStateComparisonDetails } from 'app/common/UserAPI';
 | 
			
		||||
import { CellValue } from 'app/plugin/GristData';
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
import { CellValue, CellVersions } from 'app/common/DocActions';
 | 
			
		||||
import { GristObjCode } from 'app/plugin/GristData';
 | 
			
		||||
import isString = require('lodash/isString');
 | 
			
		||||
import {removePrefix} from "./gutil";
 | 
			
		||||
import { removePrefix } from "./gutil";
 | 
			
		||||
 | 
			
		||||
// tslint:disable:object-literal-key-quotes
 | 
			
		||||
 | 
			
		||||
@ -14,23 +15,6 @@ export type GristTypeInfo =
 | 
			
		||||
  {type: 'RefList', tableId: string} |
 | 
			
		||||
  {type: Exclude<GristType, 'DateTime'|'Ref'|'RefList'>};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Letter codes for CellValue types encoded as [code, args...] tuples.
 | 
			
		||||
export const enum GristObjCode {
 | 
			
		||||
  List            = 'L',
 | 
			
		||||
  Dict            = 'O',
 | 
			
		||||
  DateTime        = 'D',
 | 
			
		||||
  Date            = 'd',
 | 
			
		||||
  Skip            = 'S',
 | 
			
		||||
  Censored        = 'C',
 | 
			
		||||
  Reference       = 'R',
 | 
			
		||||
  ReferenceList   = 'r',
 | 
			
		||||
  Exception       = 'E',
 | 
			
		||||
  Pending         = 'P',
 | 
			
		||||
  Unmarshallable  = 'U',
 | 
			
		||||
  Versions        = 'V',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const MANUALSORT = 'manualSort';
 | 
			
		||||
 | 
			
		||||
// Whether a column is internal and should be hidden.
 | 
			
		||||
@ -93,9 +77,9 @@ export function extractInfoFromColType(colType: string): GristTypeInfo {
 | 
			
		||||
export function reencodeAsAny(value: CellValue, typeInfo: GristTypeInfo): CellValue {
 | 
			
		||||
  if (typeof value === 'number') {
 | 
			
		||||
    switch (typeInfo.type) {
 | 
			
		||||
      case 'Date': return ['d', value];
 | 
			
		||||
      case 'DateTime': return ['D', value, typeInfo.timezone];
 | 
			
		||||
      case 'Ref': return ['R', typeInfo.tableId, value];
 | 
			
		||||
      case 'Date': return [GristObjCode.Date, value];
 | 
			
		||||
      case 'DateTime': return [GristObjCode.DateTime, value, typeInfo.timezone];
 | 
			
		||||
      case 'Ref': return [GristObjCode.Reference, typeInfo.tableId, value];
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return value;
 | 
			
		||||
@ -105,7 +89,7 @@ export function reencodeAsAny(value: CellValue, typeInfo: GristTypeInfo): CellVa
 | 
			
		||||
/**
 | 
			
		||||
 * Returns whether a value (as received in a DocAction) represents a custom object.
 | 
			
		||||
 */
 | 
			
		||||
export function isObject(value: CellValue): value is [string, any?] {
 | 
			
		||||
export function isObject(value: CellValue): value is [GristObjCode, any?] {
 | 
			
		||||
  return Array.isArray(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,7 @@
 | 
			
		||||
/*** THIS FILE IS AUTO-GENERATED BY core/sandbox/gen_js_schema.py ***/
 | 
			
		||||
 | 
			
		||||
import { GristObjCode } from "app/plugin/GristData";
 | 
			
		||||
 | 
			
		||||
// tslint:disable:object-literal-key-quotes
 | 
			
		||||
 | 
			
		||||
export const SCHEMA_VERSION = 24;
 | 
			
		||||
@ -216,7 +219,7 @@ export interface SchemaTypes {
 | 
			
		||||
    displayCol: number;
 | 
			
		||||
    visibleCol: number;
 | 
			
		||||
    recalcWhen: number;
 | 
			
		||||
    recalcDeps: ['L', ...number[]]|null;
 | 
			
		||||
    recalcDeps: [GristObjCode.List, ...number[]]|null;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  "_grist_Imports": {
 | 
			
		||||
@ -328,7 +331,7 @@ export interface SchemaTypes {
 | 
			
		||||
 | 
			
		||||
  "_grist_Triggers": {
 | 
			
		||||
    tableRef: number;
 | 
			
		||||
    eventTypes: ['L', ...string[]]|null;
 | 
			
		||||
    eventTypes: [GristObjCode.List, ...string[]]|null;
 | 
			
		||||
    isReadyColRef: number;
 | 
			
		||||
    actions: string;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,20 @@
 | 
			
		||||
export type CellValue = number|string|boolean|null|[string, ...unknown[]];
 | 
			
		||||
// Letter codes for CellValue types encoded as [code, args...] tuples.
 | 
			
		||||
export const enum GristObjCode {
 | 
			
		||||
  List            = 'L',
 | 
			
		||||
  Dict            = 'O',
 | 
			
		||||
  DateTime        = 'D',
 | 
			
		||||
  Date            = 'd',
 | 
			
		||||
  Skip            = 'S',
 | 
			
		||||
  Censored        = 'C',
 | 
			
		||||
  Reference       = 'R',
 | 
			
		||||
  ReferenceList   = 'r',
 | 
			
		||||
  Exception       = 'E',
 | 
			
		||||
  Pending         = 'P',
 | 
			
		||||
  Unmarshallable  = 'U',
 | 
			
		||||
  Versions        = 'V',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type CellValue = number|string|boolean|null|[GristObjCode, ...unknown[]];
 | 
			
		||||
 | 
			
		||||
export interface RowRecord {
 | 
			
		||||
  id: number;
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@
 | 
			
		||||
 */
 | 
			
		||||
// tslint:disable:max-classes-per-file
 | 
			
		||||
 | 
			
		||||
import {CellValue} from 'app/plugin/GristData';
 | 
			
		||||
import { CellValue, GristObjCode } from 'app/plugin/GristData';
 | 
			
		||||
import isPlainObject = require('lodash/isPlainObject');
 | 
			
		||||
 | 
			
		||||
// The text to show on cells whose values are pending.
 | 
			
		||||
@ -165,32 +165,32 @@ export function encodeObject(value: unknown): CellValue {
 | 
			
		||||
    if (value == null) {
 | 
			
		||||
      return null;
 | 
			
		||||
    } else if (value instanceof Reference) {
 | 
			
		||||
      return ['R', value.tableId, value.rowId];
 | 
			
		||||
      return [GristObjCode.Reference, value.tableId, value.rowId];
 | 
			
		||||
    } else if (value instanceof ReferenceList) {
 | 
			
		||||
      return ['r', value.tableId, value.rowIds];
 | 
			
		||||
      return [GristObjCode.ReferenceList, value.tableId, value.rowIds];
 | 
			
		||||
    } else if (value instanceof Date) {
 | 
			
		||||
      const timestamp = value.valueOf() / 1000;
 | 
			
		||||
      if ('timezone' in value) {
 | 
			
		||||
        return ['D', timestamp, (value as GristDateTime).timezone];
 | 
			
		||||
        return [GristObjCode.DateTime, timestamp, (value as GristDateTime).timezone];
 | 
			
		||||
      } else {
 | 
			
		||||
        // TODO Depending on how it's used, may want to return ['d', timestamp] for UTC midnight.
 | 
			
		||||
        return ['D', timestamp, 'UTC'];
 | 
			
		||||
        return [GristObjCode.DateTime, timestamp, 'UTC'];
 | 
			
		||||
      }
 | 
			
		||||
    } else if (value instanceof CensoredValue) {
 | 
			
		||||
      return ['C'];
 | 
			
		||||
      return [GristObjCode.Censored];
 | 
			
		||||
    } else if (value instanceof RaisedException) {
 | 
			
		||||
      return ['E', value.name, value.message, value.details];
 | 
			
		||||
      return [GristObjCode.Exception, value.name, value.message, value.details];
 | 
			
		||||
    } else if (Array.isArray(value)) {
 | 
			
		||||
      return ['L', ...value.map(encodeObject)];
 | 
			
		||||
      return [GristObjCode.List, ...value.map(encodeObject)];
 | 
			
		||||
    } else if (isPlainObject(value)) {
 | 
			
		||||
      return ['O', mapValues(value as any, encodeObject, {sort: true})];
 | 
			
		||||
      return [GristObjCode.Dict, mapValues(value as any, encodeObject, {sort: true})];
 | 
			
		||||
    }
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    // Fall through to return a best-effort representation.
 | 
			
		||||
  }
 | 
			
		||||
  // We either don't know how to convert the value, or failed during the conversion. Instead we
 | 
			
		||||
  // return an "UnmarshallableValue" object, with repr() of the value to show to the user.
 | 
			
		||||
  return ['U', UnknownValue.safeRepr(value)];
 | 
			
		||||
  return [GristObjCode.Unmarshallable, UnknownValue.safeRepr(value)];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,7 @@ import {BulkColValues, DocAction, TableColValues, TableDataAction, toTableDataAc
 | 
			
		||||
import * as gristTypes from 'app/common/gristTypes';
 | 
			
		||||
import * as marshal from 'app/common/marshal';
 | 
			
		||||
import * as schema from 'app/common/schema';
 | 
			
		||||
import {GristObjCode} from "app/plugin/GristData";
 | 
			
		||||
import {ActionHistoryImpl} from 'app/server/lib/ActionHistoryImpl';
 | 
			
		||||
import {ExpandedQuery} from 'app/server/lib/ExpandedQuery';
 | 
			
		||||
import {IDocStorageManager} from 'app/server/lib/IDocStorageManager';
 | 
			
		||||
@ -35,7 +36,7 @@ const debuglog = util.debuglog('db');
 | 
			
		||||
 | 
			
		||||
const maxSQLiteVariables = 500;     // Actually could be 999, so this is playing it safe.
 | 
			
		||||
 | 
			
		||||
const PENDING_VALUE = [gristTypes.GristObjCode.Pending];
 | 
			
		||||
const PENDING_VALUE = [GristObjCode.Pending];
 | 
			
		||||
 | 
			
		||||
export class DocStorage implements ISQLiteDB {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
import {ServerQuery} from 'app/common/ActiveDocAPI';
 | 
			
		||||
import {ApiError} from 'app/common/ApiError';
 | 
			
		||||
import {DocData} from 'app/common/DocData';
 | 
			
		||||
import {parseFormula} from 'app/common/Formula';
 | 
			
		||||
import {removePrefix} from 'app/common/gutil';
 | 
			
		||||
import {quoteIdent} from 'app/server/lib/SQLiteDB';
 | 
			
		||||
import { ServerQuery } from 'app/common/ActiveDocAPI';
 | 
			
		||||
import { ApiError } from 'app/common/ApiError';
 | 
			
		||||
import { DocData } from 'app/common/DocData';
 | 
			
		||||
import { parseFormula } from 'app/common/Formula';
 | 
			
		||||
import { removePrefix } from 'app/common/gutil';
 | 
			
		||||
import { GristObjCode } from 'app/plugin/GristData';
 | 
			
		||||
import { quoteIdent } from 'app/server/lib/SQLiteDB';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a query for Grist data with support for SQL-based
 | 
			
		||||
@ -19,7 +20,7 @@ export interface ExpandedQuery extends ServerQuery {
 | 
			
		||||
  // step.  That means we need to pass the error message along
 | 
			
		||||
  // explicitly.
 | 
			
		||||
  constants?: {
 | 
			
		||||
    [colId: string]: ['E', string] | ['P'];
 | 
			
		||||
    [colId: string]: [GristObjCode.Exception, string] | [GristObjCode.Pending];
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // A list of join clauses to bring in data from other tables.
 | 
			
		||||
@ -115,7 +116,7 @@ export function expandQuery(iquery: ServerQuery, docData: DocData, onDemandFormu
 | 
			
		||||
        // We add a trivial selection, and store errors in the query for substitution later.
 | 
			
		||||
        sqlFormula = '0';
 | 
			
		||||
        if (!query.constants) { query.constants = {}; }
 | 
			
		||||
        query.constants[colId] = ['E', error];
 | 
			
		||||
        query.constants[colId] = [GristObjCode.Exception, error];
 | 
			
		||||
      }
 | 
			
		||||
      if (sqlFormula) {
 | 
			
		||||
        selects.add(`${sqlFormula} as ${quoteIdent(colId)}`);
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ import { getSetMapValue, isObject, pruneArray } from 'app/common/gutil';
 | 
			
		||||
import { canEdit, canView, isValidRole, Role } from 'app/common/roles';
 | 
			
		||||
import { FullUser, UserAccessData } from 'app/common/UserAPI';
 | 
			
		||||
import { HomeDBManager } from 'app/gen-server/lib/HomeDBManager';
 | 
			
		||||
import { GristObjCode } from 'app/plugin/GristData';
 | 
			
		||||
import { compileAclFormula } from 'app/server/lib/ACLFormula';
 | 
			
		||||
import { DocClients } from 'app/server/lib/DocClients';
 | 
			
		||||
import { getDocSessionAccess, getDocSessionUser, OptDocSession } from 'app/server/lib/DocSession';
 | 
			
		||||
@ -1104,9 +1105,9 @@ export class GranularAccess implements GranularAccessForBundle {
 | 
			
		||||
    if (colValues === undefined) {
 | 
			
		||||
      censorAt = () => 1;
 | 
			
		||||
    } else if (Array.isArray(action[2])) {
 | 
			
		||||
      censorAt = (colId, idx) => (copyOnNeed() as BulkColValues)[colId][idx] = ['C'];  // censored
 | 
			
		||||
      censorAt = (colId, idx) => (copyOnNeed() as BulkColValues)[colId][idx] = [GristObjCode.Censored];
 | 
			
		||||
    } else {
 | 
			
		||||
      censorAt = (colId) => (copyOnNeed() as ColValues)[colId] = ['C'];  // censored
 | 
			
		||||
      censorAt = (colId) => (copyOnNeed() as ColValues)[colId] = [GristObjCode.Censored];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // These map an index of a row in the action to its index in rowsBefore and in rowsAfter.
 | 
			
		||||
 | 
			
		||||
@ -12,8 +12,8 @@ _ts_types = {
 | 
			
		||||
  "Int":            "number",
 | 
			
		||||
  "PositionNumber": "number",
 | 
			
		||||
  "Ref":            "number",
 | 
			
		||||
  "RefList":        "['L', ...number[]]|null",    # Non-primitive values are encoded
 | 
			
		||||
  "ChoiceList":     "['L', ...string[]]|null",
 | 
			
		||||
  "RefList":        "[GristObjCode.List, ...number[]]|null",  # Non-primitive values are encoded
 | 
			
		||||
  "ChoiceList":     "[GristObjCode.List, ...string[]]|null",
 | 
			
		||||
  "Text":           "string",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,9 @@ def get_ts_type(col_type):
 | 
			
		||||
def main():
 | 
			
		||||
  print("""\
 | 
			
		||||
/*** THIS FILE IS AUTO-GENERATED BY %s ***/
 | 
			
		||||
 | 
			
		||||
import { GristObjCode } from "app/plugin/GristData";
 | 
			
		||||
 | 
			
		||||
// tslint:disable:object-literal-key-quotes
 | 
			
		||||
 | 
			
		||||
export const SCHEMA_VERSION = %d;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user