Set migrate:safe to user defined table in waterline - waterline

I have to create user defined tables in waterline though custom query method(.query()).
custom.con.query("CREATE TABLE "+req.body.table_name+",function(err,model){});
After that i have to create coloumns in this table again through custom query.
custom.con.query("ALTER TABLE "+req.body.table_name+" ADD "+req.body.coloumn_name,function(err,model){});
Problem is once table is created and it's coloumns also created.but when i restart server coloumns in table vanish.
In other waterline models i can handle this problem by setting value of migrate:"safe".
Is there any way to set such configuration in custom tables.???

user786, it seems that you have your default migrate setting set to 'alter' or 'drop'. You can change this by adding a defaults object to your waterline initialisation, example:
var config = {
// adapters
// models
// etc...
defaults: {
// will apply to any model that doesn't have a 'migrate' definition
migrate: 'safe'
}
};
waterline.initialize(config, function(err, models) {
console.log("waterline initialised.");
});
Code example in waterline examples.
The non-destructive options are 'safe' and 'create', more details in the adapter specification docs and in sails model settings.

Related

Getting the right permitted fields of conditions

Currently, I'm building an app with with following similar logic:
...
const user = {
isAdmin: true,
company: '5faa6a847b42bf47b8f785a1',
projects: ['5faa6a847b42bf47b8f785a2']
}
function defineAbilityForUser(user) {
return defineAbility((can) => {
if (user.isAdmin) {
can('create', 'ProjectTime', {
company: user.company,
}
);
}
can(
'create',
'ProjectTime',
["company", "project", "user", "start", "end"],
{
company: user.company,
project: {
$in: user.projects
}
}
);
});
}
const userAbility = defineAbilityForUser(user); //
console.log( permittedFieldsOf(userAbility, 'create', 'ProjectTime') );
// console output: ['company', 'project', 'user', 'start', 'end']
Basically an admin should be allowed to create a project time with no field restrictions.
And a none admin user should only be allowed to set the specified fields for projects to which he belongs.
The problem is that I would expect to get [] as output because an admin should be allowed to set all fields for a project time.
The only solution I found was to set all fields on the admin user condition. But this requires a lot of migration work later when new fields are added to the project time model. (also wrapping the second condition in an else-block is not possible in my case)
Is there any other better way to do this? Or maybe, would it be better if the permittedFieldsOf-function would prioritize the condition with no field restrictions?
There is actually no way for casl to know what means all fields in context of your models. It knows almost nothing about their shapes and relies on conditions you provide it to check that objects later. So, it does not have full information.
What you need to do is to pass the 4th argument to override fieldsFrom callback. Check the api docs and reference implementation in #casl/mongoose
In casl v5, that parameter is mandatory. So, this confusion will disappear very soon

UI5 - control formatter is executed too soon, before the data is loaded into model

I have a web application which, after login, displays landing screen with the navigation pane on the left. Also, during the onInit event, I call the getUserData() which collects additional data about the user (such as roles and saves them into the model).
This navigation is of the type sap.tnt.NavigationListItem and is loaded from the model (data are hardcoded in App.controller.js). In App.view.xml, it looks like this
<tnt:NavigationListItem text="{appView>title}"
items="{path: 'appView>items', templateShareable: true}"
visible="{path: 'appView>neededRole', formatter:'.myFormatter'}">
Now, I would like to make an improvement - to show some items in the navigation list only to the users which have sufficient roles.
As you can see above, I set the formatter for the 'visible' property of the NavigationListItem. It checks the role necessary to display the NavigationListItem ('needed role'), compares it with the array of roles assigned to the user and if there is a match, shows the menu item
myFormatter: function(role) {
const oModel = this.getView().getModel('appView');
return oModel.oData.userData.roles.some(x => x.roleId === role);
}
The problem is that when the myFormatter function is running, getUserData() hasn't finished yet and the model doesn't yet contain necessary roles array of the user - as as reason, all menu items are hidden. What I need to achieve is to make sure that MyFormatter runs ONLY AFTER the getUserData() has finished (and while myFormatter will run repeatedly, getUserData must run only once). How can I achieve it? getUserData() is asynchronous and no matter if I place it into onInit or beforeRendering, it finishes only after myFormatter collected the empty array from the model.
Thanks a million
Your formatter will run first when the view gets initialized, this is part of the lifecycle.
Then it will run each time the 'needRole' entry is explicitly (via model.setProperty) modified
It seems in your code that your formatter actually uses another data from the model: 'roles'
So you could just bind your formatter to both model entries like that:
<tnt:NavigationListItem
text="{appView>title}"
items="{
path: 'appView>items',
templateShareable: true
}"
visible="{
parts: ['appView>neededRole', 'appView>/userData/roles'],
formatter:'.myFormatter'
}">
and modify your formatter to
myFormatter: function(role, roles) {
return (roles || []).some(x => x.roleId === role);
}
Then your formatter will trigger when role or roles get modified in the model.
As a side note : a formatter is meant to format data, not compute things. A better option would be to directly create an 'entryVisible' entry in the model that you could then bind on your NavigationListItem (I know formatters do the job, but they also trigger a lot of rerenders you dont need)

