Ferreteria/v0.5/portbank

From Woozle Writes Code
< Ferreteria‎ | v0.5
Revision as of 17:29, 9 March 2022 by htyp>Woozle (Woozle moved page Ferreteria/v0.5/PortBank to Ferreteria/v0.5/portbank: lowercasing everything for easier reference)
Jump to navigation Jump to search

PortBank system

PortBanks are a new set of classes designed to automate format-conversion when reading or writing structured data from/to an external interface (database, display).

Structure

  • A PortBank is a Table-configured object which contains a set of PortRows (which, by default, it creates). Each PortRow has a Type string. In theory there can be any number of these for different types of I/O, but in practice (caPortIOBank) there are 3 types:
    • Native, which is used only for internal calculations (no I/O)
    • Storage, which converts to and from SQL (or, in theory, any other database-storage format)
    • Display, which converts to and from HTML (or, in theory, any other display markup)
  • A PortRow contains a set of PortUnits, one for each field in the Table.

Connections

  • A PortBank has an array of named PortRow objects.
    • PortIOBank pre-defines three particular PortRows: native, storage, and display.
    • SpacerIOBank is a PortIOBank which provides database-object access via its Space object, which needs to be set after construction. (2022-01-02 I think the way it's supposed to work is that when the Feature fetches its Table Spec from the Depot, it can fetch the Database from there too.)
      • The Space object provides access to the parent Table and the current Rowset and Record, where applicable.
    • SpacedIOBank is a SpacerIOBank which expects the Space object to be passed in the constructor
    • A Feature is a SpacerIOBank in which each subclass represents a singleton object. See feature.
  • Each PortRow:
    • keeps a pointer to its containing PortBank object. All access to other PortRow types in the PortBank is via the PortBank.
    • has a list of named PortUnit objects, which are equivalent to fields in a table.
    • Each Native PortRow class defines the classes to use when auto-creating the PortUnits in display and storage PortRows. (These can be overridden.)
  • Each PortUnit contains a value in a particular format.
    • A PortIOUnit is a type of PortUnit which knows how to translate between an internal format and an external format, for device reading/writing (storage, display).

Data

  • There is one PortBank per Table.
    • We don't create additional PortBanks to retain values for rows other than the current one. This is mainly to avoid having to repeatedly execute all of the setup that goes into creating a PortBank and all its contents (Rows, Units).
  • PortRows:
    • The PortRow class has an OnCursorSet() event which should be called whenever the current row changes. (2021-12-07 It's not clear whether this is actually in use.)
    • A PortRow creates its own objects, but by default it needs to know the name and class to use for each one.
      • A descendant class, PortRowInternalDirect, has a default Unit class to use if one is not specified.
    • The PortIORow class adds the ability to render all the Unit values as a single string, based on a template. This is so far only used for Display output (HTML), but could theoretically also be used to render SQL for inserting or updating a record.

Significant functions:

  • PortIORow->MakeIOUnit(string $sName) : caIOUnit
  • PortRowInternalDirect->MakeUnit(string $sName) : cUnit
  • PortRowInternalDirect->FromInputArray(array $arExt) converts an array of input values in the PortRow's format into Native format, and stores them in the Native PortRow
  • IOUnit->InputToNative(?string $sValue) converts a single input value in the PortIOUnit's format into Native format, and stores it in the matching Native PortUnit

Flow

Data flow management is a feature wherein each PortBank keeps track of which of its PortRows is the current data-row source, from which PortUnit objects in other PortRows may populate missing values. This makes it unnecessary for value-retrieval code to be aware of the current state of data-retrieval operations (i.e. where should we look for source data in order to calculate missing values), or to enforce a particular state (e.g. always convert/load all Storage values from the db into Native and then into Display before doing Display-related calculations -- which assumes that we are currently reading data into Storage, and not parsing form input into Display or generating new data into Native).

It works like this (2021-12-07 code to be written):

  • The PortBank keeps track of which PortRow is the current source.
  • Every PortUnit has a function which causes its current value to be translated into Native and stored in the corresponding Native Unit.
    • For Native Units, this function is just stubbed off, since it doesn't need to do anything.
  • The PortRow class has a function which, given a field name, does the following:
    • Checks to see if the field has a PortUnit.
    • If not, it requests one from the Native Unit (MakeUnit(<row type>)).
    • If the local Unit has no value, then the PortRow:
      • requests the local PortUnit's matching source PortUnit from the PortBank.
      • asks the source PortUnit to transload its value into its matching Native PortUnit
      • transloads the Native PortUnit's value into the local PortUnit
    • Returns the local PortUnit (whether found or created).