mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Nice summary table IDs
Summary: Changes auto-generated summary table IDs from e.g. `GristSummary_6_Table1` to `Table1_summary_A_B` (meaning `Table1` grouped by `A` and `B`). This makes it easier to write formulas involving summary tables, make API requests, understand logs, etc. Because these don't encode the source table ID as reliably as before, `decode_summary_table_name` now uses the summary table schema info, not just the summary table ID. Specifically, it looks at the type of the `group` column, which is `RefList:<source table id>`. Renaming a source table renames the summary table as before, and now renaming a groupby column renames the summary table as well. Conflicting table names are resolved in the usual way by adding a number at the end, e.g. `Table1_summary_A_B2`. These summary tables are not automatically renamed when the disambiguation is no longer needed. A new migration renames all summary tables to the new scheme, and updates formulas using summary tables with a simple regex. Test Plan: Updated many tests to use the new style of name. Added new Python tests to for resolving conflicts when renaming source tables and groupby columns. Added a test for the migration, including renames in formulas. Reviewers: georgegevoian Reviewed By: georgegevoian Differential Revision: https://phab.getgrist.com/D3508
This commit is contained in:
parent
f1df6c0a46
commit
b8486dcdba
@ -4,7 +4,7 @@ import { GristObjCode } from "app/plugin/GristData";
|
|||||||
|
|
||||||
// tslint:disable:object-literal-key-quotes
|
// tslint:disable:object-literal-key-quotes
|
||||||
|
|
||||||
export const SCHEMA_VERSION = 30;
|
export const SCHEMA_VERSION = 31;
|
||||||
|
|
||||||
export const schema = {
|
export const schema = {
|
||||||
|
|
||||||
|
@ -33,9 +33,10 @@ class GristDocAPIImpl implements GristDocAPI {
|
|||||||
public async getDocName() { return this._activeDoc.docName; }
|
public async getDocName() { return this._activeDoc.docName; }
|
||||||
|
|
||||||
public async listTables(): Promise<string[]> {
|
public async listTables(): Promise<string[]> {
|
||||||
const table = this._activeDoc.docData!.getMetaTable('_grist_Tables');
|
return this._activeDoc.docData!.getMetaTable('_grist_Tables')
|
||||||
return table.getColValues('tableId')
|
.getRecords()
|
||||||
.filter(id => !id.startsWith("GristSummary_")).sort();
|
.filter(r => !r.summarySourceTable)
|
||||||
|
.map(r => r.tableId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async fetchTable(tableId: string): Promise<TableColValues> {
|
public async fetchTable(tableId: string): Promise<TableColValues> {
|
||||||
|
@ -6,7 +6,7 @@ export const GRIST_DOC_SQL = `
|
|||||||
PRAGMA foreign_keys=OFF;
|
PRAGMA foreign_keys=OFF;
|
||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_DocInfo" (id INTEGER PRIMARY KEY, "docId" TEXT DEFAULT '', "peers" TEXT DEFAULT '', "basketId" TEXT DEFAULT '', "schemaVersion" INTEGER DEFAULT 0, "timezone" TEXT DEFAULT '', "documentSettings" TEXT DEFAULT '');
|
CREATE TABLE IF NOT EXISTS "_grist_DocInfo" (id INTEGER PRIMARY KEY, "docId" TEXT DEFAULT '', "peers" TEXT DEFAULT '', "basketId" TEXT DEFAULT '', "schemaVersion" INTEGER DEFAULT 0, "timezone" TEXT DEFAULT '', "documentSettings" TEXT DEFAULT '');
|
||||||
INSERT INTO _grist_DocInfo VALUES(1,'','','',30,'','');
|
INSERT INTO _grist_DocInfo VALUES(1,'','','',31,'','');
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_Tables" (id INTEGER PRIMARY KEY, "tableId" TEXT DEFAULT '', "primaryViewId" INTEGER DEFAULT 0, "summarySourceTable" INTEGER DEFAULT 0, "onDemand" BOOLEAN DEFAULT 0, "rawViewSectionRef" INTEGER DEFAULT 0);
|
CREATE TABLE IF NOT EXISTS "_grist_Tables" (id INTEGER PRIMARY KEY, "tableId" TEXT DEFAULT '', "primaryViewId" INTEGER DEFAULT 0, "summarySourceTable" INTEGER DEFAULT 0, "onDemand" BOOLEAN DEFAULT 0, "rawViewSectionRef" INTEGER DEFAULT 0);
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_Tables_column" (id INTEGER PRIMARY KEY, "parentId" INTEGER DEFAULT 0, "parentPos" NUMERIC DEFAULT 1e999, "colId" TEXT DEFAULT '', "type" TEXT DEFAULT '', "widgetOptions" TEXT DEFAULT '', "isFormula" BOOLEAN DEFAULT 0, "formula" TEXT DEFAULT '', "label" TEXT DEFAULT '', "untieColIdFromLabel" BOOLEAN DEFAULT 0, "summarySourceCol" INTEGER DEFAULT 0, "displayCol" INTEGER DEFAULT 0, "visibleCol" INTEGER DEFAULT 0, "rules" TEXT DEFAULT NULL, "recalcWhen" INTEGER DEFAULT 0, "recalcDeps" TEXT DEFAULT NULL);
|
CREATE TABLE IF NOT EXISTS "_grist_Tables_column" (id INTEGER PRIMARY KEY, "parentId" INTEGER DEFAULT 0, "parentPos" NUMERIC DEFAULT 1e999, "colId" TEXT DEFAULT '', "type" TEXT DEFAULT '', "widgetOptions" TEXT DEFAULT '', "isFormula" BOOLEAN DEFAULT 0, "formula" TEXT DEFAULT '', "label" TEXT DEFAULT '', "untieColIdFromLabel" BOOLEAN DEFAULT 0, "summarySourceCol" INTEGER DEFAULT 0, "displayCol" INTEGER DEFAULT 0, "visibleCol" INTEGER DEFAULT 0, "rules" TEXT DEFAULT NULL, "recalcWhen" INTEGER DEFAULT 0, "recalcDeps" TEXT DEFAULT NULL);
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_Imports" (id INTEGER PRIMARY KEY, "tableRef" INTEGER DEFAULT 0, "origFileName" TEXT DEFAULT '', "parseFormula" TEXT DEFAULT '', "delimiter" TEXT DEFAULT '', "doublequote" BOOLEAN DEFAULT 0, "escapechar" TEXT DEFAULT '', "quotechar" TEXT DEFAULT '', "skipinitialspace" BOOLEAN DEFAULT 0, "encoding" TEXT DEFAULT '', "hasHeaders" BOOLEAN DEFAULT 0);
|
CREATE TABLE IF NOT EXISTS "_grist_Imports" (id INTEGER PRIMARY KEY, "tableRef" INTEGER DEFAULT 0, "origFileName" TEXT DEFAULT '', "parseFormula" TEXT DEFAULT '', "delimiter" TEXT DEFAULT '', "doublequote" BOOLEAN DEFAULT 0, "escapechar" TEXT DEFAULT '', "quotechar" TEXT DEFAULT '', "skipinitialspace" BOOLEAN DEFAULT 0, "encoding" TEXT DEFAULT '', "hasHeaders" BOOLEAN DEFAULT 0);
|
||||||
@ -42,7 +42,7 @@ export const GRIST_DOC_WITH_TABLE1_SQL = `
|
|||||||
PRAGMA foreign_keys=OFF;
|
PRAGMA foreign_keys=OFF;
|
||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_DocInfo" (id INTEGER PRIMARY KEY, "docId" TEXT DEFAULT '', "peers" TEXT DEFAULT '', "basketId" TEXT DEFAULT '', "schemaVersion" INTEGER DEFAULT 0, "timezone" TEXT DEFAULT '', "documentSettings" TEXT DEFAULT '');
|
CREATE TABLE IF NOT EXISTS "_grist_DocInfo" (id INTEGER PRIMARY KEY, "docId" TEXT DEFAULT '', "peers" TEXT DEFAULT '', "basketId" TEXT DEFAULT '', "schemaVersion" INTEGER DEFAULT 0, "timezone" TEXT DEFAULT '', "documentSettings" TEXT DEFAULT '');
|
||||||
INSERT INTO _grist_DocInfo VALUES(1,'','','',30,'','');
|
INSERT INTO _grist_DocInfo VALUES(1,'','','',31,'','');
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_Tables" (id INTEGER PRIMARY KEY, "tableId" TEXT DEFAULT '', "primaryViewId" INTEGER DEFAULT 0, "summarySourceTable" INTEGER DEFAULT 0, "onDemand" BOOLEAN DEFAULT 0, "rawViewSectionRef" INTEGER DEFAULT 0);
|
CREATE TABLE IF NOT EXISTS "_grist_Tables" (id INTEGER PRIMARY KEY, "tableId" TEXT DEFAULT '', "primaryViewId" INTEGER DEFAULT 0, "summarySourceTable" INTEGER DEFAULT 0, "onDemand" BOOLEAN DEFAULT 0, "rawViewSectionRef" INTEGER DEFAULT 0);
|
||||||
INSERT INTO _grist_Tables VALUES(1,'Table1',1,0,0,2);
|
INSERT INTO _grist_Tables VALUES(1,'Table1',1,0,0,2);
|
||||||
CREATE TABLE IF NOT EXISTS "_grist_Tables_column" (id INTEGER PRIMARY KEY, "parentId" INTEGER DEFAULT 0, "parentPos" NUMERIC DEFAULT 1e999, "colId" TEXT DEFAULT '', "type" TEXT DEFAULT '', "widgetOptions" TEXT DEFAULT '', "isFormula" BOOLEAN DEFAULT 0, "formula" TEXT DEFAULT '', "label" TEXT DEFAULT '', "untieColIdFromLabel" BOOLEAN DEFAULT 0, "summarySourceCol" INTEGER DEFAULT 0, "displayCol" INTEGER DEFAULT 0, "visibleCol" INTEGER DEFAULT 0, "rules" TEXT DEFAULT NULL, "recalcWhen" INTEGER DEFAULT 0, "recalcDeps" TEXT DEFAULT NULL);
|
CREATE TABLE IF NOT EXISTS "_grist_Tables_column" (id INTEGER PRIMARY KEY, "parentId" INTEGER DEFAULT 0, "parentPos" NUMERIC DEFAULT 1e999, "colId" TEXT DEFAULT '', "type" TEXT DEFAULT '', "widgetOptions" TEXT DEFAULT '', "isFormula" BOOLEAN DEFAULT 0, "formula" TEXT DEFAULT '', "label" TEXT DEFAULT '', "untieColIdFromLabel" BOOLEAN DEFAULT 0, "summarySourceCol" INTEGER DEFAULT 0, "displayCol" INTEGER DEFAULT 0, "visibleCol" INTEGER DEFAULT 0, "rules" TEXT DEFAULT NULL, "recalcWhen" INTEGER DEFAULT 0, "recalcDeps" TEXT DEFAULT NULL);
|
||||||
|
@ -436,7 +436,7 @@ class Engine(object):
|
|||||||
m = match_counter.MatchCounter(sample)
|
m = match_counter.MatchCounter(sample)
|
||||||
# Iterates through each valid column in the document, counting matches.
|
# Iterates through each valid column in the document, counting matches.
|
||||||
for c in search_cols:
|
for c in search_cols:
|
||||||
if (not gencode._is_special_table(c.tableId) and
|
if (not (gencode._is_special_table(c.tableId) or c.parentId.summarySourceTable) and
|
||||||
column.is_visible_column(c.colId) and
|
column.is_visible_column(c.colId) and
|
||||||
not c.type.startswith('Ref')):
|
not c.type.startswith('Ref')):
|
||||||
table = self.tables[c.tableId]
|
table = self.tables[c.tableId]
|
||||||
@ -1265,7 +1265,7 @@ class Engine(object):
|
|||||||
return sum(
|
return sum(
|
||||||
table._num_rows()
|
table._num_rows()
|
||||||
for table_id, table in six.iteritems(self.tables)
|
for table_id, table in six.iteritems(self.tables)
|
||||||
if useractions.is_user_table(table_id)
|
if useractions.is_user_table(table_id) and not table._summary_source_table
|
||||||
)
|
)
|
||||||
|
|
||||||
def apply_user_actions(self, user_actions, user=None):
|
def apply_user_actions(self, user_actions, user=None):
|
||||||
|
@ -128,7 +128,7 @@ class GenCode(object):
|
|||||||
If filter_for_user is True, includes only user-visible columns.
|
If filter_for_user is True, includes only user-visible columns.
|
||||||
"""
|
"""
|
||||||
table_id = table_info.tableId
|
table_id = table_info.tableId
|
||||||
source_table_id = summary.decode_summary_table_name(table_id)
|
source_table_id = summary.decode_summary_table_name(table_info)
|
||||||
|
|
||||||
# Sort columns by "isFormula" to output all data columns before all formula columns.
|
# Sort columns by "isFormula" to output all data columns before all formula columns.
|
||||||
columns = sorted(six.itervalues(table_info.columns), key=lambda c: c.isFormula)
|
columns = sorted(six.itervalues(table_info.columns), key=lambda c: c.isFormula)
|
||||||
@ -156,7 +156,7 @@ class GenCode(object):
|
|||||||
# Collect summary tables to group them by source table.
|
# Collect summary tables to group them by source table.
|
||||||
summary_tables = {}
|
summary_tables = {}
|
||||||
for table_info in six.itervalues(schema):
|
for table_info in six.itervalues(schema):
|
||||||
source_table_id = summary.decode_summary_table_name(table_info.tableId)
|
source_table_id = summary.decode_summary_table_name(table_info)
|
||||||
if source_table_id:
|
if source_table_id:
|
||||||
summary_tables.setdefault(source_table_id, []).append(table_info)
|
summary_tables.setdefault(source_table_id, []).append(table_info)
|
||||||
|
|
||||||
@ -167,7 +167,10 @@ class GenCode(object):
|
|||||||
for table_info in six.itervalues(schema):
|
for table_info in six.itervalues(schema):
|
||||||
fullparts.append("\n\n")
|
fullparts.append("\n\n")
|
||||||
fullparts.append(self._make_table_model(table_info, summary_tables.get(table_info.tableId)))
|
fullparts.append(self._make_table_model(table_info, summary_tables.get(table_info.tableId)))
|
||||||
if not _is_special_table(table_info.tableId):
|
if not (
|
||||||
|
_is_special_table(table_info.tableId) or
|
||||||
|
summary.decode_summary_table_name(table_info)
|
||||||
|
):
|
||||||
userparts.append("\n\n")
|
userparts.append("\n\n")
|
||||||
userparts.append(self._make_table_model(table_info, summary_tables.get(table_info.tableId),
|
userparts.append(self._make_table_model(table_info, summary_tables.get(table_info.tableId),
|
||||||
filter_for_user=True))
|
filter_for_user=True))
|
||||||
@ -193,7 +196,7 @@ class GenCode(object):
|
|||||||
|
|
||||||
|
|
||||||
def _is_special_table(table_id):
|
def _is_special_table(table_id):
|
||||||
return table_id.startswith("_grist_") or bool(summary.decode_summary_table_name(table_id))
|
return table_id.startswith("_grist_")
|
||||||
|
|
||||||
|
|
||||||
def exec_module_text(module_text):
|
def exec_module_text(module_text):
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
import six
|
import six
|
||||||
from six.moves import xrange
|
from six.moves import xrange
|
||||||
@ -378,7 +379,8 @@ def migration7(tdset):
|
|||||||
groupby_colrefs = [int(x) for x in m.group(2).strip("_").split("_")]
|
groupby_colrefs = [int(x) for x in m.group(2).strip("_").split("_")]
|
||||||
# Prepare a new-style name for the summary table. Be sure not to conflict with existing tables
|
# Prepare a new-style name for the summary table. Be sure not to conflict with existing tables
|
||||||
# or with each other (i.e. don't rename multiple tables to the same name).
|
# or with each other (i.e. don't rename multiple tables to the same name).
|
||||||
new_name = summary.encode_summary_table_name(source_table_name)
|
groupby_col_ids = [columns_map_by_ref[c].colId for c in groupby_colrefs]
|
||||||
|
new_name = summary.encode_summary_table_name(source_table_name, groupby_col_ids)
|
||||||
new_name = identifiers.pick_table_ident(new_name, avoid=table_name_set)
|
new_name = identifiers.pick_table_ident(new_name, avoid=table_name_set)
|
||||||
table_name_set.add(new_name)
|
table_name_set.add(new_name)
|
||||||
log.warn("Upgrading summary table %s for %s(%s) to %s" % (
|
log.warn("Upgrading summary table %s for %s(%s) to %s" % (
|
||||||
@ -1014,3 +1016,60 @@ def migration30(tdset):
|
|||||||
new_view_section_id += 1
|
new_view_section_id += 1
|
||||||
|
|
||||||
return tdset.apply_doc_actions(doc_actions)
|
return tdset.apply_doc_actions(doc_actions)
|
||||||
|
|
||||||
|
|
||||||
|
@migration(schema_version=31)
|
||||||
|
def migration31(tdset):
|
||||||
|
columns = list(actions.transpose_bulk_action(tdset.all_tables['_grist_Tables_column']))
|
||||||
|
tables = list(actions.transpose_bulk_action(tdset.all_tables['_grist_Tables']))
|
||||||
|
|
||||||
|
tables_by_ref = {t.id: t for t in tables}
|
||||||
|
columns_by_table_ref = defaultdict(list)
|
||||||
|
for col in columns:
|
||||||
|
columns_by_table_ref[col.parentId].append(col)
|
||||||
|
|
||||||
|
table_name_set = {t.tableId for t in tables}
|
||||||
|
|
||||||
|
table_renames = [] # List of (table, new_name) pairs
|
||||||
|
|
||||||
|
for t in six.itervalues(tables_by_ref):
|
||||||
|
if not t.summarySourceTable:
|
||||||
|
continue
|
||||||
|
source_table = tables_by_ref[t.summarySourceTable]
|
||||||
|
# Prepare a new-style name for the summary table. Be sure not to conflict with existing tables
|
||||||
|
# or with each other (i.e. don't rename multiple tables to the same name).
|
||||||
|
groupby_col_ids = [c.colId for c in columns_by_table_ref[t.id] if c.summarySourceCol]
|
||||||
|
new_name = summary.encode_summary_table_name(source_table.tableId, groupby_col_ids)
|
||||||
|
if new_name == t.tableId:
|
||||||
|
continue
|
||||||
|
new_name = identifiers.pick_table_ident(new_name, avoid=table_name_set)
|
||||||
|
table_name_set.add(new_name)
|
||||||
|
log.warn("Upgrading summary table %s for %s(%s) to %s" % (
|
||||||
|
t.tableId, source_table.tableId, groupby_col_ids, new_name))
|
||||||
|
|
||||||
|
# Schedule a rename of the summary table.
|
||||||
|
table_renames.append((t, new_name))
|
||||||
|
|
||||||
|
doc_actions = [
|
||||||
|
actions.RenameTable(t.tableId, new)
|
||||||
|
for (t, new) in table_renames
|
||||||
|
]
|
||||||
|
if table_renames:
|
||||||
|
doc_actions.append(
|
||||||
|
actions.BulkUpdateRecord(
|
||||||
|
'_grist_Tables', [t.id for t, new in table_renames],
|
||||||
|
{'tableId': [new for t, new in table_renames]}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update formulas in all columns containing old-style names like 'GristSummary_'
|
||||||
|
for col in columns:
|
||||||
|
if 'GristSummary_' not in col.formula:
|
||||||
|
continue
|
||||||
|
formula = col.formula
|
||||||
|
for table, new_name in table_renames:
|
||||||
|
# Use regex to only match whole words
|
||||||
|
formula = re.sub(r'\b%s\b' % table.tableId, new_name, formula)
|
||||||
|
doc_actions.append(actions.UpdateRecord('_grist_Tables_column', col.id, {'formula': formula}))
|
||||||
|
|
||||||
|
return tdset.apply_doc_actions(doc_actions)
|
||||||
|
@ -15,7 +15,7 @@ import six
|
|||||||
|
|
||||||
import actions
|
import actions
|
||||||
|
|
||||||
SCHEMA_VERSION = 30
|
SCHEMA_VERSION = 31
|
||||||
|
|
||||||
def make_column(col_id, col_type, formula='', isFormula=False):
|
def make_column(col_id, col_type, formula='', isFormula=False):
|
||||||
return {
|
return {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import json
|
import json
|
||||||
import re
|
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
@ -79,38 +78,34 @@ def _copy_widget_options(options):
|
|||||||
return options
|
return options
|
||||||
return json.dumps({k: v for k, v in options.items() if k != "rulesOptions"})
|
return json.dumps({k: v for k, v in options.items() if k != "rulesOptions"})
|
||||||
|
|
||||||
# To generate code, we need to know for each summary table, what its source table is. It would be
|
|
||||||
# easy if we had access to metadata records, but (at least for now) we generate all code based on
|
|
||||||
# schema only. So we encode the source table name inside of the summary table name.
|
|
||||||
#
|
|
||||||
# The encoding includes the length of the source table name, to avoid the possibility of ambiguity
|
|
||||||
# between the second summary table for "Foo", and the first summary table for "Foo2".
|
|
||||||
#
|
|
||||||
# Note that it means we need to rename summary tables when the source table is renamed.
|
|
||||||
|
|
||||||
def encode_summary_table_name(source_table_name):
|
def encode_summary_table_name(source_table_id, groupby_col_ids):
|
||||||
"""
|
"""
|
||||||
Create a summary table name that reliably encodes the source table name. It can be decoded even
|
Create a summary table name based on the source table ID and the groupby column IDs.
|
||||||
if a suffix is added to the returned name.
|
|
||||||
"""
|
"""
|
||||||
return "GristSummary_%d_%s" % (len(source_table_name), source_table_name)
|
result = source_table_id + '_summary'
|
||||||
|
if groupby_col_ids:
|
||||||
|
result += '_' + '_'.join(sorted(groupby_col_ids))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
_summary_re = re.compile(r'GristSummary_(\d+)_')
|
def decode_summary_table_name(summary_table_info):
|
||||||
|
|
||||||
def decode_summary_table_name(summary_table_name):
|
|
||||||
"""
|
"""
|
||||||
Extract the name of the source table from the summary table name.
|
Extract the name of the source table from the summary table schema info.
|
||||||
"""
|
"""
|
||||||
m = _summary_re.match(summary_table_name)
|
# To generate code, we need to know for each summary table, what its source table is. It would be
|
||||||
if m:
|
# easy if we had access to metadata records, but (at least for now) we generate all code based on
|
||||||
start = m.end(0)
|
# schema only. So we use the type of special 'group' column in the summary table.
|
||||||
length = int(m.group(1))
|
group_col = summary_table_info.columns.get('group')
|
||||||
source_name = summary_table_name[start : start + length]
|
if (
|
||||||
if len(source_name) == length:
|
group_col
|
||||||
return source_name
|
and 'getSummarySourceGroup' in group_col.formula
|
||||||
|
and group_col.type.startswith('RefList:')
|
||||||
|
):
|
||||||
|
return group_col.type[8:]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _group_colinfo(source_table):
|
def _group_colinfo(source_table):
|
||||||
"""Returns ColInfo() for the 'group' column that must be present in every summary table."""
|
"""Returns ColInfo() for the 'group' column that must be present in every summary table."""
|
||||||
return _make_col_info(colId='group', type='RefList:%s' % source_table.tableId,
|
return _make_col_info(colId='group', type='RefList:%s' % source_table.tableId,
|
||||||
@ -202,8 +197,9 @@ class SummaryActions(object):
|
|||||||
summary_table = next((t for t in source_table.summaryTables if t.summaryKey == key), None)
|
summary_table = next((t for t in source_table.summaryTables if t.summaryKey == key), None)
|
||||||
created = False
|
created = False
|
||||||
if not summary_table:
|
if not summary_table:
|
||||||
|
groupby_col_ids = [c.colId for c in groupby_colinfo]
|
||||||
result = self.useractions.doAddTable(
|
result = self.useractions.doAddTable(
|
||||||
encode_summary_table_name(source_table.tableId),
|
encode_summary_table_name(source_table.tableId, groupby_col_ids),
|
||||||
[_get_colinfo_dict(ci, with_id=True) for ci in groupby_colinfo + formula_colinfo],
|
[_get_colinfo_dict(ci, with_id=True) for ci in groupby_colinfo + formula_colinfo],
|
||||||
summarySourceTableRef=source_table.id,
|
summarySourceTableRef=source_table.id,
|
||||||
raw_section=True)
|
raw_section=True)
|
||||||
|
@ -208,7 +208,7 @@ class TestColumnActions(test_engine.EngineTestCase):
|
|||||||
Column(16, "B", "Text", False, "", 0),
|
Column(16, "B", "Text", False, "", 0),
|
||||||
Column(17, "C", "Any", True, "", 0),
|
Column(17, "C", "Any", True, "", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address", 0, 1, columns=[
|
Table(3, "Address_summary_state", 0, 1, columns=[
|
||||||
Column(18, "state", "Text", False, "", summarySourceCol=12),
|
Column(18, "state", "Text", False, "", summarySourceCol=12),
|
||||||
Column(19, "group", "RefList:Address", True, summarySourceCol=0,
|
Column(19, "group", "RefList:Address", True, summarySourceCol=0,
|
||||||
formula="table.getSummarySourceGroup(rec)"),
|
formula="table.getSummarySourceGroup(rec)"),
|
||||||
@ -249,7 +249,7 @@ class TestColumnActions(test_engine.EngineTestCase):
|
|||||||
[ 2, "b", "e", None, 2.0],
|
[ 2, "b", "e", None, 2.0],
|
||||||
[ 3, "c", "f", None, 3.0],
|
[ 3, "c", "f", None, 3.0],
|
||||||
])
|
])
|
||||||
self.assertTableData("GristSummary_7_Address", cols="subset", data=[
|
self.assertTableData("Address_summary_state", cols="subset", data=[
|
||||||
[ "id", "state", "count", "amount" ],
|
[ "id", "state", "count", "amount" ],
|
||||||
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
|
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
|
||||||
[ 2, "WA", 1, 3. ],
|
[ 2, "WA", 1, 3. ],
|
||||||
@ -297,7 +297,7 @@ class TestColumnActions(test_engine.EngineTestCase):
|
|||||||
Column(15, "A", "Text", False, "", 0),
|
Column(15, "A", "Text", False, "", 0),
|
||||||
Column(17, "C", "Any", True, "", 0),
|
Column(17, "C", "Any", True, "", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address", 0, 1, columns=[
|
Table(3, "Address_summary_state", 0, 1, columns=[
|
||||||
Column(18, "state", "Text", False, "", summarySourceCol=12),
|
Column(18, "state", "Text", False, "", summarySourceCol=12),
|
||||||
Column(19, "group", "RefList:Address", True, summarySourceCol=0,
|
Column(19, "group", "RefList:Address", True, summarySourceCol=0,
|
||||||
formula="table.getSummarySourceGroup(rec)"),
|
formula="table.getSummarySourceGroup(rec)"),
|
||||||
@ -356,7 +356,7 @@ class TestColumnActions(test_engine.EngineTestCase):
|
|||||||
Column(17, "C", "Any", True, "", 0),
|
Column(17, "C", "Any", True, "", 0),
|
||||||
]),
|
]),
|
||||||
# Note that the summary table here switches to a new one, without the deleted group-by.
|
# Note that the summary table here switches to a new one, without the deleted group-by.
|
||||||
Table(4, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(4, "Address_summary", 0, 1, columns=[
|
||||||
Column(23, "count", "Int", True, summarySourceCol=0, formula="len($group)"),
|
Column(23, "count", "Int", True, summarySourceCol=0, formula="len($group)"),
|
||||||
Column(24, "amount", "Numeric", True, summarySourceCol=0, formula="SUM($group.amount)"),
|
Column(24, "amount", "Numeric", True, summarySourceCol=0, formula="SUM($group.amount)"),
|
||||||
Column(22, "group", "RefList:Address", True, summarySourceCol=0,
|
Column(22, "group", "RefList:Address", True, summarySourceCol=0,
|
||||||
@ -406,7 +406,7 @@ class TestColumnActions(test_engine.EngineTestCase):
|
|||||||
[ 2, "b", None, 2.0],
|
[ 2, "b", None, 2.0],
|
||||||
[ 3, "c", None, 3.0],
|
[ 3, "c", None, 3.0],
|
||||||
])
|
])
|
||||||
self.assertTableData("GristSummary_7_Address2", cols="subset", data=[
|
self.assertTableData("Address_summary", cols="subset", data=[
|
||||||
[ "id", "count", "amount" ],
|
[ "id", "count", "amount" ],
|
||||||
[ 1, 7+1+1+2, 1.+2+6+7+8+10+11+3+4+5+9 ],
|
[ 1, 7+1+1+2, 1.+2+6+7+8+10+11+3+4+5+9 ],
|
||||||
])
|
])
|
||||||
|
@ -60,7 +60,7 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
self.apply_user_action(["CreateViewSection", 2, 0, 'record', [10], None])
|
self.apply_user_action(["CreateViewSection", 2, 0, 'record', [10], None])
|
||||||
|
|
||||||
# Check the results.
|
# Check the results.
|
||||||
self.assertPartialData("GristSummary_6_Orders", ["id", "year", "count", "amount", "group" ], [
|
self.assertPartialData("Orders_summary_year", ["id", "year", "count", "amount", "group" ], [
|
||||||
[1, 2012, 1, 15, [1]],
|
[1, 2012, 1, 15, [1]],
|
||||||
[2, 2013, 2, 30, [2,3]],
|
[2, 2013, 2, 30, [2,3]],
|
||||||
[3, 2014, 3, 86, [4,5,6]],
|
[3, 2014, 3, 86, [4,5,6]],
|
||||||
@ -75,9 +75,9 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
self.assertPartialOutActions(out_actions, {
|
self.assertPartialOutActions(out_actions, {
|
||||||
"stored": [
|
"stored": [
|
||||||
actions.BulkUpdateRecord("Orders", [1,2], {'amount': [14, 14]}),
|
actions.BulkUpdateRecord("Orders", [1,2], {'amount': [14, 14]}),
|
||||||
actions.BulkUpdateRecord("GristSummary_6_Orders", [1,2], {'amount': [14, 29]})
|
actions.BulkUpdateRecord("Orders_summary_year", [1,2], {'amount': [14, 29]})
|
||||||
],
|
],
|
||||||
"calls": {"GristSummary_6_Orders": {"amount": 2}}
|
"calls": {"Orders_summary_year": {"amount": 2}}
|
||||||
})
|
})
|
||||||
|
|
||||||
# Changing a record from one product to another should cause the two affected lines to change.
|
# Changing a record from one product to another should cause the two affected lines to change.
|
||||||
@ -85,16 +85,16 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
self.assertPartialOutActions(out_actions, {
|
self.assertPartialOutActions(out_actions, {
|
||||||
"stored": [
|
"stored": [
|
||||||
actions.UpdateRecord("Orders", 10, {"year": 2012}),
|
actions.UpdateRecord("Orders", 10, {"year": 2012}),
|
||||||
actions.BulkUpdateRecord("GristSummary_6_Orders", [1,4], {"amount": [31.0, 89.0]}),
|
actions.BulkUpdateRecord("Orders_summary_year", [1,4], {"amount": [31.0, 89.0]}),
|
||||||
actions.BulkUpdateRecord("GristSummary_6_Orders", [1,4], {"count": [2,3]}),
|
actions.BulkUpdateRecord("Orders_summary_year", [1,4], {"count": [2,3]}),
|
||||||
actions.BulkUpdateRecord("GristSummary_6_Orders", [1,4], {"group": [[1,10], [7,8,9]]}),
|
actions.BulkUpdateRecord("Orders_summary_year", [1,4], {"group": [[1,10], [7,8,9]]}),
|
||||||
],
|
],
|
||||||
"calls": {"GristSummary_6_Orders": {"group": 2, "amount": 2, "count": 2},
|
"calls": {"Orders_summary_year": {"group": 2, "amount": 2, "count": 2},
|
||||||
"Orders": {"#lookup##summary#GristSummary_6_Orders": 1,
|
"Orders": {"#lookup##summary#Orders_summary_year": 1,
|
||||||
"#summary#GristSummary_6_Orders": 1}}
|
"#summary#Orders_summary_year": 1}}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.assertPartialData("GristSummary_6_Orders", ["id", "year", "count", "amount", "group" ], [
|
self.assertPartialData("Orders_summary_year", ["id", "year", "count", "amount", "group" ], [
|
||||||
[1, 2012, 2, 31.0, [1,10]],
|
[1, 2012, 2, 31.0, [1,10]],
|
||||||
[2, 2013, 2, 29.0, [2,3]],
|
[2, 2013, 2, 29.0, [2,3]],
|
||||||
[3, 2014, 3, 86.0, [4,5,6]],
|
[3, 2014, 3, 86.0, [4,5,6]],
|
||||||
@ -106,20 +106,20 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
self.assertPartialOutActions(out_actions, {
|
self.assertPartialOutActions(out_actions, {
|
||||||
"stored": [
|
"stored": [
|
||||||
actions.UpdateRecord("Orders", 10, {"year": 1999}),
|
actions.UpdateRecord("Orders", 10, {"year": 1999}),
|
||||||
actions.AddRecord("GristSummary_6_Orders", 5, {'year': 1999}),
|
actions.AddRecord("Orders_summary_year", 5, {'year': 1999}),
|
||||||
actions.BulkUpdateRecord("GristSummary_6_Orders", [1,5], {"amount": [14.0, 17.0]}),
|
actions.BulkUpdateRecord("Orders_summary_year", [1,5], {"amount": [14.0, 17.0]}),
|
||||||
actions.BulkUpdateRecord("GristSummary_6_Orders", [1,5], {"count": [1,1]}),
|
actions.BulkUpdateRecord("Orders_summary_year", [1,5], {"count": [1,1]}),
|
||||||
actions.BulkUpdateRecord("GristSummary_6_Orders", [1,5], {"group": [[1], [10]]}),
|
actions.BulkUpdateRecord("Orders_summary_year", [1,5], {"group": [[1], [10]]}),
|
||||||
],
|
],
|
||||||
"calls": {
|
"calls": {
|
||||||
"GristSummary_6_Orders": {
|
"Orders_summary_year": {
|
||||||
'#lookup#year': 1, "group": 2, "amount": 2, "count": 2, "#lookup#": 1
|
'#lookup#year': 1, "group": 2, "amount": 2, "count": 2, "#lookup#": 1
|
||||||
},
|
},
|
||||||
"Orders": {"#lookup##summary#GristSummary_6_Orders": 1,
|
"Orders": {"#lookup##summary#Orders_summary_year": 1,
|
||||||
"#summary#GristSummary_6_Orders": 1}}
|
"#summary#Orders_summary_year": 1}}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.assertPartialData("GristSummary_6_Orders", ["id", "year", "count", "amount", "group" ], [
|
self.assertPartialData("Orders_summary_year", ["id", "year", "count", "amount", "group" ], [
|
||||||
[1, 2012, 1, 14.0, [1]],
|
[1, 2012, 1, 14.0, [1]],
|
||||||
[2, 2013, 2, 29.0, [2,3]],
|
[2, 2013, 2, 29.0, [2,3]],
|
||||||
[3, 2014, 3, 86.0, [4,5,6]],
|
[3, 2014, 3, 86.0, [4,5,6]],
|
||||||
@ -135,7 +135,7 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
self.load_sample(self.sample)
|
self.load_sample(self.sample)
|
||||||
|
|
||||||
self.apply_user_action(["CreateViewSection", 2, 0, 'record', [10, 12], None])
|
self.apply_user_action(["CreateViewSection", 2, 0, 'record', [10, 12], None])
|
||||||
self.assertPartialData("GristSummary_6_Orders", [
|
self.assertPartialData("Orders_summary_product_year", [
|
||||||
"id", "year", "product", "count", "amount", "group"
|
"id", "year", "product", "count", "amount", "group"
|
||||||
], [
|
], [
|
||||||
[1, 2012, "A", 1, 15.0, [1]],
|
[1, 2012, "A", 1, 15.0, [1]],
|
||||||
@ -156,23 +156,23 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
self.assertPartialOutActions(out_actions, {
|
self.assertPartialOutActions(out_actions, {
|
||||||
"stored": [
|
"stored": [
|
||||||
actions.BulkUpdateRecord("Orders", [2, 6, 7], {"product": ["B", "B", "C"]}),
|
actions.BulkUpdateRecord("Orders", [2, 6, 7], {"product": ["B", "B", "C"]}),
|
||||||
actions.AddRecord("GristSummary_6_Orders", 7, {'year': 2013, 'product': 'B'}),
|
actions.AddRecord("Orders_summary_product_year", 7, {'year': 2013, 'product': 'B'}),
|
||||||
actions.AddRecord("GristSummary_6_Orders", 8, {'year': 2015, 'product': 'C'}),
|
actions.AddRecord("Orders_summary_product_year", 8, {'year': 2015, 'product': 'C'}),
|
||||||
actions.RemoveRecord("GristSummary_6_Orders", 4),
|
actions.RemoveRecord("Orders_summary_product_year", 4),
|
||||||
actions.BulkUpdateRecord("GristSummary_6_Orders", [2,3,5,7,8], {
|
actions.BulkUpdateRecord("Orders_summary_product_year", [2,3,5,7,8], {
|
||||||
"amount": [15.0, 86.0, 17.0, 15.0, 17.0]
|
"amount": [15.0, 86.0, 17.0, 15.0, 17.0]
|
||||||
}),
|
}),
|
||||||
actions.BulkUpdateRecord("GristSummary_6_Orders", [2,3,5,7,8], {
|
actions.BulkUpdateRecord("Orders_summary_product_year", [2,3,5,7,8], {
|
||||||
"count": [1, 3, 1, 1, 1]
|
"count": [1, 3, 1, 1, 1]
|
||||||
}),
|
}),
|
||||||
actions.BulkUpdateRecord("GristSummary_6_Orders", [2,3,5,7,8], {
|
actions.BulkUpdateRecord("Orders_summary_product_year", [2,3,5,7,8], {
|
||||||
"group": [[3], [4,5,6], [10], [2], [7]]
|
"group": [[3], [4,5,6], [10], [2], [7]]
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
# Verify the results.
|
# Verify the results.
|
||||||
self.assertPartialData("GristSummary_6_Orders", [
|
self.assertPartialData("Orders_summary_product_year", [
|
||||||
"id", "year", "product", "count", "amount", "group"
|
"id", "year", "product", "count", "amount", "group"
|
||||||
], [
|
], [
|
||||||
[1, 2012, "A", 1, 15.0, [1]],
|
[1, 2012, "A", 1, 15.0, [1]],
|
||||||
@ -194,10 +194,10 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
|
|
||||||
# Create a summary on the Customers table. Adding orders involves a lookup for each customer.
|
# Create a summary on the Customers table. Adding orders involves a lookup for each customer.
|
||||||
self.apply_user_action(["CreateViewSection", 1, 0, 'record', [3], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, 'record', [3], None])
|
||||||
self.add_column("GristSummary_9_Customers", "totalAmount",
|
self.add_column("Customers_summary_state", "totalAmount",
|
||||||
formula="sum(sum(Orders.lookupRecords(customer=c).amount) for c in $group)")
|
formula="sum(sum(Orders.lookupRecords(customer=c).amount) for c in $group)")
|
||||||
|
|
||||||
self.assertPartialData("GristSummary_9_Customers", ["id", "state", "count", "totalAmount"], [
|
self.assertPartialData("Customers_summary_state", ["id", "state", "count", "totalAmount"], [
|
||||||
[1, "NY", 2, 103.0 ],
|
[1, "NY", 2, 103.0 ],
|
||||||
[2, "CT", 2, 134.0 ],
|
[2, "CT", 2, 134.0 ],
|
||||||
[3, "NJ", 1, 0.0 ],
|
[3, "NJ", 1, 0.0 ],
|
||||||
@ -219,14 +219,14 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
self.assertPartialOutActions(out_actions, {
|
self.assertPartialOutActions(out_actions, {
|
||||||
"stored": [
|
"stored": [
|
||||||
actions.UpdateRecord("Orders", 9, {"amount": 37}),
|
actions.UpdateRecord("Orders", 9, {"amount": 37}),
|
||||||
actions.UpdateRecord("GristSummary_9_Customers", 2, {"totalAmount": 135.0}),
|
actions.UpdateRecord("Customers_summary_state", 2, {"totalAmount": 135.0}),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
# In either case, changing a customer's state should trigger recomputation too.
|
# In either case, changing a customer's state should trigger recomputation too.
|
||||||
# We are changing a NY customer with $51 in orders to MA.
|
# We are changing a NY customer with $51 in orders to MA.
|
||||||
self.update_record('Customers', 2, state="MA")
|
self.update_record('Customers', 2, state="MA")
|
||||||
self.assertPartialData("GristSummary_9_Customers", ["id", "state", "count", "totalAmount"], [
|
self.assertPartialData("Customers_summary_state", ["id", "state", "count", "totalAmount"], [
|
||||||
[1, "NY", 1, 52.0 ],
|
[1, "NY", 1, 52.0 ],
|
||||||
[2, "CT", 2, 135.0 ],
|
[2, "CT", 2, 135.0 ],
|
||||||
[3, "NJ", 1, 0.0 ],
|
[3, "NJ", 1, 0.0 ],
|
||||||
@ -246,7 +246,7 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
# actions.AddRecord("Summary4", 4, {"state": "NJ"}),
|
# actions.AddRecord("Summary4", 4, {"state": "NJ"}),
|
||||||
# actions.UpdateRecord("Summary4", 4, {"manualSort": 4.0})]
|
# actions.UpdateRecord("Summary4", 4, {"manualSort": 4.0})]
|
||||||
# })
|
# })
|
||||||
self.assertPartialData("GristSummary_9_Customers", ["id", "state", "count", "totalAmount"], [
|
self.assertPartialData("Customers_summary_state", ["id", "state", "count", "totalAmount"], [
|
||||||
[1, "NY", 1, 35.0 ],
|
[1, "NY", 1, 35.0 ],
|
||||||
[2, "CT", 2, 135.0 ],
|
[2, "CT", 2, 135.0 ],
|
||||||
[3, "NJ", 1, 17.0 ],
|
[3, "NJ", 1, 17.0 ],
|
||||||
@ -264,7 +264,7 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
|
|
||||||
# Create a summary table summarizing count and total of orders by year.
|
# Create a summary table summarizing count and total of orders by year.
|
||||||
self.apply_user_action(["CreateViewSection", 2, 0, 'record', [10], None])
|
self.apply_user_action(["CreateViewSection", 2, 0, 'record', [10], None])
|
||||||
self.assertPartialData("GristSummary_6_Orders", ["id", "year", "count", "amount", "group" ], [
|
self.assertPartialData("Orders_summary_year", ["id", "year", "count", "amount", "group" ], [
|
||||||
[1, 2012, 1, 15.0, [1]],
|
[1, 2012, 1, 15.0, [1]],
|
||||||
[2, 2013, 2, 30.0, [2,3]],
|
[2, 2013, 2, 30.0, [2,3]],
|
||||||
[3, 2014, 3, 86.0, [4,5,6]],
|
[3, 2014, 3, 86.0, [4,5,6]],
|
||||||
@ -273,7 +273,7 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
|
|
||||||
# Update a record so that a new line appears in the summary table.
|
# Update a record so that a new line appears in the summary table.
|
||||||
out_actions_update = self.update_record("Orders", 1, year=2007)
|
out_actions_update = self.update_record("Orders", 1, year=2007)
|
||||||
self.assertPartialData("GristSummary_6_Orders", ["id", "year", "count", "amount", "group" ], [
|
self.assertPartialData("Orders_summary_year", ["id", "year", "count", "amount", "group" ], [
|
||||||
[2, 2013, 2, 30.0, [2,3]],
|
[2, 2013, 2, 30.0, [2,3]],
|
||||||
[3, 2014, 3, 86.0, [4,5,6]],
|
[3, 2014, 3, 86.0, [4,5,6]],
|
||||||
[4, 2015, 4, 106.0, [7,8,9,10]],
|
[4, 2015, 4, 106.0, [7,8,9,10]],
|
||||||
@ -282,7 +282,7 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
|
|
||||||
# Undo and ensure that the new line is gone from the summary table.
|
# Undo and ensure that the new line is gone from the summary table.
|
||||||
out_actions_undo = self.apply_undo_actions(out_actions_update.undo)
|
out_actions_undo = self.apply_undo_actions(out_actions_update.undo)
|
||||||
self.assertPartialData("GristSummary_6_Orders", ["id", "year", "count", "amount", "group" ], [
|
self.assertPartialData("Orders_summary_year", ["id", "year", "count", "amount", "group" ], [
|
||||||
[1, 2012, 1, 15.0, [1]],
|
[1, 2012, 1, 15.0, [1]],
|
||||||
[2, 2013, 2, 30.0, [2,3]],
|
[2, 2013, 2, 30.0, [2,3]],
|
||||||
[3, 2014, 3, 86.0, [4,5,6]],
|
[3, 2014, 3, 86.0, [4,5,6]],
|
||||||
@ -290,18 +290,18 @@ class TestDerived(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
self.assertPartialOutActions(out_actions_undo, {
|
self.assertPartialOutActions(out_actions_undo, {
|
||||||
"stored": [
|
"stored": [
|
||||||
actions.AddRecord("GristSummary_6_Orders", 1, {
|
actions.AddRecord("Orders_summary_year", 1, {
|
||||||
"amount": 15.0, "count": 1, "group": [1], "year": 2012
|
"amount": 15.0, "count": 1, "group": [1], "year": 2012
|
||||||
}),
|
}),
|
||||||
actions.RemoveRecord("GristSummary_6_Orders", 5),
|
actions.RemoveRecord("Orders_summary_year", 5),
|
||||||
actions.UpdateRecord("Orders", 1, {"year": 2012}),
|
actions.UpdateRecord("Orders", 1, {"year": 2012}),
|
||||||
],
|
],
|
||||||
"calls": {
|
"calls": {
|
||||||
"GristSummary_6_Orders": {
|
"Orders_summary_year": {
|
||||||
"#lookup#": 1, "#lookup#year": 1, "group": 1, "amount": 1, "count": 1
|
"#lookup#": 1, "#lookup#year": 1, "group": 1, "amount": 1, "count": 1
|
||||||
},
|
},
|
||||||
"Orders": {
|
"Orders": {
|
||||||
"#lookup##summary#GristSummary_6_Orders": 1, "#summary#GristSummary_6_Orders": 1,
|
"#lookup##summary#Orders_summary_year": 1, "#summary#Orders_summary_year": 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -66,25 +66,10 @@ class TestSummary(test_engine.EngineTestCase):
|
|||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
def test_encode_summary_table_name(self):
|
def test_encode_summary_table_name(self):
|
||||||
self.assertEqual(summary.encode_summary_table_name("Foo"), "GristSummary_3_Foo")
|
self.assertEqual(summary.encode_summary_table_name("Foo", []), "Foo_summary")
|
||||||
self.assertEqual(summary.encode_summary_table_name("Foo2"), "GristSummary_4_Foo2")
|
self.assertEqual(summary.encode_summary_table_name("Foo", ["A"]), "Foo_summary_A")
|
||||||
self.assertEqual(summary.decode_summary_table_name("GristSummary_3_Foo"), "Foo")
|
self.assertEqual(summary.encode_summary_table_name("Foo", ["A", "B"]), "Foo_summary_A_B")
|
||||||
self.assertEqual(summary.decode_summary_table_name("GristSummary_4_Foo2"), "Foo2")
|
self.assertEqual(summary.encode_summary_table_name("Foo", ["B", "A"]), "Foo_summary_A_B")
|
||||||
self.assertEqual(summary.decode_summary_table_name("GristSummary_3_Foo2"), "Foo")
|
|
||||||
self.assertEqual(summary.decode_summary_table_name("GristSummary_4_Foo2_2"), "Foo2")
|
|
||||||
# Test that underscore in the name is OK.
|
|
||||||
self.assertEqual(summary.decode_summary_table_name("GristSummary_5_Foo_234"), "Foo_2")
|
|
||||||
self.assertEqual(summary.decode_summary_table_name("GristSummary_4_Foo_234"), "Foo_")
|
|
||||||
self.assertEqual(summary.decode_summary_table_name("GristSummary_6__Foo_234"), "_Foo_2")
|
|
||||||
# Test that we return None for invalid values.
|
|
||||||
self.assertEqual(summary.decode_summary_table_name("Foo2"), None)
|
|
||||||
self.assertEqual(summary.decode_summary_table_name("GristSummary_3Foo"), None)
|
|
||||||
self.assertEqual(summary.decode_summary_table_name("GristSummary_4_Foo"), None)
|
|
||||||
self.assertEqual(summary.decode_summary_table_name("GristSummary_3X_Foo"), None)
|
|
||||||
self.assertEqual(summary.decode_summary_table_name("_5_Foo_234"), None)
|
|
||||||
self.assertEqual(summary.decode_summary_table_name("_GristSummary_3_Foo"), None)
|
|
||||||
self.assertEqual(summary.decode_summary_table_name("gristsummary_3_Foo"), None)
|
|
||||||
self.assertEqual(summary.decode_summary_table_name("GristSummary3_Foo"), None)
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
@ -116,7 +101,7 @@ class TestSummary(test_engine.EngineTestCase):
|
|||||||
|
|
||||||
# Verify that a new table gets created, and a new view, with a section for that table,
|
# Verify that a new table gets created, and a new view, with a section for that table,
|
||||||
# and some auto-generated summary fields.
|
# and some auto-generated summary fields.
|
||||||
summary_table1 = Table(2, "GristSummary_7_Address", primaryViewId=0, summarySourceTable=1,
|
summary_table1 = Table(2, "Address_summary", primaryViewId=0, summarySourceTable=1,
|
||||||
columns=[
|
columns=[
|
||||||
Column(14, "group", "RefList:Address", isFormula=True, summarySourceCol=0,
|
Column(14, "group", "RefList:Address", isFormula=True, summarySourceCol=0,
|
||||||
formula="table.getSummarySourceGroup(rec)"),
|
formula="table.getSummarySourceGroup(rec)"),
|
||||||
@ -135,7 +120,7 @@ class TestSummary(test_engine.EngineTestCase):
|
|||||||
self.assertViews([basic_view, summary_view1])
|
self.assertViews([basic_view, summary_view1])
|
||||||
|
|
||||||
# Verify the summarized data.
|
# Verify the summarized data.
|
||||||
self.assertTableData('GristSummary_7_Address', cols="subset", data=[
|
self.assertTableData('Address_summary', cols="subset", data=[
|
||||||
[ "id", "count", "amount"],
|
[ "id", "count", "amount"],
|
||||||
[ 1, 11, 66.0 ],
|
[ 1, 11, 66.0 ],
|
||||||
])
|
])
|
||||||
@ -145,7 +130,7 @@ class TestSummary(test_engine.EngineTestCase):
|
|||||||
|
|
||||||
# Verify that a new table gets created again, a new view, and a section for that table.
|
# Verify that a new table gets created again, a new view, and a section for that table.
|
||||||
# Note that we also check that summarySourceTable and summarySourceCol fields are correct.
|
# Note that we also check that summarySourceTable and summarySourceCol fields are correct.
|
||||||
summary_table2 = Table(3, "GristSummary_7_Address2", primaryViewId=0, summarySourceTable=1,
|
summary_table2 = Table(3, "Address_summary_state", primaryViewId=0, summarySourceTable=1,
|
||||||
columns=[
|
columns=[
|
||||||
Column(17, "state", "Text", isFormula=False, formula="", summarySourceCol=12),
|
Column(17, "state", "Text", isFormula=False, formula="", summarySourceCol=12),
|
||||||
Column(18, "group", "RefList:Address", isFormula=True, summarySourceCol=0,
|
Column(18, "group", "RefList:Address", isFormula=True, summarySourceCol=0,
|
||||||
@ -173,7 +158,7 @@ class TestSummary(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Verify the summarized data.
|
# Verify the summarized data.
|
||||||
self.assertTableData('GristSummary_7_Address2', cols="subset", data=[
|
self.assertTableData('Address_summary_state', cols="subset", data=[
|
||||||
[ "id", "state", "count", "amount" ],
|
[ "id", "state", "count", "amount" ],
|
||||||
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
|
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
|
||||||
[ 2, "WA", 1, 3. ],
|
[ 2, "WA", 1, 3. ],
|
||||||
@ -185,7 +170,7 @@ class TestSummary(test_engine.EngineTestCase):
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
||||||
|
|
||||||
# Verify the new table and views.
|
# Verify the new table and views.
|
||||||
summary_table3 = Table(4, "GristSummary_7_Address3", primaryViewId=0, summarySourceTable=1,
|
summary_table3 = Table(4, "Address_summary_city_state", primaryViewId=0, summarySourceTable=1,
|
||||||
columns=[
|
columns=[
|
||||||
Column(21, "city", "Text", isFormula=False, formula="", summarySourceCol=11),
|
Column(21, "city", "Text", isFormula=False, formula="", summarySourceCol=11),
|
||||||
Column(22, "state", "Text", isFormula=False, formula="", summarySourceCol=12),
|
Column(22, "state", "Text", isFormula=False, formula="", summarySourceCol=12),
|
||||||
@ -208,7 +193,7 @@ class TestSummary(test_engine.EngineTestCase):
|
|||||||
self.assertViews([basic_view, summary_view1, summary_view2, summary_view3])
|
self.assertViews([basic_view, summary_view1, summary_view2, summary_view3])
|
||||||
|
|
||||||
# Verify the summarized data.
|
# Verify the summarized data.
|
||||||
self.assertTableData('GristSummary_7_Address3', cols="subset", data=[
|
self.assertTableData('Address_summary_city_state', cols="subset", data=[
|
||||||
[ "id", "city", "state", "count", "amount" ],
|
[ "id", "city", "state", "count", "amount" ],
|
||||||
[ 1, "New York", "NY" , 3, 1.+6+11 ],
|
[ 1, "New York", "NY" , 3, 1.+6+11 ],
|
||||||
[ 2, "Albany", "NY" , 1, 2. ],
|
[ 2, "Albany", "NY" , 1, 2. ],
|
||||||
@ -269,7 +254,7 @@ class Address:
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
||||||
|
|
||||||
# Verify the new table and views.
|
# Verify the new table and views.
|
||||||
summary_table = Table(2, "GristSummary_7_Address", primaryViewId=0, summarySourceTable=1,
|
summary_table = Table(2, "Address_summary_city_state", primaryViewId=0, summarySourceTable=1,
|
||||||
columns=[
|
columns=[
|
||||||
Column(14, "city", "Text", isFormula=False, formula="", summarySourceCol=11),
|
Column(14, "city", "Text", isFormula=False, formula="", summarySourceCol=11),
|
||||||
Column(15, "state", "Text", isFormula=False, formula="", summarySourceCol=12),
|
Column(15, "state", "Text", isFormula=False, formula="", summarySourceCol=12),
|
||||||
@ -316,7 +301,7 @@ class Address:
|
|||||||
self.assertViews([summary_view, summary_view2, summary_view3])
|
self.assertViews([summary_view, summary_view2, summary_view3])
|
||||||
|
|
||||||
# Verify the summarized data.
|
# Verify the summarized data.
|
||||||
self.assertTableData('GristSummary_7_Address', cols="subset", data=[
|
self.assertTableData('Address_summary_city_state', cols="subset", data=[
|
||||||
[ "id", "city", "state", "count", "amount" ],
|
[ "id", "city", "state", "count", "amount" ],
|
||||||
[ 1, "New York", "NY" , 3, 1.+6+11 ],
|
[ 1, "New York", "NY" , 3, 1.+6+11 ],
|
||||||
[ 2, "Albany", "NY" , 1, 2. ],
|
[ 2, "Albany", "NY" , 1, 2. ],
|
||||||
@ -342,12 +327,12 @@ class Address:
|
|||||||
|
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary", 0, 1, columns=[
|
||||||
Column(14, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(14, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(15, "count", "Int", True, "len($group)", 0),
|
Column(15, "count", "Int", True, "len($group)", 0),
|
||||||
Column(16, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(16, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary_state", 0, 1, columns=[
|
||||||
Column(17, "state", "Text", False, "", 12),
|
Column(17, "state", "Text", False, "", 12),
|
||||||
Column(18, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(18, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(19, "count", "Int", True, "len($group)", 0),
|
Column(19, "count", "Int", True, "len($group)", 0),
|
||||||
@ -370,8 +355,8 @@ class Address:
|
|||||||
self.assertTableData("_grist_Tables", cols="subset", data=[
|
self.assertTableData("_grist_Tables", cols="subset", data=[
|
||||||
['id', 'tableId', 'summarySourceTable'],
|
['id', 'tableId', 'summarySourceTable'],
|
||||||
[ 1, 'Address', 0],
|
[ 1, 'Address', 0],
|
||||||
[ 2, 'GristSummary_7_Address', 1],
|
[ 2, 'Address_summary', 1],
|
||||||
[ 3, 'GristSummary_7_Address2', 1],
|
[ 3, 'Address_summary_state', 1],
|
||||||
[ 4, 'Address2', 0],
|
[ 4, 'Address2', 0],
|
||||||
])
|
])
|
||||||
|
|
||||||
@ -382,12 +367,12 @@ class Address:
|
|||||||
# Make sure this creates new section rather than reuses similar ones for the wrong table.
|
# Make sure this creates new section rather than reuses similar ones for the wrong table.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary", 0, 1, columns=[
|
||||||
Column(14, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(14, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(15, "count", "Int", True, "len($group)", 0),
|
Column(15, "count", "Int", True, "len($group)", 0),
|
||||||
Column(16, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(16, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary_state", 0, 1, columns=[
|
||||||
Column(17, "state", "Text", False, "", 12),
|
Column(17, "state", "Text", False, "", 12),
|
||||||
Column(18, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(18, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(19, "count", "Int", True, "len($group)", 0),
|
Column(19, "count", "Int", True, "len($group)", 0),
|
||||||
@ -399,12 +384,12 @@ class Address:
|
|||||||
Column(23, "state", "Text", False, "", 0),
|
Column(23, "state", "Text", False, "", 0),
|
||||||
Column(24, "amount", "Numeric", False, "", 0),
|
Column(24, "amount", "Numeric", False, "", 0),
|
||||||
]),
|
]),
|
||||||
Table(5, "GristSummary_8_Address2", 0, 4, columns=[
|
Table(5, "Address2_summary", 0, 4, columns=[
|
||||||
Column(25, "group", "RefList:Address2", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(25, "group", "RefList:Address2", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(26, "count", "Int", True, "len($group)", 0),
|
Column(26, "count", "Int", True, "len($group)", 0),
|
||||||
Column(27, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(27, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
]),
|
]),
|
||||||
Table(6, "GristSummary_8_Address2_2", 0, 4, columns=[
|
Table(6, "Address2_summary_state", 0, 4, columns=[
|
||||||
Column(28, "state", "Text", False, "", 23),
|
Column(28, "state", "Text", False, "", 23),
|
||||||
Column(29, "group", "RefList:Address2", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(29, "group", "RefList:Address2", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(30, "count", "Int", True, "len($group)", 0),
|
Column(30, "count", "Int", True, "len($group)", 0),
|
||||||
@ -424,7 +409,7 @@ class Address:
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
||||||
|
|
||||||
# Verify that the summary table respects all updates to the source table.
|
# Verify that the summary table respects all updates to the source table.
|
||||||
self._do_test_updates("Address", "GristSummary_7_Address")
|
self._do_test_updates("Address", "Address_summary_city_state")
|
||||||
|
|
||||||
def _do_test_updates(self, source_tbl_name, summary_tbl_name):
|
def _do_test_updates(self, source_tbl_name, summary_tbl_name):
|
||||||
# This is the main part of test_summary_updates(). It's moved to its own method so that
|
# This is the main part of test_summary_updates(). It's moved to its own method so that
|
||||||
@ -541,7 +526,7 @@ class Address:
|
|||||||
# Check what tables we have now.
|
# Check what tables we have now.
|
||||||
self.assertPartialData("_grist_Tables", ["id", "tableId", "summarySourceTable"], [
|
self.assertPartialData("_grist_Tables", ["id", "tableId", "summarySourceTable"], [
|
||||||
[1, "Address", 0],
|
[1, "Address", 0],
|
||||||
[2, "GristSummary_7_Address", 1],
|
[2, "Address_summary_city_state", 1],
|
||||||
])
|
])
|
||||||
|
|
||||||
# Rename the table: this is what we are really testing in this test case.
|
# Rename the table: this is what we are really testing in this test case.
|
||||||
@ -549,11 +534,11 @@ class Address:
|
|||||||
|
|
||||||
self.assertPartialData("_grist_Tables", ["id", "tableId", "summarySourceTable"], [
|
self.assertPartialData("_grist_Tables", ["id", "tableId", "summarySourceTable"], [
|
||||||
[1, "Location", 0],
|
[1, "Location", 0],
|
||||||
[2, "GristSummary_8_Location", 1],
|
[2, "Location_summary_city_state", 1],
|
||||||
])
|
])
|
||||||
|
|
||||||
# Verify that the bigger summary table respects all updates to the renamed source table.
|
# Verify that the bigger summary table respects all updates to the renamed source table.
|
||||||
self._do_test_updates("Location", "GristSummary_8_Location")
|
self._do_test_updates("Location", "Location_summary_city_state")
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
@ -565,11 +550,11 @@ class Address:
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [], None])
|
||||||
self.assertPartialData("_grist_Tables", ["id", "tableId", "summarySourceTable"], [
|
self.assertPartialData("_grist_Tables", ["id", "tableId", "summarySourceTable"], [
|
||||||
[1, "Address", 0],
|
[1, "Address", 0],
|
||||||
[2, "GristSummary_7_Address", 1],
|
[2, "Address_summary_city_state", 1],
|
||||||
[3, "GristSummary_7_Address2", 1],
|
[3, "Address_summary", 1],
|
||||||
])
|
])
|
||||||
# Verify the data in the simple totals-only summary table.
|
# Verify the data in the simple totals-only summary table.
|
||||||
self.assertTableData('GristSummary_7_Address2', cols="subset", data=[
|
self.assertTableData('Address_summary', cols="subset", data=[
|
||||||
[ "id", "count", "amount"],
|
[ "id", "count", "amount"],
|
||||||
[ 1, 11, 66.0 ],
|
[ 1, 11, 66.0 ],
|
||||||
])
|
])
|
||||||
@ -578,21 +563,21 @@ class Address:
|
|||||||
self.apply_user_action(["RenameTable", "Address", "Addresses"])
|
self.apply_user_action(["RenameTable", "Address", "Addresses"])
|
||||||
self.assertPartialData("_grist_Tables", ["id", "tableId", "summarySourceTable"], [
|
self.assertPartialData("_grist_Tables", ["id", "tableId", "summarySourceTable"], [
|
||||||
[1, "Addresses", 0],
|
[1, "Addresses", 0],
|
||||||
[2, "GristSummary_9_Addresses", 1],
|
[2, "Addresses_summary_city_state", 1],
|
||||||
[3, "GristSummary_9_Addresses2", 1],
|
[3, "Addresses_summary", 1],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_9_Addresses2', cols="subset", data=[
|
self.assertTableData('Addresses_summary', cols="subset", data=[
|
||||||
[ "id", "count", "amount"],
|
[ "id", "count", "amount"],
|
||||||
[ 1, 11, 66.0 ],
|
[ 1, 11, 66.0 ],
|
||||||
])
|
])
|
||||||
|
|
||||||
# Remove one of the tables so that we can use _do_test_updates to verify updates still work.
|
# Remove one of the tables so that we can use _do_test_updates to verify updates still work.
|
||||||
self.apply_user_action(["RemoveTable", "GristSummary_9_Addresses2"])
|
self.apply_user_action(["RemoveTable", "Addresses_summary"])
|
||||||
self.assertPartialData("_grist_Tables", ["id", "tableId", "summarySourceTable"], [
|
self.assertPartialData("_grist_Tables", ["id", "tableId", "summarySourceTable"], [
|
||||||
[1, "Addresses", 0],
|
[1, "Addresses", 0],
|
||||||
[2, "GristSummary_9_Addresses", 1],
|
[2, "Addresses_summary_city_state", 1],
|
||||||
])
|
])
|
||||||
self._do_test_updates("Addresses", "GristSummary_9_Addresses")
|
self._do_test_updates("Addresses", "Addresses_summary_city_state")
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
@ -610,14 +595,14 @@ class Address:
|
|||||||
# These are the tables and columns we automatically get.
|
# These are the tables and columns we automatically get.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(14, "city", "Text", False, "", 11),
|
Column(14, "city", "Text", False, "", 11),
|
||||||
Column(15, "state", "Text", False, "", 12),
|
Column(15, "state", "Text", False, "", 12),
|
||||||
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(17, "count", "Int", True, "len($group)", 0),
|
Column(17, "count", "Int", True, "len($group)", 0),
|
||||||
Column(18, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(18, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary", 0, 1, columns=[
|
||||||
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(20, "count", "Int", True, "len($group)", 0),
|
Column(20, "count", "Int", True, "len($group)", 0),
|
||||||
Column(21, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(21, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
@ -626,7 +611,7 @@ class Address:
|
|||||||
|
|
||||||
# Now change a formula using one of the summary tables. It should trigger an equivalent
|
# Now change a formula using one of the summary tables. It should trigger an equivalent
|
||||||
# change in the other.
|
# change in the other.
|
||||||
self.apply_user_action(["ModifyColumn", "GristSummary_7_Address", "amount",
|
self.apply_user_action(["ModifyColumn", "Address_summary_city_state", "amount",
|
||||||
{"formula": "10*sum($group.amount)"}])
|
{"formula": "10*sum($group.amount)"}])
|
||||||
self.assertTableData('_grist_Tables_column', rows="subset", cols="subset", data=[
|
self.assertTableData('_grist_Tables_column', rows="subset", cols="subset", data=[
|
||||||
['id', 'colId', 'type', 'formula', 'widgetOptions', 'label'],
|
['id', 'colId', 'type', 'formula', 'widgetOptions', 'label'],
|
||||||
@ -635,7 +620,7 @@ class Address:
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Change a formula and a few other fields in the other table, and verify a change to both.
|
# Change a formula and a few other fields in the other table, and verify a change to both.
|
||||||
self.apply_user_action(["ModifyColumn", "GristSummary_7_Address2", "amount",
|
self.apply_user_action(["ModifyColumn", "Address_summary", "amount",
|
||||||
{"formula": "100*sum($group.amount)",
|
{"formula": "100*sum($group.amount)",
|
||||||
"type": "Text",
|
"type": "Text",
|
||||||
"widgetOptions": "hello",
|
"widgetOptions": "hello",
|
||||||
@ -649,7 +634,7 @@ class Address:
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Check the values in the summary tables: they should reflect the new formula.
|
# Check the values in the summary tables: they should reflect the new formula.
|
||||||
self.assertTableData('GristSummary_7_Address', cols="subset", data=[
|
self.assertTableData('Address_summary_city_state', cols="subset", data=[
|
||||||
[ "id", "city", "state", "count", "amount" ],
|
[ "id", "city", "state", "count", "amount" ],
|
||||||
[ 1, "New York", "NY" , 3, str(100*(1+6+11))],
|
[ 1, "New York", "NY" , 3, str(100*(1+6+11))],
|
||||||
[ 2, "Albany", "NY" , 1, "200" ],
|
[ 2, "Albany", "NY" , 1, "200" ],
|
||||||
@ -661,7 +646,7 @@ class Address:
|
|||||||
[ 8, "Boston", "MA" , 1, "900" ],
|
[ 8, "Boston", "MA" , 1, "900" ],
|
||||||
[ 9, "Yonkers", "NY" , 1, "1000" ],
|
[ 9, "Yonkers", "NY" , 1, "1000" ],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_7_Address2', cols="subset", data=[
|
self.assertTableData('Address_summary', cols="subset", data=[
|
||||||
[ "id", "count", "amount"],
|
[ "id", "count", "amount"],
|
||||||
[ 1, 11, "6600"],
|
[ 1, 11, "6600"],
|
||||||
])
|
])
|
||||||
@ -670,19 +655,19 @@ class Address:
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [12], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [12], None])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(14, "city", "Text", False, "", 11),
|
Column(14, "city", "Text", False, "", 11),
|
||||||
Column(15, "state", "Text", False, "", 12),
|
Column(15, "state", "Text", False, "", 12),
|
||||||
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(17, "count", "Int", True, "len($group)", 0),
|
Column(17, "count", "Int", True, "len($group)", 0),
|
||||||
Column(18, "amount", "Text", True, "100*sum($group.amount)", 0),
|
Column(18, "amount", "Text", True, "100*sum($group.amount)", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary", 0, 1, columns=[
|
||||||
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(20, "count", "Int", True, "len($group)", 0),
|
Column(20, "count", "Int", True, "len($group)", 0),
|
||||||
Column(21, "amount", "Text", True, "100*sum($group.amount)", 0),
|
Column(21, "amount", "Text", True, "100*sum($group.amount)", 0),
|
||||||
]),
|
]),
|
||||||
Table(4, "GristSummary_7_Address3", 0, 1, columns=[
|
Table(4, "Address_summary_state", 0, 1, columns=[
|
||||||
Column(22, "state", "Text", False, "", 12),
|
Column(22, "state", "Text", False, "", 12),
|
||||||
Column(23, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(23, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(24, "count", "Int", True, "len($group)", 0),
|
Column(24, "count", "Int", True, "len($group)", 0),
|
||||||
@ -697,7 +682,7 @@ class Address:
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Verify the summarized data.
|
# Verify the summarized data.
|
||||||
self.assertTableData('GristSummary_7_Address3', cols="subset", data=[
|
self.assertTableData('Address_summary_state', cols="subset", data=[
|
||||||
[ "id", "state", "count", "amount" ],
|
[ "id", "state", "count", "amount" ],
|
||||||
[ 1, "NY", 7, str(int(100*(1.+2+6+7+8+10+11))) ],
|
[ 1, "NY", 7, str(int(100*(1.+2+6+7+8+10+11))) ],
|
||||||
[ 2, "WA", 1, "300" ],
|
[ 2, "WA", 1, "300" ],
|
||||||
@ -722,7 +707,7 @@ class Address:
|
|||||||
Column(3, "B", "Numeric", False, "", 0),
|
Column(3, "B", "Numeric", False, "", 0),
|
||||||
Column(4, "C", "Any", True, "", 0),
|
Column(4, "C", "Any", True, "", 0),
|
||||||
]),
|
]),
|
||||||
Table(2, "GristSummary_6_Table1", summarySourceTable=1, primaryViewId=0, columns=[
|
Table(2, "Table1_summary_A", summarySourceTable=1, primaryViewId=0, columns=[
|
||||||
Column(5, "A", "Numeric", False, "", 2),
|
Column(5, "A", "Numeric", False, "", 2),
|
||||||
Column(6, "group", "RefList:Table1", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(6, "group", "RefList:Table1", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(7, "count", "Int", True, "len($group)", 0),
|
Column(7, "count", "Int", True, "len($group)", 0),
|
||||||
@ -735,7 +720,7 @@ class Address:
|
|||||||
[ 2, 2.0, 20, 2.0, None ],
|
[ 2, 2.0, 20, 2.0, None ],
|
||||||
[ 3, 3.0, 10, 3.0, None ],
|
[ 3, 3.0, 10, 3.0, None ],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_6_Table1', data=[
|
self.assertTableData('Table1_summary_A', data=[
|
||||||
[ "id", "A", "group", "count", "B" ],
|
[ "id", "A", "group", "count", "B" ],
|
||||||
[ 1, 10, [1,3], 2, 4 ],
|
[ 1, 10, [1,3], 2, 4 ],
|
||||||
[ 2, 20, [2], 1, 2 ],
|
[ 2, 20, [2], 1, 2 ],
|
||||||
@ -753,7 +738,7 @@ class Address:
|
|||||||
Column(3, "B", "Numeric", False, "", 0),
|
Column(3, "B", "Numeric", False, "", 0),
|
||||||
Column(4, "C", "Any", True, "", 0),
|
Column(4, "C", "Any", True, "", 0),
|
||||||
]),
|
]),
|
||||||
Table(2, "GristSummary_6_Table1", summarySourceTable=1, primaryViewId=0, columns=[
|
Table(2, "Table1_summary_A", summarySourceTable=1, primaryViewId=0, columns=[
|
||||||
Column(5, "A", "Text", False, "", 2),
|
Column(5, "A", "Text", False, "", 2),
|
||||||
Column(6, "group", "RefList:Table1", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(6, "group", "RefList:Table1", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(7, "count", "Int", True, "len($group)", 0),
|
Column(7, "count", "Int", True, "len($group)", 0),
|
||||||
@ -766,7 +751,7 @@ class Address:
|
|||||||
[ 2, 2.0, "20", 2.0, None ],
|
[ 2, 2.0, "20", 2.0, None ],
|
||||||
[ 3, 3.0, "10", 3.0, None ],
|
[ 3, 3.0, "10", 3.0, None ],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_6_Table1', data=[
|
self.assertTableData('Table1_summary_A', data=[
|
||||||
[ "id", "A", "group", "count", "B" ],
|
[ "id", "A", "group", "count", "B" ],
|
||||||
[ 1, "10", [1,3], 2, 4 ],
|
[ 1, "10", [1,3], 2, 4 ],
|
||||||
[ 2, "20", [2], 1, 2 ],
|
[ 2, "20", [2], 1, 2 ],
|
||||||
@ -791,7 +776,7 @@ class Address:
|
|||||||
Column(3, "B", "Numeric", False, "", 0),
|
Column(3, "B", "Numeric", False, "", 0),
|
||||||
Column(4, "C", "Numeric", False, "", 0),
|
Column(4, "C", "Numeric", False, "", 0),
|
||||||
]),
|
]),
|
||||||
Table(2, "GristSummary_6_Table1", summarySourceTable=1, primaryViewId=0, columns=[
|
Table(2, "Table1_summary_A_B", summarySourceTable=1, primaryViewId=0, columns=[
|
||||||
Column(5, "A", "Text", False, "", 2),
|
Column(5, "A", "Text", False, "", 2),
|
||||||
Column(6, "B", "Numeric", False, "", 3),
|
Column(6, "B", "Numeric", False, "", 3),
|
||||||
Column(7, "group", "RefList:Table1", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(7, "group", "RefList:Table1", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
@ -805,7 +790,7 @@ class Address:
|
|||||||
[ 2, 2.0, 'b', 1.0, 5 ],
|
[ 2, 2.0, 'b', 1.0, 5 ],
|
||||||
[ 3, 3.0, 'c', 2.0, 6 ],
|
[ 3, 3.0, 'c', 2.0, 6 ],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_6_Table1', data=[
|
self.assertTableData('Table1_summary_A_B', data=[
|
||||||
[ "id", "A", "B", "group", "count", "C" ],
|
[ "id", "A", "B", "group", "count", "C" ],
|
||||||
[ 1, 'a', 1.0, [1], 1, 4 ],
|
[ 1, 'a', 1.0, [1], 1, 4 ],
|
||||||
[ 2, 'b', 1.0, [2], 1, 5 ],
|
[ 2, 'b', 1.0, [2], 1, 5 ],
|
||||||
@ -822,7 +807,7 @@ class Address:
|
|||||||
Column(3, "B", "Numeric", False, "", 0),
|
Column(3, "B", "Numeric", False, "", 0),
|
||||||
Column(4, "C", "Numeric", False, "", 0),
|
Column(4, "C", "Numeric", False, "", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_6_Table1_2", summarySourceTable=1, primaryViewId=0, columns=[
|
Table(3, "Table1_summary_B", summarySourceTable=1, primaryViewId=0, columns=[
|
||||||
Column(10, "B", "Numeric", False, "", 3),
|
Column(10, "B", "Numeric", False, "", 3),
|
||||||
Column(12, "count", "Int", True, "len($group)", 0),
|
Column(12, "count", "Int", True, "len($group)", 0),
|
||||||
Column(13, "C", "Numeric", True, "SUM($group.C)", 0),
|
Column(13, "C", "Numeric", True, "SUM($group.C)", 0),
|
||||||
@ -835,7 +820,7 @@ class Address:
|
|||||||
[ 2, 2.0, 1.0, 5 ],
|
[ 2, 2.0, 1.0, 5 ],
|
||||||
[ 3, 3.0, 2.0, 6 ],
|
[ 3, 3.0, 2.0, 6 ],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_6_Table1_2', data=[
|
self.assertTableData('Table1_summary_B', data=[
|
||||||
[ "id", "B", "group", "count", "C" ],
|
[ "id", "B", "group", "count", "C" ],
|
||||||
[ 1, 1.0, [1,2], 2, 9 ],
|
[ 1, 1.0, [1,2], 2, 9 ],
|
||||||
[ 2, 2.0, [3], 1, 6 ],
|
[ 2, 2.0, [3], 1, 6 ],
|
||||||
|
@ -4,9 +4,9 @@ files: test_summary.py and test_summary2.py.
|
|||||||
"""
|
"""
|
||||||
import actions
|
import actions
|
||||||
import logger
|
import logger
|
||||||
import objtypes
|
|
||||||
import test_engine
|
import test_engine
|
||||||
import test_summary
|
import test_summary
|
||||||
|
import testutil
|
||||||
|
|
||||||
from test_engine import Table, Column, View, Section, Field
|
from test_engine import Table, Column, View, Section, Field
|
||||||
|
|
||||||
@ -32,15 +32,15 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
|
|
||||||
# Check that we cannot add a non-formula column.
|
# Check that we cannot add a non-formula column.
|
||||||
with self.assertRaisesRegex(ValueError, r'non-formula column'):
|
with self.assertRaisesRegex(ValueError, r'non-formula column'):
|
||||||
self.apply_user_action(["AddColumn", "GristSummary_7_Address", "average",
|
self.apply_user_action(["AddColumn", "Address_summary_city_state", "average",
|
||||||
{"type": "Text", "isFormula": False}])
|
{"type": "Text", "isFormula": False}])
|
||||||
|
|
||||||
# Add two formula columns: one for 'state' (an existing column name, and a group-by column in
|
# Add two formula columns: one for 'state' (an existing column name, and a group-by column in
|
||||||
# some tables), and one for 'average' (a new column name).
|
# some tables), and one for 'average' (a new column name).
|
||||||
self.apply_user_action(["AddVisibleColumn", "GristSummary_7_Address2", "state",
|
self.apply_user_action(["AddVisibleColumn", "Address_summary", "state",
|
||||||
{"formula": "':'.join(sorted(set($group.state)))"}])
|
{"formula": "':'.join(sorted(set($group.state)))"}])
|
||||||
|
|
||||||
self.apply_user_action(["AddVisibleColumn", "GristSummary_7_Address", "average",
|
self.apply_user_action(["AddVisibleColumn", "Address_summary_city_state", "average",
|
||||||
{"formula": "$amount / $count"}])
|
{"formula": "$amount / $count"}])
|
||||||
|
|
||||||
# Add two more summary tables: by 'city', and by 'state', and see what columns they get.
|
# Add two more summary tables: by 'city', and by 'state', and see what columns they get.
|
||||||
@ -52,7 +52,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
# Check the table and columns for all the summary tables.
|
# Check the table and columns for all the summary tables.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(14, "city", "Text", False, "", 11),
|
Column(14, "city", "Text", False, "", 11),
|
||||||
Column(15, "state", "Text", False, "", 12),
|
Column(15, "state", "Text", False, "", 12),
|
||||||
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
@ -60,13 +60,13 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Column(18, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(18, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
Column(23, "average", "Any", True, "$amount / $count", 0),
|
Column(23, "average", "Any", True, "$amount / $count", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary", 0, 1, columns=[
|
||||||
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(20, "count", "Int", True, "len($group)", 0),
|
Column(20, "count", "Int", True, "len($group)", 0),
|
||||||
Column(21, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(21, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
Column(22, "state", "Any", True, "':'.join(sorted(set($group.state)))", 0),
|
Column(22, "state", "Any", True, "':'.join(sorted(set($group.state)))", 0),
|
||||||
]),
|
]),
|
||||||
Table(4, "GristSummary_7_Address3", 0, 1, columns=[
|
Table(4, "Address_summary_city", 0, 1, columns=[
|
||||||
Column(24, "city", "Text", False, "", 11),
|
Column(24, "city", "Text", False, "", 11),
|
||||||
Column(25, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(25, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(26, "count", "Int", True, "len($group)", 0),
|
Column(26, "count", "Int", True, "len($group)", 0),
|
||||||
@ -74,7 +74,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Column(28, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(28, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
]),
|
]),
|
||||||
# Note that since 'state' is used as a group-by column here, we skip the 'state' formula.
|
# Note that since 'state' is used as a group-by column here, we skip the 'state' formula.
|
||||||
Table(5, "GristSummary_7_Address4", 0, 1, columns=[
|
Table(5, "Address_summary_state", 0, 1, columns=[
|
||||||
Column(29, "state", "Text", False, "", 12),
|
Column(29, "state", "Text", False, "", 12),
|
||||||
Column(30, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(30, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(31, "count", "Int", True, "len($group)", 0),
|
Column(31, "count", "Int", True, "len($group)", 0),
|
||||||
@ -106,7 +106,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
|
|
||||||
|
|
||||||
# Check that the data is as we expect.
|
# Check that the data is as we expect.
|
||||||
self.assertTableData('GristSummary_7_Address', cols="all", data=[
|
self.assertTableData('Address_summary_city_state', cols="all", data=[
|
||||||
[ "id", "city", "state", "group", "count", "amount", "average" ],
|
[ "id", "city", "state", "group", "count", "amount", "average" ],
|
||||||
[ 1, "New York", "NY" , [21,26,31],3, 1.+6+11 , (1.+6+11)/3 ],
|
[ 1, "New York", "NY" , [21,26,31],3, 1.+6+11 , (1.+6+11)/3 ],
|
||||||
[ 2, "Albany", "NY" , [22], 1, 2. , 2. ],
|
[ 2, "Albany", "NY" , [22], 1, 2. , 2. ],
|
||||||
@ -118,11 +118,11 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
[ 8, "Boston", "MA" , [29], 1, 9. , 9. ],
|
[ 8, "Boston", "MA" , [29], 1, 9. , 9. ],
|
||||||
[ 9, "Yonkers", "NY" , [30], 1, 10. , 10. ],
|
[ 9, "Yonkers", "NY" , [30], 1, 10. , 10. ],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_7_Address2', cols="all", data=[
|
self.assertTableData('Address_summary', cols="all", data=[
|
||||||
[ "id", "count", "amount", "state" , "group" ],
|
[ "id", "count", "amount", "state" , "group" ],
|
||||||
[ 1, 11, 66.0 , "IL:MA:NY:WA" , [21,22,23,24,25,26,27,28,29,30,31]],
|
[ 1, 11, 66.0 , "IL:MA:NY:WA" , [21,22,23,24,25,26,27,28,29,30,31]],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_7_Address3', cols="subset", data=[
|
self.assertTableData('Address_summary_city', cols="subset", data=[
|
||||||
[ "id", "city", "count", "amount", "state" ],
|
[ "id", "city", "count", "amount", "state" ],
|
||||||
[ 1, "New York", 3, 1.+6+11 , "NY" ],
|
[ 1, "New York", 3, 1.+6+11 , "NY" ],
|
||||||
[ 2, "Albany", 1, 2. , "NY" ],
|
[ 2, "Albany", 1, 2. , "NY" ],
|
||||||
@ -133,7 +133,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
[ 7, "Boston", 1, 9. , "MA" ],
|
[ 7, "Boston", 1, 9. , "MA" ],
|
||||||
[ 8, "Yonkers", 1, 10. , "NY" ],
|
[ 8, "Yonkers", 1, 10. , "NY" ],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_7_Address4', cols="subset", data=[
|
self.assertTableData('Address_summary_state', cols="subset", data=[
|
||||||
[ "id", "state", "count", "amount" ],
|
[ "id", "state", "count", "amount" ],
|
||||||
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
|
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
|
||||||
[ 2, "WA", 1, 3. ],
|
[ 2, "WA", 1, 3. ],
|
||||||
@ -146,16 +146,16 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
self.assertPartialOutActions(out_actions, {
|
self.assertPartialOutActions(out_actions, {
|
||||||
"stored": [
|
"stored": [
|
||||||
actions.UpdateRecord("Address", 28, {'state': 'MA'}),
|
actions.UpdateRecord("Address", 28, {'state': 'MA'}),
|
||||||
actions.RemoveRecord("GristSummary_7_Address", 7),
|
actions.RemoveRecord("Address_summary_city_state", 7),
|
||||||
actions.UpdateRecord("GristSummary_7_Address", 5, {'amount': 5.0 + 8.0}),
|
actions.UpdateRecord("Address_summary_city", 5, {'state': "MA"}),
|
||||||
actions.UpdateRecord("GristSummary_7_Address", 5, {'average': 6.5}),
|
actions.UpdateRecord("Address_summary_city_state", 5, {'amount': 5.0 + 8.0}),
|
||||||
actions.UpdateRecord("GristSummary_7_Address", 5, {'count': 2}),
|
actions.UpdateRecord("Address_summary_city_state", 5, {'average': 6.5}),
|
||||||
actions.UpdateRecord("GristSummary_7_Address", 5, {'group': [25, 28]}),
|
actions.UpdateRecord("Address_summary_city_state", 5, {'count': 2}),
|
||||||
actions.UpdateRecord("GristSummary_7_Address3", 5, {'state': "MA"}),
|
actions.UpdateRecord("Address_summary_city_state", 5, {'group': [25, 28]}),
|
||||||
actions.BulkUpdateRecord("GristSummary_7_Address4", [1,4],
|
actions.BulkUpdateRecord("Address_summary_state", [1,4],
|
||||||
{'amount': [1.+2+6+7+10+11, 5.+8+9]}),
|
{'amount': [1.+2+6+7+10+11, 5.+8+9]}),
|
||||||
actions.BulkUpdateRecord("GristSummary_7_Address4", [1,4], {'count': [6, 3]}),
|
actions.BulkUpdateRecord("Address_summary_state", [1,4], {'count': [6, 3]}),
|
||||||
actions.BulkUpdateRecord("GristSummary_7_Address4", [1,4],
|
actions.BulkUpdateRecord("Address_summary_state", [1,4],
|
||||||
{'group': [[21,22,26,27,30,31], [25,28,29]]}),
|
{'group': [[21,22,26,27,30,31], [25,28,29]]}),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@ -175,11 +175,11 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
# Check that we cannot rename a summary group-by column. (Perhaps it's better to raise an
|
# Check that we cannot rename a summary group-by column. (Perhaps it's better to raise an
|
||||||
# exception, but currently we translate the invalid request to a no-op.)
|
# exception, but currently we translate the invalid request to a no-op.)
|
||||||
with self.assertRaisesRegex(ValueError, r'Cannot modify .* group-by'):
|
with self.assertRaisesRegex(ValueError, r'Cannot modify .* group-by'):
|
||||||
self.apply_user_action(["RenameColumn", "GristSummary_7_Address", "state", "s"])
|
self.apply_user_action(["RenameColumn", "Address_summary_city_state", "state", "s"])
|
||||||
|
|
||||||
# Verify all data. We'll repeat this after renamings to make sure there are no errors.
|
# Verify all data. We'll repeat this after renamings to make sure there are no errors.
|
||||||
self.assertTableData("Address", self.starting_table_data)
|
self.assertTableData("Address", self.starting_table_data)
|
||||||
self.assertTableData('GristSummary_7_Address', cols="all", data=[
|
self.assertTableData('Address_summary_city_state', cols="all", data=[
|
||||||
[ "id", "city", "state", "group", "count", "amount" ],
|
[ "id", "city", "state", "group", "count", "amount" ],
|
||||||
[ 1, "New York", "NY" , [21,26,31],3, 1.+6+11 ],
|
[ 1, "New York", "NY" , [21,26,31],3, 1.+6+11 ],
|
||||||
[ 2, "Albany", "NY" , [22], 1, 2. ],
|
[ 2, "Albany", "NY" , [22], 1, 2. ],
|
||||||
@ -191,25 +191,25 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
[ 8, "Boston", "MA" , [29], 1, 9. ],
|
[ 8, "Boston", "MA" , [29], 1, 9. ],
|
||||||
[ 9, "Yonkers", "NY" , [30], 1, 10. ],
|
[ 9, "Yonkers", "NY" , [30], 1, 10. ],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_7_Address2', cols="all", data=[
|
self.assertTableData('Address_summary', cols="all", data=[
|
||||||
[ "id", "count", "amount", "group" ],
|
[ "id", "count", "amount", "group" ],
|
||||||
[ 1, 11, 66.0 , [21,22,23,24,25,26,27,28,29,30,31]],
|
[ 1, 11, 66.0 , [21,22,23,24,25,26,27,28,29,30,31]],
|
||||||
])
|
])
|
||||||
|
|
||||||
# This should work fine, and should affect sister tables.
|
# This should work fine, and should affect sister tables.
|
||||||
self.apply_user_action(["RenameColumn", "GristSummary_7_Address", "count", "xcount"])
|
self.apply_user_action(["RenameColumn", "Address_summary_city_state", "count", "xcount"])
|
||||||
|
|
||||||
# These are the tables and columns we automatically get.
|
# These are the tables and columns we automatically get.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(14, "city", "Text", False, "", 11),
|
Column(14, "city", "Text", False, "", 11),
|
||||||
Column(15, "state", "Text", False, "", 12),
|
Column(15, "state", "Text", False, "", 12),
|
||||||
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(17, "xcount", "Int", True, "len($group)", 0),
|
Column(17, "xcount", "Int", True, "len($group)", 0),
|
||||||
Column(18, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(18, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary", 0, 1, columns=[
|
||||||
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(20, "xcount", "Int", True, "len($group)", 0),
|
Column(20, "xcount", "Int", True, "len($group)", 0),
|
||||||
Column(21, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(21, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
@ -226,14 +226,14 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Column(12, "xstate", "Text", False, "", 0),
|
Column(12, "xstate", "Text", False, "", 0),
|
||||||
Column(13, "xamount", "Numeric", False, "", 0),
|
Column(13, "xamount", "Numeric", False, "", 0),
|
||||||
]),
|
]),
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary_city_xstate", 0, 1, columns=[
|
||||||
Column(14, "city", "Text", False, "", 11),
|
Column(14, "city", "Text", False, "", 11),
|
||||||
Column(15, "xstate", "Text", False, "", 12),
|
Column(15, "xstate", "Text", False, "", 12),
|
||||||
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(17, "xcount", "Int", True, "len($group)", 0),
|
Column(17, "xcount", "Int", True, "len($group)", 0),
|
||||||
Column(18, "xamount", "Numeric", True, "SUM($group.xamount)", 0),
|
Column(18, "xamount", "Numeric", True, "SUM($group.xamount)", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary", 0, 1, columns=[
|
||||||
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(20, "xcount", "Int", True, "len($group)", 0),
|
Column(20, "xcount", "Int", True, "len($group)", 0),
|
||||||
Column(21, "xamount", "Numeric", True, "SUM($group.xamount)", 0),
|
Column(21, "xamount", "Numeric", True, "SUM($group.xamount)", 0),
|
||||||
@ -247,7 +247,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
address_table_data = replace_col_names(
|
address_table_data = replace_col_names(
|
||||||
self.starting_table_data, state='xstate', amount='xamount')
|
self.starting_table_data, state='xstate', amount='xamount')
|
||||||
self.assertTableData("Address", address_table_data)
|
self.assertTableData("Address", address_table_data)
|
||||||
self.assertTableData('GristSummary_7_Address', cols="all", data=[
|
self.assertTableData('Address_summary_city_xstate', cols="all", data=[
|
||||||
[ "id", "city", "xstate", "group", "xcount", "xamount" ],
|
[ "id", "city", "xstate", "group", "xcount", "xamount" ],
|
||||||
[ 1, "New York", "NY" , [21,26,31],3, 1.+6+11 ],
|
[ 1, "New York", "NY" , [21,26,31],3, 1.+6+11 ],
|
||||||
[ 2, "Albany", "NY" , [22], 1, 2. ],
|
[ 2, "Albany", "NY" , [22], 1, 2. ],
|
||||||
@ -259,14 +259,14 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
[ 8, "Boston", "MA" , [29], 1, 9. ],
|
[ 8, "Boston", "MA" , [29], 1, 9. ],
|
||||||
[ 9, "Yonkers", "NY" , [30], 1, 10. ],
|
[ 9, "Yonkers", "NY" , [30], 1, 10. ],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_7_Address2', cols="all", data=[
|
self.assertTableData('Address_summary', cols="all", data=[
|
||||||
[ "id", "xcount", "xamount", "group" ],
|
[ "id", "xcount", "xamount", "group" ],
|
||||||
[ 1, 11, 66.0 , [21,22,23,24,25,26,27,28,29,30,31]],
|
[ 1, 11, 66.0 , [21,22,23,24,25,26,27,28,29,30,31]],
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
# Add a conflicting name to a summary table and see how renames behave.
|
# Add a conflicting name to a summary table and see how renames behave.
|
||||||
self.apply_user_action(["AddColumn", "GristSummary_7_Address", "foo",
|
self.apply_user_action(["AddColumn", "Address_summary_city_xstate", "foo",
|
||||||
{"formula": "$xamount * 100"}])
|
{"formula": "$xamount * 100"}])
|
||||||
self.apply_user_action(["RenameColumn", "Address", "xstate", "foo"])
|
self.apply_user_action(["RenameColumn", "Address", "xstate", "foo"])
|
||||||
self.apply_user_action(["RenameColumn", "Address", "xamount", "foo"])
|
self.apply_user_action(["RenameColumn", "Address", "xamount", "foo"])
|
||||||
@ -278,7 +278,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Column(12, "foo2", "Text", False, "", 0),
|
Column(12, "foo2", "Text", False, "", 0),
|
||||||
Column(13, "foo3", "Numeric", False, "", 0),
|
Column(13, "foo3", "Numeric", False, "", 0),
|
||||||
]),
|
]),
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary_city_foo2", 0, 1, columns=[
|
||||||
Column(14, "city", "Text", False, "", 11),
|
Column(14, "city", "Text", False, "", 11),
|
||||||
Column(15, "foo2", "Text", False, "", 12),
|
Column(15, "foo2", "Text", False, "", 12),
|
||||||
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
@ -286,7 +286,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Column(18, "foo3", "Numeric", True, "SUM($group.foo3)", 0),
|
Column(18, "foo3", "Numeric", True, "SUM($group.foo3)", 0),
|
||||||
Column(22, "foo", "Any", True, "$foo3 * 100", 0),
|
Column(22, "foo", "Any", True, "$foo3 * 100", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary", 0, 1, columns=[
|
||||||
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(20, "xcount", "Int", True, "len($group)", 0),
|
Column(20, "xcount", "Int", True, "len($group)", 0),
|
||||||
Column(21, "foo3", "Numeric", True, "SUM($group.foo3)", 0),
|
Column(21, "foo3", "Numeric", True, "SUM($group.foo3)", 0),
|
||||||
@ -297,7 +297,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
address_table_data = replace_col_names(
|
address_table_data = replace_col_names(
|
||||||
address_table_data, xstate='foo2', xamount='foo3')
|
address_table_data, xstate='foo2', xamount='foo3')
|
||||||
self.assertTableData("Address", address_table_data)
|
self.assertTableData("Address", address_table_data)
|
||||||
self.assertTableData('GristSummary_7_Address', cols="all", data=[
|
self.assertTableData('Address_summary_city_foo2', cols="all", data=[
|
||||||
[ "id", "city", "foo2" , "group", "xcount", "foo3", "foo" ],
|
[ "id", "city", "foo2" , "group", "xcount", "foo3", "foo" ],
|
||||||
[ 1, "New York", "NY" , [21,26,31],3, 1.+6+11, 100*(1.+6+11) ],
|
[ 1, "New York", "NY" , [21,26,31],3, 1.+6+11, 100*(1.+6+11) ],
|
||||||
[ 2, "Albany", "NY" , [22], 1, 2. , 100*(2.) ],
|
[ 2, "Albany", "NY" , [22], 1, 2. , 100*(2.) ],
|
||||||
@ -309,7 +309,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
[ 8, "Boston", "MA" , [29], 1, 9. , 100*(9.) ],
|
[ 8, "Boston", "MA" , [29], 1, 9. , 100*(9.) ],
|
||||||
[ 9, "Yonkers", "NY" , [30], 1, 10. , 100*(10.) ],
|
[ 9, "Yonkers", "NY" , [30], 1, 10. , 100*(10.) ],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_7_Address2', cols="all", data=[
|
self.assertTableData('Address_summary', cols="all", data=[
|
||||||
[ "id", "xcount", "foo3" , "group" ],
|
[ "id", "xcount", "foo3" , "group" ],
|
||||||
[ 1, 11, 66.0 , [21,22,23,24,25,26,27,28,29,30,31]],
|
[ 1, 11, 66.0 , [21,22,23,24,25,26,27,28,29,30,31]],
|
||||||
])
|
])
|
||||||
@ -328,6 +328,145 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
[21, 'foo3', True, 'WidgetOptions2'],
|
[21, 'foo3', True, 'WidgetOptions2'],
|
||||||
], rows=lambda r: r.colId in ('foo2', 'foo3'))
|
], rows=lambda r: r.colId in ('foo2', 'foo3'))
|
||||||
|
|
||||||
|
def test_summary_col_rename_conflict(self):
|
||||||
|
sample = testutil.parse_test_sample({
|
||||||
|
"SCHEMA": [
|
||||||
|
[1, "Table1", [
|
||||||
|
[11, "A", "Text", False, "", "A", ""],
|
||||||
|
[12, "B", "Text", False, "", "B", ""],
|
||||||
|
]],
|
||||||
|
[2, "Table1_summary_A_B", [
|
||||||
|
[13, "A", "Text", False, "", "A", ""],
|
||||||
|
]],
|
||||||
|
],
|
||||||
|
"DATA": {}
|
||||||
|
})
|
||||||
|
self.load_sample(sample)
|
||||||
|
|
||||||
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11, 12], None])
|
||||||
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11], None])
|
||||||
|
|
||||||
|
table1 = Table(
|
||||||
|
1, "Table1", primaryViewId=0, summarySourceTable=0, columns=[
|
||||||
|
Column(11, "A", "Text", False, "", 0),
|
||||||
|
Column(12, "B", "Text", False, "", 0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Normal table whose name conflicts with the automatically-generated summary table name below
|
||||||
|
fake_summary = Table(
|
||||||
|
2, "Table1_summary_A_B", primaryViewId=0, summarySourceTable=0, columns=[
|
||||||
|
Column(13, "A", "Text", False, "", 0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Auto-generated name has to have a '2' to disambiguate from the normal table.
|
||||||
|
summary_by_a_and_b = Table(
|
||||||
|
3, "Table1_summary_A_B2", primaryViewId=0, summarySourceTable=1, columns=[
|
||||||
|
Column(14, "A", "Text", False, "", 11),
|
||||||
|
Column(15, "B", "Text", False, "", 12),
|
||||||
|
Column(16, "group", "RefList:Table1", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
|
Column(17, "count", "Int", True, "len($group)", 0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# nothing special here yet
|
||||||
|
summary_by_a = Table(
|
||||||
|
4, "Table1_summary_A", primaryViewId=0, summarySourceTable=1, columns=[
|
||||||
|
Column(18, "A", "Text", False, "", 11),
|
||||||
|
Column(19, "group", "RefList:Table1", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
|
Column(20, "count", "Int", True, "len($group)", 0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
tables = [table1, fake_summary, summary_by_a_and_b, summary_by_a]
|
||||||
|
self.assertTables(tables)
|
||||||
|
|
||||||
|
# Add some formulas using summary table names that are about to change
|
||||||
|
self.add_column("Table1", "summary_ref1",
|
||||||
|
type="RefList:Table1_summary_A_B2",
|
||||||
|
formula="Table1_summary_A_B2.lookupRecords(A=1)",
|
||||||
|
isFormula=True)
|
||||||
|
self.add_column("Table1", "summary_ref2",
|
||||||
|
type="Ref:Table1_summary_A",
|
||||||
|
formula="Table1_summary_A.lookupOne(A=23)",
|
||||||
|
isFormula=True)
|
||||||
|
|
||||||
|
# I got the weirdest heisenbug ever when renaming straight from A to A_B.
|
||||||
|
# The order of renaming is not deterministic so it may end up with
|
||||||
|
# 'Table1_summary_A_B3', but asserting that name made it come out as
|
||||||
|
# 'Table1_summary_A_B2' instead. Seems that file contents play a role in
|
||||||
|
# order in sets/dictionaries?
|
||||||
|
self.apply_user_action(["RenameColumn", "Table1", "A", "A2"])
|
||||||
|
self.apply_user_action(["RenameColumn", "Table1", "A2", "A_B"])
|
||||||
|
|
||||||
|
# Summary tables are automatically renamed to match the new column names.
|
||||||
|
summary_by_a_and_b = summary_by_a_and_b._replace(tableId="Table1_summary_A_B_B")
|
||||||
|
summary_by_a = summary_by_a._replace(tableId="Table1_summary_A_B2")
|
||||||
|
|
||||||
|
table1.columns[0] = table1.columns[0]._replace(colId="A_B")
|
||||||
|
summary_by_a_and_b.columns[0] = summary_by_a_and_b.columns[0]._replace(colId="A_B")
|
||||||
|
summary_by_a.columns[0] = summary_by_a.columns[0]._replace(colId="A_B")
|
||||||
|
|
||||||
|
table1.columns.extend([
|
||||||
|
Column(21, "summary_ref1", "RefList:Table1_summary_A_B_B", True,
|
||||||
|
"Table1_summary_A_B_B.lookupRecords(A_B=1)", 0),
|
||||||
|
Column(22, "summary_ref2", "Ref:Table1_summary_A_B2", True,
|
||||||
|
"Table1_summary_A_B2.lookupOne(A_B=23)", 0),
|
||||||
|
])
|
||||||
|
|
||||||
|
tables = [table1, fake_summary, summary_by_a_and_b, summary_by_a]
|
||||||
|
self.assertTables(tables)
|
||||||
|
|
||||||
|
def test_source_table_rename_conflict(self):
|
||||||
|
sample = testutil.parse_test_sample({
|
||||||
|
"SCHEMA": [
|
||||||
|
[1, "Table1", [
|
||||||
|
[11, "A", "Text", False, "", "A", ""],
|
||||||
|
]],
|
||||||
|
[2, "Table2_summary", [
|
||||||
|
[13, "A", "Text", False, "", "A", ""],
|
||||||
|
]],
|
||||||
|
],
|
||||||
|
"DATA": {}
|
||||||
|
})
|
||||||
|
self.load_sample(sample)
|
||||||
|
|
||||||
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [], None])
|
||||||
|
|
||||||
|
table1 = Table(
|
||||||
|
1, "Table1", primaryViewId=0, summarySourceTable=0, columns=[
|
||||||
|
Column(11, "A", "Text", False, "", 0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
fake_summary = Table(
|
||||||
|
2, "Table2_summary", primaryViewId=0, summarySourceTable=0, columns=[
|
||||||
|
Column(13, "A", "Text", False, "", 0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
summary = Table(
|
||||||
|
3, "Table1_summary", primaryViewId=0, summarySourceTable=1, columns=[
|
||||||
|
Column(14, "group", "RefList:Table1", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
|
Column(15, "count", "Int", True, "len($group)", 0),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
tables = [table1, fake_summary, summary]
|
||||||
|
self.assertTables(tables)
|
||||||
|
|
||||||
|
self.apply_user_action(["RenameTable", "Table1", "Table2"])
|
||||||
|
|
||||||
|
table1 = table1._replace(tableId="Table2")
|
||||||
|
# Summary table is automatically renamed to match the new table name.
|
||||||
|
# Needs a '2' to disambiguate from the fake_summary table.
|
||||||
|
summary = summary._replace(tableId="Table2_summary2")
|
||||||
|
summary.columns[0] = summary.columns[0]._replace(type="RefList:Table2")
|
||||||
|
|
||||||
|
tables = [table1, fake_summary, summary]
|
||||||
|
self.assertTables(tables)
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
def test_restrictions(self):
|
def test_restrictions(self):
|
||||||
@ -342,7 +481,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [], None])
|
||||||
|
|
||||||
self.assertTableData('GristSummary_7_Address', cols="all", data=[
|
self.assertTableData('Address_summary_city_state', cols="all", data=[
|
||||||
[ "id", "city", "state", "group", "count", "amount" ],
|
[ "id", "city", "state", "group", "count", "amount" ],
|
||||||
[ 1, "New York", "NY" , [21,26,31],3, 1.+6+11 ],
|
[ 1, "New York", "NY" , [21,26,31],3, 1.+6+11 ],
|
||||||
[ 2, "Albany", "NY" , [22], 1, 2. ],
|
[ 2, "Albany", "NY" , [22], 1, 2. ],
|
||||||
@ -357,48 +496,49 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
|
|
||||||
# (1) no adding/removing/renaming non-formula columns.
|
# (1) no adding/removing/renaming non-formula columns.
|
||||||
with self.assertRaisesRegex(ValueError, r'non-formula column'):
|
with self.assertRaisesRegex(ValueError, r'non-formula column'):
|
||||||
self.apply_user_action(["AddColumn", "GristSummary_7_Address", "foo",
|
self.apply_user_action(["AddColumn", "Address_summary_city_state", "foo",
|
||||||
{"type": "Numeric", "isFormula": False}])
|
{"type": "Numeric", "isFormula": False}])
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, r'group-by column'):
|
with self.assertRaisesRegex(ValueError, r'group-by column'):
|
||||||
self.apply_user_action(["RemoveColumn", "GristSummary_7_Address", "state"])
|
self.apply_user_action(["RemoveColumn", "Address_summary_city_state", "state"])
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, r'Cannot modify .* group-by'):
|
with self.assertRaisesRegex(ValueError, r'Cannot modify .* group-by'):
|
||||||
self.apply_user_action(["RenameColumn", "GristSummary_7_Address", "state", "st"])
|
self.apply_user_action(["RenameColumn", "Address_summary_city_state", "state", "st"])
|
||||||
|
|
||||||
# (2) no converting between formula/non-formula
|
# (2) no converting between formula/non-formula
|
||||||
with self.assertRaisesRegex(ValueError, r'Cannot change .* formula and data'):
|
with self.assertRaisesRegex(ValueError, r'Cannot change .* formula and data'):
|
||||||
self.apply_user_action(["ModifyColumn", "GristSummary_7_Address", "amount",
|
self.apply_user_action(["ModifyColumn", "Address_summary_city_state", "amount",
|
||||||
{"isFormula": False}])
|
{"isFormula": False}])
|
||||||
|
|
||||||
with self.assertRaisesRegex(ValueError, r'Cannot change .* formula and data'):
|
with self.assertRaisesRegex(ValueError, r'Cannot change .* formula and data'):
|
||||||
self.apply_user_action(["ModifyColumn", "GristSummary_7_Address", "state",
|
self.apply_user_action(["ModifyColumn", "Address_summary_city_state", "state",
|
||||||
{"isFormula": True}])
|
{"isFormula": True}])
|
||||||
|
|
||||||
# (3) no editing values in non-formula columns
|
# (3) no editing values in non-formula columns
|
||||||
with self.assertRaisesRegex(ValueError, r'Cannot enter data .* group-by'):
|
with self.assertRaisesRegex(ValueError, r'Cannot enter data .* group-by'):
|
||||||
self.apply_user_action(["UpdateRecord", "GristSummary_7_Address", 6, {"state": "ny"}])
|
self.apply_user_action(["UpdateRecord", "Address_summary_city_state", 6, {"state": "ny"}])
|
||||||
|
|
||||||
# (4) no removing rows (this is questionable b/c empty rows might be OK to remove)
|
# (4) no removing rows (this is questionable b/c empty rows might be OK to remove)
|
||||||
with self.assertRaisesRegex(ValueError, r'Cannot remove record .* summary'):
|
with self.assertRaisesRegex(ValueError, r'Cannot remove record .* summary'):
|
||||||
self.apply_user_action(["RemoveRecord", "GristSummary_7_Address", 6])
|
self.apply_user_action(["RemoveRecord", "Address_summary_city_state", 6])
|
||||||
|
|
||||||
# (5) no renaming summary tables.
|
# (5) no renaming summary tables.
|
||||||
with self.assertRaisesRegex(ValueError, r'cannot rename .* summary'):
|
with self.assertRaisesRegex(ValueError, r'cannot rename .* summary'):
|
||||||
self.apply_user_action(["RenameTable", "GristSummary_7_Address", "GristSummary_hello"])
|
self.apply_user_action(["RenameTable", "Address_summary_city_state", "Address_summary_X"])
|
||||||
|
|
||||||
# Check that we can add an empty column, then set a formula for it.
|
# Check that we can add an empty column, then set a formula for it.
|
||||||
self.apply_user_action(["AddColumn", "GristSummary_7_Address", "foo", {}])
|
self.apply_user_action(["AddColumn", "Address_summary_city_state", "foo", {}])
|
||||||
self.apply_user_action(["ModifyColumn", "GristSummary_7_Address", "foo", {"formula": "1+1"}])
|
self.apply_user_action(["ModifyColumn", "Address_summary_city_state", "foo",
|
||||||
|
{"formula": "1+1"}])
|
||||||
with self.assertRaisesRegex(ValueError, "Can't save .* to formula"):
|
with self.assertRaisesRegex(ValueError, "Can't save .* to formula"):
|
||||||
self.apply_user_action(["UpdateRecord", "GristSummary_7_Address", 1, {"foo": "hello"}])
|
self.apply_user_action(["UpdateRecord", "Address_summary_city_state", 1, {"foo": "hello"}])
|
||||||
|
|
||||||
# But we cannot add an empty column, then add a value to it.
|
# But we cannot add an empty column, then add a value to it.
|
||||||
self.apply_user_action(["AddColumn", "GristSummary_7_Address", "foo2", {}])
|
self.apply_user_action(["AddColumn", "Address_summary_city_state", "foo2", {}])
|
||||||
with self.assertRaisesRegex(ValueError, r'Cannot change .* between formula and data'):
|
with self.assertRaisesRegex(ValueError, r'Cannot change .* between formula and data'):
|
||||||
self.apply_user_action(["UpdateRecord", "GristSummary_7_Address", 1, {"foo2": "hello"}])
|
self.apply_user_action(["UpdateRecord", "Address_summary_city_state", 1, {"foo2": "hello"}])
|
||||||
|
|
||||||
self.assertTableData('GristSummary_7_Address', cols="all", data=[
|
self.assertTableData('Address_summary_city_state', cols="all", data=[
|
||||||
[ "id", "city", "state", "group", "count", "amount", "foo", "foo2" ],
|
[ "id", "city", "state", "group", "count", "amount", "foo", "foo2" ],
|
||||||
[ 1, "New York", "NY" , [21,26,31],3, 1.+6+11 , 2 , None ],
|
[ 1, "New York", "NY" , [21,26,31],3, 1.+6+11 , 2 , None ],
|
||||||
[ 2, "Albany", "NY" , [22], 1, 2. , 2 , None ],
|
[ 2, "Albany", "NY" , [22], 1, 2. , 2 , None ],
|
||||||
@ -426,7 +566,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
# We should have a single summary table, and a single section referring to it.
|
# We should have a single summary table, and a single section referring to it.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(14, "city", "Text", False, "", 11),
|
Column(14, "city", "Text", False, "", 11),
|
||||||
Column(15, "state", "Text", False, "", 12),
|
Column(15, "state", "Text", False, "", 12),
|
||||||
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
@ -442,7 +582,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Field(8, colRef=18),
|
Field(8, colRef=18),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address'])
|
self.assertEqual(get_helper_cols('Address'), ['#summary#Address_summary_city_state'])
|
||||||
|
|
||||||
# Verify more fields of some of the new column objects.
|
# Verify more fields of some of the new column objects.
|
||||||
self.assertTableData('_grist_Tables_column', rows="subset", cols="subset", data=[
|
self.assertTableData('_grist_Tables_column', rows="subset", cols="subset", data=[
|
||||||
@ -457,7 +597,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
# Note that Table #2 is gone at this point, since it's unused.
|
# Note that Table #2 is gone at this point, since it's unused.
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary_state", 0, 1, columns=[
|
||||||
Column(19, "state", "Text", False, "", 12),
|
Column(19, "state", "Text", False, "", 12),
|
||||||
Column(20, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(20, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(21, "count", "Int", True, "len($group)", 0),
|
Column(21, "count", "Int", True, "len($group)", 0),
|
||||||
@ -471,14 +611,14 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Field(8, colRef=22),
|
Field(8, colRef=22),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertTableData('GristSummary_7_Address2', cols="subset", data=[
|
self.assertTableData('Address_summary_state', cols="subset", data=[
|
||||||
[ "id", "state", "count", "amount" ],
|
[ "id", "state", "count", "amount" ],
|
||||||
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
|
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
|
||||||
[ 2, "WA", 1, 3. ],
|
[ 2, "WA", 1, 3. ],
|
||||||
[ 3, "IL", 1, 4. ],
|
[ 3, "IL", 1, 4. ],
|
||||||
[ 4, "MA", 2, 5.+9 ],
|
[ 4, "MA", 2, 5.+9 ],
|
||||||
])
|
])
|
||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address2'])
|
self.assertEqual(get_helper_cols('Address'), ['#summary#Address_summary_state'])
|
||||||
|
|
||||||
# Verify more fields of some of the new column objects.
|
# Verify more fields of some of the new column objects.
|
||||||
self.assertTableData('_grist_Tables_column', rows="subset", cols="subset", data=[
|
self.assertTableData('_grist_Tables_column', rows="subset", cols="subset", data=[
|
||||||
@ -492,7 +632,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
# Note that Table #3 is gone at this point, since it's unused.
|
# Note that Table #3 is gone at this point, since it's unused.
|
||||||
Table(4, "GristSummary_7_Address", 0, 1, columns=[
|
Table(4, "Address_summary_city", 0, 1, columns=[
|
||||||
Column(23, "city", "Text", False, "", 11),
|
Column(23, "city", "Text", False, "", 11),
|
||||||
Column(24, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(24, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(25, "count", "Int", True, "len($group)", 0),
|
Column(25, "count", "Int", True, "len($group)", 0),
|
||||||
@ -506,7 +646,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Field(8, colRef=26),
|
Field(8, colRef=26),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertTableData('GristSummary_7_Address', cols="subset", data=[
|
self.assertTableData('Address_summary_city', cols="subset", data=[
|
||||||
[ "id", "city", "count", "amount" ],
|
[ "id", "city", "count", "amount" ],
|
||||||
[ 1, "New York", 3, 1.+6+11 ],
|
[ 1, "New York", 3, 1.+6+11 ],
|
||||||
[ 2, "Albany", 1, 2. ],
|
[ 2, "Albany", 1, 2. ],
|
||||||
@ -517,7 +657,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
[ 7, "Boston", 1, 9. ],
|
[ 7, "Boston", 1, 9. ],
|
||||||
[ 8, "Yonkers", 1, 10. ],
|
[ 8, "Yonkers", 1, 10. ],
|
||||||
])
|
])
|
||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address'])
|
self.assertEqual(get_helper_cols('Address'), ['#summary#Address_summary_city'])
|
||||||
|
|
||||||
# Verify more fields of some of the new column objects.
|
# Verify more fields of some of the new column objects.
|
||||||
self.assertTableData('_grist_Tables_column', rows="subset", cols="subset", data=[
|
self.assertTableData('_grist_Tables_column', rows="subset", cols="subset", data=[
|
||||||
@ -531,7 +671,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
# Note that Table #4 is gone at this point, since it's unused.
|
# Note that Table #4 is gone at this point, since it's unused.
|
||||||
Table(5, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(5, "Address_summary", 0, 1, columns=[
|
||||||
Column(27, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(27, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(28, "count", "Int", True, "len($group)", 0),
|
Column(28, "count", "Int", True, "len($group)", 0),
|
||||||
Column(29, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(29, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
@ -543,18 +683,18 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Field(8, colRef=29),
|
Field(8, colRef=29),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertTableData('GristSummary_7_Address2', cols="subset", data=[
|
self.assertTableData('Address_summary', cols="subset", data=[
|
||||||
[ "id", "count", "amount"],
|
[ "id", "count", "amount"],
|
||||||
[ 1, 11, 66.0 ],
|
[ 1, 11, 66.0 ],
|
||||||
])
|
])
|
||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address2'])
|
self.assertEqual(get_helper_cols('Address'), ['#summary#Address_summary'])
|
||||||
|
|
||||||
# Back to full circle, but with group-by columns differently arranged.
|
# Back to full circle, but with group-by columns differently arranged.
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 2, [12,11]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [12,11]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
# Note that Table #5 is gone at this point, since it's unused.
|
# Note that Table #5 is gone at this point, since it's unused.
|
||||||
Table(6, "GristSummary_7_Address", 0, 1, columns=[
|
Table(6, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(30, "state", "Text", False, "", 12),
|
Column(30, "state", "Text", False, "", 12),
|
||||||
Column(31, "city", "Text", False, "", 11),
|
Column(31, "city", "Text", False, "", 11),
|
||||||
Column(32, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(32, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
@ -570,7 +710,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Field(8, colRef=34),
|
Field(8, colRef=34),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertTableData('GristSummary_7_Address', cols="subset", data=[
|
self.assertTableData('Address_summary_city_state', cols="subset", data=[
|
||||||
[ "id", "city", "state", "count", "amount" ],
|
[ "id", "city", "state", "count", "amount" ],
|
||||||
[ 1, "New York", "NY" , 3, 1.+6+11 ],
|
[ 1, "New York", "NY" , 3, 1.+6+11 ],
|
||||||
[ 2, "Albany", "NY" , 1, 2. ],
|
[ 2, "Albany", "NY" , 1, 2. ],
|
||||||
@ -582,13 +722,13 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
[ 8, "Boston", "MA" , 1, 9. ],
|
[ 8, "Boston", "MA" , 1, 9. ],
|
||||||
[ 9, "Yonkers", "NY" , 1, 10. ],
|
[ 9, "Yonkers", "NY" , 1, 10. ],
|
||||||
])
|
])
|
||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address'])
|
self.assertEqual(get_helper_cols('Address'), ['#summary#Address_summary_city_state'])
|
||||||
|
|
||||||
# Now add a different view section with the same group-by columns.
|
# Now add a different view section with the same group-by columns.
|
||||||
self.apply_user_action(["CreateViewSection", 1, 1, "record", [11,12], None])
|
self.apply_user_action(["CreateViewSection", 1, 1, "record", [11,12], None])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(6, "GristSummary_7_Address", 0, 1, columns=[
|
Table(6, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(30, "state", "Text", False, "", 12),
|
Column(30, "state", "Text", False, "", 12),
|
||||||
Column(31, "city", "Text", False, "", 11),
|
Column(31, "city", "Text", False, "", 11),
|
||||||
Column(32, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(32, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
@ -610,20 +750,20 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Field(27, colRef=34),
|
Field(27, colRef=34),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address'])
|
self.assertEqual(get_helper_cols('Address'), ['#summary#Address_summary_city_state'])
|
||||||
|
|
||||||
# Change one view section, and ensure there are now two summary tables.
|
# Change one view section, and ensure there are now two summary tables.
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 7, []])
|
self.apply_user_action(["UpdateSummaryViewSection", 7, []])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(6, "GristSummary_7_Address", 0, 1, columns=[
|
Table(6, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(30, "state", "Text", False, "", 12),
|
Column(30, "state", "Text", False, "", 12),
|
||||||
Column(31, "city", "Text", False, "", 11),
|
Column(31, "city", "Text", False, "", 11),
|
||||||
Column(32, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(32, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(33, "count", "Int", True, "len($group)", 0),
|
Column(33, "count", "Int", True, "len($group)", 0),
|
||||||
Column(34, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(34, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
]),
|
]),
|
||||||
Table(7, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(7, "Address_summary", 0, 1, columns=[
|
||||||
Column(35, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(35, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(36, "count", "Int", True, "len($group)", 0),
|
Column(36, "count", "Int", True, "len($group)", 0),
|
||||||
Column(37, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(37, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
@ -641,15 +781,15 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Field(27, colRef=37),
|
Field(27, colRef=37),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address',
|
self.assertEqual(get_helper_cols('Address'), ['#summary#Address_summary_city_state',
|
||||||
'#summary#GristSummary_7_Address2'])
|
'#summary#Address_summary'])
|
||||||
|
|
||||||
# Delete one view section, and see that the summary table is gone.
|
# Delete one view section, and see that the summary table is gone.
|
||||||
self.apply_user_action(["RemoveViewSection", 7])
|
self.apply_user_action(["RemoveViewSection", 7])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
# Note that Table #7 is gone at this point, since it's now unused.
|
# Note that Table #7 is gone at this point, since it's now unused.
|
||||||
Table(6, "GristSummary_7_Address", 0, 1, columns=[
|
Table(6, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(30, "state", "Text", False, "", 12),
|
Column(30, "state", "Text", False, "", 12),
|
||||||
Column(31, "city", "Text", False, "", 11),
|
Column(31, "city", "Text", False, "", 11),
|
||||||
Column(32, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(32, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
@ -665,14 +805,14 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Field(8, colRef=34),
|
Field(8, colRef=34),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertEqual(get_helper_cols('Address'), ['#summary#GristSummary_7_Address'])
|
self.assertEqual(get_helper_cols('Address'), ['#summary#Address_summary_city_state'])
|
||||||
|
|
||||||
# Change the section to add and then remove the "amount" to the group-by column; check that
|
# Change the section to add and then remove the "amount" to the group-by column; check that
|
||||||
# column "amount" was correctly restored
|
# column "amount" was correctly restored
|
||||||
self.apply_user_action(["UpdateSummaryViewSection", 2, [11, 12, 13]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [11, 12, 13]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(7, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(7, "Address_summary_amount_city_state", 0, 1, columns=[
|
||||||
Column(35, "city", "Text", False, "", 11),
|
Column(35, "city", "Text", False, "", 11),
|
||||||
Column(36, "state", "Text", False, "", 12),
|
Column(36, "state", "Text", False, "", 12),
|
||||||
Column(37, "amount", "Numeric", False, "", 13),
|
Column(37, "amount", "Numeric", False, "", 13),
|
||||||
@ -691,7 +831,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
self.apply_user_action(["UpdateSummaryViewSection", 2, [11,12]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [11,12]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(8, "GristSummary_7_Address", 0, 1, columns=[
|
Table(8, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(40, "city", "Text", False, "", 11),
|
Column(40, "city", "Text", False, "", 11),
|
||||||
Column(41, "state", "Text", False, "", 12),
|
Column(41, "state", "Text", False, "", 12),
|
||||||
Column(42, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(42, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
@ -715,7 +855,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
self.apply_user_action(["UpdateSummaryViewSection", 2, [11]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [11]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(9, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(9, "Address_summary_city", 0, 1, columns=[
|
||||||
Column(45, "city", "Text", False, "", 11),
|
Column(45, "city", "Text", False, "", 11),
|
||||||
Column(46, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(46, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
Column(48, "count", "Int", True, "len($group)", 0),
|
Column(48, "count", "Int", True, "len($group)", 0),
|
||||||
@ -741,13 +881,13 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
|
|
||||||
self.load_sample(self.sample)
|
self.load_sample(self.sample)
|
||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [12], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [12], None])
|
||||||
self.apply_user_action(["AddVisibleColumn", "GristSummary_7_Address", "city",
|
self.apply_user_action(["AddVisibleColumn", "Address_summary_state", "city",
|
||||||
{"formula": "$state.lower()"}])
|
{"formula": "$state.lower()"}])
|
||||||
|
|
||||||
# We should have a single summary table, and a single section referring to it.
|
# We should have a single summary table, and a single section referring to it.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary_state", 0, 1, columns=[
|
||||||
Column(14, "state", "Text", False, "", 12),
|
Column(14, "state", "Text", False, "", 12),
|
||||||
Column(15, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(15, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(16, "count", "Int", True, "len($group)", 0),
|
Column(16, "count", "Int", True, "len($group)", 0),
|
||||||
@ -763,7 +903,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Field(8, colRef=18),
|
Field(8, colRef=18),
|
||||||
])
|
])
|
||||||
])])
|
])])
|
||||||
self.assertTableData('GristSummary_7_Address', cols="subset", data=[
|
self.assertTableData('Address_summary_state', cols="subset", data=[
|
||||||
[ "id", "state", "count", "amount" , "city"],
|
[ "id", "state", "count", "amount" , "city"],
|
||||||
[ 1, "NY", 7, 1.+2+6+7+8+10+11 , "ny" ],
|
[ 1, "NY", 7, 1.+2+6+7+8+10+11 , "ny" ],
|
||||||
[ 2, "WA", 1, 3. , "wa" ],
|
[ 2, "WA", 1, 3. , "wa" ],
|
||||||
@ -775,7 +915,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
self.apply_user_action(["UpdateSummaryViewSection", 2, [11,12]])
|
self.apply_user_action(["UpdateSummaryViewSection", 2, [11,12]])
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(19, "city", "Text", False, "", 11),
|
Column(19, "city", "Text", False, "", 11),
|
||||||
Column(20, "state", "Text", False, "", 12),
|
Column(20, "state", "Text", False, "", 12),
|
||||||
Column(21, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(21, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
@ -812,19 +952,19 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
# We should have a single summary table, and a single section referring to it.
|
# We should have a single summary table, and a single section referring to it.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(14, "city", "Text", False, "", 11),
|
Column(14, "city", "Text", False, "", 11),
|
||||||
Column(15, "state", "Text", False, "", 12),
|
Column(15, "state", "Text", False, "", 12),
|
||||||
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(17, "count", "Int", True, "len($group)", 0),
|
Column(17, "count", "Int", True, "len($group)", 0),
|
||||||
Column(18, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(18, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary", 0, 1, columns=[
|
||||||
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(20, "count", "Int", True, "len($group)", 0),
|
Column(20, "count", "Int", True, "len($group)", 0),
|
||||||
Column(21, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(21, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
]),
|
]),
|
||||||
Table(4, "GristSummary_7_Address3", 0, 1, columns=[
|
Table(4, "Address_summary_state", 0, 1, columns=[
|
||||||
Column(22, "state", "Text", False, "", 12),
|
Column(22, "state", "Text", False, "", 12),
|
||||||
Column(23, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(23, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(24, "count", "Int", True, "len($group)", 0),
|
Column(24, "count", "Int", True, "len($group)", 0),
|
||||||
@ -862,7 +1002,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
# Verify that unused summary tables are also gone, but the one used remains.
|
# Verify that unused summary tables are also gone, but the one used remains.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(14, "city", "Text", False, "", 11),
|
Column(14, "city", "Text", False, "", 11),
|
||||||
Column(15, "state", "Text", False, "", 12),
|
Column(15, "state", "Text", False, "", 12),
|
||||||
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
@ -893,7 +1033,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
# We should have a single summary table, and a single (non-raw) section referring to it.
|
# We should have a single summary table, and a single (non-raw) section referring to it.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(14, "city", "Text", False, "", 11),
|
Column(14, "city", "Text", False, "", 11),
|
||||||
Column(15, "state", "Text", False, "", 12),
|
Column(15, "state", "Text", False, "", 12),
|
||||||
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
@ -912,7 +1052,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
# Note that Table #2 is gone at this point, since it's unused.
|
# Note that Table #2 is gone at this point, since it's unused.
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary_state", 0, 1, columns=[
|
||||||
Column(19, "state", "Text", False, "", 12),
|
Column(19, "state", "Text", False, "", 12),
|
||||||
Column(20, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(20, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(21, "count", "Int", True, "len($group)", 0),
|
Column(21, "count", "Int", True, "len($group)", 0),
|
||||||
@ -935,13 +1075,13 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11,12], None])
|
||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [], None])
|
||||||
# Add a formula column
|
# Add a formula column
|
||||||
self.apply_user_action(["AddVisibleColumn", "GristSummary_7_Address", "average",
|
self.apply_user_action(["AddVisibleColumn", "Address_summary_city_state", "average",
|
||||||
{"formula": "$amount / $count"}])
|
{"formula": "$amount / $count"}])
|
||||||
|
|
||||||
# Check the table and columns for all the summary tables.
|
# Check the table and columns for all the summary tables.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(2, "GristSummary_7_Address", 0, 1, columns=[
|
Table(2, "Address_summary_city_state", 0, 1, columns=[
|
||||||
Column(14, "city", "Text", False, "", 11),
|
Column(14, "city", "Text", False, "", 11),
|
||||||
Column(15, "state", "Text", False, "", 12),
|
Column(15, "state", "Text", False, "", 12),
|
||||||
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(16, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
@ -949,7 +1089,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Column(18, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(18, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
Column(22, "average", "Any", True, "$amount / $count", 0),
|
Column(22, "average", "Any", True, "$amount / $count", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary", 0, 1, columns=[
|
||||||
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(20, "count", "Int", True, "len($group)", 0),
|
Column(20, "count", "Int", True, "len($group)", 0),
|
||||||
Column(21, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(21, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
@ -986,7 +1126,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
# Check the table and columns for all the summary tables.
|
# Check the table and columns for all the summary tables.
|
||||||
self.assertTables([
|
self.assertTables([
|
||||||
self.starting_table,
|
self.starting_table,
|
||||||
Table(3, "GristSummary_7_Address2", 0, 1, columns=[
|
Table(3, "Address_summary", 0, 1, columns=[
|
||||||
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(19, "group", "RefList:Address", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(20, "count", "Int", True, "len($group)", 0),
|
Column(20, "count", "Int", True, "len($group)", 0),
|
||||||
Column(21, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
Column(21, "amount", "Numeric", True, "SUM($group.amount)", 0),
|
||||||
@ -1039,7 +1179,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
[ 8, 8.0, "Boston", "MA" , [29], 1, 9. , 9. ],
|
[ 8, 8.0, "Boston", "MA" , [29], 1, 9. , 9. ],
|
||||||
[ 9, 9.0, "Yonkers", "NY" , [30], 1, 10. , 10. ],
|
[ 9, 9.0, "Yonkers", "NY" , [30], 1, 10. , 10. ],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_7_Address2', cols="all", data=[
|
self.assertTableData('Address_summary', cols="all", data=[
|
||||||
[ "id", "count", "amount", "group" ],
|
[ "id", "count", "amount", "group" ],
|
||||||
[ 1, 11, 66.0 , [21,22,23,24,25,26,27,28,29,30,31]],
|
[ 1, 11, 66.0 , [21,22,23,24,25,26,27,28,29,30,31]],
|
||||||
])
|
])
|
||||||
@ -1069,7 +1209,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
Column(24, "group", "RefList:Address", True,
|
Column(24, "group", "RefList:Address", True,
|
||||||
"Address.lookupRecords(city=$city, state=$state)", 0),
|
"Address.lookupRecords(city=$city, state=$state)", 0),
|
||||||
]),
|
]),
|
||||||
Table(4, "GristSummary_6_Table1", primaryViewId=0, summarySourceTable=3, columns=[
|
Table(4, "Table1_summary_state", primaryViewId=0, summarySourceTable=3, columns=[
|
||||||
Column(25, "state", "Text", False, "", 21),
|
Column(25, "state", "Text", False, "", 21),
|
||||||
Column(26, "group", "RefList:Table1", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(26, "group", "RefList:Table1", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(27, "count", "Int", True, "SUM($group.count)", 0),
|
Column(27, "count", "Int", True, "SUM($group.count)", 0),
|
||||||
@ -1090,7 +1230,7 @@ class TestSummary2(test_engine.EngineTestCase):
|
|||||||
[ 8, 8.0, "Boston", "MA" , [29], 1, 9. ],
|
[ 8, 8.0, "Boston", "MA" , [29], 1, 9. ],
|
||||||
[ 9, 9.0, "Yonkers", "NY" , [30], 1, 10. ],
|
[ 9, 9.0, "Yonkers", "NY" , [30], 1, 10. ],
|
||||||
])
|
])
|
||||||
self.assertTableData('GristSummary_6_Table1', cols="all", data=[
|
self.assertTableData('Table1_summary_state', cols="all", data=[
|
||||||
[ "id", "state", "group", "count", "amount" ],
|
[ "id", "state", "group", "count", "amount" ],
|
||||||
[ 1, "NY", [1,2,6,7,9], 7, 1.+6+11+2+7+8+10 ],
|
[ 1, "NY", [1,2,6,7,9], 7, 1.+6+11+2+7+8+10 ],
|
||||||
[ 2, "WA", [3], 1, 3. ],
|
[ 2, "WA", [3], 1, 3. ],
|
||||||
|
@ -46,7 +46,7 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11], None])
|
||||||
|
|
||||||
summary_table1 = Table(
|
summary_table1 = Table(
|
||||||
2, "GristSummary_6_Source", primaryViewId=0, summarySourceTable=1,
|
2, "Source_summary_choices1", primaryViewId=0, summarySourceTable=1,
|
||||||
columns=[
|
columns=[
|
||||||
Column(13, "choices1", "Choice", isFormula=False, formula="", summarySourceCol=11),
|
Column(13, "choices1", "Choice", isFormula=False, formula="", summarySourceCol=11),
|
||||||
Column(14, "group", "RefList:Source", isFormula=True, summarySourceCol=0,
|
Column(14, "group", "RefList:Source", isFormula=True, summarySourceCol=0,
|
||||||
@ -60,7 +60,7 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11, 12], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11, 12], None])
|
||||||
|
|
||||||
summary_table2 = Table(
|
summary_table2 = Table(
|
||||||
3, "GristSummary_6_Source2", primaryViewId=0, summarySourceTable=1,
|
3, "Source_summary_choices1_choices2", primaryViewId=0, summarySourceTable=1,
|
||||||
columns=[
|
columns=[
|
||||||
Column(16, "choices1", "Choice", isFormula=False, formula="", summarySourceCol=11),
|
Column(16, "choices1", "Choice", isFormula=False, formula="", summarySourceCol=11),
|
||||||
Column(17, "choices2", "Choice", isFormula=False, formula="", summarySourceCol=12),
|
Column(17, "choices2", "Choice", isFormula=False, formula="", summarySourceCol=12),
|
||||||
@ -75,7 +75,7 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [10], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [10], None])
|
||||||
|
|
||||||
summary_table3 = Table(
|
summary_table3 = Table(
|
||||||
4, "GristSummary_6_Source3", primaryViewId=0, summarySourceTable=1,
|
4, "Source_summary_other", primaryViewId=0, summarySourceTable=1,
|
||||||
columns=[
|
columns=[
|
||||||
Column(20, "other", "Text", isFormula=False, formula="", summarySourceCol=10),
|
Column(20, "other", "Text", isFormula=False, formula="", summarySourceCol=10),
|
||||||
Column(21, "group", "RefList:Source", isFormula=True, summarySourceCol=0,
|
Column(21, "group", "RefList:Source", isFormula=True, summarySourceCol=0,
|
||||||
@ -89,7 +89,7 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [10, 11], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [10, 11], None])
|
||||||
|
|
||||||
summary_table4 = Table(
|
summary_table4 = Table(
|
||||||
5, "GristSummary_6_Source4", primaryViewId=0, summarySourceTable=1,
|
5, "Source_summary_choices1_other", primaryViewId=0, summarySourceTable=1,
|
||||||
columns=[
|
columns=[
|
||||||
Column(23, "other", "Text", isFormula=False, formula="", summarySourceCol=10),
|
Column(23, "other", "Text", isFormula=False, formula="", summarySourceCol=10),
|
||||||
Column(24, "choices1", "Choice", isFormula=False, formula="", summarySourceCol=11),
|
Column(24, "choices1", "Choice", isFormula=False, formula="", summarySourceCol=11),
|
||||||
@ -105,13 +105,13 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Verify the summarized data.
|
# Verify the summarized data.
|
||||||
self.assertTableData('GristSummary_6_Source', data=[
|
self.assertTableData('Source_summary_choices1', data=[
|
||||||
["id", "choices1", "group", "count"],
|
["id", "choices1", "group", "count"],
|
||||||
[1, "a", [21], 1],
|
[1, "a", [21], 1],
|
||||||
[2, "b", [21], 1],
|
[2, "b", [21], 1],
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertTableData('GristSummary_6_Source2', data=[
|
self.assertTableData('Source_summary_choices1_choices2', data=[
|
||||||
["id", "choices1", "choices2", "group", "count"],
|
["id", "choices1", "choices2", "group", "count"],
|
||||||
[1, "a", "c", [21], 1],
|
[1, "a", "c", [21], 1],
|
||||||
[2, "a", "d", [21], 1],
|
[2, "a", "d", [21], 1],
|
||||||
@ -119,12 +119,12 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
[4, "b", "d", [21], 1],
|
[4, "b", "d", [21], 1],
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertTableData('GristSummary_6_Source3', data=[
|
self.assertTableData('Source_summary_other', data=[
|
||||||
["id", "other", "group", "count"],
|
["id", "other", "group", "count"],
|
||||||
[1, "foo", [21], 1],
|
[1, "foo", [21], 1],
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertTableData('GristSummary_6_Source4', data=[
|
self.assertTableData('Source_summary_choices1_other', data=[
|
||||||
["id", "other", "choices1", "group", "count"],
|
["id", "other", "choices1", "group", "count"],
|
||||||
[1, "foo", "a", [21], 1],
|
[1, "foo", "a", [21], 1],
|
||||||
[2, "foo", "b", [21], 1],
|
[2, "foo", "b", [21], 1],
|
||||||
@ -132,28 +132,30 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
|
|
||||||
# Verify the optimisation works for the table without choicelists
|
# Verify the optimisation works for the table without choicelists
|
||||||
self.assertIs(self.engine.tables["Source"]._summary_simple, None)
|
self.assertIs(self.engine.tables["Source"]._summary_simple, None)
|
||||||
self.assertIs(self.engine.tables["GristSummary_6_Source"]._summary_simple, False)
|
self.assertIs(self.engine.tables["Source_summary_choices1"]._summary_simple, False)
|
||||||
self.assertIs(self.engine.tables["GristSummary_6_Source2"]._summary_simple, False)
|
self.assertIs(self.engine.tables["Source_summary_choices1_choices2"]._summary_simple, False)
|
||||||
# simple summary and lookup
|
# simple summary and lookup
|
||||||
self.assertIs(self.engine.tables["GristSummary_6_Source3"]._summary_simple, True)
|
self.assertIs(self.engine.tables["Source_summary_other"]._summary_simple, True)
|
||||||
self.assertIs(self.engine.tables["GristSummary_6_Source4"]._summary_simple, False)
|
self.assertIs(self.engine.tables["Source_summary_choices1_other"]._summary_simple, False)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
{k: type(v) for k, v in self.engine.tables["Source"]._special_cols.items()},
|
{k: type(v) for k, v in self.engine.tables["Source"]._special_cols.items()},
|
||||||
{
|
{
|
||||||
'#summary#GristSummary_6_Source': column.ReferenceListColumn,
|
'#summary#Source_summary_choices1': column.ReferenceListColumn,
|
||||||
"#lookup#_Contains(value='#summary#GristSummary_6_Source', match_empty=no_match_empty)":
|
"#lookup#_Contains(value='#summary#Source_summary_choices1', match_empty=no_match_empty)":
|
||||||
lookup.ContainsLookupMapColumn,
|
lookup.ContainsLookupMapColumn,
|
||||||
'#summary#GristSummary_6_Source2': column.ReferenceListColumn,
|
'#summary#Source_summary_choices1_choices2': column.ReferenceListColumn,
|
||||||
"#lookup#_Contains(value='#summary#GristSummary_6_Source2', match_empty=no_match_empty)":
|
"#lookup#_Contains(value='#summary#Source_summary_choices1_choices2', "
|
||||||
|
"match_empty=no_match_empty)":
|
||||||
lookup.ContainsLookupMapColumn,
|
lookup.ContainsLookupMapColumn,
|
||||||
|
|
||||||
# simple summary and lookup
|
# simple summary and lookup
|
||||||
'#summary#GristSummary_6_Source3': column.ReferenceColumn,
|
'#summary#Source_summary_other': column.ReferenceColumn,
|
||||||
'#lookup##summary#GristSummary_6_Source3': lookup.SimpleLookupMapColumn,
|
'#lookup##summary#Source_summary_other': lookup.SimpleLookupMapColumn,
|
||||||
|
|
||||||
'#summary#GristSummary_6_Source4': column.ReferenceListColumn,
|
'#summary#Source_summary_choices1_other': column.ReferenceListColumn,
|
||||||
"#lookup#_Contains(value='#summary#GristSummary_6_Source4', match_empty=no_match_empty)":
|
"#lookup#_Contains(value='#summary#Source_summary_choices1_other', "
|
||||||
|
"match_empty=no_match_empty)":
|
||||||
lookup.ContainsLookupMapColumn,
|
lookup.ContainsLookupMapColumn,
|
||||||
|
|
||||||
"#lookup#": lookup.SimpleLookupMapColumn,
|
"#lookup#": lookup.SimpleLookupMapColumn,
|
||||||
@ -169,12 +171,12 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Verify that the summary table rows containing 'b' are removed
|
# Verify that the summary table rows containing 'b' are removed
|
||||||
self.assertTableData('GristSummary_6_Source', data=[
|
self.assertTableData('Source_summary_choices1', data=[
|
||||||
["id", "choices1", "group", "count"],
|
["id", "choices1", "group", "count"],
|
||||||
[1, "a", [21], 1],
|
[1, "a", [21], 1],
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertTableData('GristSummary_6_Source2', data=[
|
self.assertTableData('Source_summary_choices1_choices2', data=[
|
||||||
["id", "choices1", "choices2", "group", "count"],
|
["id", "choices1", "choices2", "group", "count"],
|
||||||
[1, "a", "c", [21], 1],
|
[1, "a", "c", [21], 1],
|
||||||
[2, "a", "d", [21], 1],
|
[2, "a", "d", [21], 1],
|
||||||
@ -184,13 +186,13 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
self.update_record("Source", 21, choices2=["L", "c", "d", "e"])
|
self.update_record("Source", 21, choices2=["L", "c", "d", "e"])
|
||||||
|
|
||||||
# First summary table unaffected
|
# First summary table unaffected
|
||||||
self.assertTableData('GristSummary_6_Source', data=[
|
self.assertTableData('Source_summary_choices1', data=[
|
||||||
["id", "choices1", "group", "count"],
|
["id", "choices1", "group", "count"],
|
||||||
[1, "a", [21], 1],
|
[1, "a", [21], 1],
|
||||||
])
|
])
|
||||||
|
|
||||||
# New row added for 'e'
|
# New row added for 'e'
|
||||||
self.assertTableData('GristSummary_6_Source2', data=[
|
self.assertTableData('Source_summary_choices1_choices2', data=[
|
||||||
["id", "choices1", "choices2", "group", "count"],
|
["id", "choices1", "choices2", "group", "count"],
|
||||||
[1, "a", "c", [21], 1],
|
[1, "a", "c", [21], 1],
|
||||||
[2, "a", "d", [21], 1],
|
[2, "a", "d", [21], 1],
|
||||||
@ -205,12 +207,12 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
[21, None, ["c", "d", "e"], "foo"],
|
[21, None, ["c", "d", "e"], "foo"],
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertTableData('GristSummary_6_Source', data=[
|
self.assertTableData('Source_summary_choices1', data=[
|
||||||
["id", "choices1", "group", "count"],
|
["id", "choices1", "group", "count"],
|
||||||
[2, "", [21], 1],
|
[2, "", [21], 1],
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertTableData('GristSummary_6_Source2', data=[
|
self.assertTableData('Source_summary_choices1_choices2', data=[
|
||||||
["id", "choices1", "choices2", "group", "count"],
|
["id", "choices1", "choices2", "group", "count"],
|
||||||
[4, "", "c", [21], 1],
|
[4, "", "c", [21], 1],
|
||||||
[5, "", "d", [21], 1],
|
[5, "", "d", [21], 1],
|
||||||
@ -221,11 +223,11 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
self.remove_record("Source", 21)
|
self.remove_record("Source", 21)
|
||||||
|
|
||||||
# All summary rows are now empty and thus removed
|
# All summary rows are now empty and thus removed
|
||||||
self.assertTableData('GristSummary_6_Source', data=[
|
self.assertTableData('Source_summary_choices1', data=[
|
||||||
["id", "choices1", "group", "count"],
|
["id", "choices1", "group", "count"],
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertTableData('GristSummary_6_Source2', data=[
|
self.assertTableData('Source_summary_choices1_choices2', data=[
|
||||||
["id", "choices1", "choices2", "group", "count"],
|
["id", "choices1", "choices2", "group", "count"],
|
||||||
])
|
])
|
||||||
|
|
||||||
@ -263,7 +265,7 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Summary tables now have an even distribution of combinations
|
# Summary tables now have an even distribution of combinations
|
||||||
self.assertTableData('GristSummary_6_Source', data=[
|
self.assertTableData('Source_summary_choices1', data=[
|
||||||
["id", "choices1", "group", "count"],
|
["id", "choices1", "group", "count"],
|
||||||
[1, "a", [101, 103, 104, 106, 107, 109], 6],
|
[1, "a", [101, 103, 104, 106, 107, 109], 6],
|
||||||
[2, "b", [102, 103, 105, 106, 108, 109], 6],
|
[2, "b", [102, 103, 105, 106, 108, 109], 6],
|
||||||
@ -279,7 +281,7 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
[5, "", "", [110], 1],
|
[5, "", "", [110], 1],
|
||||||
]
|
]
|
||||||
|
|
||||||
self.assertTableData('GristSummary_6_Source2', data=summary_data)
|
self.assertTableData('Source_summary_choices1_choices2', data=summary_data)
|
||||||
|
|
||||||
# Verify that "DetachSummaryViewSection" useraction works correctly.
|
# Verify that "DetachSummaryViewSection" useraction works correctly.
|
||||||
self.apply_user_action(["DetachSummaryViewSection", 4])
|
self.apply_user_action(["DetachSummaryViewSection", 4])
|
||||||
@ -336,7 +338,7 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11], None])
|
||||||
|
|
||||||
summary_table = Table(
|
summary_table = Table(
|
||||||
2, "GristSummary_6_Source", primaryViewId=0, summarySourceTable=1,
|
2, "Source_summary_choices1", primaryViewId=0, summarySourceTable=1,
|
||||||
columns=[
|
columns=[
|
||||||
Column(12, "choices1", "Choice", isFormula=False, formula="", summarySourceCol=11),
|
Column(12, "choices1", "Choice", isFormula=False, formula="", summarySourceCol=11),
|
||||||
Column(13, "group", "RefList:Source", isFormula=True, summarySourceCol=0,
|
Column(13, "group", "RefList:Source", isFormula=True, summarySourceCol=0,
|
||||||
@ -353,7 +355,7 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
self.assertTables([starting_table, summary_table])
|
self.assertTables([starting_table, summary_table])
|
||||||
self.assertTableData('GristSummary_6_Source', data=data)
|
self.assertTableData('Source_summary_choices1', data=data)
|
||||||
|
|
||||||
# Change the column from Choice to ChoiceList
|
# Change the column from Choice to ChoiceList
|
||||||
self.apply_user_action(["UpdateRecord", "_grist_Tables_column", 11, {"type": "ChoiceList"}])
|
self.apply_user_action(["UpdateRecord", "_grist_Tables_column", 11, {"type": "ChoiceList"}])
|
||||||
@ -365,7 +367,7 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
|
|
||||||
starting_table.columns[1] = starting_table.columns[1]._replace(type="ChoiceList")
|
starting_table.columns[1] = starting_table.columns[1]._replace(type="ChoiceList")
|
||||||
self.assertTables([starting_table, summary_table])
|
self.assertTables([starting_table, summary_table])
|
||||||
self.assertTableData('GristSummary_6_Source', data=data)
|
self.assertTableData('Source_summary_choices1', data=data)
|
||||||
|
|
||||||
def test_rename_choices(self):
|
def test_rename_choices(self):
|
||||||
self.load_sample(self.sample)
|
self.load_sample(self.sample)
|
||||||
@ -374,7 +376,7 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11, 12], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [11, 12], None])
|
||||||
|
|
||||||
summary_table = Table(
|
summary_table = Table(
|
||||||
2, "GristSummary_6_Source", primaryViewId=0, summarySourceTable=1,
|
2, "Source_summary_choices1_choices2", primaryViewId=0, summarySourceTable=1,
|
||||||
columns=[
|
columns=[
|
||||||
Column(13, "choices1", "Choice", isFormula=False, formula="", summarySourceCol=11),
|
Column(13, "choices1", "Choice", isFormula=False, formula="", summarySourceCol=11),
|
||||||
Column(14, "choices2", "Choice", isFormula=False, formula="", summarySourceCol=12),
|
Column(14, "choices2", "Choice", isFormula=False, formula="", summarySourceCol=12),
|
||||||
@ -397,17 +399,17 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
self.assertPartialOutActions(out_actions, {'stored': [
|
self.assertPartialOutActions(out_actions, {'stored': [
|
||||||
['UpdateRecord', 'Source', 21, {'choices1': ['L', u'aa', u'bb']}],
|
['UpdateRecord', 'Source', 21, {'choices1': ['L', u'aa', u'bb']}],
|
||||||
['BulkAddRecord',
|
['BulkAddRecord',
|
||||||
'GristSummary_6_Source',
|
'Source_summary_choices1_choices2',
|
||||||
[5, 6, 7, 8],
|
[5, 6, 7, 8],
|
||||||
{'choices1': [u'aa', u'aa', u'bb', u'bb'],
|
{'choices1': [u'aa', u'aa', u'bb', u'bb'],
|
||||||
'choices2': [u'c', u'd', u'c', u'd']}],
|
'choices2': [u'c', u'd', u'c', u'd']}],
|
||||||
['BulkRemoveRecord', 'GristSummary_6_Source', [1, 2, 3, 4]],
|
['BulkRemoveRecord', 'Source_summary_choices1_choices2', [1, 2, 3, 4]],
|
||||||
['BulkUpdateRecord',
|
['BulkUpdateRecord',
|
||||||
'GristSummary_6_Source',
|
'Source_summary_choices1_choices2',
|
||||||
[5, 6, 7, 8],
|
[5, 6, 7, 8],
|
||||||
{'count': [1, 1, 1, 1]}],
|
{'count': [1, 1, 1, 1]}],
|
||||||
['BulkUpdateRecord',
|
['BulkUpdateRecord',
|
||||||
'GristSummary_6_Source',
|
'Source_summary_choices1_choices2',
|
||||||
[5, 6, 7, 8],
|
[5, 6, 7, 8],
|
||||||
{'group': [['L', 21],
|
{'group': [['L', 21],
|
||||||
['L', 21],
|
['L', 21],
|
||||||
@ -423,7 +425,7 @@ class TestSummaryChoiceList(EngineTestCase):
|
|||||||
|
|
||||||
# Final summary table is very similar to before, but with two empty chunks of 4 rows
|
# Final summary table is very similar to before, but with two empty chunks of 4 rows
|
||||||
# left over from each rename
|
# left over from each rename
|
||||||
self.assertTableData('GristSummary_6_Source', data=[
|
self.assertTableData('Source_summary_choices1_choices2', data=[
|
||||||
["id", "choices1", "choices2", "group", "count"],
|
["id", "choices1", "choices2", "group", "count"],
|
||||||
[9, "aa", "cc", [21], 1],
|
[9, "aa", "cc", [21], 1],
|
||||||
[10, "aa", "dd", [21], 1],
|
[10, "aa", "dd", [21], 1],
|
||||||
|
@ -31,7 +31,7 @@ class TestSummaryUndo(test_engine.EngineTestCase):
|
|||||||
self.load_sample(self.sample)
|
self.load_sample(self.sample)
|
||||||
# Create a summary section, grouped by the "State" column.
|
# Create a summary section, grouped by the "State" column.
|
||||||
self.apply_user_action(["CreateViewSection", 1, 0, "record", [1], None])
|
self.apply_user_action(["CreateViewSection", 1, 0, "record", [1], None])
|
||||||
self.assertTableData('GristSummary_6_Person', cols="subset", data=[
|
self.assertTableData('Person_summary_state', cols="subset", data=[
|
||||||
[ "id", "state", "count"],
|
[ "id", "state", "count"],
|
||||||
[ 1, "NY", 2],
|
[ 1, "NY", 2],
|
||||||
[ 2, "IL", 2],
|
[ 2, "IL", 2],
|
||||||
@ -39,7 +39,7 @@ class TestSummaryUndo(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
out_actions = self.update_record('Person', 4, state='ME')
|
out_actions = self.update_record('Person', 4, state='ME')
|
||||||
self.assertTableData('GristSummary_6_Person', cols="subset", data=[
|
self.assertTableData('Person_summary_state', cols="subset", data=[
|
||||||
[ "id", "state", "count"],
|
[ "id", "state", "count"],
|
||||||
[ 1, "NY", 1],
|
[ 1, "NY", 1],
|
||||||
[ 2, "IL", 2],
|
[ 2, "IL", 2],
|
||||||
@ -47,7 +47,7 @@ class TestSummaryUndo(test_engine.EngineTestCase):
|
|||||||
])
|
])
|
||||||
|
|
||||||
self.apply_undo_actions(out_actions.undo[0:1])
|
self.apply_undo_actions(out_actions.undo[0:1])
|
||||||
self.assertTableData('GristSummary_6_Person', cols="subset", data=[
|
self.assertTableData('Person_summary_state', cols="subset", data=[
|
||||||
[ "id", "state", "count"],
|
[ "id", "state", "count"],
|
||||||
[ 1, "NY", 2],
|
[ 1, "NY", 2],
|
||||||
[ 2, "IL", 2],
|
[ 2, "IL", 2],
|
||||||
|
@ -71,7 +71,7 @@ class TestTableActions(test_engine.EngineTestCase):
|
|||||||
Column(7, "address", "Ref:Address", False, "", 0),
|
Column(7, "address", "Ref:Address", False, "", 0),
|
||||||
Column(8, "city", "Any", True, "$address.city", 0),
|
Column(8, "city", "Any", True, "$address.city", 0),
|
||||||
]),
|
]),
|
||||||
Table(3, "GristSummary_7_Address", 0, 1, columns=[
|
Table(3, "Address_summary_state", 0, 1, columns=[
|
||||||
Column(9, "state", "Text", False, "", summarySourceCol=3),
|
Column(9, "state", "Text", False, "", summarySourceCol=3),
|
||||||
Column(10, "group", "RefList:Address", True, summarySourceCol=0,
|
Column(10, "group", "RefList:Address", True, summarySourceCol=0,
|
||||||
formula="table.getSummarySourceGroup(rec)"),
|
formula="table.getSummarySourceGroup(rec)"),
|
||||||
@ -116,7 +116,7 @@ class TestTableActions(test_engine.EngineTestCase):
|
|||||||
# Verify the data we've loaded.
|
# Verify the data we've loaded.
|
||||||
self.assertTableData('Address', cols="subset", data=self.address_table_data)
|
self.assertTableData('Address', cols="subset", data=self.address_table_data)
|
||||||
self.assertTableData('People', cols="subset", data=self.people_table_data)
|
self.assertTableData('People', cols="subset", data=self.people_table_data)
|
||||||
self.assertTableData("GristSummary_7_Address", cols="subset", data=[
|
self.assertTableData("Address_summary_state", cols="subset", data=[
|
||||||
[ "id", "state", "count", "amount" ],
|
[ "id", "state", "count", "amount" ],
|
||||||
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
|
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
|
||||||
[ 2, "WA", 1, 3. ],
|
[ 2, "WA", 1, 3. ],
|
||||||
@ -142,7 +142,7 @@ class TestTableActions(test_engine.EngineTestCase):
|
|||||||
["id", "tableId"],
|
["id", "tableId"],
|
||||||
[1, "Location"],
|
[1, "Location"],
|
||||||
[2, "Persons"],
|
[2, "Persons"],
|
||||||
[3, "GristSummary_8_Location"],
|
[3, "Location_summary_state"],
|
||||||
])
|
])
|
||||||
|
|
||||||
# Check that reference columns to renamed tables get their type modified.
|
# Check that reference columns to renamed tables get their type modified.
|
||||||
@ -161,14 +161,14 @@ class TestTableActions(test_engine.EngineTestCase):
|
|||||||
self.assertPartialOutActions(out_actions, {
|
self.assertPartialOutActions(out_actions, {
|
||||||
"stored": [
|
"stored": [
|
||||||
["ModifyColumn", "Persons", "address", {"type": "Int"}],
|
["ModifyColumn", "Persons", "address", {"type": "Int"}],
|
||||||
["ModifyColumn", "GristSummary_8_Location", "group", {"type": "Int"}],
|
["ModifyColumn", "Location_summary_state", "group", {"type": "Int"}],
|
||||||
["RenameTable", "Location", "A2"],
|
["RenameTable", "Location", "A2"],
|
||||||
["RenameTable", "GristSummary_8_Location", "GristSummary_2_A2"],
|
["RenameTable", "Location_summary_state", "A2_summary_state"],
|
||||||
["RenameTable", "Persons", "A3"],
|
["RenameTable", "Persons", "A3"],
|
||||||
["BulkUpdateRecord", "_grist_Tables", [1, 3, 2],
|
["BulkUpdateRecord", "_grist_Tables", [1, 3, 2],
|
||||||
{"tableId": ["A2", "GristSummary_2_A2", "A3"]}],
|
{"tableId": ["A2", "A2_summary_state", "A3"]}],
|
||||||
["ModifyColumn", "A3", "address", {"type": "Ref:A2"}],
|
["ModifyColumn", "A3", "address", {"type": "Ref:A2"}],
|
||||||
["ModifyColumn", "GristSummary_2_A2", "group", {"type": "RefList:A2"}],
|
["ModifyColumn", "A2_summary_state", "group", {"type": "RefList:A2"}],
|
||||||
["BulkUpdateRecord", "_grist_Tables_column", [7, 10], {"type": ["Ref:A2", "RefList:A2"]}],
|
["BulkUpdateRecord", "_grist_Tables_column", [7, 10], {"type": ["Ref:A2", "RefList:A2"]}],
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@ -178,7 +178,7 @@ class TestTableActions(test_engine.EngineTestCase):
|
|||||||
["id", "tableId"],
|
["id", "tableId"],
|
||||||
[1, "A2"],
|
[1, "A2"],
|
||||||
[2, "A3"],
|
[2, "A3"],
|
||||||
[3, "GristSummary_2_A2"],
|
[3, "A2_summary_state"],
|
||||||
[4, "A"],
|
[4, "A"],
|
||||||
])
|
])
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ class TestTableActions(test_engine.EngineTestCase):
|
|||||||
# Verify the data we've loaded.
|
# Verify the data we've loaded.
|
||||||
self.assertTableData('A2', cols="subset", data=self.address_table_data)
|
self.assertTableData('A2', cols="subset", data=self.address_table_data)
|
||||||
self.assertTableData('A3', cols="subset", data=self.people_table_data)
|
self.assertTableData('A3', cols="subset", data=self.people_table_data)
|
||||||
self.assertTableData("GristSummary_2_A2", cols="subset", data=[
|
self.assertTableData("A2_summary_state", cols="subset", data=[
|
||||||
[ "id", "state", "count", "amount" ],
|
[ "id", "state", "count", "amount" ],
|
||||||
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
|
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
|
||||||
[ 2, "WA", 1, 3. ],
|
[ 2, "WA", 1, 3. ],
|
||||||
@ -226,15 +226,15 @@ class TestTableActions(test_engine.EngineTestCase):
|
|||||||
self.assertPartialOutActions(out_actions, {
|
self.assertPartialOutActions(out_actions, {
|
||||||
"stored": [
|
"stored": [
|
||||||
["ModifyColumn", "People", "address", {"type": "Int"}],
|
["ModifyColumn", "People", "address", {"type": "Int"}],
|
||||||
["ModifyColumn", "GristSummary_7_Address", "group", {"type": "Int"}],
|
["ModifyColumn", "Address_summary_state", "group", {"type": "Int"}],
|
||||||
["ModifyColumn", "GristSummary_6_People", "address", {"type": "Int"}],
|
["ModifyColumn", "People_summary_address", "address", {"type": "Int"}],
|
||||||
["RenameTable", "Address", "Location"],
|
["RenameTable", "Address", "Location"],
|
||||||
["RenameTable", "GristSummary_7_Address", "GristSummary_8_Location"],
|
["RenameTable", "Address_summary_state", "Location_summary_state"],
|
||||||
["BulkUpdateRecord", "_grist_Tables", [1, 3],
|
["BulkUpdateRecord", "_grist_Tables", [1, 3],
|
||||||
{"tableId": ["Location", "GristSummary_8_Location"]}],
|
{"tableId": ["Location", "Location_summary_state"]}],
|
||||||
["ModifyColumn", "People", "address", {"type": "Ref:Location"}],
|
["ModifyColumn", "People", "address", {"type": "Ref:Location"}],
|
||||||
["ModifyColumn", "GristSummary_8_Location", "group", {"type": "RefList:Location"}],
|
["ModifyColumn", "Location_summary_state", "group", {"type": "RefList:Location"}],
|
||||||
["ModifyColumn", "GristSummary_6_People", "address", {"type": "Ref:Location"}],
|
["ModifyColumn", "People_summary_address", "address", {"type": "Ref:Location"}],
|
||||||
["BulkUpdateRecord", "_grist_Tables_column", [7, 10, 13],
|
["BulkUpdateRecord", "_grist_Tables_column", [7, 10, 13],
|
||||||
{"type": ["Ref:Location", "RefList:Location", "Ref:Location"]}],
|
{"type": ["Ref:Location", "RefList:Location", "Ref:Location"]}],
|
||||||
]
|
]
|
||||||
|
@ -156,7 +156,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
|
|
||||||
# Create another section for the same view, this time summarized.
|
# Create another section for the same view, this time summarized.
|
||||||
self.apply_user_action(["CreateViewSection", 1, 1, "record", [21], None])
|
self.apply_user_action(["CreateViewSection", 1, 1, "record", [21], None])
|
||||||
summary_table = Table(2, "GristSummary_7_Address", 0, summarySourceTable=1, columns=[
|
summary_table = Table(2, "Address_summary_city", 0, summarySourceTable=1, columns=[
|
||||||
Column(22, "city", "Text", isFormula=False, formula="", summarySourceCol=21),
|
Column(22, "city", "Text", isFormula=False, formula="", summarySourceCol=21),
|
||||||
Column(23, "group", "RefList:Address", isFormula=True,
|
Column(23, "group", "RefList:Address", isFormula=True,
|
||||||
formula="table.getSummarySourceGroup(rec)", summarySourceCol=0),
|
formula="table.getSummarySourceGroup(rec)", summarySourceCol=0),
|
||||||
@ -248,7 +248,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
Column(33, "C", "Any", isFormula=True, formula="", summarySourceCol=0),
|
Column(33, "C", "Any", isFormula=True, formula="", summarySourceCol=0),
|
||||||
])
|
])
|
||||||
# A summary of it.
|
# A summary of it.
|
||||||
summary_table = Table(5, "GristSummary_6_Table3", 0, summarySourceTable=4, columns=[
|
summary_table = Table(5, "Table3_summary", 0, summarySourceTable=4, columns=[
|
||||||
Column(34, "group", "RefList:Table3", isFormula=True,
|
Column(34, "group", "RefList:Table3", isFormula=True,
|
||||||
formula="table.getSummarySourceGroup(rec)", summarySourceCol=0),
|
formula="table.getSummarySourceGroup(rec)", summarySourceCol=0),
|
||||||
Column(35, "count", "Int", isFormula=True, formula="len($group)", summarySourceCol=0),
|
Column(35, "count", "Int", isFormula=True, formula="len($group)", summarySourceCol=0),
|
||||||
@ -287,7 +287,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
Column(3, "state", "Text", False, "", 0),
|
Column(3, "state", "Text", False, "", 0),
|
||||||
Column(4, "size", "Numeric", False, "", 0),
|
Column(4, "size", "Numeric", False, "", 0),
|
||||||
]),
|
]),
|
||||||
Table(2, "GristSummary_7_Schools", 0, 1, columns=[
|
Table(2, "Schools_summary_state", 0, 1, columns=[
|
||||||
Column(5, "state", "Text", False, "", 3),
|
Column(5, "state", "Text", False, "", 3),
|
||||||
Column(6, "group", "RefList:Schools", True, "table.getSummarySourceGroup(rec)", 0),
|
Column(6, "group", "RefList:Schools", True, "table.getSummarySourceGroup(rec)", 0),
|
||||||
Column(7, "count", "Int", True, "len($group)", 0),
|
Column(7, "count", "Int", True, "len($group)", 0),
|
||||||
@ -398,7 +398,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||||
[ 'id', 'tableId', 'primaryViewId' ],
|
[ 'id', 'tableId', 'primaryViewId' ],
|
||||||
[ 1, 'Schools', 1],
|
[ 1, 'Schools', 1],
|
||||||
[ 2, 'GristSummary_7_Schools', 0],
|
[ 2, 'Schools_summary_state', 0],
|
||||||
[ 3, 'Table1', 0],
|
[ 3, 'Table1', 0],
|
||||||
])
|
])
|
||||||
self.assertTableData('_grist_Views', cols="subset", data=[
|
self.assertTableData('_grist_Views', cols="subset", data=[
|
||||||
@ -416,7 +416,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||||
[ 'id', 'tableId', 'primaryViewId' ],
|
[ 'id', 'tableId', 'primaryViewId' ],
|
||||||
[ 1, 'Schools', 1],
|
[ 1, 'Schools', 1],
|
||||||
[ 2, 'GristSummary_7_Schools', 0],
|
[ 2, 'Schools_summary_state', 0],
|
||||||
[ 3, 'Table1', 0],
|
[ 3, 'Table1', 0],
|
||||||
])
|
])
|
||||||
self.assertTableData('_grist_Views', cols="subset", data=[
|
self.assertTableData('_grist_Views', cols="subset", data=[
|
||||||
@ -434,7 +434,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||||
['id', 'tableId'],
|
['id', 'tableId'],
|
||||||
[1, 'Bars', 1],
|
[1, 'Bars', 1],
|
||||||
[2, 'GristSummary_4_Bars', 0],
|
[2, 'Bars_summary_state', 0],
|
||||||
[3, 'Table1', 0],
|
[3, 'Table1', 0],
|
||||||
])
|
])
|
||||||
self.assertTableData('_grist_Views', cols="subset", data=[
|
self.assertTableData('_grist_Views', cols="subset", data=[
|
||||||
@ -452,7 +452,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||||
['id', 'tableId'],
|
['id', 'tableId'],
|
||||||
[1, 'A', 1],
|
[1, 'A', 1],
|
||||||
[2, 'GristSummary_1_A', 0],
|
[2, 'A_summary_state', 0],
|
||||||
[3, 'Table1', 0],
|
[3, 'Table1', 0],
|
||||||
])
|
])
|
||||||
self.assertTableData('_grist_Views', cols="subset", data=[
|
self.assertTableData('_grist_Views', cols="subset", data=[
|
||||||
@ -468,7 +468,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||||
['id', 'tableId', 'primaryViewId', 'rawViewSectionRef'],
|
['id', 'tableId', 'primaryViewId', 'rawViewSectionRef'],
|
||||||
[1, 'Z', 1, 2],
|
[1, 'Z', 1, 2],
|
||||||
[2, 'GristSummary_1_Z', 0, 4],
|
[2, 'Z_summary_state', 0, 4],
|
||||||
[3, 'Table1', 0, 7],
|
[3, 'Table1', 0, 7],
|
||||||
])
|
])
|
||||||
self.assertTableData('_grist_Views', cols="subset", data=[
|
self.assertTableData('_grist_Views', cols="subset", data=[
|
||||||
@ -485,7 +485,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||||
['id', 'tableId', 'primaryViewId', 'rawViewSectionRef'],
|
['id', 'tableId', 'primaryViewId', 'rawViewSectionRef'],
|
||||||
[1, 'Z', 1, 2],
|
[1, 'Z', 1, 2],
|
||||||
[2, 'GristSummary_1_Z', 0, 4],
|
[2, 'Z_summary_state', 0, 4],
|
||||||
[3, 'Table1', 0, 7],
|
[3, 'Table1', 0, 7],
|
||||||
[4, 'Stations', 4, 10],
|
[4, 'Stations', 4, 10],
|
||||||
])
|
])
|
||||||
@ -513,7 +513,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||||
['id', 'tableId'],
|
['id', 'tableId'],
|
||||||
[1, 'Schools'],
|
[1, 'Schools'],
|
||||||
[2, 'GristSummary_7_Schools'],
|
[2, 'Schools_summary_state'],
|
||||||
[3, 'Table1'],
|
[3, 'Table1'],
|
||||||
[4, 'Stations'],
|
[4, 'Stations'],
|
||||||
])
|
])
|
||||||
@ -618,7 +618,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
|||||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||||
[ 'id', 'tableId', 'primaryViewId' ],
|
[ 'id', 'tableId', 'primaryViewId' ],
|
||||||
[ 1, 'Schools', 1],
|
[ 1, 'Schools', 1],
|
||||||
[ 2, 'GristSummary_7_Schools', 0],
|
[ 2, 'Schools_summary_state', 0],
|
||||||
[ 3, 'C', 0],
|
[ 3, 'C', 0],
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -561,7 +561,7 @@ class UserActions(object):
|
|||||||
update_pairs.append((rec, values))
|
update_pairs.append((rec, values))
|
||||||
if has_diff_value(values, 'tableId', rec.tableId):
|
if has_diff_value(values, 'tableId', rec.tableId):
|
||||||
# Disallow renaming of summary tables.
|
# Disallow renaming of summary tables.
|
||||||
if rec.summarySourceTable:
|
if rec.summarySourceTable and self._indirection_level == DIRECT_ACTION:
|
||||||
raise ValueError("RenameTable: cannot rename a summary table")
|
raise ValueError("RenameTable: cannot rename a summary table")
|
||||||
|
|
||||||
# Find a non-conflicting name, except that we don't need to avoid the old name.
|
# Find a non-conflicting name, except that we don't need to avoid the old name.
|
||||||
@ -572,7 +572,8 @@ class UserActions(object):
|
|||||||
if new_table_id != rec.tableId:
|
if new_table_id != rec.tableId:
|
||||||
# If there are summary tables based on this table, rename them to appropriate names.
|
# If there are summary tables based on this table, rename them to appropriate names.
|
||||||
for st in rec.summaryTables:
|
for st in rec.summaryTables:
|
||||||
st_table_id = summary.encode_summary_table_name(new_table_id)
|
groupby_col_ids = [c.colId for c in st.columns if c.summarySourceCol]
|
||||||
|
st_table_id = summary.encode_summary_table_name(new_table_id, groupby_col_ids)
|
||||||
st_table_id = identifiers.pick_table_ident(st_table_id, avoid=avoid_tableid_set)
|
st_table_id = identifiers.pick_table_ident(st_table_id, avoid=avoid_tableid_set)
|
||||||
avoid_tableid_set.add(st_table_id)
|
avoid_tableid_set.add(st_table_id)
|
||||||
update_pairs.append((st, {'tableId': st_table_id}))
|
update_pairs.append((st, {'tableId': st_table_id}))
|
||||||
@ -697,6 +698,7 @@ class UserActions(object):
|
|||||||
|
|
||||||
make_acl_updates = acl.prepare_acl_col_renames(self._docmodel, self, renames)
|
make_acl_updates = acl.prepare_acl_col_renames(self._docmodel, self, renames)
|
||||||
|
|
||||||
|
rename_summary_tables = set()
|
||||||
for c, values in update_pairs:
|
for c, values in update_pairs:
|
||||||
# Trigger ModifyColumn and RenameColumn as necessary
|
# Trigger ModifyColumn and RenameColumn as necessary
|
||||||
schema_colinfo = select_keys(values, _modify_col_schema_props)
|
schema_colinfo = select_keys(values, _modify_col_schema_props)
|
||||||
@ -704,6 +706,8 @@ class UserActions(object):
|
|||||||
self.doModifyColumn(c.parentId.tableId, c.colId, schema_colinfo)
|
self.doModifyColumn(c.parentId.tableId, c.colId, schema_colinfo)
|
||||||
if has_diff_value(values, 'colId', c.colId):
|
if has_diff_value(values, 'colId', c.colId):
|
||||||
self._do_doc_action(actions.RenameColumn(c.parentId.tableId, c.colId, values['colId']))
|
self._do_doc_action(actions.RenameColumn(c.parentId.tableId, c.colId, values['colId']))
|
||||||
|
if c.summarySourceCol:
|
||||||
|
rename_summary_tables.add(c.parentId)
|
||||||
|
|
||||||
# If we change a column's type, we should ALSO unset each affected field's displayCol.
|
# If we change a column's type, we should ALSO unset each affected field's displayCol.
|
||||||
type_changed = [c for c, values in update_pairs if has_diff_value(values, 'type', c.type)]
|
type_changed = [c for c, values in update_pairs if has_diff_value(values, 'type', c.type)]
|
||||||
@ -718,6 +722,12 @@ class UserActions(object):
|
|||||||
|
|
||||||
make_acl_updates()
|
make_acl_updates()
|
||||||
|
|
||||||
|
for table in rename_summary_tables:
|
||||||
|
groupby_col_ids = [c.colId for c in table.columns if c.summarySourceCol]
|
||||||
|
new_table_id = summary.encode_summary_table_name(table.summarySourceTable.tableId,
|
||||||
|
groupby_col_ids)
|
||||||
|
with self.indirect_actions():
|
||||||
|
self.RenameTable(table.tableId, new_table_id)
|
||||||
|
|
||||||
@override_action('BulkUpdateRecord', '_grist_Views_section')
|
@override_action('BulkUpdateRecord', '_grist_Views_section')
|
||||||
def _updateViewSections(self, table_id, row_ids, col_values):
|
def _updateViewSections(self, table_id, row_ids, col_values):
|
||||||
|
BIN
test/fixtures/docs/Hello.grist
vendored
BIN
test/fixtures/docs/Hello.grist
vendored
Binary file not shown.
Loading…
Reference in New Issue
Block a user