Ejemplo n.º 1
0
def migration26(tdset):
    """
  Add rawViewSectionRef column to _grist_Tables
  and new raw view sections for each 'normal' table.
  """
    doc_actions = [
        add_column('_grist_Tables', 'rawViewSectionRef',
                   'Ref:_grist_Views_section')
    ]

    tables = list(
        actions.transpose_bulk_action(tdset.all_tables["_grist_Tables"]))
    columns = list(
        actions.transpose_bulk_action(
            tdset.all_tables["_grist_Tables_column"]))
    views = {
        view.id: view
        for view in actions.transpose_bulk_action(
            tdset.all_tables["_grist_Views"])
    }

    new_view_section_id = next_id(tdset, "_grist_Views_section")

    for table in sorted(tables, key=lambda t: t.tableId):
        old_view = views.get(table.primaryViewId)
        if not (table.primaryViewId and old_view):
            continue

        table_columns = [
            col for col in columns
            if table.id == col.parentId and is_visible_column(col.colId)
        ]
        table_columns.sort(key=lambda c: c.parentPos)
        fields = {
            "parentId": [new_view_section_id] * len(table_columns),
            "colRef": [col.id for col in table_columns],
            "parentPos": [col.parentPos for col in table_columns],
        }
        field_ids = [None] * len(table_columns)

        doc_actions += [
            actions.AddRecord(
                "_grist_Views_section", new_view_section_id, {
                    "tableRef": table.id,
                    "parentId": 0,
                    "parentKey": "record",
                    "title": old_view.name,
                    "defaultWidth": 100,
                    "borderWidth": 1,
                }),
            actions.UpdateRecord("_grist_Tables", table.id, {
                "rawViewSectionRef": new_view_section_id,
            }),
            actions.BulkAddRecord("_grist_Views_section_field", field_ids,
                                  fields),
        ]

        new_view_section_id += 1

    return tdset.apply_doc_actions(doc_actions)
Ejemplo n.º 2
0
def migration14(tdset):
    # Create the ACL table AND also the default ACL groups, default resource, and the default rule.
    # These match the actions applied to new document by 'InitNewDoc' useraction (as of v14).
    return tdset.apply_doc_actions([
        actions.AddTable('_grist_ACLMemberships', [
            schema.make_column('parent', 'Ref:_grist_ACLPrincipals'),
            schema.make_column('child', 'Ref:_grist_ACLPrincipals'),
        ]),
        actions.AddTable('_grist_ACLPrincipals', [
            schema.make_column('userName', 'Text'),
            schema.make_column('groupName', 'Text'),
            schema.make_column('userEmail', 'Text'),
            schema.make_column('instanceId', 'Text'),
            schema.make_column('type', 'Text'),
        ]),
        actions.AddTable('_grist_ACLResources', [
            schema.make_column('colIds', 'Text'),
            schema.make_column('tableId', 'Text'),
        ]),
        actions.AddTable('_grist_ACLRules', [
            schema.make_column('aclFormula', 'Text'),
            schema.make_column('principals', 'Text'),
            schema.make_column('resource', 'Ref:_grist_ACLResources'),
            schema.make_column('aclColumn', 'Ref:_grist_Tables_column'),
            schema.make_column('permissions', 'Int'),
        ]),

        # Set up initial ACL data.
        actions.BulkAddRecord(
            '_grist_ACLPrincipals', [1, 2, 3, 4], {
                'type': ['group', 'group', 'group', 'group'],
                'groupName': ['Owners', 'Admins', 'Editors', 'Viewers'],
            }),
        actions.AddRecord('_grist_ACLResources', 1, {
            'tableId': '',
            'colIds': ''
        }),
        actions.AddRecord('_grist_ACLRules', 1, {
            'resource': 1,
            'permissions': 0x3F,
            'principals': '[1]'
        }),
    ])
