StrongLoop modify data before each get on model - loopbackjs

I have the following model in LoopBackJS:
{
"name": "member",
"base": "PersistedModel",
"properties": {
"firstName": {
"type": "string"
}
"public": {
"type": "boolean"
}
},
"relations": {
"spouse": {
"type": "hasOne",
"model": "spouse",
"foreignKey": "spouseId"
}
}
}
Now I need to modify the firstName field, so one can only see "public": true members first name and the others gets firstName: "*". The function for that I have already.
But how can I access the data on each data-access-request?
I tried it with the with the operation hook e.g. find, findOne,... but when I miss one of them some users could access the firstName.
With the remote hook it's the same.
Now I'm trying it with the connector hook:
connector.observe('after execute', function(ctx, next) {
if (ctx.model === 'familyMember') {
if (ctx.req.command === 'find') {
}
}
next();
});
For all find queries (mongodb) but there I can't access the data. Is there a way to access those data? Or is there a much better (build-in) solution for this problem?

You need to check result after each remote :
member.afterRemote('**', function(ctx, modelInstance, next) {
if (ctx.result) {
if (Array.isArray(modelInstance)) {
var answer = [];
ctx.result.forEach(function (result) {
if(result.public === false)
result.firstName = "*";
answer.push(result);
});
} else {
var answer =ctx.result;
if(answer.public === false)
answer.firstName = "*";
}
ctx.result = answer;
}
next();
});

Related

Ember Data Serializer & Adapter with Supabase returns empty (Proxy { })

Struggling to create my customised adapter & serializer to integrate Supabase, how I'm stuck why no data in Ember Data.
Trying out with a simple findAll() method. See below:
Service ⬇️:
export default class SupabaseService extends Service {
client;
constructor() {
super(...arguments);
const { url, key } = ENV.supabase;
const supabase = createClient(url, key);
this.client = supabase;
}
}
Model ⬇️:
export default class CourseModel extends Model {
#attr('string') name;
#attr('date') date_added;
}
Adapter ⬇️:
export default class ApplicationAdapter extends RESTAdapter {
#service supabase;
async findAll(store, type, neverSet, snapshotRecordArray) {
return new Promise(async (resolve, reject) => {
try {
const { data, error, status } = await this.supabase.client
.from(pluralize(type.modelName))
.select('*');
if (error) {
reject(error);
} else {
resolve(data);
}
} catch (error) {
reject(error);
}
});
}
}
Serializer ⬇️:
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
// parse the response data from the server and return it in the format that Ember Data expects
let newPayload = {
data: payload.map(item => {
let attributes = JSON.parse(JSON.stringify(item));
delete attributes.id;
return {
id: item.id,
type: primaryModelClass.modelName,
attributes: attributes
}
})
}
return super.normalizeResponse(store, primaryModelClass, newPayload, id, requestType);
}
✅ The service works fine. The adapter manage to get data and returns as follows:
[
{
"id": "259f46fd-3321-4cc9-ad5e-6d6ec880f7f1",
"date_added": "2022-12-31T00:03:14.618585+00:00",
"name": "Science"
},
{
"id": "62a6a085-604b-4600-8cc4-59a8c9af284a",
"date_added": "2022-12-31T00:03:30.010963+00:00",
"name": "Physics"
}
]
The serializer newPayload to follow JSON API schema, returns:
{
"data": [
{
"id": "259f46fd-3321-4cc9-ad5e-6d6ec880f7f1",
"type": "course",
"attributes": {
"name": "Science",
"date_added": "2022-12-31T00:03:14.618585+00:00"
}
},
{
"id": "62a6a085-604b-4600-8cc4-59a8c9af284a",
"type": "course",
"attributes": {
"name": "Physics",
"date_added": "2022-12-31T00:03:30.010963+00:00"
}
}
]
}
But the problem is no data in store. Logging model in template shows empty Proxy {}.
I have no idea why. Ember Inspector shows no model in Data.
Any suggestions?

JSON Validate check based on response from arrayElement

I wanted to check from the response format if status=AVAILABLE then arrayElement should return with roomTypeId else roomTypeId should not return for other status.
[
{
"status": "SOLDOUT",
"propertyId": "dc00e77f",
"Fee": 0,
"isComp": false
},
{
"roomTypeId": "c5730b9e",
"status": "AVAILABLE",
"propertyId": "dc00e77f",
"price": {
"baseAveragePrice": 104.71,
"discountedAveragePrice": 86.33
},
"Fee": 37,
"isComp": false
},
]
[
{
"status": "SOLDOUT",
"propertyId": "773000cc-468a-4d86-a38f-7ae78ecfa6aa",
"resortFee": 0,
"isComp": false
},
{
"roomTypeId": "c5730b9e-78d1-4c1c-a429-06ae279e6d4d",
"status": "AVAILABLE",
"propertyId": "dc00e77f-d6bb-4dd7-a8ea-dc33ee9675ad",
"price": {
"baseAveragePrice": 104.71,
"discountedAveragePrice": 86.33
},
"resortFee": 37,
"isComp": false
},
]
I tried to check this from below;
pm.test("Verify if Status is SOLDOUT, roomTypeId and price information is not returned ", () => {
var jsonData = pm.response.json();
jsonData.forEach(function(arrayElement) {
if (arrayElement.status == "SOLDOUT")
{
pm.expect(arrayElement).to.not.include("roomTypeId");
}
else if (arrayElement.status == "AVAILABLE")
{
pm.expect(arrayElement).to.include("roomTypeId");
}
});
});
You need to check if the property exists or not.
With the have.property syntax you can do that.
You can read the Postman API reference docs and also Postman uses a fork of chai internally, so ChaiJS docs should also help you.
Updated script:
pm.test("Verify if Status is SOLDOUT, roomTypeId and price information is not returned ", () => {
var jsonData = pm.response.json();
jsonData.forEach(function(arrayElement) {
if (arrayElement.status === "SOLDOUT") {
pm.expect(arrayElement).to.not.have.property("roomTypeId");
} else if (arrayElement.status === "AVAILABLE") {
pm.expect(arrayElement).to.have.property("roomTypeId");
}
});
});

