1.1.2 • Published 4 years ago

item-item v1.1.2

Weekly downloads
2
License
UNLICENSED
Repository
github
Last release
4 years ago

Item

Table of Contents

Basic Types

Oh items. Where to begin. How about basic schema first. Any item is basically a bag of values. Let's start with basic types:

IItem

Property NameTypeDescription
idstringa UUID (even used for inline items)
itemTypestringa string that describes the set of fields and validations for this item, currently an enum but likely to become a simple string soon
fieldValuesRecord<string, IFieldValue[] | undefined>a bag of values, all values are stored as arrays with their field determining whether they can have more than one value in practice.

IFieldValue

Property NameTypeDescription
rawany serializablebasically any value that can be converted to a string, think json and primitives, the value allowed is determined by the field in terms of data type along with logical validations
meta?jsonarbitrary values that inform the raw value used in practice to house display values for a dynamically fetched list option

IItemType

(a rarely used object currently because we rarely do item type level validations but conceptually important)

Note: the type is currently the most important part of itemType and is used to narrow the set of IFields that apply to a given item (currently codified in BASE_FIELDS_BY_ITEM_TYPE).

Property NameTypeDescription
typestringa string used to identify the item type
sortBy?string[]fieldIds to sort the items of this type by in order
validations?IItemTypeValidations(needs refactoring) an object describing validations that must apply to the entire set of items of this type

FieldType

Property NameDescription
TEXTbasically strings, rendering this field in UI results in a text editor, and the raw field value will be stored as and assumed to be on read, a string
NUMBERraw values will be numbers, when attempting to edit non numeric characters are ignored or considered invalid
IDthe UUID of another data object in the system, generally assumed to be an item id and the fieldProperty itemType is expected to be supplied on fields of this type to specify which item type it refers to
BOOLEANraw values will be either true or false, editor is generally a checkbox
DATEraw values will be a string of format MM/DD/YYYY. Identifies a particular day but not a particular time, editor is a date picker, formats using the field format property or by default to MM/DD/YYYY
DATE_RANGEhas two field values in which the raw value is a date string. represents a range of dates, editor is a range date picker, formats to two dates separated by hyphen
DATE_TIMEraw values will be an ISO string, identifies a particular millisecond in time, editor is a date picker but could at some point include a time component, formats using the field format property or by default to MM/DD/YYYY
LISTa field whose raw value is the id component and meta data contains {display : 'list option display value'} of an IFieldListOption object, basically a select menu where the set of options is known (at some point even if that is fetched at run time)
ITEM_LINKan more explicit version of ID, probably unnecessary, carries the same behavior
ITEMinline items. raw values of this type are themselves items, the editor by default shows a list of all the items stored on the fieldvalue, allowing the user to add and remove new items of the type and edit each field on that item. This field is nearly always the best way to represent non-item data that has nested structures. For example, {application : {applicant : {firstName : 'blah'}}} is represented as an APPLICATION item with an APPLICANT item field on it
LINKED_FIELDa field whose behavior and value is defined by another field. Used to pull values from one item to another subject to a certain set of conditions. See below for more info.
JSONraw values are any JSON, the structure of which isn't known. Generally a bad idea to use. Since the structure of the data isn't known, it is opaque to the item machinery. Almost always it is better to represent these structures with inline items so the schema is known and configurable.

IField

(arguably the most important type in items)

Property NameTypeDescription
idstringan id unique to our system but generally not a uuid for readability
namestringthe displayable description of this field
typeFieldTypean enum describing the data type allowed by this field. Text, Number, etc. (see below for full list)
format?stringstring describing how a date or number should be formated, uses moment and numeral formats respectively
parseCalc?stringa numeric formula string with access to a special "parsed" value which always refers to the raw field value, the parseCalc is run after parsing a string into a number, so for example parseCalc : 'parsed * 12' will result in '10' => 10 => 120 as the raw
displayCalc?stringa numeric formula string with access to a special "parsed" value which always refers to the raw field value, the displayCalc is run on the raw before formatting, so for example displayCalc : 'parsed / 12' will result in 120 => 10 => '10' as the formatted value, generally displayCalc and parseCalc should be complementary functions that reverse each other for consistency
displayReplacePatterns?IReplacePattern[]an array of RegExp replace objects to run on TEXT values when formatting for raw
parseReplacePatterns?IReplacePattern[]an array of RegExp replace objects to run on TEXT values when parsing to a raw
isMultiValue?booleanwhen set to true the field is allowed to have more than one value
listOptions?IFieldListOption[]for fields that want a select menu and/or a discrete set of values, defines the set of options available
linkedFieldConfig?ILinkedFieldConfigan object that describes how this linked field gets its value from another field on another item. see description and examples below
validations?FieldValidation[]an array of validation objects that must be satisified for the fieldvalue to be valid. see examples and descriptions below
itemType?string // for itemKey field typesan item type speciyfing what kind of items the field refers to when it is type ITEM, ID, or ITEM_LINK
editorType?EditorTypeoverride for list and boolean fields only for now, allows a different editor then the default to be specified
editorOptions?IEditorOptionsoptions configuring how the editor for this field should operate differently than it's default
isUIOnly?booleansetting this to true indicates that the field is used temporarily in UI only and the value will not be persisted to the item nor retrieved from the backend