Ejemplo n.º 3
0
 def alist():
     return [
         actions.BulkUpdateRecord("Table1", [1, 2, 3],
                                  {'Foo': [10, 20, 30]}),
         actions.BulkUpdateRecord("Table2", [1, 2, 3], {
             'Foo': [10, 20, 30],
             'Bar': ['a', 'b', 'c']
         }),
         actions.UpdateRecord("Table1", 17, {'Foo': 10}),
         actions.UpdateRecord("Table2", 18, {
             'Foo': 10,
             'Bar': 'a'
         }),
         actions.AddRecord("Table1", 17, {'Foo': 10}),
         actions.BulkAddRecord("Table2", 18, {
             'Foo': 10,
             'Bar': 'a'
         }),
         actions.ReplaceTableData("Table2", 18, {
             'Foo': 10,
             'Bar': 'a'
         }),
         actions.RemoveRecord("Table1", 17),
         actions.BulkRemoveRecord("Table2", [17, 18]),
         actions.AddColumn("Table1", "Foo", {"type": "Text"}),
         actions.RenameColumn("Table1", "Foo", "Bar"),
         actions.ModifyColumn("Table1", "Foo", {"type": "Text"}),
         actions.RemoveColumn("Table1", "Foo"),
         actions.AddTable("THello", [{
             "id": "Foo"
         }, {
             "id": "Bar"
         }]),
         actions.RemoveTable("THello"),
         actions.RenameTable("THello", "TWorld"),
     ]
Ejemplo n.º 4
0
def schema_version0():
    # This is the initial version of the schema before the very first migration. It's a historical
    # snapshot, and thus should not be edited. The test verifies that starting with this v0,
    # migrations bring the schema to the current version.
    def make_column(col_id, col_type, formula='', isFormula=False):
        return {
            "id": col_id,
            "type": col_type,
            "isFormula": isFormula,
            "formula": formula
        }

    return [
        actions.AddTable("_grist_DocInfo", [
            make_column("docId", "Text"),
            make_column("peers", "Text"),
            make_column("schemaVersion", "Int"),
        ]),
        actions.AddTable("_grist_Tables", [
            make_column("tableId", "Text"),
        ]),
        actions.AddTable("_grist_Tables_column", [
            make_column("parentId", "Ref:_grist_Tables"),
            make_column("parentPos", "PositionNumber"),
            make_column("colId", "Text"),
            make_column("type", "Text"),
            make_column("widgetOptions", "Text"),
            make_column("isFormula", "Bool"),
            make_column("formula", "Text"),
            make_column("label", "Text")
        ]),
        actions.AddTable("_grist_Imports", [
            make_column("tableRef", "Ref:_grist_Tables"),
            make_column("origFileName", "Text"),
            make_column("parseFormula",
                        "Text",
                        isFormula=True,
                        formula="grist.parseImport(rec, table._engine)"),
            make_column("delimiter", "Text", formula="','"),
            make_column("doublequote", "Bool", formula="True"),
            make_column("escapechar", "Text"),
            make_column("quotechar", "Text", formula="'\"'"),
            make_column("skipinitialspace", "Bool"),
            make_column("encoding", "Text", formula="'utf8'"),
            make_column("hasHeaders", "Bool"),
        ]),
        actions.AddTable("_grist_External_database", [
            make_column("host", "Text"),
            make_column("port", "Int"),
            make_column("username", "Text"),
            make_column("dialect", "Text"),
            make_column("database", "Text"),
            make_column("storage", "Text"),
        ]),
        actions.AddTable("_grist_External_table", [
            make_column("tableRef", "Ref:_grist_Tables"),
            make_column("databaseRef", "Ref:_grist_External_database"),
            make_column("tableName", "Text"),
        ]),
        actions.AddTable("_grist_TabItems", [
            make_column("tableRef", "Ref:_grist_Tables"),
            make_column("viewRef", "Ref:_grist_Views"),
        ]),
        actions.AddTable("_grist_Views", [
            make_column("name", "Text"),
            make_column("type", "Text"),
            make_column("layoutSpec", "Text"),
        ]),
        actions.AddTable("_grist_Views_section", [
            make_column("tableRef", "Ref:_grist_Tables"),
            make_column("parentId", "Ref:_grist_Views"),
            make_column("parentKey", "Text"),
            make_column("title", "Text"),
            make_column("defaultWidth", "Int", formula="100"),
            make_column("borderWidth", "Int", formula="1"),
            make_column("theme", "Text"),
            make_column("chartType", "Text"),
            make_column("layoutSpec", "Text"),
            make_column("filterSpec", "Text"),
            make_column("sortColRefs", "Text"),
            make_column("linkSrcSectionRef", "Ref:_grist_Views_section"),
            make_column("linkSrcColRef", "Ref:_grist_Tables_column"),
            make_column("linkTargetColRef", "Ref:_grist_Tables_column"),
        ]),
        actions.AddTable("_grist_Views_section_field", [
            make_column("parentId", "Ref:_grist_Views_section"),
            make_column("parentPos", "PositionNumber"),
            make_column("colRef", "Ref:_grist_Tables_column"),
            make_column("width", "Int"),
            make_column("widgetOptions", "Text"),
        ]),
        actions.AddTable("_grist_Validations", [
            make_column("formula", "Text"),
            make_column("name", "Text"),
            make_column("tableRef", "Int")
        ]),
        actions.AddTable("_grist_REPL_Hist", [
            make_column("code", "Text"),
            make_column("outputText", "Text"),
            make_column("errorText", "Text")
        ]),
        actions.AddTable("_grist_Attachments", [
            make_column("fileIdent", "Text"),
            make_column("fileName", "Text"),
            make_column("fileType", "Text"),
            make_column("fileSize", "Int"),
            make_column("timeUploaded", "DateTime")
        ]),
        actions.AddRecord("_grist_DocInfo", 1, {})
    ]
