Modeling

All data Model classes extend from the com.psddev.dari.db.Record class in the Dari framework. All fields in a subclass of Record are persisted as a database record when the object is saved. In addition, Dari creates and saves an object type definition that contains the metadata of the Model.

Creating a Model

The following is a simple data Model of an article. It extends the Dari Record class and includes getter and setter methods for the headline, body, and leadImage fields. All fields in a Record object are persisted to the underlying database, with the exception of fields marked with the Java transient keyword.

package com.psddev.dari.test;
import com.psddev.dari.db.*;

public class Article extends Record {

   @Required // Annotation specifies that value is required for headline field
   @Indexed  // Annotation specifies that field is to be indexed
   private String headline;

   @Indexed
   private String body;

   private Image leadImage;

   public String getHeadline() {
      return headline;
   }
   public void setHeadline(String headline) {
      this.headline = headline;
   }

   public String getBody() {
      return body;
   }
   public void setBody(String body) {
      this.body = body;
  }

  public Image getLeadImage() {
      return leadImage;
   }
   public void setLeadImage(Image leadImage) {
      this.leadImage = leadImage;
   }
}

Dari detects when a Model class is saved, automatically compiling and reloading the class in your Brightspot runtime environment.

Object Type Definitions

For each Model created, Dari persists an object type definition, represented by an ObjectType class. An ObjectType defines the structure and the metadata of the Model. This includes the core Model class, such as Article in the above example, and any modifications, augmentations, or substitutions to the core Model class. When a Model is updated, the object type definition is updated.

The ObjectType#getInstance method returns an object type definition as a JSON object. For example, using the Code Editor, you can return the object type definition for the Article Model class.

return ObjectType.getInstance(psddev.dari.test.Article.class);

The returned object is a comprehensive metadata listing, which includes attributes about the Model class, its fields, and its relationships to other classes. For example, the following JSON fragment for the Article Model shows information about two of the Model fields, headline and author. The headline field is declared in the core Article class. However, the author field is declared in ArticleModification (not shown), a modification that extends the Article class with a new field.

...
"fields" : [ {
 ...
 "isRequired" : true,
 "java.field" : "headline",
 "java.declaringClass" : "com.psddev.dari.test.Article",
 ...
},
{
 ...
 "isRequired" : false,
 "java.field" : "author",
 "java.declaringClass" : "com.psddev.dari.test.ArticleModification",
 ...
} ],

The next JSON fragment shows that there are indexes for two fields in the Article Model, headline and body. The indexes are a result of the @Indexed annotations applied to these fields in the Article class.

"indexes" : [ {
 "field" : "headline",
 "fields" : [ "headline" ],
 "type" : "text",
 "isUnique" : false,
 "caseSensitive" : false,
 "visibility" : false,
 "java.declaringClass" : "com.psddev.dari.test.Article"
 },
 {
 "field" : "body",
 "fields" : [ "body" ],
 "type" : "text",
 "isUnique" : false,
 "caseSensitive" : false,
 "visibility" : false,
 "java.declaringClass" : "com.psddev.dari.test.Article"
 } ],

The object type definition also specifies other classes that contribute to the Article Model. In addition to the modification class, an augmentation, ArticleAugmentation, is applied to the Article core class.

 "java.objectClass" : "com.psddev.dari.test.Article",
 "java.modificationClasses" : [ "com.psddev.dari.test.Article", "com.psddev.dari.test.ArticleModification" ],
 "java.superClasses" : [ "com.psddev.dari.test.Article", "com.psddev.dari.db.Record", "java.lang.Object" ],
 "java.assignableClasses" : [ "com.psddev.dari.test.Article", "com.psddev.dari.db.Record", "java.beans.BeanInfo", "java.lang.Cloneable", "java.lang.Comparable", "com.psddev.dari.util.HtmlObject", "com.psddev.dari.db.Recordable", "java.lang.Object" ],
 "augmentationClassNamesByTargetClassName" : {
 "com.psddev.dari.test.Downloadable" : [ "com.psddev.dari.test.ArticleAugmentation" ]
 },

ObjectType also contains methods for getting specific metadata items, such as fields, methods, and indexes.

Object State

A Record object is linked to state information that is also persisted to the database. A Record object’s state is represented by a State object that is retrievable from Record. Changes to either the Record or to the State object are copied to its associated object. Record and State include the same save methods, as Record delegates to State to execute those methods.

You can get a Record object’s state in one of the following ways:

State state = object.getState();
// OR
State.getInstance(object);

State provides numerous methods that return comprehensive information about a Record object. For example, there are methods to return an object’s metadata and instance data. The getStatus method returns com.psddev.dari.db.StateStatus, indicating if the object is deleted, reference-only, or saved. For Image or Video objects to which the @Recordable.PreviewField annotation is applied, the getPreview method returns the storage item that Brightspot uses to preview the object.

State includes methods to describe an object’s visibility based on visibility-indexed fields. isVisible indicates if an object is hidden from queries for published objects. For hidden objects that implement visibility labels, getVisibilityLabel returns the object’s current non-published state.

A State object reflects the state of the original Record object and any other objects that might subsequently be linked to the original object. Linked objects are modifications and augmentations. State provides methods to work with linked objects. The isInstantiableTo method indicates if an original object is linked to modifications or augmentations. If it is, the as method converts the state of an original object to an instance of a modification or augmentation. The linkObject and unLinkObject methods link and unlink related objects to the state of the Record object.

Model Constructors

All subclasses of Record must have a nullary constructor. If you wish to have a constructor with arguments, you must also provide a nullary constructor.

Additionally, Record provides an afterCreate API which is called by the nullary constructor of the Record class. It does nothing by default, but you can override the method to perform operations which need to occur when objects are created.

Be advised that the nullary constructor (and therefore afterCreate) will be called every time the object is instantiated out of the database. If you want code to run only once, when an object is created for the first time, use the following pattern in a nullary constructor or the afterCreate method:

if (getState().isNew()) {
   // one-time operations here
}