ember-data mappings for sideloading revision 11 - ember-data

What has happened to mappings to the revision 11 ember-data with regard to sideloading?
I have the following 2 model classes:
WZ.Exercise = WZ.Model.extend
name: DS.attr 'string'
description: DS.attr 'string'
group: DS.belongsTo('WZ.Group', {key: 'groups'}) #I don't think the key does anything
WZ.Group = WZ.Model.extend
name: DS.attr 'string'
exercises: DS.hasMany('WZ.Exercise')
Previously I had a mappings property on the adapter which no longer seems to do anything:
WZ.Store = DS.Store.extend
revision: 11
adapter: DS.RESTAdapter.create
bulkCommit: false
mappings:
groups: WZ.Group
The sideloading code expects the sideloaded root json property to be the same as the property name:
for (var prop in json) {
if (!json.hasOwnProperty(prop)) { continue; }
if (prop === root) { continue; }
if (prop === this.configOption(type, 'meta')) { continue; }
sideloadedType = type.typeForRelationship(prop);
I don't see anyway to get round this. Either the json is in the state the code expects or it will not work.

This is how I sideload data:
DS.RESTAdapter.configure('App.Groups', {
sideloadAs: 'groups'
});
App.Store = DS.Store.extend({
revision: 11,
adapter: DS.RESTAdapter.create({})
});

I encountered a similar problem and found a mapping in the ember_data_example project that resolved it for me. In my case, a ticketEntries: hasMany('App.TicketEntry') was not loading.
// Prepare our global Ember Data 'store'
App.RESTSerializer = DS.RESTSerializer.extend({
init: function() {
this._super();
this.map('App.Ticket', {
creator: {embedded: 'always'},
ticketEntries: {embedded: 'always'}
});
}
});
App.Adapter = DS.RESTAdapter.extend({
bulkCommit: false,
serializer: App.RESTSerializer.create()
});
App.Store = DS.Store.extend({
revision: 11,
adapter: App.Adapter.create()
});
App.store = App.Store.create(
);

Related

I get different result from Graphql playground and front-end

I am using graphql and Vue.js and apollo
Here is my DateBank
const sensorsdb = [
{
name: "sensor 1",
id: "s-1",
timestamp: 1582021371,
value: 100
},
{
name: "sensor 1",
id: "s-1",
timestamp: 1579451703,
value: 150
},
{
name: "sensor 2-1",
id: "s-2-1",
timestamp: 1582021371,
value: 200
},
{
name: "sensor 2-2",
id: "s-2-2",
timestamp: 1579451703,
value: 350
},
{
name: "sensor 2-2",
id: "s-2-2",
timestamp: 1582021371,
value: 300
},
{
name: "sensor 3",
id: "s-3",
timestamp: 1582021371,
value: 400
},];
I want to get all objects according to object id. sensorId is an array. because I want to get multiple objects with multiple ids.
The following is my API function to get object.
async getDataById({ sensorId }) {
let sensorsData = [];
for (let i = 0; i < sensorId.length; i++) {
let sensorData = this.sensorDataStore.sensors.filter(sensor => sensor.id === sensorId[i]);
sensorsData = sensorsData.concat(sensorData);
}
return sensorsData;
}
In Front-end, gql file is following:
query sensorData($id: [String]){
sensorData(id: $id){
name
id
value
timestamp
}}
and with my apollo query code in vue.js, in this case selectedSensorId is ["s-2-1", "s-2-2"]
<ApolloQuery :query="require('../graphql/sensorDataById.gql')" :variables="{ id: selectedSensorId }">
<template v-slot="{ result: { loading, error, data } }">
<b-loading :is-full-page=true :active.sync=loading :can-cancel="false"/>
<div v-if="error">
<no-data-error />
</div>
<div v-if="data">
{{ data }}
<bar-chart-view :sensorInfo="data.sensorData"/>
</div>
</template>
</ApolloQuery>
But I got the following different result:
Graphql playground which has correct result
The front-end result with duplicated sensor-s-2
Apollo Client normalizes results according to the id and __typename fields as described in the docs. If an array returns multiple items with the same id, by default they will share the same cache key, which means what's returned by the client will be the same object.
You should provide a custom dataIdFromObject function to your InMemoryCache constructor that accommodates your specific use case. Something like:
const dataIdFromObject = object => {
switch (object.__typename) {
case 'SensorDataPoint': return `SensorDataPoint:${object.id}:{value}`;
default: return defaultDataIdFromObject(object);
}
}
Note that if you use the same type elsewhere, you may experience issues with the cache updated correctly after mutations because we are now keying off both the value and id. You might want to consider a different approach to your schema where the ids are actually unique :
type SensorDataPoint {
id: ID!
sensorId: ID!
sensorName: String!
value: Int!
timestamp: Int!
}
or even better
type SensorDataPoint {
id: ID!
value: Int!
timestamp: Int!
sensor: Sensor!
}
type Sensor {
id: ID!
name: String!
}
I know it its been a while but what Daniel Rearden mentioned above, I included the { addTypename: false } as options for InMemoryCache
const client = new ApolloClient({
link: ApolloLink.from([
onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
graphQLErrors.forEach(({ message, extensions }) => {
console.log(`[GraphQL error]: Message: ${message}, Code: ${extensions?.code}`)
})
if (networkError) {
console.log(`[Network error] ->: ${networkError}`)
Toast.show('Connection Error', {
position: Toast.positions.TOP,
type: 'danger',
duration: 3000,
})
}
}),
authMiddleware,
link,
]),
cache: new InMemoryCache({ addTypename: false }),
});

