예제 #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)
예제 #2
0
  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}
예제 #3
0
  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)
예제 #4
0
  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
예제 #5
0
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