Does sequelize have any change tracking built-in mechanism? - javascript

I was wondering whether sequelize implements (or plans to implement) any change tracking mechanism, which goal would be to avoid running unnecessary queries. For example:
var user = sequelize.User.find { where: { name: 'bob' } };
user.name = 'john';
user.save();
The sequelize will of course update the username. Now, imagine that the assignment is missing.
var user = sequelize.User.find { where: { name: 'bob' } };
user.save();
Is sequelize smart enough to figure it out that no database update is needed (and won't do one)? Is there any flag exposed by the sequelize object to see whether any changes were done to the model?
Or should I simply test by hand each property against the original model?
I have noticed an user._previousDataValues and user.options.isDirty properties on the sequelize model, but I am not sure what is their purpose and whether I should rely my code on those in any way.

You can call user.changed() to get an array of keys that have been changed. However, I think that calling .save() will trigger the save regardless if there has been a change in the instance.

Related

Sequelize .update() not using the correct where and updates all rows

I'm trying to create an approval command.
Everything about it, should be working, but it never works correctly.
I've changed my Database to have "id" first, but it still prefers to update on "user" instead.
I've tried having my code just be; but that never worked out. Even though I use it everywhere else.
await ticketApproval.update({status: 1});
I've checked documentation and other StackOverflow questions and answers.
Nothing has worked yet, but from what I can tell, nothing in my code should be telling it to update on the "user" id. Since I only ever tell it to search on the ticket "id" and "server" id
It feels like it's just outright ignoring the Where.
Code
Console
Test Sample
You clearly confuse the update method of a record instance with the static update of a model.
Only static update has the where option because it updates several records in DB using passed conditions in contrast to the instance update method that uses a primary key value of a certain record to update it with passed values.
Compare:
// here we have a model instance for a concrete record
const ticketApproval = await Ticket.findOne({
where: {
id: ticketToApprove
}
})
// by calling the instance `update` we always update this concrete record only
// using a primary key value condition, see a primary key field defined in a model
await ticketApproval.update({ status: 1 });
with
// by calling the static `update` we update all records that satisfy the indicated conditions
await Ticket.update({ status: 1 }, {
where: {
id: ticketToApprove
}
});

How to update an attribute object's attribute before running acceptance test?

First, we setup a scenario like so:
setupProject(server, []);
visit('/items');
This all works fine. The issue occurs when trying to update attributes of the current user prior to running the test.
Then update the current user with:
let user = server.create('user', 'organization', { enableManage: true });
This is intended to go to the specific user, go to an attribute object on that user called 'organization', and update an attribute of 'organization' called 'enableManage' to true.
Any help is appreciated.
You can always access Mirage's ORM via server.schema to mutate data in the database, prior to running a test.
let user = server.schema.users.find(1);
user.update({ organization: { enableManage: true });
That would update the organization property of this user record in the db.
If organization is an object you might want to do a clone, something like:
user.update({ organization: Object.assign(user.organization, { enableManage: true }));
By the way, depending on your API it looks like you might want to consider making organization a separate model, instead of a POJO that lives in each User's record.

createRecord with custom ID in emberjs 2.x and Firebase 3.x

Until now, I saved all my data with the following line of code:
saveUser(params) {
let newUser = this.store.createRecord('user', params);
newUser.save();
this.transitionTo('index');
This worked fine, but didn't allow for custom ID's in firebase, so I changed it into:
saveUser(params) {
let newUser = this.store.createRecord('user', {
id: params.loginId,
name: params.name,
nickname: params.nickname,
imageUrl: params.imageUrl,
email: params.email
});
newUser.save();
this.transitionTo('index');
Processes them exactly as I want them to be stored on the Firebase database, so no problem there. I'm wondering though, and not finding any solution on the web, how I can combine the two, so that I don't have to bind every param. It's bound to give problems when I add/remove model properties.
Something I'm looking for would look like this (pseudo, yes I tried it, didn't work!):
let newUser = this.store.createRecord('user', {id: params.loginId}, params);
In short, I'm looking for the dynamic properties of ('model', params), but with the option to manually adjust 1 (or more) records without having to type out all of the params.
Thanks in advance !
You will probably want to customize your serializer to accomplish this. The example in the docs is a good one, so it should be pretty straightforward: https://guides.emberjs.com/v2.13.0/models/customizing-serializers/
I am, of course, assuming you are using Ember Data for your models.

Using Apollo, how can I distinguish newly created objects?

My use case is the following:
I have a list of comments that I fetch using a GraphQL query. When the user writes a new comment, it gets submitted using a GraphQL mutation. Then I'm using updateQueries to append the new comment to the list.
In the UI, I want to highlight the newly created comments. I tried to add a property isNew: true on the new comment in mutationResult, but Apollo removes the property before saving it to the store (I assume that's because the isNew field isn't requested in the gql query).
Is there any way to achieve this?
Depends on what do you mean by "newly created objects". If it is authentication based application with users that can login, you can compare the create_date of comment with some last_online date of user. If the user is not forced to create an account, you can store such an information in local storage or cookies (when he/she last time visited the website).
On the other hand, if you think about real-time update of comments list, I would recommend you take a look at graphql-subscriptions with use of websockets. It provides you with reactivity in your user interface with use of pub-sub mechanism. Simple use case - whenever new comment is added to a post, every user/viewer is notified about that, the comment can be appended to the comments list and highlighted in a way you want it.
In order to achieve this, you could create a subscription called newCommentAdded, which client would subscribe to and every time a new comment is being created, the server side of the application would notify (publish) about that.
Simple implementation of such a case could look like that
const Subscription = new GraphQLObjectType({
name: 'Subscription',
fields: {
newCommentAdded: {
type: Comment, // this would be your GraphQLObject type for Comment
resolve: (root, args, context) => {
return root.comment;
}
}
}
});
// then create graphql schema with use of above defined subscription
const graphQLSchema = new GraphQLSchema({
query: Query, // your query object
mutation: Mutation, // your mutation object
subscription: Subscription
});
The above part is only the graphql-js part, however it is necessary to create a SubscriptionManager which uses the PubSub mechanism.
import { SubscriptionManager, PubSub } from 'graphql-subscriptions';
const pubSub = new PubSub();
const subscriptionManagerOptions = {
schema: graphQLSchema,
setupFunctions: {
newCommentAdded: (options, args) => {
newCommentAdded: {
filter: ( payload ) => {
// return true -> means that the subscrition will be published to the client side in every single case you call the 'publish' method
// here you can provide some conditions when to publish the result, like IDs of currently logged in user to whom you would publish the newly created comment
return true;
}
}
},
pubsub: pubSub
});
const subscriptionManager = new SubscriptionManager(subscriptionManagerOptions);
export { subscriptionManager, pubSub };
And the final step is to publish newly created comment to the client side when it is necessary, via above created SubscriptionManager instance. You could do that in the mutation method creating new comment, or wherever you need
// here newComment is your comment instance
subscriptionManager.publish( 'newCommentAdded', { comment: newComment } );
In order to make the pub-sub mechanism with use of websockets, it is necessary to create such a server alongside your main server. You can use the subscriptions-transport-ws module.
The biggest advantage of such a solution is that it provides reactivity in your application (real-time changes applied to comments list below post etc.). I hope that this might be a good choice for your use case.
I could see this being done a couple of ways. You are right that Apollo will strip the isNew value because it is not a part of your schema and is not listed in the queries selection set. I like to separate the concerns of the server data that is managed by apollo and the front-end application state that lends itself to using redux/flux or even more simply by managing it in your component's state.
Apollo gives you the option to supply your own redux store. You can allow apollo to manage its data fetching logic and then manage your own front-end state alongside it. Here is a write up discussing how you can do this: http://dev.apollodata.com/react/redux.html.
If you are using React, you might be able to use component lifecycle hooks to detect when new comments appear. This might be a bit of a hack but you could use componentWillReceiveProps to compare the new list of comments with the old list of comments, identify which are new, store that in the component state, and then invalidate them after a period of time using setTimeout.
componentWillReceiveProps(newProps) {
// Compute a diff.
const oldCommentIds = new Set(this.props.data.allComments.map(comment => comment.id));
const nextCommentIds = new Set(newProps.data.allComments.map(comment => comment.id));
const newCommentIds = new Set(
[...nextCommentIds].filter(commentId => !oldCommentIds.has(commentId))
);
this.setState({
newCommentIds
});
// invalidate after 1 second
const that = this;
setTimeout(() => {
that.setState({
newCommentIds: new Set()
})
}, 1000);
}
// Then somewhere in your render function have something like this.
render() {
...
{
this.props.data.allComments.map(comment => {
const isNew = this.state.newCommentIds.has(comment.id);
return <CommentComponent isNew={isNew} comment={comment} />
})
}
...
}
The code above was right off the cuff so you might need to play around a bit. Hope this helps :)

Fully virtual Mongoose schema, held in memory and not persisted

Can't find any docs or posts for this, which may indicate I'm trying to do something incorrect.
Is it possible to use a Mongoose schema that is entirely virtual, i.e. not persisted to the db?
I have a number of models, most of which are persisted to db, but would like to consistently include models that are only retained in memory, not persisted?
The closest I can come up with is along these lines, but it will still persist objects with only an id attribute in the database. Simplified here:
// access_token.js
var schema = mongoose.Schema({});
schema.virtual('token').get(function() {
return 'abcde12345';
});
module.exports = mongoose.model('AccessToken', schema);
The idea in doing this is to abstract models so that the consuming part of the app does not need to be aware of whether a model is persisted to the database or only held in memory. Of course this could be achieved by creating the same object and methods as a plain object, but that approach would quickly become repetitive.
You could override (monkey patch) the Mongoose methods which save data (e.g. .save) but I suspect what you are trying to do is difficult/impossible.
You could take a look at sift.js, which is a query library to do in-memory querying.
https://github.com/crcn/sift.js
You can set a pre middleware for this model which always fails.
schema.pre('save', function (next) {
next(new Error('This can't be saved!');
});
So you will know when you are doing wrong.

Categories