Saving Sequelize Query Text In Database - express

I have a sequelize query that I would like to save in a database and then execute on demand. In order to do this I am first testing how this would work in a variable as a string (because in a database it will be stored as a string):
queryToRun = models.user.findAll({
attributes: [
['name', 'name'],
[Sequelize.literal("COUNT(DISTINCT(user.id))"), "user_count"]
],
group: Sequelize.col("user.name")
})
With this query I would like to use it like so:
Promise.all(queryToRun);
I am successfully able to save the object (object that goes inside findAll with the attributes etc) as a string and then execute, but I can't figure out how to save every part of the query. I want to save the actual "model.user.findAll()"string and evaluate it at a later time.
This is important because I want to define the model that I need to run findAll on and save it in the database.

This is actually fairly simple
Don't use the multiline string it trips up the function call for some reason
Use eval to evaluate the string
Example:
let queryToRun = 'models.project.findAll({})';
Promise.all([eval(queryToRun)]);

Related

Use Postgres generated columns in Sequelize model

I have a table where it's beneficial to generate a pre-calculated value in the database engine rather than in my application code. For this, I'm using Postgres' generated column feature. The SQL is like this:
ALTER TABLE "Items"
ADD "generatedValue" DOUBLE PRECISION GENERATED ALWAYS AS (
LEAST("someCol", "someOtherCol")
) STORED;
This works well, but I'm using Sequelize with this database. I want to find a way to define this column in my model definition, so that Sequelize will query it, not attempt to update a row's value for that column, and ideally will create the column on sync.
class Item extends Sequelize.Model {
static init(sequelize) {
return super.init({
someCol: Sequelize.DOUBLE,
someOtherColl: Sequelize.DOUBLE,
generatedValue: // <<<-- What goes here??
});
}
}
How can I do this with Sequelize?
I can specify the column as a DOUBLE, and Sequelize will read it, but the column won't be created correctly on sync. Perhaps there's some post-sync hook I can use? I was considering afterSync to drop the column and re-add it with my generated value statement, but I would first need to detect that the column wasn't already converted or I would lose my data. (I run sync [without force: true] on every app startup.)
Any thoughts, or alternative ideas would be appreciated.
Until Sequelize supports readOnly fields and the GENERATED datatype, you can get around Sequelize with a custom datatype:
const Item = sequelize.define('Item', {
someCol: { type: DataTypes.DOUBLE },
someOtherCol: { type: DataTypes.DOUBLE },
generatedValue: {
type: 'DOUBLE PRECISION GENERATED ALWAYS AS (LEAST("someCol", "someOtherCol")) STORED',
set() {
throw new Error('generatedValue is read-only')
},
},
})
This will generate the column correctly in postgres when using sync(), and prevent setting the generatedValue in javascript by throwing an Error.
Assuming that sequelize never tries to update the field if it hasn't changed, as specified in https://sequelize.org/master/manual/model-instances.html#change-awareness-of-save, then it should work.

laravel add and delete column to database using controller

is it possible to add and delete column to my existing database using the controller? is it possible not to use the migration? and how do my model automatically picked up the new column which is create and automatically put in inside fillable? anyone has idea on how to approach this type of situation,if you could point me into a tutorial that would be so cool.
Reason: i have a table with the student mark-book points breakdown column example: [Exam, Homework,Quiz etc..] then every term or year we will remove it or changed it or add more so that's why i need to something like dynamic approach on this matter. where anytime i can change the column or add new column.
Same way the migrations do it, use the Schema builder class. For example:
$newColumnType = 'string';
$newColumnName = 'my_new_column';
Schema::table('my_table', function (Blueprint $table) use ($newColumnType, $newColumnName) {
$table->$newColumnType($newColumnName);
});
You probably should use $guarded = ['id', 'foo', 'bar'] in your model instead of fillable if you're going to be adding columns.

Phalcon working with MySQL routines