Concept Overview

Conceptually, IItemType and IField are analagous to classes in code, and IItem and IFieldValue[] are respectively analagous to instances of the class. The difference, and really the entire point of items, is that not only is the content data stored serializably but the descriptions of how that data is used, collected, what values are alowed, etc are also stored in a non-code form. That is to say that rather than a piece of code (a class for example) codifying the behavior of how data is treated, a serializable object (an IField object for example) describes that behavior and a single core engine is the only piece of code used to enforce the behavior described by that data.

The benefits of this paradigm shift are a couple:

  • Configuration: Changes to the behavior of a given piece of data are made by changing other data rather than code. This allows a user (or us) for example to configure their own behavior without making code changes. Rather than someone making changes to code to ensure that a field only allows numbers greater than 0, someone only needs to add a fieldValidation object, specifying that behavior, to the data of the field controlling that value. Because all behavior is data and not code, it can also be stored in the DB allowing per org or user behaviors that would otherwise require frightening switch statement type code.
  • DRY: It stringently standardizes the types of behaviors allowed and how all data is treated. This allows us to render for example a grid of values that are Orgs in one case and Applications in another without a single code change. Because of this centralization of code, it dramatically DRY's out the code, leading to us only implementing one single select menu or a single request call, for example, each configured to modify its behavior rather than repreating ourselves in slightly varying ways.
  • Validation: Because all behaviors are codified clearly in a standard format and not simply implied by code, it can make it easier to reason about what is possible within the system. That means in theory we can look at a single config describing a form step for example, and know (and write code against) whether the values collected can satisfy the contract of a given api call, etc.

Examples

(If you don't see something here check out item/src/field-processor/index.test.ts because every unique field configuration requires at least one example test case and that can help you understand how they are being used)

An Item:

const applicantItem = {
  // must be universally unique even for inline items
  id : 'a_UUID', 
  
  // a string (currently an enum) that specifies which set of Fields and which validations apply to this item
  itemType : 'APPLICANT',
  
   // a bag of fieldId (string )to IFieldValue[] | undefined, basically all the actual data
  fieldValues : {
  
    // field id is also unique within our system (but not UUID for readability, mostly enforced with code today)
    'applicant-phone' : [{raw : '3039690876'}] 
  }
}

A Field:

 export const APPLICANT_PHONE: IField = {
  id: 'applicant-phone', // unique id
  name: 'Phone', // the user readable name of the field, generally displayed in ui
  type: FieldTypeConst.TEXT, // the data type allowed by the field
};

The field id is used as the key in the fieldValues object of the item. The type will imply how values are collected and processed. For example, text will result in an being rendered when editing. It will also determine how the field is formatted and parsed among other things.

Examples TODO:

String field with replace patterns

Numeric field with parse display calcs

List Option field whose type is not Text

Random Stuff that should organizaed but dont want to forget

  • Currently, there is a meaningful difference between a fieldValue being undefined versus []. In both cases the raw value is essentially undefined, but right now a defined [] means that fieldValue has been loaded and is known to be undefined. A true undefined is used to indicate that the fieldValue hasn't even come back from the DB or Api so its value is more akin to being unknown. This allows us to render a spinner on a particular field until its value is loaded, even when other fieldValues have been loaded.

  • Validations live at three levels:

    • itemtype level - validations that apply to the entire set of items of a given (aka, only one item of this type can have a FEE_TYPE of DOCUMENTATION)
    • item level (conceptually only, not currently implemented) - validations that apply to the entire set of fieldValues for a single item (aka if phone number is supplied email cannot be supplied or something like that)
    • field level - validations applying to just a particular field (number must be greater than 0, or string cannot be longer than 10, etc)