Ejemplo n.º 5
0
  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
    # updates can be verified the same way after a table rename.

    # Verify the summarized data.
    self.assertTableData(summary_tbl_name, cols="subset", data=[
      [ "id", "city",     "state", "count", "amount"  ],
      [ 1,    "New York", "NY"   , 3,       1.+6+11   ],
      [ 2,    "Albany",   "NY"   , 1,       2.        ],
      [ 3,    "Seattle",  "WA"   , 1,       3.        ],
      [ 4,    "Chicago",  "IL"   , 1,       4.        ],
      [ 5,    "Bedford",  "MA"   , 1,       5.        ],
      [ 6,    "Buffalo",  "NY"   , 1,       7.        ],
      [ 7,    "Bedford",  "NY"   , 1,       8.        ],
      [ 8,    "Boston",   "MA"   , 1,       9.        ],
      [ 9,    "Yonkers",  "NY"   , 1,       10.       ],
    ])

    # Change an amount (New York, NY, 6 -> 106), check that the right calc action gets emitted.
    out_actions = self.update_record(source_tbl_name, 26, amount=106)
    self.assertPartialOutActions(out_actions, {
      "stored": [
        actions.UpdateRecord(source_tbl_name, 26, {'amount': 106}),
        actions.UpdateRecord(summary_tbl_name, 1, {'amount': 1.+106+11}),
      ]
    })

    # Change a groupby value so that a record moves from one summary group to another.
    # Bedford, NY, 8.0 -> Bedford, MA, 8.0
    out_actions = self.update_record(source_tbl_name, 28, state="MA")
    self.assertPartialOutActions(out_actions, {
      "stored": [
        actions.UpdateRecord(source_tbl_name, 28, {'state': 'MA'}),
        actions.BulkUpdateRecord(summary_tbl_name, [5,7], {'amount': [5.0 + 8.0, 0.0]}),
        actions.BulkUpdateRecord(summary_tbl_name, [5,7], {'count': [2, 0]}),
        actions.BulkUpdateRecord(summary_tbl_name, [5,7], {'group': [[25, 28], []]}),
      ]
    })

    # Add a record to an existing group (Bedford, MA, 108.0)
    out_actions = self.add_record(source_tbl_name, city="Bedford", state="MA", amount=108.0)
    self.assertPartialOutActions(out_actions, {
      "stored": [
        actions.AddRecord(source_tbl_name, 32,
                          {'city': 'Bedford', 'state': 'MA', 'amount': 108.0}),
        actions.UpdateRecord(summary_tbl_name, 5, {'amount': 5.0 + 8.0 + 108.0}),
        actions.UpdateRecord(summary_tbl_name, 5, {'count': 3}),
        actions.UpdateRecord(summary_tbl_name, 5, {'group': [25, 28, 32]}),
      ]
    })

    # Remove a record (rowId=28, Bedford, MA, 8.0)
    out_actions = self.remove_record(source_tbl_name, 28)
    self.assertPartialOutActions(out_actions, {
      "stored": [
        actions.RemoveRecord(source_tbl_name, 28),
        actions.UpdateRecord(summary_tbl_name, 5, {'amount': 5.0 + 108.0}),
        actions.UpdateRecord(summary_tbl_name, 5, {'count': 2}),
        actions.UpdateRecord(summary_tbl_name, 5, {'group': [25, 32]}),
      ]
    })

    # Change groupby value to create a new combination (rowId 25, Bedford, MA, 5.0 -> Salem, MA).
    # A new summary record should be added.
    out_actions = self.update_record(source_tbl_name, 25, city="Salem")
    self.assertPartialOutActions(out_actions, {
      "stored": [
        actions.UpdateRecord(source_tbl_name, 25, {'city': 'Salem'}),
        actions.AddRecord(summary_tbl_name, 10, {'city': 'Salem', 'state': 'MA'}),
        actions.BulkUpdateRecord(summary_tbl_name, [5,10], {'amount': [108.0, 5.0]}),
        actions.BulkUpdateRecord(summary_tbl_name, [5,10], {'count': [1, 1]}),
        actions.BulkUpdateRecord(summary_tbl_name, [5,10], {'group': [[32], [25]]}),
      ]
    })

    # Add a record with a new combination (Amherst, MA, 17)
    out_actions = self.add_record(source_tbl_name, city="Amherst", state="MA", amount=17.0)
    self.assertPartialOutActions(out_actions, {
      "stored": [
        actions.AddRecord(source_tbl_name, 33, {'city': 'Amherst', 'state': 'MA', 'amount': 17.}),
        actions.AddRecord(summary_tbl_name, 11, {'city': 'Amherst', 'state': 'MA'}),
        actions.UpdateRecord(summary_tbl_name, 11, {'amount': 17.0}),
        actions.UpdateRecord(summary_tbl_name, 11, {'count': 1}),
        actions.UpdateRecord(summary_tbl_name, 11, {'group': [33]}),
      ]
    })

    # Verify the resulting data after all the updates.
    self.assertTableData(summary_tbl_name, cols="subset", data=[
      [ "id", "city",     "state", "count", "amount"  ],
      [ 1,    "New York", "NY"   , 3,       1.+106+11 ],
      [ 2,    "Albany",   "NY"   , 1,       2.        ],
      [ 3,    "Seattle",  "WA"   , 1,       3.        ],
      [ 4,    "Chicago",  "IL"   , 1,       4.        ],
      [ 5,    "Bedford",  "MA"   , 1,       108.      ],
      [ 6,    "Buffalo",  "NY"   , 1,       7.        ],
      [ 7,    "Bedford",  "NY"   , 0,       0.        ],
      [ 8,    "Boston",   "MA"   , 1,       9.        ],
      [ 9,    "Yonkers",  "NY"   , 1,       10.       ],
      [ 10,   "Salem",    "MA"   , 1,       5.0       ],
      [ 11,   "Amherst",  "MA"   , 1,       17.0      ],
    ])
