UpviseJS Database & Storage Guide
UpviseJS provides the following Database API and Services:
- Simple JavaScript API to declare database tables structures with the Config class
- Standard JavaScript API to perform SQL queries of the database tables with the Query class
- Local database engine & storage of data (mobile+web)
- Master back-end SQL database storage in the Upvise Cloud.
- Automatic optimized & secure delta synchronization of the data between the master cloud database and each client (mobile+Web)
- Automatic database structure upgrade as part of the application deployment
Defining a Table Data Structure
Use the Config.tables array property
Config.tables["mytable"] = "id;name;date DATE;price REAL;status INTEGER"; Config.tables["anothertable"] = "..."
- Each table is defined with a single statement : Config.tables["name"], where name is your table name.
- Each table name must be unique within your application.
- Specify the table structure as a string containing all columns names separated by a semi column ;
- Each table must have an id primary key.
- By default columns have string type. You can specify the type of the column by adding a white space and using the following values: INTEGER, DATE or REAL
How Database synchronization work
- When a record is inserted or updated on one device, the insert/update operation occurs on the local device database. It is also posted in a outbox queue which is sent to the Upvise Cloud servers as soon as there is a network connection.
- When another device sends a sync request, all modified records since the last sync are sent to the client and its local database is updated.
- By default, all insert / update / delete queries are sent instantly if there is a network connection.
- For Select queries, there is a 5 minute local time to live between sync requests. A manual refresh on the device will force a sync request
Reserved Column Names
id and owner column names (string) should be defined for each table. id specifies the primary key and owner allows you to defined record level access rightsPrimary Keys
Because UpviseJS is designed to work offline and later sync data in the cloud, it is essential for primary keys to be unique in a distributed world. So when you do not specify a id primary key, the framework generates a random GUID string, for example "753643D05EB714E7993BF1E2B106F3", which is a random number based on your user token and device id.
Automatic Table Schema Upgrade
UpviseJS supports automatic database table schema upgrades as part as the application upgrade while preserving the existing data based on the following rules:
- To add new table, add a new Config.tables["newtable"] statement
- To add new columns to an existing table, modify the value of the Config.tables["mytable"] statement
- All updated string columns have a default empty string value and all DATE, INTEGER or REAL columns types have a 0 value
- To delete an existing column, simply remove its column name
- You CANNOT rename an existing table name
- You CANNOT rename an existing column or change its type
Config.version = "1"; Config.tables["invoices"] = "id;name;date DATE;price REAL;status INTEGER";
// In this new version // 1. new paid column is added to invocies with a default value of 0 // 2. status column is deleted from invoices table // 3. ew leads table Config.version = "2"; Config.tables["invoices"] = "id;name;date DATE;price REAL;paid DATE"; Config.tables["leads"] = "id;name;source";
Making Select Queries
To return a single record matching its primary key for a given table, use the Query.selectId(table, id) method. It returns a javascript object containing all column values. Record value is accessible as object properties. string columns are mapped to javascript string and INTEGER, REAL and DATE to javascript numbers.
Config.tables["leads"] = "id;name;date DATE" .... var lead = Query.selectId("leads", myid); if (lead != null) { var id = lead.id; var name = lead.name; var date = lead.date; }
To return a list of records matching a where clause, use Query.select(table, columns, where, orderby). The columns parameter is a string containing the list of columns to be returned separated by a semi-column ;. where is standard SQL WHERE clause. The return value is a javascript array of objects, each object representing a record. Only the specified columns are be returned for each object.
Config.tables["leads"] = "id;name;status INTEGER;date DATE" .... // Returns all leads var leads = Query.select("leads", "id;name"); // Return all leads sorted by name var leads = Query.select("leads", "id;name", null, "name"); // Return all leads older than the current month where status=0 and sorted by date var monthStart = Date.month(); var leads = Query.select("leads", "id;name", "date<{monthStart} AND status=0", "date"); for (var i = 0; i < leads.length; i++) { var lead = leads[i]; List.addItem(lead.name, "view"); }
Inserting Data
Use the Query.insert(table, values) method. values is a javascript object containing the values for the column to insert.
It returns the primary key of the newly inserted records.Config.tables["leads"] = "id;name;date DATE" ... var values = new Object(); values.name = "John"; values.date = Date.now(); var id = Query.insert("leads", values); // or a shorter version in one line using JSON notation var id = Query.insert("leads", {name:"John", date:Date.now()}); // Insert an empty record var id = Query.insert("leads", {});
Updating Data
To update one field of one record, use Query.updateId(table, recordid, columnName, value)
var id="someid"; Query.updateId('leads', id, 'name', "John");
To update multiple columns for multiple records, use Query.update(table, values, where)
var groupid = "some id"; Query.update("leads", {name:"Hello", status:0}, "groupid={groupid}");
Working with Dates
To store date in a table use the DATE type when defining the column in the Config.tables property.
Config.tables["mytable"] = "id;name;startdate DATE;column2"
date values are stored internaly in the database in epoch format (number of milliseconds since Jan 1st 1970 UTC.). When you query a record containing a date column, the value in javacript is a number in Epoch format. You can then manipulate it by creating a Date object in Javascript using the new Date(millisecond) constructor.
.... Config.tables["leads"] = "id;name;date DATE" .... var lead = Query.select("leads", myid); if (lead != null) { var milisec = lead.date; var date = new Date(milisec); // now use date as a regular Javascript data object App.alert(date.toLocaleString()); }
In addition to using the standard javascript Date class to manipulate dates, UpviseJS adds some convience static methods to the Date class to easily format and work with dates.
Config.tables["leads"] = "id;name;date DATE" .... var lead = Query.select("leads", myid); // Compute the time duration since the lead was created var nbMinutes = (Date.now() - lead.date)/Date.MINUTE; App.alert("This lead was created" + Format.duration(nbMinutes) + "ago");
Useful Convenience functions
you can use Query.count(table, where) to return the number of record as a number
.... var openCount = Query.count("Tasks.tasks", "status=0"); var completedCount = Query.count("Tasks.tasks", "status=1"); List.addItem("Open Tasks", "viewOpenTasks()", {count : openCount}); List.addItem("Completed Tasks", "viewCompletedTasks()", {count : completedCount}); List.show();
Managing Record Access rights
UpviseJS defines 2 levels of users : standard users and managers/admin.
Access other application tables
You can access all other tables in all other application by prefixing the table name by the applicationid. For example, to select the all records from the companies table of the contacts app, perform a query on the table named "contacts.companies"
var companies = Query.select("contacts.companies", "id;name;email", null, "name"); var openTasks = Query.select("tasks.tasks", "id;name;duedate;owner", "status=1", "duedate DESC");
System Tables
Upvise has a set a predefied system tables, prefixed by system keyword:
- system.files: contains information about all files in your account. Columns are are: id;name;linkedtable;linkedrecid;size INTEGER;_date DATE;mime
- system.users : contains all users in your account: Columns are : id;name;email