Automatically assign assignee when changing status of ticket

I created an "Agile-Board" in youtrack and I want every ticket that is moved to the column (which is mapped to the field Status) "In Produktivsetzung" to be automatically assigned to my user.
Like this:
How can this be done?
One can set it up with a custom workflow script as follows
var entities = require('#jetbrains/youtrack-scripting-api/entities');
exports.rule = entities.Issue.onChange({
title: 'Set logged-in user as an assignee when they move it to In Produktivsetzung state',
guard: function(ctx) {
var issue = ctx.issue;
return issue.isReported &&
issue.fields.Assignee === null &&
issue.fields.becomes(ctx.State, ctx.State.InProgress) &&
!issue.fields.isChanged("project");
},
action: function(ctx) {
var isCurrentUserAssignee = false;
ctx.Assignee.values.forEach(function(it) {
if (it.login == ctx.currentUser.login) {
isCurrentUserAssignee = true;
}
});
if (isCurrentUserAssignee) {
ctx.issue.Assignee = ctx.currentUser;
}
},
requirements: {
Assignee: {
type: entities.User.fieldType
},
State: {
type: entities.State.fieldType,
InProgress: {
name: 'In Produktivsetzung'
}
}
}
});
I want to set assignee on every state change. After a couple hours trial & error (the documentation is really not that good) I had success:
var entities = require('#jetbrains/youtrack-scripting-api/entities');
exports.rule = entities.Issue.onChange({
title: 'Assign issue to current user when state changes',
guard: function(ctx) {
return ctx.issue.fields.isChanged(ctx.State);
},
action: (ctx) => {
ctx.issue.fields.Assignee = ctx.currentUser;
},
requirements: {
Assignee: {
type: entities.User.fieldType
},
State: {
type: entities.State.fieldType
}
}
});
I don't really understand why I have to use a "guard function" - I could just use a conditional statement in the action and the whole "requirements" section doesn't make any sense to me but if it is necessary... I don't care. Finally works as expected... I hope that it works some years longer than the "legacy scripts" - I don't want to touch it again. 🙂
Based on the answer this is what I'm using now, I created multiple modules where I just had to change the two variables at the top of my code:
var entities = require('#jetbrains/youtrack-scripting-api/entities');
var assigneeLogin = '<some.login>';
var stateName = '<Some Statename, see possible values in console.log(ctx.State)>';
exports.rule = entities.Issue.onChange({
title: 'Set ' + assigneeLogin + ' as the assignee when ticket is moved to "'+ stateName + '"',
guard: function(ctx) {
var issue = ctx.issue;
return issue.fields.becomes(ctx.State, ctx.State.InProgress);
},
action: function(ctx) {
ctx.Assignee.values.forEach(function(it) {
if (it.login === assigneeLogin) {
ctx.issue.Assignee = it;
}
});
},
requirements: {
Assignee: {
type: entities.User.fieldType
},
State: {
type: entities.State.fieldType,
InProgress: {
name: stateName
}
}
}
});

How to avoid duplicate entries in IBM JSONStore