Ejemplo n.º 6
0
    def test_add_remove_lookup(self):
        # Verify that when we add or remove a lookup formula, we get appropriate changes.
        self.load_sample(testsamples.sample_students)

        # Add another lookup formula.
        out_actions = self.add_column(
            "Schools",
            "lastNames",
            formula=(
                "','.join(Students.lookupRecords(schoolName=$name).lastName)"))
        self.assertPartialOutActions(
            out_actions, {
                "stored": [
                    actions.AddColumn(
                        "Schools", "lastNames", {
                            "formula":
                            "','.join(Students.lookupRecords(schoolName=$name).lastName)",
                            "isFormula": True,
                            "type": "Any"
                        }),
                    actions.AddRecord(
                        "_grist_Tables_column", 22, {
                            "colId": "lastNames",
                            "formula":
                            "','.join(Students.lookupRecords(schoolName=$name).lastName)",
                            "isFormula": True,
                            "label": "lastNames",
                            "parentId": 2,
                            "parentPos": 6.0,
                            "type": "Any",
                            "widgetOptions": ""
                        }),
                    _bulk_update(
                        "Schools", ["id", "lastNames"],
                        [[1, "Obama,Clinton"], [2, "Obama,Clinton"],
                         [3, "Bush,Bush,Ford"], [4, "Bush,Bush,Ford"]]),
                ],
                "calls": {
                    "Schools": {
                        "lastNames": 4
                    },
                    "Students": {
                        "#lookup#schoolName": 6
                    }
                },
            })

        # Make sure it responds to changes.
        out_actions = self.update_record("Students", 5, schoolName="Columbia")
        self.assertPartialOutActions(
            out_actions, {
                "stored": [
                    actions.UpdateRecord("Students", 5,
                                         {"schoolName": "Columbia"}),
                    _bulk_update("Schools", ["id", "lastNames"],
                                 [[1, "Obama,Clinton,Reagan"],
                                  [2, "Obama,Clinton,Reagan"]]),
                    actions.UpdateRecord(
                        "Students", 5, {"schoolCities": "New York:Colombia"}),
                    actions.UpdateRecord("Students", 5, {"schoolIds": "1:2"}),
                ],
                "calls": {
                    "Students": {
                        'schoolCities': 1,
                        'schoolIds': 1,
                        '#lookup#schoolName': 1
                    },
                    "Schools": {
                        'lastNames': 2
                    }
                },
            })

        # Modify the column: in the process, the LookupMapColumn on Students.schoolName becomes unused
        # while the old formula column is removed, but used again when it's added. It should not have
        # to be rebuilt (so there should be no calls to recalculate the LookupMapColumn.
        out_actions = self.modify_column(
            "Schools",
            "lastNames",
            formula=(
                "','.join(Students.lookupRecords(schoolName=$name).firstName)"
            ))
        self.assertPartialOutActions(
            out_actions, {
                "stored": [
                    actions.ModifyColumn(
                        "Schools", "lastNames", {
                            "formula":
                            "','.join(Students.lookupRecords(schoolName=$name).firstName)"
                        }),
                    actions.UpdateRecord(
                        "_grist_Tables_column", 22, {
                            "formula":
                            "','.join(Students.lookupRecords(schoolName=$name).firstName)"
                        }),
                    _bulk_update(
                        "Schools", ["id", "lastNames"],
                        [[1, "Barack,Bill,Ronald"], [2, "Barack,Bill,Ronald"],
                         [3, "George W,George H,Gerald"],
                         [4, "George W,George H,Gerald"]])
                ],
                "calls": {
                    "Schools": {
                        "lastNames": 4
                    }
                }
            })

        # Remove the new lookup formula.
        out_actions = self.remove_column("Schools", "lastNames")
        self.assertPartialOutActions(out_actions, {})  # No calc actions

        # Make sure that changes still work without errors.
        out_actions = self.update_record("Students", 5, schoolName="Eureka")
        self.assertPartialOutActions(
            out_actions,
            {
                "stored": [
                    actions.UpdateRecord("Students", 5,
                                         {"schoolName": "Eureka"}),
                    actions.UpdateRecord("Students", 5, {"schoolCities": ""}),
                    actions.UpdateRecord("Students", 5, {"schoolIds": ""}),
                ],
                # This should NOT have '#lookup#schoolName' recalculation because there are no longer any
                # formulas which do such a lookup.
                "calls": {
                    "Students": {
                        'schoolCities': 1,
                        'schoolIds': 1
                    }
                }
            })