I have a MySQL database which has GUID's stored as binary(16) for the primary keys. I'm using a MySQL user defined routine when inserting and selecting to convert the id's to and from GUID's (GUIDToBinary() and BinaryToGUID()).
In order to use my routines in Phalcon, I am setting the 'columns' parameter for the find() and findFirst() model functions which now means i'm working with incomplete objects as the functions return an instance of Phalcon\Mvc\Model\Row.
The docs state when using the columns parameter the following occurs;
Return specific columns instead of the full columns in the model. When
using this option an incomplete object is returned
UserController.php
// Returns Phalcon\Mvc\Model\Row
$incompleteUser = User::find(['columns' => 'BinaryToGUID(id) as id, status, username, password, .....']);
// Create a new user object to update
$user = new User();
// Populate with existing data
$user->assign($incompleteUser->toArray());
// Assign new changes requested by the user
$user->assign($this->request->getPost());
// Update
$user->updateUser();
User.php
public function updateUser()
{
$manager = $this->getModelsManager();
return $manager->executeQuery("UPDATE User SET ..... WHERE id = GUIDToBinary(".$this->getDI()->get('db')->escapeString($this->id).")");
}
Irrespective of the fact that I've explicitly defined an update, an insert is performed due to the Model being in a transient state.
One solution I thought of was to move the binary to GUID conversion into Phalcon by using Model events however I can't find a suitable method for performing the conversion when selecting. Updating/Inserting is possible by using the beforeSave() and beforeUpdate() events. Perhaps I could just have different properties getId() and getIdGuid() within the model but I would prefer to avoid this if possible.
Is there a way to use MySQL user defined routines in Phalcon and hydrate my model so that it remains in a persistent state? Or do i need to go down the raw SQL route for my updates and avoid PHQL?
Thanks in advance for your time.

Add row to Eloquent Collection by default based on raw query

In my Eloquent collections, I'd like to add an extra column called "editable". "Editable" should be included in each query I run on some models. "Editable" show either be true or false, based on a raw query.
So I have a query that should be runned in each query on my models. Adding an extra column to my collection. The value of "editable" is determined by a raw query.
What is the best way to do this?
You could add an addSelect() method to your query chain to include the custom attribute..
Something like
$results = YourModelClass::select("*")
->addSelect(DB::raw("IF(condition,1,0) AS editable"))
->get();
In the above case, you would replace condition with your relevant SQL statement that would be evaluated per-row as part of the query. If the statement is true, then editable = 1 and if false then editable = 0 for each row returned to your Collection.
EDIT: I just saw that you want this on every query, so you probably would need a global scope/trait for your models, but the above technique for including the extra attribute should be the correct one.
I won't copy/paste the documentation on adding global scopes, that's in the core Laravel docs and I'm sure you can find it.
You can add a custom getter to your model:
public function getEditableAttribute()
{
/* return result from your raw query here */;
}

How do I implement, for instance, "group membership" many-to-many in Parse.com REST Cloud Code?

A user can create groups
A group had to have created by a user
A user can belong to multiple groups
A group can have multiple users
I have something like the following:
Parse.Cloud.afterSave('Group', function(request) {
var creator = request.user;
var group = request.object;
var wasGroupCreated = group.existed;
if(wasGroupCreated) {
var hasCreatedRelation = creator.relation('hasCreated');
hasCreatedRelation.add(group);
var isAMemberOfRelation = creator.relation('isMemberOf');
isAMemberOfRelation.add(group);
creator.save();
}
});
Now when I GET user/me with include=isMemberOf,hasCreated, it returns me the user object but with the following:
hasCreated: {
__type: "Relation"
className: "Group"
},
isMemberOf: {
__type: "Relation"
className: "Group"
}
I'd like to have the group objects included in say, 'hasCreated' and 'isMemberOf' arrays. How do I pull that using the REST API?
More in general though, am I approaching this the right way? Thoughts? Help is much appreciated!
First off, existed is a function that returns true or false (in your case the wasGroupCreated variable is always going to be a reference to the function and will tis always evaluate to true). It probably isn't going to return what you expect anyway if you were using it correctly.
I think what you want is the isNew() function, though I would test if this works in the Parse.Cloud.afterSave() method as I haven't tried it there.
As for the second part of your question, you seem to want to use your Relations like Arrays. If you used an array instead (and the size was small enough), then you could just include the Group objects in the query (add include parameter set to isMemberOf for example in your REST query).
If you do want to stick to Relations, realise that you'll need to read up more in the documentation. In particular you'll need to query the Group object using a where expression that has a $relatedTo pointer for the user. To query in this manner, you will probably need a members property on the Group that is a relation to Users.
Something like this in your REST query might work (replace the objectId with the right User of course):
where={"$relatedTo":{"object":{"__type":"Pointer","className":"_User","objectId":"8TOXdXf3tz"},"key":"members"}}