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)
def _MakeDefaultTransformRule(self, hidden_table_id, dest_table_id): """ Makes a basic transform_rule.dest_cols copying all the source cols hidden_table_id: table with src data dest_table_id: table data is going to If dst_table is null, copy all src columns If dst_table exists, copy all dst columns, and make copy formulas if any names match returns transform_rule with only destCols filled in """ tables = self._docmodel.tables hidden_table_rec = tables.lookupOne(tableId=hidden_table_id) # will use these to set default formulas (if column names match in src and dest table) src_cols = {c.colId for c in hidden_table_rec.columns} target_table = tables.lookupOne(tableId=dest_table_id) if dest_table_id else hidden_table_rec target_cols = target_table.columns # makes dest_cols for each column in target_cols (defaults to same columns as hidden_table) #loop through visible, non-formula target columns dest_cols = [] for c in target_cols: if column.is_visible_column(c.colId) and (not c.isFormula or c.formula == ""): dest_cols.append( { "label": c.label, "colId": c.colId if dest_table_id else None, #should be None if into new table "type": c.type, "formula": ("$" + c.colId) if (c.colId in src_cols) else '' }) return {"destCols": dest_cols}
def _make_table_model(self, table_info, summary_tables, filter_for_user=False): """ Returns the code for a table model. If filter_for_user is True, includes only user-visible columns. """ table_id = table_info.tableId source_table_id = summary.decode_summary_table_name(table_id) # Sort columns by "isFormula" to output all data columns before all formula columns. columns = sorted(table_info.columns.itervalues(), key=lambda c: c.isFormula) if filter_for_user: columns = [c for c in columns if is_visible_column(c.colId)] parts = ["@grist.UserTable\nclass %s:\n" % table_id] if source_table_id: parts.append(indent(textbuilder.Text("_summarySourceTable = %r\n" % source_table_id))) for col_info in columns: parts.append(indent(self._make_field(col_info, table_id))) if summary_tables: # Include summary formulas, for the user's information. formulas = OrderedDict((c.colId, c) for s in summary_tables for c in s.columns.itervalues() if c.isFormula) parts.append(indent(textbuilder.Text("\nclass _Summary:\n"))) for col_info in formulas.itervalues(): parts.append(indent(self._make_field(col_info, table_id), levels=2)) return textbuilder.Combiner(parts)
def _create_summary_colinfo(self, source_table, source_groupby_columns): """Come up automatically with a list of columns to include into a summary table.""" # Column 'group' defines the group of records that map to this summary line. all_colinfo = [_group_colinfo(source_table)] # For every column in the source data, if there is a same-named formula column in another # summary table, use it here; otherwise if it's a numerical column, automatically add a # same-named column with the sum of the values in the group. groupby_col_ids = {c.colId for c in source_groupby_columns} for col in source_table.columns: if col.colId in groupby_col_ids or col.colId == 'group' or not is_visible_column(col.colId): continue c = self._find_sister_column(source_table, col.colId) if c: all_colinfo.append(_make_col_info(col=c)) elif col.type in ('Int', 'Numeric'): all_colinfo.append(_make_col_info(col=col, isFormula=True, formula='SUM($group.%s)' % col.colId)) # Add a default 'count' column for the number of records in the group, unless a different # 'count' was already added (which we would then prefer as presumably more useful). We add the # default 'count' right after 'group', to make it the first of the visible formula columns. if not any(c.colId == 'count' for c in all_colinfo): all_colinfo.insert(1, _make_col_info(colId='count', type='Int', isFormula=True, formula='len($group)')) return all_colinfo
def _prepare_record_dict(record, dates_as_iso=False, expand_refs=0): table_id = record._table.table_id docmodel = record._table._engine.docmodel columns = docmodel.get_table_rec(table_id).columns frame = record._table._engine.get_current_frame() result = {'id': int(record)} errors = {} for col in columns: col_id = col.colId # Skip helper columns. if not column.is_visible_column(col_id): continue # Avoid trying to access the cell being evaluated, since cycles get detected even if the # CircularRef exception is caught. TODO This is hacky, and imperfect. If another column # references a column containing the RECORD(rec) call, CircularRefError will still happen. if frame and frame.node == (table_id, col_id): continue try: val = getattr(record, col_id) if dates_as_iso and isinstance(val, datetime.date): val = val.isoformat() elif expand_refs and isinstance(val, (Record, RecordSet)): # Reduce expand_refs levels. if val: val = RECORD(val, dates_as_iso=dates_as_iso, expand_refs=expand_refs - 1) else: val = None result[col_id] = val except Exception as e: result[col_id] = None while isinstance(e, CellError): # The extra information from CellError is redundant here e = e.error # pylint: disable=no-member errors[col_id] = "%s: %s" % (type(e).__name__, str(e)) if errors: result["_error_"] = errors return result