Ejemplo n.º 7
0
def migration10(tdset):
    """
  Add displayCol to all reference cols, with formula $<ref_col_id>.<visible_col_id>
  (Note that displayCol field was added in the previous migration.)
  """
    doc_actions = []
    tables = list(
        actions.transpose_bulk_action(tdset.all_tables['_grist_Tables']))
    columns = list(
        actions.transpose_bulk_action(
            tdset.all_tables['_grist_Tables_column']))

    # Maps tableRef to tableId.
    tables_map = {t.id: t.tableId for t in tables}

    # Maps tableRef to sets of colIds in the tables. Used to prevent repeated colIds.
    table_col_ids = {
        t.id: set(tdset.all_tables[t.tableId].columns.keys())
        for t in tables
    }

    # Get the next sequential column row id.
    row_id = next_id(tdset, '_grist_Tables_column')

    for c in columns:
        # If a column is a reference with an unset display column, add a display column.
        if c.type.startswith('Ref:') and not c.displayCol:
            # Get visible_col_id. If not found, row id is used and no display col is necessary.
            visible_col_id = ""
            try:
                visible_col_id = json.loads(c.widgetOptions).get('visibleCol')
                if not visible_col_id:
                    continue
            except Exception:
                continue  # If invalid widgetOptions, skip this column.

            # Set formula to use the current visibleCol in widgetOptions.
            formula = ("$%s.%s" % (c.colId, visible_col_id))

            # Get a unique colId for the display column, and add it to the set of used ids.
            used_col_ids = table_col_ids[c.parentId]
            display_col_id = identifiers.pick_col_ident('gristHelper_Display',
                                                        avoid=used_col_ids)
            used_col_ids.add(display_col_id)

            # Add all actions to the list.
            doc_actions.append(
                add_column(tables_map[c.parentId],
                           'gristHelper_Display',
                           'Any',
                           formula=formula,
                           isFormula=True))
            doc_actions.append(
                actions.AddRecord(
                    '_grist_Tables_column', row_id, {
                        'parentPos': 1.0,
                        'label': 'gristHelper_Display',
                        'isFormula': True,
                        'parentId': c.parentId,
                        'colId': 'gristHelper_Display',
                        'formula': formula,
                        'widgetOptions': '',
                        'type': 'Any'
                    }))
            doc_actions.append(
                actions.UpdateRecord('_grist_Tables_column', c.id,
                                     {'displayCol': row_id}))

            # Increment row id to the next unused.
            row_id += 1

    return tdset.apply_doc_actions(doc_actions)
