Skip to content

Data Modelling

Julio Carneiro edited this page Dec 12, 2017 · 5 revisions

The interface between the JS44D Library and 4D's RESTApi Component is done via a Data Modeling functionality. That is done thru the FourDModel class, which implements the base functionality to retrieve, create, update and delete records on 4D side.

On Typescript side, each 4D Table is represented by its Data Model class, which is an extension to the FourDModel class. Those classes can be generated from 4D, as described in this wiki page.

Data Models contain 3 types, blocks, of declarations:

  1. a set of static string constants for each field in the table, which can be used whenever you need a string for the field name
    • example: public static kLocationName:string = 'Location.LocationName';
    • and you can use it for example in: query = Location.kLocationName + ";=;Lisbon";
    • using it that way avoids spelling errors and also gives you code completion
  2. an array of field description objects, which are used for declaring all fields in a table and their attributes
    • example: {name:'RecordID', longname:'Licensee.RecordID', type:'number', required:true, readonly:true, indexed:true, unique:true}
    • or: {name:'LicenseStatus', longname:'Licensee.LicenseStatus', type:'string', list:'Status', length:20}
  3. and a list of getter/setter for each field in the table
    • example:
	get Phone():string {return this.get('Phone');}
	set Phone(v:string) {this.set('Phone',v);}

Field Declarations

The array of Field Description objects that declare each field's metadata can take the following properties:

  • name: the field name; this is a mandatory property and corresponds to the field's getter/setter functions; it must be unique on a DataModel
  • longname: if a database table field, this is the 4D field name in dot long format, as in table.field
  • type: the field type, which can take the following values:
    • text: 4D field type alpha or text
    • number: 4D field is integer, longint or real
    • boolean: a boolean field
    • date: a 4D date type field
    • time: a 4D time field
    • json: field is a 4D Object
    • picture: field is a picture
  • formula: field contents is calculated on 4D side; this property is a 4D expression that returns a String value; it is called by 4D RESTApi when populating the record data
  • subTable: represents a collection of related records; this property is a Data Model class that corresponds to the related record class declaration; joinFK and joinPK properties are required when declaring a subTable field
  • joinFK: the name of the foreign key field in the related many table; in dot long format, table.field
  • joinPK: the name of the main table primary key field to use when retrieving the subordinate records; also in dot format, table.field
  • isrelated: indicates that the field is a related field, coming from a different table
  • readonly: field is read only, can't be modified
  • list: the name of 4D Choice List associated to the field
  • required: field is mandatory, that is, it cannot be empty when sending it to 4D for insert/update
  • length: the field length, used only for Alpha fields

Example Data Model

Here is a complete example of a Data Model class definition:

import { FourDModel } from 'js44D';

export class Location extends FourDModel {

	public static kTABLE:string = 'Location';
	public static kRecordID:string = 'Location.RecordID';
	public static kCreationDate:string = 'Location.CreationDate';
	public static kLastUpdateDate:string = 'Location.LastUpdateDate';
	public static kTimeStamp:string = 'Location.TimeStamp';
	public static kLocationName:string = 'Location.LocationName';
	public static kCity:string = 'Location.City';
	public static kCountry:string = 'Location.Country';
	public static kGeoLocation:string = 'Location.GeoLocation';
	public static kLocale:string = 'Location.Locale';

	tableName:string = 'Location';
	tableNumber:number = 2;
	primaryKey_:string = 'RecordID';
	fields:Array<any> = [
		{name:'RecordID', longname:'Location.RecordID', type:'number', required:true, readonly:true, indexed:true, unique:true},
		{name:'CreationDate', longname:'Location.CreationDate', type:'Date'},
		{name:'LastUpdateDate', longname:'Location.LastUpdateDate', type:'Date'},
		{name:'TimeStamp', longname:'Location.TimeStamp', type:'string', length:255},
		{name:'LocationName', longname:'Location.LocationName', type:'string', length:255, indexed:true},
		{name:'City', longname:'Location.City', type:'string', length:255},
		{name:'Country', longname:'Location.Country', type:'string', length:255},
		{name:'GeoLocation', longname:'Location.GeoLocation', type:'string', length:255},
		{name:'Locale', longname:'Location.Locale', type:'string', length:5}
	];

	get RecordID():number {return this.get('RecordID');}
	set RecordID(v:number) {this.set('RecordID',v);}

	get CreationDate():Date {return this.get('CreationDate');}
	set CreationDate(v:Date) {this.set('CreationDate',new Date(<any>v));}

	get LastUpdateDate():Date {return this.get('LastUpdateDate');}
	set LastUpdateDate(v:Date) {this.set('LastUpdateDate',new Date(<any>v));}

	get TimeStamp():string {return this.get('TimeStamp');}
	set TimeStamp(v:string) {this.set('TimeStamp',v);}

	get LocationName():string {return this.get('LocationName');}
	set LocationName(v:string) {this.set('LocationName',v);}

	get City():string {return this.get('City');}
	set City(v:string) {this.set('City',v);}

	get Country():string {return this.get('Country');}
	set Country(v:string) {this.set('Country',v);}

	get GeoLocation():string {return this.get('GeoLocation');}
	set GeoLocation(v:string) {this.set('GeoLocation',v);}

	get Locale():string {return this.get('Locale');}
	set Locale(v:string) {this.set('Locale',v);}


}