Canjs model returns undefined after resolved - javascriptmvc

I cannot find a way to retrieve data from the server and convert them to model instance. I folloed the instructions here but it's still doesn't work.
Here is my setup:
url for the service: services/foo/barOne. The response is : {"calendar":1352793756534,"objectId":"id2"}
The model is defined as follow:
var myModel = can.Model(
model: function(raw) {
newObject = {id:raw.objectId};
return can.Model.model.call(this,newObject);
},
findOne: {
url: 'services/foo/barOne',
datatype: 'json'
}
)
And here is how I use that:
myBar = myModel.findOne()
myBar.then(function() {
console.log("resolved with arguments:",arguments); //[undefined]
})
I put various log and tracked all of function called, the request is correctly done, and the ajax resolved correctly. The model method is also correct and return an object of type Constructor with the right parameters.
But after that, inside the pipe function of canjs, the result is lost (ie, I got the result undefined when d.resolve.apply(d, arguments) is called)
What is wrong with this scenario ?
I am using canJS with jquery version 1.0.7

I don't think you need a custom converter just for changing the id. You can change it by setting the static id property. Try it like this:
var MyModel = can.Model({
id : 'objectId'
}, {
findOne: 'services/foo/barOne'
});
MyModel.findOne({ id : 'test' }).done(function(model) {
console.log(model);
});

Related

usage of classMethods vs instanceMethods in sequilizejs?