Ejemplo n.º 8
0
    def test_prune_actions(self):
        # prune_actions is in-place, so we make a new list every time.
        def alist():
            return [
                actions.BulkUpdateRecord("Table1", [1, 2, 3],
                                         {'Foo': [10, 20, 30]}),
                actions.BulkUpdateRecord("Table2", [1, 2, 3], {
                    'Foo': [10, 20, 30],
                    'Bar': ['a', 'b', 'c']
                }),
                actions.UpdateRecord("Table1", 17, {'Foo': 10}),
                actions.UpdateRecord("Table2", 18, {
                    'Foo': 10,
                    'Bar': 'a'
                }),
                actions.AddRecord("Table1", 17, {'Foo': 10}),
                actions.BulkAddRecord("Table2", 18, {
                    'Foo': 10,
                    'Bar': 'a'
                }),
                actions.ReplaceTableData("Table2", 18, {
                    'Foo': 10,
                    'Bar': 'a'
                }),
                actions.RemoveRecord("Table1", 17),
                actions.BulkRemoveRecord("Table2", [17, 18]),
                actions.AddColumn("Table1", "Foo", {"type": "Text"}),
                actions.RenameColumn("Table1", "Foo", "Bar"),
                actions.ModifyColumn("Table1", "Foo", {"type": "Text"}),
                actions.RemoveColumn("Table1", "Foo"),
                actions.AddTable("THello", [{
                    "id": "Foo"
                }, {
                    "id": "Bar"
                }]),
                actions.RemoveTable("THello"),
                actions.RenameTable("THello", "TWorld"),
            ]

        def prune(table_id, col_id):
            a = alist()
            actions.prune_actions(a, table_id, col_id)
            return a

        self.assertEqual(
            prune('Table1', 'Foo'),
            [
                actions.BulkUpdateRecord("Table2", [1, 2, 3], {
                    'Foo': [10, 20, 30],
                    'Bar': ['a', 'b', 'c']
                }),
                actions.UpdateRecord("Table2", 18, {
                    'Foo': 10,
                    'Bar': 'a'
                }),
                actions.BulkAddRecord("Table2", 18, {
                    'Foo': 10,
                    'Bar': 'a'
                }),
                actions.ReplaceTableData("Table2", 18, {
                    'Foo': 10,
                    'Bar': 'a'
                }),
                actions.RemoveRecord("Table1", 17),
                actions.BulkRemoveRecord("Table2", [17, 18]),
                # It doesn't do anything with column renames; it can be addressed if needed.
                actions.RenameColumn("Table1", "Foo", "Bar"),
                # It doesn't do anything with AddTable, which is expected.
                actions.AddTable("THello", [{
                    "id": "Foo"
                }, {
                    "id": "Bar"
                }]),
                actions.RemoveTable("THello"),
                actions.RenameTable("THello", "TWorld"),
            ])

        self.assertEqual(prune('Table2', 'Foo'), [
            actions.BulkUpdateRecord("Table1", [1, 2, 3],
                                     {'Foo': [10, 20, 30]}),
            actions.BulkUpdateRecord("Table2", [1, 2, 3],
                                     {'Bar': ['a', 'b', 'c']}),
            actions.UpdateRecord("Table1", 17, {'Foo': 10}),
            actions.UpdateRecord("Table2", 18, {'Bar': 'a'}),
            actions.AddRecord("Table1", 17, {'Foo': 10}),
            actions.BulkAddRecord("Table2", 18, {'Bar': 'a'}),
            actions.ReplaceTableData("Table2", 18, {'Bar': 'a'}),
            actions.RemoveRecord("Table1", 17),
            actions.BulkRemoveRecord("Table2", [17, 18]),
            actions.AddColumn("Table1", "Foo", {"type": "Text"}),
            actions.RenameColumn("Table1", "Foo", "Bar"),
            actions.ModifyColumn("Table1", "Foo", {"type": "Text"}),
            actions.RemoveColumn("Table1", "Foo"),
            actions.AddTable("THello", [{
                "id": "Foo"
            }, {
                "id": "Bar"
            }]),
            actions.RemoveTable("THello"),
            actions.RenameTable("THello", "TWorld"),
        ])