How to query objects with property contains a value in loopback

I have a model event which referenceMany user.
"relations": {
"attendees": {
"type": "referencesMany",
"model": "user",
"foreignKey": "attendeeIds",
"options": {
"validate": true,
"forceId": false,
"persistent": true
}
}
How can I query event which attendees property contain a given value? attendees is an array containing userId.
For example:
Event.find({
where: {
attendees: {
contains: givenUserId
}
}
}
)
This feature is called 'Filter on level 2 properties' as referenced here and is being implemented for Memory and MongoDB connectors. It still has some issues.
For SQL connectors, this isn't supported yet and - as mentioned also inside this open discussion link - it requires some time which cannot be afforded now.
Possible work around here with regexp that would apply to the underlying JSON string and executing SQL directly via datasource.connector.execute()
Simple implementaion could be:
AnyModel.getApp((err, app) => {
if (err) {
console.log(err);
next(err);
}
// Using MySQL
const MySQL = app.dataSources.MySQL;
MySQL.connector.execute(`select * from Table where column like '%${string}%'`,
[], {}, (err, data) => {
if (err) {
console.log(err);
next(err);
}
console.log(data);
next();
});
});

How to create a loopback <model>.json file from unstructured data

I can create a loopback model from an example json instance as shown here https://docs.strongloop.com/display/public/LB/Creating+models+from+unstructured+data. But from there is there an API to create the .json file in common/models?
#BoLaMN from Looback Gitter said this:
try app.registry.modelBuilder.introspect(json); that should give you a properties object. Then just add name, base to it and fs.writeSync JSON.stringify(obj).
I haven't tried yet, but it makes sense.
I've been using this:
var User = db.buildModelFromInstance('User', user, {idInjection: true});
var UserModel = (loopback.getModel(User));
var UserModelJSON = {}
UserModelJSON.name = 'User';
UserModelJSON.base = 'PersistedModel';
UserModelJSON.properties = UserModel.definition.rawProperties;
console.log(JSON.stringify(UserModelJSON));
fs.writeFile('User.json', 'UserModelJSON', function(err) {
if (err) throw err;
});
In your loopback /server directory at the root of your project, if you define the datasources.json file like so
{
"db": {
...
},
"restResourceName": {
"name": "restResourceName",
"baseURL": "http://restResourceUrl/",
"crud": true,
"connector": "rest"
}
}
And you define a boot script, like so
const fs = require('fs')
const path = require('path')
const writeInstance = (server, modelName, instance) => {
let Model = server.dataSources.restResourceName.buildModelFromInstance(modelName, instance)
let modelJson = Model.definition.toJSON()
delete modelJson.settings.base
fs.writeFile(path.join(__dirname, '..', 'models', modelName + '.json'),
JSON.stringify(modelJson, null, 2), (/*...*/) => {
/*...*/
})
}
module.exports = function (server) {
writeInstance(server, "Atom", {
atomicWeight: 6
})
}
You will generate a model file Atom.json
{
"name": "Atom",
"properties": {
"atomicWeight": {
"type": "Number"
},
"id": {
"type": "Number",
"id": 1,
"generated": true,
"updateOnly": true
}
},
"settings": {
"strict": false,
"forceId": "auto",
"replaceOnPUT": true
}
}
If you want to see the models in the loopback api explorer (swagger GUI), you must add the model to the model-config.json with a public: true property
{
"_meta": {
"sources": [
...
],
"mixins": [
...
]
},
"Atom": {
"public": true,
"dataSource": "restResourceName"
}
}

Ember.js Unable to get hasMany id when using .filter()

It seems a no-brainer to me, but could not get this to work:
My ApplicationRoute:
model: function () {
this.controllerFor('categories').set('model', this.store.find('category'));
}
CategoriesController:
App.CategoriesController = Ember.ArrayController.extend();
ArticlesRoute: (using query-params-new)
model: function(params) {
if (params.category) {
return this.store.find('article').filter(function(item) {
console.log(item.get('category.id'); // => undefined
return (item.get('category.id') === params.category); // => always false
});
} else {
return this.store.find('article');
}
}
As you can see is the above code the problem. item.get('category.id') simple does always return undefined. However the Articles do have a category defined:
REST response: (including relationship values)
{
"articles":[
{
"id":116,
"name": "Article 1"
"category":[
11
],
},
{
"id":115,
"name": "Article 2"
"category":[
6
],
},
{
"id":114,
"name": "Article 3"
"category":[
11
],
}
],
"categories":[
{
"id":6,
"name":"Category 1",
},
{
"id":11,
"name":"Category 2",
}
],
}
Edit: item.get('category') does return a <DS.ManyArray:ember747> in the console.
I found it already.
HasMany is an Array of Objects. That way we have to use findBy to search for the ID. (correct me I am wrong).
Use item.get('category').findBy('id', params.category) to filter by ID.