Skip to content

Second Tutorial Part 5: Basic APIs

Laurent Hasson edited this page Dec 3, 2019 · 2 revisions
Previous Main Next
<-- Part 4 Main Part 6 -->

At the most basic level, you want to be able to do a simple CRUD cycle, i.e., Create/Read/Update/Delete. In a Factory/Data architecture, you can expect to use the Factory to:

  • Create a new object instance
  • Lookup one or more object instances
  • Allow object instances (i.e., records) to be updated.

The way Tilda generates its APIs is completely defined by the Tilda JSON definition:

  • In order to create a new objects, you ave to make sure that at least ALL not-null fields are set.
  • In order to lookup an object, you generally have to have a primary key, or any other natural identity (i.e., a unique index).
  • In order to lookup a list of objects, you generally have to have one or more fields, generally mapping to a non-unique index.

If we take the User entity defined in this tutorial, it's defined as follows:

{ "name":"User"
 ,"description":"Users"
 ,"columns":[
     { "name":"id"   , "type":"STRING", "size": 40, "nullable":false, "description":"The user's id"    }
    ,{ "name":"email", "type":"STRING", "size":255, "nullable":false, "description":"The user's email" }
    ,{ "name":"name" , "type":"STRING", "size":255, "nullable":true , "description":"The user's full name" }
   ]
 ,"primary": { "autogen": true, "keyBatch": 500 }
 ,"indices": [ 
     { "name":"Id"   , "columns": ["id"   ] }
    ,{ "name":"Email", "columns": ["email"] }
    ,{ "name":"All"                        , "orderBy": ["lastUpdated desc"]}
   ]
}

We have defined all those things:

  • A set of not-null fields (id and email)
  • A primary Key (auto-generated, and thus, refnum)
  • Two natural identities (unique indices, i.e., indices without an orderBy definition)
    • The unique Index Id covering the field id
    • The unique Index Email covering the field email
  • A non-unique index
    • The index All with only an orderBy over lastUpdated

Every one of those definitions in effect will generate APIs in the factory class, respectively:

static public User_Data create(String id, String email) throws Exception;
static public User_Data lookupByPrimaryKey(long refnum) throws Exception;
static public User_Data lookupById(String id) throws Exception;
static public User_Data lookupByEmail(String email) throws Exception;
static public ListResults<User_Data> lookupWhereAll(Connection C, int Start, int Size) throws Exception;

At the core of Tilda in Java, we establish compile-time artifacts that capture the semantics of the entity at many levels. This helps a lot when doing rapid iterative development (the 'I' in Tilda) where the semantics of entities will invariably change. With compile-time artifacts, a change in not-null fields will change the create() API and as such, it will be flagged anywhere it's used throughout your code. Other frameworks using run-time code generation are unable to do this typically. Similarly, removing or changing a natural identity (a unique index constraint), or changing privileged access methods (backed by indices in the database) will change Factory-level APIs and will immediately be flagged by the compiler across a project.

🎈 NOTE: In our experience, this is fairly radical as it encourages "breaking the schema" without fear of actually breaking the application at runtime accidentally. Complex migrations already handled automatically by the Migrate utility are also supported natively of sorts through the Java compiler.

🎈 NOTE: If you look closely, there is a material difference between the lookupByXxx methods that return a single Object, and the lookupWhereXxx methods that return a list: The lookupWhereXxx methods take in a Connection object. This is a pattern throughout the Tilda API: passing a Connection object to an API implies that API will access the database. We'll see below how this manifests itself in practice, but:

  • The lookupWhereXxx methods access the data store by executing a select query and returning 0 or more records that have been fully read from the data store.
  • The create and lookupByXxx methods initialize an in-memory object that can then be further manipulated or modified until it is actually written to or read from the data store (using the read(Connection C) and write(Connection C) APIs in the Data object.

As for the Data class, you will find all the getters and setters you might expect, as well as the read(Connection C) and write(Connection C) methods to read/write the record from/to the data store. The read method will typically called after a lookupBy whereas the write method will be called after a create or after an object's state has been modified via setters.

🎈 NOTE: There are settings when defining an entity in the Tilda JSON definition file that will affect how those methods are generated. For example:

  • invariant fields will have a setter that will fail if it's used at any time after an object has been written to the database.
  • A nullable field will have an isXxxNull() method whereas a not-null field won't.
  • If the entity's lc (life-cycle) is defined as READ_ONLY, then the Write method and setters won't be generated.
  • If the entity's lc is WORM (Write Once Read Many), setters and write will fail after the first time an object was initially created (i.e., inserts and selects only, but no update).
Previous Main Next
<-- Part 4 Main Part 6 -->
Clone this wiki locally