Ejemplo n.º 9
0
    def test_group_by_one(self):
        """
    Test basic summary table operation, for a table grouped by one columns.
    """
        self.load_sample(self.sample)

        # Create a derived table summarizing count and total of orders by year.
        self.apply_user_action(["CreateViewSection", 2, 0, 'record', [10]])

        # Check the results.
        self.assertPartialData("GristSummary_6_Orders",
                               ["id", "year", "count", "amount", "group"], [
                                   [1, 2012, 1, 15, [1]],
                                   [2, 2013, 2, 30, [2, 3]],
                                   [3, 2014, 3, 86, [4, 5, 6]],
                                   [4, 2015, 4, 106, [7, 8, 9, 10]],
                               ])

        # Updating amounts should cause totals to be updated in the summary.
        out_actions = self.update_records("Orders", ["id", "amount"],
                                          [[1, 14], [2, 14]])
        self.assertPartialOutActions(
            out_actions, {
                "stored": [
                    actions.BulkUpdateRecord("Orders", [1, 2],
                                             {'amount': [14, 14]}),
                    actions.BulkUpdateRecord("GristSummary_6_Orders", [1, 2],
                                             {'amount': [14, 29]})
                ],
                "calls": {
                    "GristSummary_6_Orders": {
                        "amount": 2
                    }
                }
            })

        # Changing a record from one product to another should cause the two affected lines to change.
        out_actions = self.update_record("Orders", 10, year=2012)
        self.assertPartialOutActions(
            out_actions, {
                "stored": [
                    actions.UpdateRecord("Orders", 10, {"year": 2012}),
                    actions.BulkUpdateRecord("GristSummary_6_Orders", [1, 4],
                                             {"amount": [31.0, 89.0]}),
                    actions.BulkUpdateRecord("GristSummary_6_Orders", [1, 4],
                                             {"count": [2, 3]}),
                    actions.BulkUpdateRecord("GristSummary_6_Orders", [1, 4],
                                             {"group": [[1, 10], [7, 8, 9]]}),
                ],
                "calls": {
                    "GristSummary_6_Orders": {
                        "group": 2,
                        "amount": 2,
                        "count": 2
                    },
                    "Orders": {
                        "#lookup##summary#GristSummary_6_Orders": 1,
                        "#summary#GristSummary_6_Orders": 1
                    }
                }
            })

        self.assertPartialData("GristSummary_6_Orders",
                               ["id", "year", "count", "amount", "group"], [
                                   [1, 2012, 2, 31.0, [1, 10]],
                                   [2, 2013, 2, 29.0, [2, 3]],
                                   [3, 2014, 3, 86.0, [4, 5, 6]],
                                   [4, 2015, 3, 89.0, [7, 8, 9]],
                               ])

        # Changing a record to a new year that wasn't in the summary should cause an add-record.
        out_actions = self.update_record("Orders", 10, year=1999)
        self.assertPartialOutActions(
            out_actions, {
                "stored": [
                    actions.UpdateRecord("Orders", 10, {"year": 1999}),
                    actions.AddRecord("GristSummary_6_Orders", 5,
                                      {'year': 1999}),
                    actions.BulkUpdateRecord("GristSummary_6_Orders", [1, 5],
                                             {"amount": [14.0, 17.0]}),
                    actions.BulkUpdateRecord("GristSummary_6_Orders", [1, 5],
                                             {"count": [1, 1]}),
                    actions.BulkUpdateRecord("GristSummary_6_Orders", [1, 5],
                                             {"group": [[1], [10]]}),
                ],
                "calls": {
                    "GristSummary_6_Orders": {
                        '#lookup#year': 1,
                        "group": 2,
                        "amount": 2,
                        "count": 2
                    },
                    "Orders": {
                        "#lookup##summary#GristSummary_6_Orders": 1,
                        "#summary#GristSummary_6_Orders": 1
                    }
                }
            })

        self.assertPartialData("GristSummary_6_Orders",
                               ["id", "year", "count", "amount", "group"], [
                                   [1, 2012, 1, 14.0, [1]],
                                   [2, 2013, 2, 29.0, [2, 3]],
                                   [3, 2014, 3, 86.0, [4, 5, 6]],
                                   [4, 2015, 3, 89.0, [7, 8, 9]],
                                   [5, 1999, 1, 17.0, [10]],
                               ])