Sequelize returning `null` object for hasOne association's linked model after bulk inserting pre-existed data

I have a pre-existing data in the form of JSON files which I am trying to insert into Sequelize SQLite table. I have 2 tables: Master_Vessel and Requests. There is a Request.hasOne(Vessel) association, meaning that every request has a vessel associated with it.
The key connecting both the models is vessel.Vessel_Name, which is a string. The data has been generated from a system which validates the keys so it is consistent (every request.Vessel_Name exists in vessel.Vessel_Name, vessel.Vessel_Name is unique).
I want to load this data into Sequelize managed table. I am creating the models as follows:
var Request = sequelize.define('request', {
// other fields
Vessel_Name: {
type: Sequelize.STRING
}
}, {
tableName: 'Request'
});
var Vessel = sequelize.define('vessel', {
// other fields
Vessel_Name: {
type: Sequelize.STRING,
primaryKey: true
}
}, {
tableName: 'Master_Vessel'
});
And, the association is as follows:
Request.hasOne(Vessel, {foreignKey: 'Vessel_Name', allowNull: true});
Now, I am loading the data in following steps:
Create and bulk load the Vessel model
Create the Request model, the association and bulk load the Request model
Everything runs fine without any issues. However when I try to query using the association as follows:
Request.findOne()
.then(request => {
console.log(request.get())
request.getVessel()
.then(vessel => console.log(vessel))
});
request instance contains the Vessel_Name foreign key, however the vessel instance is null.
Can anybody please help?
Okay this is happenning because I got the Sequelize 'vocabulary' mixed up, Request.hasOne(Vessel) does NOT mean Request will have one Vessel_Name that will point to a Vessel. It is to be read R->L for correct meaning, not L->R.
The solution to the problem was changing the association from hasOne to belongsTo as follows: Request.belongsTo(Vessel), so now the FK will be created on Request.
Quite a confusing choice of association names and semantics!

validating custom object in Meteor Simpleschema

