strongloop / loopback-example-offline-sync

Offline sync, change tracking, and replication.
http://loopback.io/doc/en/lb2/Synchronization.html
Other
286 stars 110 forks source link

Type of property "id" changes from "string" to "number" #63

Closed Oliver-G closed 9 years ago

Oliver-G commented 9 years ago

I'm using LoopBack as Backend with MySQL as a datastore. Everything works as expected even with relation between objects and ACL-checks.

Now I want to create a app with offline-sync functionality.

I defined a Person model on server side according to the docs (http://docs.strongloop.com/display/public/LB/Synchronization) like this:

{
  "name": "Person", 
  "base": "PersistedModel", 
  "strict": "validate", 
  "trackChanges": true, 
  "persistUndefinedAsNull": true,
  "mixins": { ... },
  "properties": {
    "id": {
      "id": true,
      "type": "string",
      "defaultFn": "guid"
    },
    "firstname": {
      "type": "string",
      "required": false
    },
    ...
  },
  "validations": [],
  "relations": {
    ...
  },
  "acls": [
    ...
  ],
  "methods": []
}

In database I changed the id column type to varchar(255) in Person table and added the tables "Person-change" and "checkpoint". About this step I didn't found much documentation. Only this: https://groups.google.com/d/msg/loopbackjs/LfFtXvjK-VA/6aYLqaayEAwJ

CREATE TABLE IF NOT EXISTS `Person-change` (
 `id` varchar(255) NOT NULL,
 `rev` varchar(512) DEFAULT NULL,
 `prev` varchar(512) DEFAULT NULL,
 `checkpoint` int(11) DEFAULT NULL,
 `modelName` varchar(512) DEFAULT NULL,
 `modelId` varchar(512) DEFAULT NULL,
 PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `checkpoint` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `seq` int(11) DEFAULT NULL,
 `time` datetime DEFAULT NULL,
 `sourceId` varchtyar(512) DEFAULT NULL,
 PRIMARY KEY (`id`)
);

During the start process of the server I get this message:

loopback deprecated The model Person is tracking changes, 
which requries a string id with GUID/UUID default value. at events.js:180:16

I found the same error related with the grunt build script in issue #58.

I tried to dive in code but I don't feel that I come closer to a solution. In "Registry.createModel" and "ModelBuilder.define" the type of property id is "string". Later in "DataSource.setupDataAccess" and "PersistedModel.enableChangeTracking" the type of property id is "Function: Number".

Because of the changed id type the call of Person.create({ ... data without id... }, function(err, result) {}); leads to a mysql error (Column 'id' cannot be null).

{"code":"ER_BAD_NULL_ERROR","errno":1048,"sqlState":"23000","index":0}

At first I thought it is may a race conditions problem because the generation of the uuid. In "result" of the callback function is not null and the id is present (as uuid) but there are no data stored in mysql.

I found a different way of property setup here (https://github.com/strongloop/loopback-example-offline-sync/blob/master/common/models/todo.json - with some missing options) but this produces the same result.

How do I set up the properties right? In which cases set properties will be ignored and overwritten by default id type of datastore?

Thanks in Advance.

Oliver-G commented 9 years ago

Relations are the problem. In case I remove the relation and store the data in fields manually then loopback deprecated message and sql error disappear. uuid generation for a new Person works fine.

In my scenario I use a relation between a user (hasOne) and a person (belongsTo). User model don't uses trackChanges. Creating and modify user data is not needed offline.

Person model is set to trackChanges: true. Person data should manipulable offline.

To lose relation because is not an option.

Do I have to pay attention on other settings if I want to use relation in sync?

Oliver-G commented 9 years ago

Using "trackChanges"-models for ALL models with relations solved the problem.