Ferreteria/v0.5/portbank: Difference between revisions

From Woozle Writes Code
Jump to navigation Jump to search
No edit summary
No edit summary
 
(12 intermediate revisions by 2 users not shown)
Line 1: Line 1:
=Data Object Management=
==PortBank system==
v0.5 includes a [[wooz:2021/11/08/data objects refactoring|significant refactoring of how database-related objects are managed]]. The goal was to simplify access to global singleton objects in general, and databases and tabloids in particular, while retaining flexibility (e.g. for different applications to determine the database in which each table is stored).
==Databases==
Creating a database requires a database spec (<code>ferret\data\cDatabaseSpec</code> descendant). ''(yes, I know this bit is hopelessly incomplete)''
==PortBanks==
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).
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===
===Structure===
* A '''PortBank''' is a Table-configured object which contains a set of '''PortRow'''s (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:
* A '''PortBank''' is an object which contains
** '''Native''', which is used only for internal calculations (no I/O)
** a set of '''{{l/ver|PortRow}}''' objects (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 usually 3 types.
** '''Storage''', which converts to and from SQL (or, in theory, any other database-storage format)
** a set of '''{{l/ver|PortDock}}''' objects, typically created on the fly rather than being persistent in memory.
** '''Display''', which converts to and from HTML (or, in theory, any other display markup)
 
* A '''PortRow''' contains a set of '''PortUnit'''s, one for each field in the Table.
A Dock may be thought of as a "column": an array of {{l/ver|PortUnit}}s corresponding to the same field across all available {{l/ver|PortRow}}s.
===Access===
===Connections===
* Each '''PortRow''' keeps a pointer to its containing '''PortBank''' object. All access to other PortRow types in the PortBank is via the PortBank.
* A '''PortBank''' ({{l/ferreteria/code|data/fields/bank/base.php}}) has an array of named PortRow objects.
* A specialized '''PortBank''' class, called a '''SpaceIOBank''', expects a Space object in its constructor, and retains it. This provides access to the parent Table and the current Rowset and Record, where applicable. (Pretty much everything descends from SpaceIOBank rather than PortBank.)
** '''PortIOBank''' pre-defines three particular PortRows: native, storage, and display.
* TODO The Native PortRow has the ability to create I/O Units for known fields by fetching the default I/O Unit class from the corresponding Native Unit.
** '''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 {{l/same|feature}}.
* Each '''PortRow''' ({{l/ferreteria/code|data/fields/row}}):
** 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''' ({{l/ferreteria/code|data/fields/unit}}) 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===
===Data===
* There is one '''PortBank''' per '''Table'''.
* There is one '''PortBank''' per '''Table'''.
Line 25: Line 31:


Significant functions:
Significant functions:
* '''caPortIORow->MakeIOUnit(string $sName) : caIOUnit'''
* '''PortIORow->MakeIOUnit(string $sName) : caIOUnit'''
* '''caPortRowInternalDirect->MakeUnit(string $sName) : cUnit'''
* '''PortRowInternalDirect->MakeUnit(string $sName) : cUnit'''
* '''caPortRowInternalDirect->FromInputArray(array $arExt)''' converts an array of input values in the PortRow's format into Native format, and stores them in the Native PortRow
* '''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
* '''caIOUnit->InputToNative(?string $sValue)''' converts a single input value in the PortIOUnit's format into Native format, and stores it in the matching Native PortUnit
* '''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===
===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).
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)'':
It works like this:
* The '''PortBank''' keeps track of which PortRow is the current source.
* 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.
* Every '''PortUnit''' has a function which causes its current value to be translated into Native and stored in the corresponding Native Unit.
Line 44: Line 50:
*** transloads the Native PortUnit's value into the local PortUnit
*** transloads the Native PortUnit's value into the local PortUnit
** Returns the local PortUnit (whether found or created).
** Returns the local PortUnit (whether found or created).
The IOUnit <code>TransloadInput</code> and <code>TransloadOutput</code> methods base their actions on the current flow state:
* '''<code>TransloadInput()</code>''' tells the I/O Unit to translate its value to Native and store it in the corresponding Native Unit.
* '''<code>TransloadOutput()</code>''' tells the Unit to read the corresponding Native value, translate to its own output format, and store the result locally.
The corresponding IORow functions do the same thing on the Row level, using the Unit Transload methods to handle each Unit's values:
* '''<code>TransloadInput()</code>''' iterates through each of its (local) Units and calls the Unit's <code>TransloadInput()</code>.
* '''<code>TransloadOutput()</code>''' first makes sure it has a local Unit for each Native Unit, creating them where needed, and ''then'' calls <code>TransloadOutput()</code> on each one.
** To ensure that a Unit exists, it calls MakeIOUnit($sName) &ndash; which in turn will ask the Native Row to create a Unit of the appropriate class for the given [field] name and [Row] type (typically storage or display).
==Posts==
* [[2021/11/22/PortBank refactoring]]

Latest revision as of 20:39, 18 April 2023

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 an object which contains
    • a set of PortRow objects (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 usually 3 types.
    • a set of PortDock objects, typically created on the fly rather than being persistent in memory.

A Dock may be thought of as a "column": an array of PortUnits corresponding to the same field across all available PortRows.

Connections

  • A PortBank (data/fields/bank/base.php) 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 (data/fields/row):
    • 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 (data/fields/unit) 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:

  • 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).

The IOUnit TransloadInput and TransloadOutput methods base their actions on the current flow state:

  • TransloadInput() tells the I/O Unit to translate its value to Native and store it in the corresponding Native Unit.
  • TransloadOutput() tells the Unit to read the corresponding Native value, translate to its own output format, and store the result locally.

The corresponding IORow functions do the same thing on the Row level, using the Unit Transload methods to handle each Unit's values:

  • TransloadInput() iterates through each of its (local) Units and calls the Unit's TransloadInput().
  • TransloadOutput() first makes sure it has a local Unit for each Native Unit, creating them where needed, and then calls TransloadOutput() on each one.
    • To ensure that a Unit exists, it calls MakeIOUnit($sName) – which in turn will ask the Native Row to create a Unit of the appropriate class for the given [field] name and [Row] type (typically storage or display).

Posts