I am trying to validate an object using SimpleSchema in Meteor, before inserting it into the database.
The object looks like this, as I print it from the Meteor method that calls the insert:
channels: { '1': [ 'rect4557-6-4-5-7-4-2', 'rect4557-6-4-97-0-7-6-3' ] } }
If I insert it in the database without attaching a schema to it, it works fine. However, when I have it run through SimpleSchema, the field value as outputted from console.log in the custom validation method is an empty object {}. Even if I don't run any validation, an empty object is stored if SimpleSchema is used.
Code to produce the simpleschema value output:
Arch.schema = new SimpleSchema({
channels: {
type: Object,
custom: function validateChannels() {
console.log("this.value:", this.value)
}
});
Architectures.attachSchema(Architectures.schema);
Really, what should I do? Is this a bug in SimpleSchema?
It looks like you just need to add blackbox: true option. SimpleSchema does not support arbitrary object keys unless you mark it as a blackbox object. See https://github.com/aldeed/meteor-simple-schema#blackbox
The filtering, which is part of the automatic cleaning, is what strips this out for you. If you want to prevent that in a specific insert call, just pass filter: false option. See https://github.com/aldeed/meteor-collection2#skip-removing-properties-that-are-not-in-the-schema

Registering and retrieving 'interactions' with SCORM 1.2

We've been using SCORM in our previous e-learning 'engine' but we want to change the elements our Managed Learning Environment (MLE) tracks, namely each completable component in an e-learning module.
At runtime, we run the following code to set up our SCORM connection:
var vault = {}; //vault 'namespace' helps ensure no conflicts with possible other "SCORM" variables
vault.UTILS = {}; //For holding UTILS functions
vault.debug = { isActive: true }; //Enable (true) or disable (false) for debug mode
vault.SCORM = { //Define the SCORM object
version: null, //Store SCORM version.
handleCompletionStatus: true, //Whether or not the wrapper should automatically handle the initial completion status
handleExitMode: true, //Whether or not the wrapper should automatically handle the exit mode
API:{handle: null, isFound: false}, //Create API child object
connection: { isActive: false }, //Create connection child object
data: { completionStatus: null, exitStatus: null}, //Create data child object
debug:{} //Create debug child object
};
vault.SCORM.API.find('win');
vault.SCORM.connection.initialize();
if (vault.SCORM.data.get("cmi.core.lesson_status")=="not attempted") {
vault.SCORM.data.set("cmi.core.lesson_status" , "incomplete");
vault.SCORM.data.save();
}
There are many more functions in the SCORM.js file, but the point is this all works; When the module is loaded into our MLE, the following code triggers course completion:
vault.SCORM.data.set("cmi.core.lesson_status" , "completed");
So how would we register a completable component with SCORM? (Components in our 'engine' are jQuery objects usually called 'element'). Would something like the following work, or are custom calls in SCORM not possible?
vault.SCORM.data.set("cmi.interactions.n."+element.componentId() , "incomplete");
But then if I registered an interaction by specifying an id, as follows...
vault.SCORM.data.set("cmi.interactions.n.id", element.componentId());
...how do I then set or access 'completion' on that component?
I've been reading posts and pdf specs from various sites, but the explanations are sparse at best.
I know there aren't a lot of SCORM followers here, but if you have any info, I'd be keen to hear it.
FWIW, that's my pipwerks SCORM wrapper, but with the variable pipwerks changed to ncalt.
There is documentation on how to use my wrapper at http://pipwerks.com (search for "scorm wrapper" in the search field). The original source code can be found at https://github.com/pipwerks/scorm-api-wrapper.
Note your sample code is not using the wrapper the way it was intended to be used. For example, this:
ncalt.SCORM.data.set("cmi.core.lesson_status" , "completed");
should be this (data is an internal helper and not necessary):
ncalt.SCORM.set("cmi.core.lesson_status" , "completed");
You can shorten it even further via a reference variable, like so:
var scorm = ncalt.SCORM;
scorm.set("cmi.core.lesson_status" , "completed");
scorm.save();
scorm.get("cmi.core.lesson_status"); //returns "completed"
As for your 'components', if you'd like to use SCORM's cmi.interactions model, be sure you're using the correct syntax. The "n" in the SCORM documentation (cmi.interactions.n.id) is meant to represent a number, it's not a literal "n".
scorm.set("cmi.interactions.0.id", "myfirstinteraction");
scorm.save();
To retrieve data from that interaction, you need to specify the number in place of the n:
scorm.get("cmi.interactions.0.id"); //returns "myfirstinteraction"
Note the CMI data model doesn't provide a 'status' field for cmi.interactions. You'd need to use cmi.objectives.
scorm.set("cmi.objectives.0.status", "completed");
scorm.save();
scorm.get("cmi.objectives.0.status"); // returns "completed"
The CMI data model (as available in SCORM) is spelled out here: http://scorm.com/scorm-explained/technical-scorm/run-time/run-time-reference/

Resources