Capture differential / delta payload in Knockout view model - mvvm

I am using a KO viewmodel which interfaces a REST end-point. The REST end-point serves me plain JSON data like:
var data = {
"firstName": "John",
"lastName": "Doe
};
Data is then transformed to a viewModel using ko.mapping as follows:
var viewModel = ko.mapping.fromJS(data);
On the view, it is possible only a part of the data will be modified, say firstName. In that case, I wish to construct a payload containing:
{
"firstName": "Jane"
}
which I can then send to my server to perform an update only on those fields.
Is there any framework or utility (possibly in KO) which already does this?

Related

complex query fetching latest inserted data from mongodb to compare with indexed data in array

I'm trying to construct middleware-code in d-lang that reads an array of struct DATA from a connected POSIX named pipe and identify changes by comparing with existing data, if changes occurred add the changed struct data into db.
Struct is constructed like this and all variables are likely to be changed
struct DATA
{
char[20] name;
int_16 sect;
int_16 ptyp;
ulong mode;
ulong cpmap;
}
DATA [NO_OF_STRUCTS*sizeof(struct DATA)] flowDATA;
Input from pipe works but when it comes to fetch individual latest version from the database, I'm outside of my knowledge
I.e. my problem is how to construct the query (code not for terminal) to retrieve the latest inserted data for each array indexposition from the db to compare and if changed, write/insert into db and also inform och what changed back via the pipe.
Feels like I need to add extra fields like an index_no to filter on.
The query would be like this in below pseudo code (can't get this code correct in my d-code):
db.lab.aggregate([{$match {dateadded{$in:["dateadded"]}}.{ $group:{_id:"$name"}}}]);
Select DATA from lab Where LATEST(dateAdded) and index_no == arrayIndex
Any ideas?
My testcode init the db like this
db.lab.insert([
{"name": "News 1",
"sektion":2,
"ptyp":1,
"mode":1024,
"cpmap":886,
dateAdded: new Date()
},{
"name": "Base 2",
"sektion":2,
"ptyp":1,
"mode":1024,
"cpmap":886,
dateAdded: new Date()
},{
"name": "Name 3",
"sektion":1,
"ptyp":3,
"mode":24,
"cpmap":886,
dateAdded: new Date()
},{
"name": "Name 4",
"sektion":1,
"ptyp":1,
"mode":0,
"cpmap":1024,
dateAdded: new Date()
}]};

Is it possible to extract a set of database rows with RestTemplate?

I am having difficulties getting multiple datasets out of my database with RestTemplate. I have many routines that extract a single row, with a format like:
IndicatorModel indicatorModel = restTemplate.getForObject(URL + id,
IndicatorModel.class);
and they work fine. However, if I try to extract a set of data, such as:
Map<String, List<S_ServiceCoreTypeModel>> coreTypesMap =
restTemplate.getForObject(URL + id, Map.class);
this returns values in a
Map<String, LinkedHashMap<>>
format. Is there an easy way to return a List<> or Set<> in the desired format?
Fundamentally the issue is that your Java object model does not match the structure of your json document. You are attempting to deserialize a single json element into a java List. Your JSON document looks like:
{
"serviceCoreTypes":[
{
"serviceCoreType":{
"name":"ALL",
"description":"All",
"dateCreated":"2016-06-23 14:46:32.09",
"dateModified":"2016-06-23 14:46:32.09",
"deleted":false,
"id":1
}
},
{
"serviceCoreType":{
"name":"HSI",
"description":"High-speed Internet",
"dateCreated":"2016-06-23 14:47:31.317",
"dateModified":"2016-06-23 14:47:31.317",
"deleted":false,
"id":2
}
}
]
}
But you cannot turn a serviceCoreTypes into a List, you can only turn a Json Array into a List. For instance if you removed the unnecessary wrapper elements from your json and your input document looked like:
[
{
"name": "ALL",
"description": "All",
"dateCreated": "2016-06-23 14:46:32.09",
"dateModified": "2016-06-23 14:46:32.09",
"deleted": false,
"id": 1
},
{
"name": "HSI",
"description": "High-speed Internet",
"dateCreated": "2016-06-23 14:47:31.317",
"dateModified": "2016-06-23 14:47:31.317",
"deleted": false,
"id": 2
}
]
You should be able to then deserialize THAT into a List< S_ServiceCoreTypeModel>. Alternately if you cannot change the json structure, you could create a Java object model that models the json document by creating some wrapper classes. Something like:
class ServiceCoreTypes {
List<ServiceCoreType> serviceCoreTypes;
...
}
class ServiceCoreTypeWrapper {
ServiceCoreType serviceCoreType;
...
}
class ServiceCoreType {
String name;
String description;
...
}
I'm assuming you don't actually mean database, but instead a restful service as you're using RestTemplate
The problem you're facing is that you want to get a Collection back, but the getForObject method can only take in a single type parameter and cannot figure out what the type of the returned collection is.
I'd encourage you to consider using RestTemplate.exchange(...)
which should allow you request for and receive back a collection type.
I have a solution that works, for now at least. I would prefer a solution such as the one proposed by Ben, where I can get the HTTP response body as a list of items in the format I chose, but at least here I can extract each individual item from the JSON node. The code:
S_ServiceCoreTypeModel endModel;
RestTemplate restTemplate = new RestTemplate();
JsonNode node = restTemplate.getForObject(URL, JsonNode.class);
JsonNode allNodes = node.get("serviceCoreTypes");
JsonNode oneNode = allNodes.get(1);
ObjectMapper objectMapper = new ObjectMapper();
endModel = objectMapper.readValue(oneNode.toString(), S_ServiceCoreTypeModel.class);
If anyone has thoughts on how to make Ben's solution work, I would love to hear it.

Apigility: How to render embedded objects?

How do I render embedded objects in Apigility? For example, if I have a 'user' object and it composes a 'country' object, should I be rendering the 'country' object as an embedded object? And how should I do this?
I am using the Zend\Stdlib\Hydrator\ArraySerializable. My getArrayCopy() method simply returns an array of properties that I want exposed. The array keys are the property names. The array values are the property values. In the case of user->country, the value is an object, not a scalar.
When I return the user object from UserResource->fetch(), here's how it is rendered:
{
"id": "1",
"firstName": "Joe",
"lastName": "Bloggs",
"status": "Active",
"email": "test#example.com",
"country": {
"code": "AU",
"name": "Australia"
},
"settings": "0",
"_links": {
"self": {
"href": "http://api.mydomain.local/users/1"
}
}
}
Note that 'country' is not in an _embedded field. If it is supposed to be in _embedded, I would have thought that Apigility would automatically do that (since it automatically adds the _links object).
As a related issue, how do I go about returning other rel links, such as back, forward, etc?
The easiest way to get Apigility to render embedded resources is when there is an API/resource associated to the embedded object. What I mean for your example is that you'd have an API resource that has a country entity. In that case, if your getArrayCopy returned the the CountryEntity, Apigility would render it automatically as an embedded resource.
If your getArrayCopy is returning country as an array with code and name, you'll end up with what you saw.
For the other part, the rel links for first, last, prev and next will come from the fetchAll method when you return a Paginator. Your collection extends from this already, but it needs an adapter. The code could look something like this:
public function fetchAll($params)
{
// Return a \Zend\Db\Select object that will retrieve the
// stuff you want from the database
$select = $this->service->fetchAll($params);
$entityClass = $this->getEntityClass();
$entity = new $entityClass();
$hydrator = new \Zend\Stdlib\ArraySerializable();
$prototype = new \Zend\Db\ResultSet\HydratingResultSet($hydrator, $entity);
$paginator = new \Zend\Paginator\Adapter\DbSelect($select, $this->sql, $prototype);
$collectionClass = $this->getCollectionClass();
return new $collectionClass($paginator);
}
There are other paginator adapters as well - an ArrayAdapter which will take in an array of however big and then paginate it so you only get the desired number of results. The downside to this if you use it with database results, you'll potentially be retrieving and discarding a lot of results. The DbSelect paginator will modify the $select object to add the limit and order clause automatically so you only retrieve the bits you need. There are also adapters if you're using DbTableGateway, Iterators or even callbacks. You can also implement your own of course.
Hope this helps. If you have more specific needs or clarification, please comment and I'll do my best.
I posted this example on github.
https://github.com/martins-smb/apigility-renderCollection-example
Hope this helps.

Using backbone collections with a rest route that returns an object

Looking at the example code
var accounts = new Backbone.Collection;
accounts.url = '/accounts';
accounts.fetch();
this works if the route returns an array
[{id:1, name:'bob'}, {id:2, name:'joe'}]
but the REST service I'm using returns an object like this
{
items: [{id:1, name:'bob'}, {id:2, name:'joe'}],
page: 1,
href: '/acounts'
}
How to I go about telling Backbone.Collection that the collection is in items?
Parse function seems appropriate.
From the documentation:
http://backbonejs.org/
"When fetching raw JSON data from an API, a Collection will automatically populate itself with data formatted as an array, while a Model will automatically populate itself with data formatted as an object:
[{"id": 1}] ..... populates a Collection with one model.
{"id": 1} ....... populates a Model with one attribute.
However, it's fairly common to encounter APIs that return data in a different format than what Backbone expects. For example, consider fetching a Collection from an API that returns the real data array wrapped in metadata:
{
"page": 1,
"limit": 10,
"total": 2,
"books": [
{"id": 1, "title": "Pride and Prejudice"},
{"id": 4, "title": "The Great Gatsby"}
]
}
In the above example data, a Collection should populate using the "books" array rather than the root object structure. This difference is easily reconciled using a parse method that returns (or transforms) the desired portion of API data:
var Books = Backbone.Collection.extend({
url: '/books',
parse: function(data) {
return data.books;
}
});
"
Hope it helps.

Using HATEOAS and Backbone.js

I've started experimenting with Backbone.js, and was struck by the documentation for the documentation for the url property on Backbone.Model.
In particular, I'm building out a REST API that uses HATEOAS/hypermedia to drive the client(s).
I can see the usefulness of Backbone's default behaviour of building up URLs itself for items in a collection, but for my case, would prefer to have the model URLs built out of the data that is parsed.
Has anyone extended/built on Backbone to make it do this? Maybe building upon a "standard" like HAL?
EDIT:
For clarification, let's say I have the following:
GET /orders >>
[
{
"_links": {
"self": "/orders/123"
}
"name": "Order #123",
"date": "2012/02/23"
},
{
"_links": {
"self": "/orders/6666"
}
"name": "Order #666",
"date": "2012/03/01"
},
]
and I have an Order model like:
var Order = Backbone.Model.extend({
});
I would like the url property to be automatically pulled out of the "self" reference in the HAL. I think creating a new base model something like (not tested):
var HalModel = Backbone.Model.extend({
url: function() {
return get("_links").self;
},
});
Thoughts?
I've extended backbone to do exactly this, the library is available here:
https://github.com/mikekelly/backbone.hal
Thanks for the clarification #Pete.
I think I see what your proposing and I suppose it could work. However, in your example, you first had to know the /Orders url before you were able to get the orders. And if you reworked your json to have an id property, you'd be pretty close to the default implementation of backbone.
Now if you just want to use a generic model or base model (e.g. HALModel) and just bootstrap it with data, your approach could be useful and definitely could work. However, I would look at overriding parse to pull the url out and set it on the model:
parse: function(response) {
this.url = response._links.self;
delete response._links;
return response;
}
I complement here the response of Simon to explain how to easily do it using gomoob/backbone.hateoas.
// Instanciation of an Hal.Model object is done the same way as you're
// used to with a standard Backbone model
var user = new Hal.Model({
firstName: "John",
lastName: "Doe",
_links: {
avatar: {
href: "http://localhost/api/users/1/avatar.png"
},
self: {
href: "http://localhost/api/users/1"
}
},
_embedded: {
address: {
"city" : "Paris",
"country" : "France",
"street" : "142 Rue de Rivoli",
"zip" : "75001",
"_links" : {
"self" : {
"href" : "http://localhost/api/addresses/1"
}
}
}
}
});
// Now we you can easily get links, those lines are equivalent
var link1 = user.getLink('avatar');
var link2 = user.getLinks().get('avatar');
// So getting self link is simple too
var self = user.getLink('self');
// All the Hal.Link objects returned by backbone.hateoas are in fact
// standard Backbone models so its standard Backbone
link1.get('href');
link1.getHref();
// You can do more with shortcut methods if your HAL links
// have more properties
link1.get('deprecation');
link1.getDeprecation();
link1.get('name');
link1.getName();
link1.get('hreflang');
link1.getHreflang();
link1.get('profile');
link1.getProfile();
link1.get('title');
link1.getTitle();
link1.get('type');
link1.getType();
linke1.get('templated');
link1.isTemplated();
// You can also manipulate embedded resources if you need
user.getEmbedded('address').get('city');
user.getEmbedded('address').getLink('self');
...
Finally we provide an Hal.Model.url() implementation which is more powerful than standard Backbone url() and which is very useful if you use HAL.
// By default url() returns the href of the self link if this self
// link is present
user.url();
// If the self link is not defined then url() has the same behavior
// as standard Backbone url() method
// My user is link to a user collection having a URL equal to
// 'http://localhost/user1'
user.url(); // http://localhost/users/1
// My user is not link to a user collection in this case the URL is
// generate using the model urlRoot property by default
user.urlRoot = 'http://myserver/users';
user.url(); // http://localhost/users/1
// backbone.hateoas also allows you to define an application wide root
// URL which prevent to use absolute URLs everywhere in your code
Hal.urlRoot = 'http://localhost/api'; // HAL root API URL
var user = new Hal.Model({ id : 1});
user.urlMiddle = 'users';
user.url(); // http://localhost/api/users/1
Hope this helps, don't hesitate to post issues on our github if you need help on this.
You can override the url function on the model to calculate the URL however you want; it's completely extensible.