Ejemplo n.º 10
0
    def test_group_by_two(self):
        """
    Test a summary table created by grouping on two columns.
    """
        self.load_sample(self.sample)

        self.apply_user_action(["CreateViewSection", 2, 0, 'record', [10, 12]])
        self.assertPartialData(
            "GristSummary_6_Orders",
            ["id", "year", "product", "count", "amount", "group"], [
                [1, 2012, "A", 1, 15.0, [1]],
                [2, 2013, "A", 2, 30.0, [2, 3]],
                [3, 2014, "B", 2, 70.0, [4, 5]],
                [4, 2014, "A", 1, 16.0, [6]],
                [5, 2015, "A", 2, 34.0, [7, 10]],
                [6, 2015, "B", 2, 72.0, [8, 9]],
            ])

        # Changing a record from one product to another should cause the two affected lines to change,
        # or new lines to be created as needed.
        out_actions = self.update_records("Orders", ["id", "product"], [
            [2, "B"],
            [6, "B"],
            [7, "C"],
        ])
        self.assertPartialOutActions(
            out_actions, {
                "stored": [
                    actions.BulkUpdateRecord("Orders", [2, 6, 7],
                                             {"product": ["B", "B", "C"]}),
                    actions.AddRecord("GristSummary_6_Orders", 7, {
                        'year': 2013,
                        'product': 'B'
                    }),
                    actions.AddRecord("GristSummary_6_Orders", 8, {
                        'year': 2015,
                        'product': 'C'
                    }),
                    actions.BulkUpdateRecord(
                        "GristSummary_6_Orders", [2, 3, 4, 5, 7, 8],
                        {"amount": [15.0, 86.0, 0, 17.0, 15.0, 17.0]}),
                    actions.BulkUpdateRecord("GristSummary_6_Orders",
                                             [2, 3, 4, 5, 7, 8],
                                             {"count": [1, 3, 0, 1, 1, 1]}),
                    actions.BulkUpdateRecord(
                        "GristSummary_6_Orders", [2, 3, 4, 5, 7, 8],
                        {"group": [[3], [4, 5, 6], [], [10], [2], [7]]}),
                ],
            })

        # Verify the results.
        self.assertPartialData(
            "GristSummary_6_Orders",
            ["id", "year", "product", "count", "amount", "group"], [
                [1, 2012, "A", 1, 15.0, [1]],
                [2, 2013, "A", 1, 15.0, [3]],
                [3, 2014, "B", 3, 86.0, [4, 5, 6]],
                [4, 2014, "A", 0, 0.0, []],
                [5, 2015, "A", 1, 17.0, [10]],
                [6, 2015, "B", 2, 72.0, [8, 9]],
                [7, 2013, "B", 1, 15.0, [2]],
                [8, 2015, "C", 1, 17.0, [7]],
            ])