I am new to sequilizejs and basically am trying to refactor code that i've written in the controller and came across classMethods and instanceMethods. I see instance methods defined like so:
/lib/model/db/users.js
module.exports = function(sequelize, DataTypes) {
var instance_methods = get_instance_methods(sequelize);
var User = sequelize.define("User", {
email : {
type : DataTypes.STRING,
allowNull : false
},
}, {
classMethods: class_methods,
instanceMethods : instance_methods,
});
return User;
};
function get_instance_methods(sequelize) {
return {
is_my_password : function( password ) {
return sequelize.models.User.hashify_password( password ) === this.password;
},
};
function get_class_methods(sequelize) {
return {
hashify_password : function( password ) {
return crypto
.createHash('md5')
.update(
password + config.get('crypto_secret'),
(config.get('crypto_hash_encoding') || 'binary')
)
.digest('hex');
},
};
My understanding of the above is that classMethods are generic functions defined for the whole model and instanceMethods are basically a reference to a given row in a table/model, am i right in assuming this ? this would be my primary question.
Also i don't see any reference of classMethods and instanceMethods in the docs HERE. I only found this previous answer HERE. That provides a somewhat comprehensive understanding of the difference between instanceMethods and classMethods.
Basically i'am just trying to confirm weather my understanding matches the intended usage for class vs instance methods and also links to the official docs for the same would be highly appreciated.
The official way to add both static and instance methods is using classes like this:
class User extends Model {
static classLevelMethod() {
return 'foo';
}
instanceLevelMethod() {
return 'bar';
}
getFullname() {
return [this.firstname, this.lastname].join(' ');
}
}
User.init({
firstname: Sequelize.TEXT,
lastname: Sequelize.TEXT
}, { sequelize });
See Models as classes
Your understand is correct. In short: classes can have instances. Models are classes. So, Models can have instances. When working with an instance method, you will notice the this — which is the context, which refers to that particular class/model instance.
Hence, if you have a User model that has:
an instance method called is_my_password
a class model called hashify_password
User.hashify_password('123') will return the hashed version of 123. The User instance is not needed here. hashify_password is general function attached to the User model (class).
Now, if you'd like to call is_my_password() you do need a User instance:
User.findOne({...}).then(function (user) {
if (user.is_my_password('123')) {
// ^ Here we call `is_my_password` as a method of the user instance.
...
}
}).catch(console.error)
In general, when you have functions that do not need the particular model instance data, you will define them as class methods. They are static methods.
And when the function works with the instance data, you define it as instance method to make it easier and nicer to call.

how to make this axios delete request work?

I'm creating a bank app with react, node js and MongoDB.
The data is posted through 3 different inputs done by the user, but I'm having problems with the delete request. It is in 3 different classes (props passed accordingly). The error I'm getting says that it cannot read the property _id of undefined. The id is received from the DB. How can I make it work? Thanks in advance!
class App extends Component {
constructor() {
super()
this.state = {
transactions: []
}
}
deleteTransaction = async (transaction) => {
await axios.delete('http://localhost:8080/transaction', {data: {id: transaction._id }})
let response = await this.getTransactions()
this.setState({ transactions: response.data })
}
class Transactions extends Component {
deleteTransaction = () => { this.props.deleteTransaction() }
class Transaction extends Component {
<button onClick={this.props.deleteTransaction.bind(this)}><DeleteIcon /></button>
You don't need to use the bind when it is passed as a prop.
First, you have to remove the deleteTransaction function which is declared inside the Transactions component
Second, You have to pass the value the transaction argument in deleteTransaction function which is declared in App component
<button onClick={(event) => this.props.deleteTransaction(transaction)}><DeleteIcon/></button>
You haven't passed the value to the callback function which is why you are getting the cannot read the property _id of undefined. By default transaction argument value in deleteTransaction(App) is undefined. Since you haven't passed any value to the transaction argument, it works as expected.
Note:
Try to use React Context API whenever is possible which will avoid the prop drilling.

Node.js Testing with Mongoose. unique gets ignored

I'm having a little trouble with an integration test for my mongoose application. The problem is, that my unique setting gets constantly ignored. The Schema looks more or less like this (so no fancy stuff in there)
const RealmSchema:Schema = new mongoose.Schema({
Title : {
type : String,
required : true,
unique : true
},
SchemaVersion : {
type : String,
default : SchemaVersion,
enum: [ SchemaVersion ]
}
}, {
timestamps : {
createdAt : "Created",
updatedAt : "Updated"
}
});
It looks like basically all the rules set in the schema are beeing ignored. I can pass in a Number/Boolean where string was required. The only thing that is working is fields that have not been declared in the schema won't be saved to the db
First probable cause:
I have the feeling, that it might have to do with the way I test. I have multiple integration tests. After each one my database gets dropped (so I have the same condition for every test and precondition the database in that test).
Is is possible that the reason is my indices beeing droped with the database and not beeing reinitiated when the next text creates database and collection again? And if this is the case, how could I make sure that after every test I get an empty database that still respects all my schema settings?
Second probable cause:
I'm using TypeScript in this project. Maybe there is something wrong in defining the Schema and the Model. This is what i do.
1. Create the Schema (code from above)
2. Create an Interface for the model (where IRealmM extends the Interface for the use in mongoose)
import { SpecificAttributeSelect } from "../classes/class.specificAttribute.Select";
import { SpecificAttributeText } from "../classes/class.specificAttribute.Text";
import { Document } from "mongoose";
interface IRealm{
Title : String;
Attributes : (SpecificAttributeSelect | SpecificAttributeText)[];
}
interface IRealmM extends IRealm, Document {
}
export { IRealm, IRealmM }
3. Create the model
import { RealmSchema } from '../schemas/schema.Realm';
import { Model } from 'mongoose';
import { IRealmM } from '../interfaces/interface.realm';
// Apply Authentication Plugin and create Model
const RealmModel:Model<IRealmM> = mongoose.model('realm', RealmSchema);
// Export the Model
export { RealmModel }
Unique options is not a validator. Check out this link from Mongoose docs.
OK i finally figured it out. The key issue is described here
Mongoose Unique index not working!
Solstice333 states in his answer that ensureIndex is deprecated (a warning I have been getting for some time now, I thought it was still working though)
After adding .createIndexes() to the model leaving me with the following code it works (at least as far as I'm not testing. More on that after the code)
// Apply Authentication Plugin and create Model
const RealmModel:Model<IRealmM> = mongoose.model('realm', RealmSchema);
RealmModel.createIndexes();
Now the problem with this will be that the indexes are beeing set when you're connection is first established, but not if you drop the database in your process (which at least for me occurs after every integration test)
So in my tests the resetDatabase function will look like this to make sure all the indexes are set
const resetDatabase = done => {
if(mongoose.connection.readyState === 1){
mongoose.connection.db.dropDatabase( async () => {
await resetIndexes(mongoose.models);
done();
});
} else {
mongoose.connection.once('open', () => {
mongoose.connection.db.dropDatabase( async () => {
await resetIndexes(mongoose.models);
done();
});
});
}
};
const resetIndexes = async (Models:Object) => {
let indexesReset: any[] = [];
for(let key in Models){
indexesReset.push(Models[key].createIndexes());
}
Promise.all(indexesReset).then( () => {
return true;
});
}

Always fetch from related models in Bookshelf.js

I would like baffle.where({id: 1}).fetch() to always get typeName attribute as a part of baffle model, without fetching it from baffleType explicitly each time.
The following works for me but it seems that withRelated will load relations if baffle model is fetched directly, not by relation:
let baffle = bookshelf.Model.extend({
constructor: function() {
bookshelf.Model.apply(this, arguments);
this.on('fetching', function(model, attrs, options) {
options.withRelated = options.withRelated || [];
options.withRelated.push('type');
});
},
virtuals: {
typeName: {
get: function () {
return this.related('type').attributes.typeName;
}
}
},
type: function () {
return this.belongsTo(baffleType, 'type_id');
}
});
let baffleType = bookshelf.Model.extend({});
What is the proper way to do that?
Issue on repo is related to Fetched event, However Fetching event is working fine (v0.9.2).
So just for example if you have a 3rd model like
var Test = Bookshelf.model.extend({
tableName : 'test',
baffleField : function(){
return this.belongsTo(baffle)
}
})
and then do Test.forge().fetch({ withRelated : ['baffleField']}), fetching event on baffle will fire. However ORM will not include type (sub Related model) unless you specifically tell it to do so by
Test.forge().fetch({ withRelated : ['baffleField.type']})
However I would try to avoid this if it is making N Query for N records.
UPDATE 1
I was talking about same thing that you were doing on fetching event like
fetch: function fetch(options) {
var options = options || {}
options.withRelated = options.withRelated || [];
options.withRelated.push('type');
// Fetch uses all set attributes.
return this._doFetch(this.attributes, options);
}
in model.extend. However as you can see, this might fail on version changes.
This question is super old, but I'm answering anyway.
I solved this by just adding a new function, fetchFull, which keeps things pretty DRY.
let MyBaseModel = bookshelf.Model.extend({
fetchFull: function() {
let args;
if (this.constructor.withRelated) {
args = {withRelated: this.constructor.withRelated};
}
return this.fetch(args);
},
};
let MyModel = MyBaseModel.extend({
tableName: 'whatever',
}, {
withRelated: [
'relation1',
'relation1.related2'
]
}
);
Then whenever you're querying, you can either call Model.fetchFull() to load everything, or in cases where you don't want to take a performance hit, you can still resort to Model.fetch().

Mongoose default filter/query params for find()

If I have a collection of docs such as:
{
type: 'post',
text: 'example',
status: 'private' // or 'public'
}
What kind of middleware or schema config can I use to make sure that by default, Model.find() only returns docs where status != 'private' ?
I don't want to have to have to redundantly query for status != 'private' every single time I query the collection.
Thanks for the help!
You could try implement a wrapper method, e.g findNonPrivate(), to your model which you can then delegate to finding every document with status not equal to "private". Something like this:
var Model = mongoose.model('Model', theSchema);
Model.findNonPrivate = function (q, callback) {
q.status = q.status || {"$ne": "private"};
this.find(q, callback);
}
You could then get what you want with Model.findNonPrivate({}, callback).

Resources