WL.JSONStore.get(collectionName).change(data, options) method does not seem to work for duplicate values. I get duplicate values entered whenever data is loaded through the adapter. Below is the code that I have used to avoid duplicate entries.
init(){
console.log('JSONStore init function callled');
let collections = {
activities: {
searchField: {serialKey: 'string'},
adapter: {
name: 'ServiceAdapter',
add: 'pushActivities',
remove: 'removeActivity',
replace: 'replaceActivity',
load: {
procedure: 'getActivities',
params: [],
key: 'rows'
}
}
}
}
WL.JSONStore.init(collections).then((success) => {
console.log('-->JSONStore init success')
}, (failure) => {
console.log('-->JSONStore init failed', failure)
})
}
load() {
let dataRequest = new
WLResourceRequest("/adapters/ServiceAdapter/getActivities",
WLResourceRequest.GET);
dataRequest.send().then(
(response) => {
this.data = response.responseJSON.rows;
this.activityService.put(this.data);
})
}
put(data){
console.log('--> JSONStore put function called');
let collectionName = 'activities';
let options = {
replaceCriteria: ['serialKey'],
addNew: true,
markDirty: false
};
WL.JSONStore.get(collectionName).change(data, options).then((success) => {
console.log('--> JSONStore put success')
}, (failure) => {
console.log('--> JSONStore put failed', failure)
})
}
Adapter Function:
function getActivities() {
var path = 'employees' + '/_all_docs?include_docs=true';
var input = {
method : 'get',
returnedContentType : 'json',
path : path,
};
var response = MFP.Server.invokeHttp(input);
if (!response.rows) {
response.isSuccessful = false;
return response;
} else {
var results = [];
for (var i=0; i < response.rows.length; i++) {
results.push(response.rows[i].doc);
}
return {'rows': results};
}
}
I have even tried by:
searchFields: {serialKey: 'string',serialId: 'string'}
replaceCriteria: ['serialKey','serialId']
But no luck.
NOTE: There is no error in the former one, whereas the later results in an error.
ERROR : PROVISION_TABLE_SEARCH_FIELDS_MISMATCH (I have already tried to destroy the collection and perform the change, as the link suggests.
I have followed the below link:
https://www.youtube.com/watch?v=Ep6w1zXoI-k
I am using the below versions:
mfpdev : 8.0.0-2017102406
Let me know if you need any more details.

Realm does not seems to working

I am trying to use realm in react-native android and I just wanted to test if it is working or not.
It seems to save data since it throws duplicated primaryKey error.
However, realm.objects('Person') does not return data but
Proxy
[[Handler]]
:
Object
[[Target]]
:
Results
[[IsRevoked]]
:
false
class Person {}
Person.schema = {
name: 'Person',
primaryKey: 'name',
properties: {
name: 'string',
age: {type: 'int', default: 0},
},
};
const realm = new Realm({schema: [Person],schemaVersion: 2});
// Write
realm.write(() => {
const savedPerson = realm.create('Person', {
name: 'Hal Incanden1za',
age: 17,
});
});
console.log(realm.objects('Person'))
The value you get from a realm.objects() call is not a normal array, so console.log may not be doing what you are expecting here. Try iterating through it instead.

How to use jsonschema for Loopback remoteMethod?

In my app I want define JSON schemas for custom API.
For example from: http://docs.strongloop.com/display/public/LB/Remote+methods#Remotemethods-Example
module.exports = function(Person){
Person.greet = function(msg, cb) {
cb(null, 'Greetings... ' + msg);
}
Person.remoteMethod(
'greet',
{
accepts: <generate definitions from jsonschema>,
returns: <generate definitions from jsonschema>
}
);
};
How to do that?
This is right way?
MY SOLUTION - validation decorator + remote method params with object type
var validate = require('jsonschema').validate;
bySchema = function (schema) {
return function (func) {
return function () {
var data = arguments[0],
callback = arguments[1];
var result = validate(data, schema);
if (result.errors.length > 0) {
// some errors in request body
callback(null, {
success: false,
error: 'schema validation error',
});
return;
}
return func.apply(this, arguments);
};
};
};
defaultRemoteArguments = {
accepts: {
arg: 'data',
type: 'object',
http: function(ctx) {
return ctx.req.body;
}
},
returns: {
arg: 'data',
type: 'object',
root: true
}
};
Example:
Auth.login = bySchema(require('<path to shcemajson json for this request>'))
(function(data, cb) {
// process request
});
Auth.remoteMethod('login', defaultRemoteArguments);
In this solution contrib loopback explorer will not be useful, because request/response are objects, not fields...
The correct way to do it is to set the type in the returns attribute to the model name.
In your case you would write:
Person.remoteMethod(
'greet',
{
...
returns: {type:'Person', ...}
}
);
You need to modify your output to match the format accepted by the returns property.
...
returns: [{arg: "key1", type: "string"}, {arg: "key2", type: "object"}, ...];
...