gristlabs_grist-core/sandbox/grist/test_table_actions.py
Alex Hall be96db4689 (core) Remove code related to _grist_TableViews
Summary:
Removed some TS and python code interacting with this meta table. Not touching schema or migrations.

This is not really necessary, just checking my understanding and cleaning up in preparation for raw data views. I can also remove _grist_TabItems code while I'm at it.

Test Plan: this

Reviewers: dsagal

Reviewed By: dsagal

Differential Revision: https://phab.getgrist.com/D3161
2021-11-30 23:51:30 +02:00

309 lines
12 KiB
Python

import logger
import testutil
import test_engine
from test_engine import Table, Column, View, Section, Field
log = logger.Logger(__name__, logger.INFO)
class TestTableActions(test_engine.EngineTestCase):
address_table_data = [
["id", "city", "state", "amount" ],
[ 21, "New York", "NY" , 1. ],
[ 22, "Albany", "NY" , 2. ],
[ 23, "Seattle", "WA" , 3. ],
[ 24, "Chicago", "IL" , 4. ],
[ 25, "Bedford", "MA" , 5. ],
[ 26, "New York", "NY" , 6. ],
[ 27, "Buffalo", "NY" , 7. ],
[ 28, "Bedford", "NY" , 8. ],
[ 29, "Boston", "MA" , 9. ],
[ 30, "Yonkers", "NY" , 10. ],
[ 31, "New York", "NY" , 11. ],
]
people_table_data = [
["id", "name", "address" ],
[ 1, "Alice", 22 ],
[ 2, "Bob", 25 ],
[ 3, "Carol", 27 ],
]
def init_sample_data(self):
# Add a couple of tables, including references.
self.apply_user_action(["AddTable", "Address", [
{"id": "city", "type": "Text"},
{"id": "state", "type": "Text"},
{"id": "amount", "type": "Numeric"},
]])
self.apply_user_action(["AddTable", "People", [
{"id": "name", "type": "Text"},
{"id": "address", "type": "Ref:Address"},
{"id": "city", "type": "Any", "formula": "$address.city" }
]])
# Populate some data.
d = testutil.table_data_from_rows("Address", self.address_table_data[0],
self.address_table_data[1:])
self.apply_user_action(["BulkAddRecord", "Address", d.row_ids, d.columns])
d = testutil.table_data_from_rows("People", self.people_table_data[0],
self.people_table_data[1:])
self.apply_user_action(["BulkAddRecord", "People", d.row_ids, d.columns])
# Add a view with several sections, including a summary table.
self.apply_user_action(["CreateViewSection", 1, 0, 'record', None])
self.apply_user_action(["CreateViewSection", 1, 3, 'record', [3]])
self.apply_user_action(["CreateViewSection", 2, 3, 'record', None])
# Verify the new structure of tables and views.
self.assertTables([
Table(1, "Address", primaryViewId=1, summarySourceTable=0, columns=[
Column(1, "manualSort", "ManualSortPos", False, "", 0),
Column(2, "city", "Text", False, "", 0),
Column(3, "state", "Text", False, "", 0),
Column(4, "amount", "Numeric", False, "", 0),
]),
Table(2, "People", primaryViewId=2, summarySourceTable=0, columns=[
Column(5, "manualSort", "ManualSortPos", False, "", 0),
Column(6, "name", "Text", False, "", 0),
Column(7, "address", "Ref:Address", False, "", 0),
Column(8, "city", "Any", True, "$address.city", 0),
]),
Table(3, "GristSummary_7_Address", 0, 1, columns=[
Column(9, "state", "Text", False, "", summarySourceCol=3),
Column(10, "group", "RefList:Address", True, summarySourceCol=0,
formula="table.getSummarySourceGroup(rec)"),
Column(11, "count", "Int", True, summarySourceCol=0, formula="len($group)"),
Column(12, "amount", "Numeric", True, summarySourceCol=0, formula="SUM($group.amount)"),
]),
])
self.assertViews([
View(1, sections=[
Section(1, parentKey="record", tableRef=1, fields=[
Field(1, colRef=2),
Field(2, colRef=3),
Field(3, colRef=4),
]),
]),
View(2, sections=[
Section(2, parentKey="record", tableRef=2, fields=[
Field(4, colRef=6),
Field(5, colRef=7),
Field(6, colRef=8),
]),
]),
View(3, sections=[
Section(3, parentKey="record", tableRef=1, fields=[
Field(7, colRef=2),
Field(8, colRef=3),
Field(9, colRef=4),
]),
Section(4, parentKey="record", tableRef=3, fields=[
Field(10, colRef=9),
Field(11, colRef=11),
Field(12, colRef=12),
]),
Section(5, parentKey="record", tableRef=2, fields=[
Field(13, colRef=6),
Field(14, colRef=7),
Field(15, colRef=8),
]),
]),
])
# Verify the data we've loaded.
self.assertTableData('Address', cols="subset", data=self.address_table_data)
self.assertTableData('People', cols="subset", data=self.people_table_data)
self.assertTableData("GristSummary_7_Address", cols="subset", data=[
[ "id", "state", "count", "amount" ],
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
[ 2, "WA", 1, 3. ],
[ 3, "IL", 1, 4. ],
[ 4, "MA", 2, 5.+9 ],
])
#----------------------------------------------------------------------
@test_engine.test_undo
def test_table_updates(self):
# Verify table renames triggered by UpdateRecord actions, and related behavior.
# Load a sample with a few table and views.
self.init_sample_data()
# Verify that we can rename tables via UpdatRecord actions, including multiple tables.
self.apply_user_action(["BulkUpdateRecord", "_grist_Tables", [1,2],
{"tableId": ["Location", "Persons"]}])
# Check that requested tables and summary tables got renamed correctly.
self.assertTableData('_grist_Tables', cols="subset", data=[
["id", "tableId"],
[1, "Location"],
[2, "Persons"],
[3, "GristSummary_8_Location"],
])
# Check that reference columns to renamed tables get their type modified.
self.assertTableData('_grist_Tables_column', rows="subset", cols="subset", data=[
["id", "colId", "type"],
[7, "address", "Ref:Location"],
[10, "group", "RefList:Location"],
])
# Do a bulk update to rename A and B to conflicting names.
self.apply_user_action(["AddTable", "A", [{"id": "a", "type": "Text"}]])
out_actions = self.apply_user_action(["BulkUpdateRecord", "_grist_Tables", [1,2],
{"tableId": ["A", "A"]}])
# See what doc-actions get generated.
self.assertPartialOutActions(out_actions, {
"stored": [
["ModifyColumn", "Persons", "address", {"type": "Int"}],
["ModifyColumn", "GristSummary_8_Location", "group", {"type": "Int"}],
["RenameTable", "Location", "A2"],
["RenameTable", "GristSummary_8_Location", "GristSummary_2_A2"],
["RenameTable", "Persons", "A3"],
["BulkUpdateRecord", "_grist_Tables", [1, 3, 2],
{"tableId": ["A2", "GristSummary_2_A2", "A3"]}],
["ModifyColumn", "A3", "address", {"type": "Ref:A2"}],
["ModifyColumn", "GristSummary_2_A2", "group", {"type": "RefList:A2"}],
["BulkUpdateRecord", "_grist_Tables_column", [7, 10], {"type": ["Ref:A2", "RefList:A2"]}],
]
})
# Check that requested tables and summary tables got renamed correctly.
self.assertTableData('_grist_Tables', cols="subset", data=[
["id", "tableId"],
[1, "A2"],
[2, "A3"],
[3, "GristSummary_2_A2"],
[4, "A"],
])
# Check that reference columns to renamed tables get their type modified.
self.assertTableData('_grist_Tables_column', rows="subset", cols="subset", data=[
["id", "colId", "type"],
[7, "address", "Ref:A2"],
[10, "group", "RefList:A2"],
])
# Verify the data we've loaded.
self.assertTableData('A2', cols="subset", data=self.address_table_data)
self.assertTableData('A3', cols="subset", data=self.people_table_data)
self.assertTableData("GristSummary_2_A2", cols="subset", data=[
[ "id", "state", "count", "amount" ],
[ 1, "NY", 7, 1.+2+6+7+8+10+11 ],
[ 2, "WA", 1, 3. ],
[ 3, "IL", 1, 4. ],
[ 4, "MA", 2, 5.+9 ],
])
#----------------------------------------------------------------------
@test_engine.test_undo
def test_table_renames_summary_by_ref(self):
# Verify table renames when there is a group-by column that's a Reference.
# This tests a potential bug since a table rename needs to modify Reference types, but
# group-by columns aren't supposed to be modifiable.
self.init_sample_data()
# Add a table grouped by a reference column (the 'Ref:Address' column named 'address').
self.apply_user_action(["CreateViewSection", 2, 0, 'record', [7]])
self.assertTableData('_grist_Tables_column', cols="subset", data=[
["id", "colId", "type", "isFormula", "formula" ],
[ 13, "address", "Ref:Address", False, "" ],
[ 14, "group", "RefList:People", True, "table.getSummarySourceGroup(rec)" ],
[ 15, "count", "Int", True, "len($group)" ],
], rows=lambda r: (r.parentId.id == 4))
# Now rename the table Address -> Location.
out_actions = self.apply_user_action(["RenameTable", "Address", "Location"])
# See what doc-actions get generated.
self.assertPartialOutActions(out_actions, {
"stored": [
["ModifyColumn", "People", "address", {"type": "Int"}],
["ModifyColumn", "GristSummary_7_Address", "group", {"type": "Int"}],
["ModifyColumn", "GristSummary_6_People", "address", {"type": "Int"}],
["RenameTable", "Address", "Location"],
["RenameTable", "GristSummary_7_Address", "GristSummary_8_Location"],
["BulkUpdateRecord", "_grist_Tables", [1, 3],
{"tableId": ["Location", "GristSummary_8_Location"]}],
["ModifyColumn", "People", "address", {"type": "Ref:Location"}],
["ModifyColumn", "GristSummary_8_Location", "group", {"type": "RefList:Location"}],
["ModifyColumn", "GristSummary_6_People", "address", {"type": "Ref:Location"}],
["BulkUpdateRecord", "_grist_Tables_column", [7, 10, 13],
{"type": ["Ref:Location", "RefList:Location", "Ref:Location"]}],
]
})
self.assertTableData('_grist_Tables_column', cols="subset", data=[
["id", "colId", "type", "isFormula", "formula" ],
[ 13, "address", "Ref:Location", False, "" ],
[ 14, "group", "RefList:People", True, "table.getSummarySourceGroup(rec)" ],
[ 15, "count", "Int", True, "len($group)" ],
], rows=lambda r: (r.parentId.id == 4))
#----------------------------------------------------------------------
@test_engine.test_undo
def test_table_removes(self):
# Verify table removals triggered by UpdateRecord actions, and related behavior.
# Same setup as previous test.
self.init_sample_data()
# Add one more table, and one more view for tables #1 and #4 (those we are about to delete).
self.apply_user_action(["AddEmptyTable"])
out_actions = self.apply_user_action(["CreateViewSection", 1, 0, 'detail', None])
self.assertEqual(out_actions.retValues[0]["viewRef"], 5)
self.apply_user_action(["CreateViewSection", 4, 5, 'detail', None])
# See what's in TabBar table, to verify after we remove a table.
self.assertTableData('_grist_TabBar', cols="subset", data=[
["id", "viewRef"],
[1, 1],
[2, 2],
[3, 3],
[4, 4],
[5, 5],
])
# Remove two tables, ensure certain views get removed.
self.apply_user_action(["BulkRemoveRecord", "_grist_Tables", [1, 4]])
# See that some TabBar entries disappear, or tableRef gets unset.
self.assertTableData('_grist_TabBar', cols="subset", data=[
["id", "viewRef"],
[2, 2],
[3, 3],
])
# Check that reference columns to this table get removed, with associated fields.
self.assertTables([
Table(2, "People", primaryViewId=2, summarySourceTable=0, columns=[
Column(5, "manualSort", "ManualSortPos", False, "", 0),
Column(6, "name", "Text", False, "", 0),
Column(8, "city", "Any", True, "$address.city", 0),
]),
# Note that the summary table is also gone.
])
self.assertViews([
View(2, sections=[
Section(2, parentKey="record", tableRef=2, fields=[
Field(4, colRef=6),
Field(6, colRef=8),
]),
]),
View(3, sections=[
Section(5, parentKey="record", tableRef=2, fields=[
Field(13, colRef=6),
Field(15, colRef=8),
]),
]),
])