Resource model declaration
Contents
Model declaration overview
Presently, each model maps to a single database table and the following list provides other basic information:
- Each resource model is declared in its own JSON definition file in
{app_root}/app/models. - A resource model MUST have a Fields declaration. Each field represents a database field.
- A resource model defines the data shape of a default collection. Each declared resource model automatically gets a default collection on which to perform LCRUD operations.
- Named collections are custom collections that can be optionally declared in the model declaration.
- ZRM provides database generation functionality, as well as programmatic and HTTP REST access APIs.
A resource model example
This example model defines a persons resource model that has first_name and
birth_date fields:
{
"fields" : {
"first_name": {"type": "string"},
"birth_date": {"type": "date"}
}
}
The first_name and birth_date fields are fields of the resource model. Each
field is assigned metadata that modify its behavior at runtime (for example,
validation rules) and field attribute maps to a database column.
The previous persons model would create a database table as shown in the following example:
CREATE TABLE persons (
first_name VARCHAR(30) NOT NULL,
birth_date DATE,
id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
START WITH 100, INCREMENT BY 1) NOT NULL,
updated TIMESTAMP NOT NULL
)
Technical notes:
- The name of the table,
persons, is automatically derived from file name{app_root}/app/models/persons.jsonbut can be overridden. See the following table customization section. - An
idfield is added automatically. Keys are generated by default and begin at 100, incrementing by 1. - An
updatedfield is added automatically. - The CREATE TABLE SQL in this example is formatted using Derby syntax.
Currently DB2, Derby, MySQL, and Oracle are supported and syntax will be
selected based on the configured database in
zero.config.
Fields
The most important part of a resource model (and the only required part) is the list of fields it declares. Fields are specified by a data structure assigned to fields as shown in the previous example.
Field name restrictions
Three restrictions exist on resource model field names:
- A field name cannot be a Java, Groovy, or SQL reserved word.
- At present, a field name cannot contain more than one underscore in a row, due to the way the query lookup syntax works.
Field types
Each field in your resource model must have a specified type string. This string maps to a field class. The resource model uses the field class types to determine the following things:
- The database column type (for example,
INTEGER,VARCHAR). - The minimal validation requirements.
The supported data types for a resource declaration are:
string
Field for small- to large-sized strings and other character-based values. The
string field can optionally take a format to modify it's validating
behavior.
| Parameter | Required | Description |
|---|---|---|
| max_length | No | The maximum character length is by default 50.
However, string can take max_length as extra
parameter which specifies the maximum character
length of the field. The max_length is enforced at
the database level and in the Resource Model
validation. |
| format | No | The format parameter modifies the validating
behavior of string types. Valid values are:
large, email, phone, and region. |
The large format optimizes for very large amounts of character-based values.
The email and phone formats use a regular expression during validation.
Fields with phone specified for the format must validate against
(999) 999-9999 style of phone numbers. The region format is a 2
character abbreviation for a U.S. state.
boolean
A true/false field. Valid values for true are: true, 't', 'true', 'True', '1',
or 1. Valid values for false are false, 'f', 'false', 'False', '0', 0.
date
A field representing a date (day, month, and year). Valid values take the form
of yyyy-MM-dd.
| Parameter | Required | Description |
|---|---|---|
| auto_create | No |
false is default. If set to true, when the
member resource is first created ZRM will
automatically set the value of this field to the
current date. This parameter is mutually exclusive
with auto_update. |
| auto_update | No |
false is default. If set to true, when the
member resource is first created and each
subsequent update ZRM will automatically set the
value of this field to the current date. This
parameter is mutually exclusive with auto_update. |
date-time
A field representing an instance or timestamp (second, minute, hour, day, month,
and year). Valid values take the form of any of yyyy-MM-dd,
yyyy-MM-dd HH:mm, or yyyy-MM-dd HH:mm:ss.
time
A field representing a time independent of a date (second, minute, and hour).
Valid values take the form of HH:mm and HH:mm:ss.
decimal
A decimal number represented in Java by a java.math.BigDecimal.
| Parameter | Required | Description |
|---|---|---|
| max_digits | Yes | The maximum number of digits allowed in the number. |
| decimal_places | Yes | The number of decimal places to store with the number (the decimal number's scale). |
float
A floating-point number represented in Java by a float.
integer
An integer.
Using fields
A resource declaration using the types described in the previous sections looks like the following example:
{
"fields" : {
"name": {"type": "string", "max_length":50},
"birth_date": {"type": "date"},
"age": {"type": "integer"},
"salary": {"type": "decimal", "max_digits": 9, "decimal_places": 2},
"takes_lunch_at": {"type": "time"},
"favorite_moment": {"type": "date-time"},
"favorite_number": {"type": "float"},
"biography": {"type": "string", "format": "large"},
"address ":{"type ":"string", "max_length": 60},
"city": {"type": "string", "max_length": 45},
"state": {"type": "string", "format":"region"},
"phone": {"type": "string", "format":"phone"},
"email": {"type ":"string", "format":"email"}
}
}
Field options
The following optional arguments are available to all field types:
required
Default is false, which means all fields by default are not required to have
a value. If true, the field is required. This constraint is enforced during:
-
create()andupdate()on a Collection -
validate()on a Member instance - POST and PUT on the HTTP resource
null.
Example:
{
"fields" : {
"first_name": {"type": "string", "max_length": 25},
"last_name": {"type": "string", "max_length": 35, "required": true},
"email": {"type": "string", "format": "email", "required": false}
}
}
In this example, first_name and email are not required whereas
last_name is required.
label
The label parameter is a "friendly" name for the field.
Example:
"first_name": {"type":"string", "label": "Your first name"}
description
The description parameter allows the developer to provide detailed
information about the field. Not only is this useful for documentation purposes,
but it can also be used in user interfaces to provide additional help to assist
application users.
Example:
"first_name": {"type":"string", "description": "The first name is your given name"}
default_value
When the default_value parameter is set it is used when the create() method
is called and no value has been set for the field. It is not used when a resource
instance is updated.
Example:
"first_name": {"type":"string", "default_value": "Bob"}
default_value can
options
A list of values that are valid for the field.
Named collections
Resources are accessed using collection-like constructs. A filter can be applied to such collection to create a new collection that is a subset of the original. A filter condition can be applied either programmatically or using HTTP at runtime. Filters can also be specified in the model declaration by defining a named collection:
{
"fields" : {
"first_name": {"type": "string", "max_length": 30},
"birth_date": {"type": "date"},
"is_child": {"type": "boolean"}
},
"collections" : {
"children": {"memberFilters": {"is_child": true}},
"christmas_birthdays": {"memberFilters": {"birth_date__day": "25", "birth_date__month": "12"}}
}
}
Database generation
ZRM can generate a database table for each resource using a top down mapping scheme. By default, the name of the model file maps to the name of the database table and the field names map to column names. Each table also has a special field, id, that is the unique identifier for that resource.
Synchronizing the database
In order to create required database artifacts, you must first run the
model sync task from the command line. This task will read the model
declarations, determine what required database tables are missing and create
them for you. However, if the table exists, then ZRM leaves it intact. If you
modify a model file and want the table be recreated, you must run
model reset. This command drops the database and calls model sync.
Following is an example of executing the model sync task from the command
line:
zero model sync
firstname and then later, after data has been saved into the table, you
change the field name to fname, there is no way to determine that
firstname is fname. Automation would drop the firstname column
(along with all its data) and a fname column is created.
Because of this limitation, any changes you make to your ZRM declaration will
need to manually changed. To do this, you can use the runsql command line
task from the zero.data module. The following example illustrates this:
zero runsql alter_table.sql
The zero.data documentation has more information on the runsql task.
Loading initial data fixtures
In addition to creating the database tables at application initialization, ZRM
searches for initial_data.json files across all dependencies in
/app/models/fixtures directories and loads its data into the database.
Once the table has been initialized with the data in initial_data.json the data is not loaded until the table is manually dropped.
The following initial_data.json example assumes the following model
declaration at /app/models/persons.json:
{
"fields": {
"first_name":{"type": "string"},
"birth_date":{"type": "date"},
"is_child":{"type": "boolean"}
}
}
The following example of an initial_data.json file would load two instances
of the above model into the backing database table:
[
{
"type": "persons",
"fields": {
"id" : "1",
"first_name" : "Tom",
"birth_date" : "2005-12-12",
"is_child" : "0"
}
},
{
"type": "persons",
"fields": {
"id" : "2",
"first_name" : "Bill",
"birth_date" : "2001-03-1",
"is_child" : "1"
}
}
]
The initial_data.json file can contain populate multiple resource model types
from the same file. Just ensure that the appropriate type value is specified.
initial_data.json file, it is
sanitized. This means it is validated and in process converted to a native
Java type. It is then stored in the backing database. Some fields are flexible
in what data it can handle. For instance, the boolean type can take, not only
actual boolean values, but also 0, '0', 'false' for false values and 1, '1',
'true' for true values. If initial_data.json has any of these alternate
values, it will be saved as boolean and subsequent access will reflect its
sanitized conversion.
Table customization
You can customize the table name against which ZRM generates and maps your
resource declaration. For example, if your application sets the resource type
name to be articles but needs the database table name to be
magazine_editorials, then you can specify the following in your resource model
file:
{
"db_table": "magazine_editorials",
"fields": {
"title":{"type": "string"},
"publish_date":{"type": "date"},
"body":{"type": "string", "format": "large"}
}
}