I'm being driven slowly mad by this issue.
Using a local Apollo Server instance being accessed by Apollo Studio, I am attempting a simple mutation, createUser, and this issue is arising. What have I misunderstood?
Am I incorrectly consuming the context I provided in the server's creation? Or incorrectly accessing this model, maybe? Not sure!
Here is the error showing in Apollo Studio, followed by my files:
{
"errors": [
{
"message": "Cannot read properties of undefined (reading 'findOne')",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"createUser"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"TypeError: Cannot read properties of undefined (reading 'findOne')",
" at Object.createUser (/Volumes/T7 Touch/Projects/PassTheArt/pass-the-art-server/graphql/resolvers/user.js:22:46)",
" at field.resolve (/Volumes/T7 Touch/Projects/PassTheArt/pass-the-art-server/node_modules/apollo-server-core/dist/utils/schemaInstrumentation.js:56:26)",
" at executeField (/Volumes/T7 Touch/Projects/PassTheArt/pass-the-art-server/node_modules/graphql/execution/execute.js:479:20)",
" at /Volumes/T7 Touch/Projects/PassTheArt/pass-the-art-server/node_modules/graphql/execution/execute.js:375:22",
" at promiseReduce (/Volumes/T7 Touch/Projects/PassTheArt/pass-the-art-server/node_modules/graphql/jsutils/promiseReduce.js:23:9)",
" at executeFieldsSerially (/Volumes/T7 Touch/Projects/PassTheArt/pass-the-art-server/node_modules/graphql/execution/execute.js:371:43)",
" at executeOperation (/Volumes/T7 Touch/Projects/PassTheArt/pass-the-art-server/node_modules/graphql/execution/execute.js:345:14)",
" at execute (/Volumes/T7 Touch/Projects/PassTheArt/pass-the-art-server/node_modules/graphql/execution/execute.js:136:20)",
" at execute (/Volumes/T7 Touch/Projects/PassTheArt/pass-the-art-server/node_modules/apollo-server-core/dist/requestPipeline.js:205:48)",
" at processGraphQLRequest (/Volumes/T7 Touch/Projects/PassTheArt/pass-the-art-server/node_modules/apollo-server-core/dist/requestPipeline.js:148:34)"
]
}
}
}
],
"data": null
}
// ./server.js
require('dotenv').config();
import express from 'express';
import db from './db';
import resolvers from './graphql/resolvers';
import typeDefs from './graphql/typeDefs';
import http from 'http';
import { ApolloServer } from 'apollo-server-express';
async function startApolloServer(){
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: true,
playground: true,
context: async() => {
return {
db
}
}
});
const app = express();
const httpServer = http.createServer(app);
server.start().then(res=>{
server.applyMiddleware({app, path: '/graphql'});
db.sequelize.sync({force: true}).then(async()=>{
console.log('database synced');
});
httpServer.listen({port: process.env.PORT}, ()=>{
console.log(`Apollo Server is ready at http://localhost:${process.env.PORT}/graphql`)
})
})
}
startApolloServer();
// ./graphql/resolvers/user.js
import { UserInputError } from "apollo-server-express";
import { Op } from "sequelize";
export default {
Query: {
// ! This query is for the logged in user
me: async(root, args, {db, me}, info) => {
const user = await db.user.findByPk(me.id);
return user;
},
// ! This query returns all users
users: async(root, args, {db}, info) => {
const users = await db.user.findAll();
if (!users) throw new Error('No users found')
return users;
}
},
Mutation: {
// ! This mutation creates a new user
createUser: async(root, {input}, {db}) => {
const {email} = input;
const userExists = await db.user.findOne({
where: {
[Op.eq]: [{email}]
}
})
if (userExists) {
throw new Error('A user with this email already exists');
}
const user = await db.user.create({
...input
});
return user;
},
// !
login: async(root, {email, password}, {db}, info) => {
const user = await db.user.findOne({
where: {email},
});
if(!user) throw new UserInputError(`User ${email} does not exist`);
const isValid = await user.validatePassword(password);
if(!isValid) throw new UserInputError(`Password is incorrect`);
return user;
}
}
}
// ./db.js
require('dotenv').config();
import fs from 'fs';
import path from 'path';
import { Sequelize } from 'sequelize';
const basename = path.basename(__filename);
const db = {};
const sequelize = new Sequelize(
process.env.POSTGRES_DB,
process.env.POSTGRES_USER,
process.env.POSTGRES_PASSWORD,
{
host: process.env.POSTGRES_HOST,
port: process.env.POSTGRES_PORT,
dialect: 'postgres'
}
);
sequelize.authenticate()
.then(console.log(()=>'Connection has been established successfully.'))
.catch(e=>console.error('Unable to connect to the database:', e));
const modelPath = path.join(__dirname, '/models');
fs.readdirSync(path.join(modelPath))
.filter((file)=>
file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js'
)
.forEach((file)=>{
const model = sequelize.define(path.join(modelPath, file));
db[model.name] = model;
});
Object.keys(db).forEach((modelName)=>{
if (db[modelName].associate){
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
export default db;
// ./models/User.js
import bcrypt from 'bcryptjs';
export default (sequelize, DataTypes) => {
const User = sequelize.define(
'user',
{
name: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: {
args: true,
msg: 'Invalid email'
},
},
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
freezeTableName: true,
},
);
User.findByLogin = async (login) => {
let user = await User.findOne({
where: {email: login},
});
return user;
};
User.beforeCreate(async (user) => {
if (user.password){
user.password = await user.generatePasswordHash();
}
});
User.prototype.updatePasswordHash = async function (password) {
const saltRounds = 10;
return await bcrypt.hash(password, saltRounds);
};
User.prototype.updatePasswordHash = async function () {
const saltRounds = 10;
return await bcrypt.hash(this.password, saltRounds);
};
User.prototype.validatePassword = async function (password) {
return await bcrypt.compare(password, this.password);
};
return User;
}
// ./graphql/typedefs/User.js
import { gql } from "apollo-server-express";
export default gql`
#---------------------------------------
# TYPES
#---------------------------------------
type User {
id: ID
name: String!
email: String!
}
#---------------------------------------
# QUERIES
#---------------------------------------
extend type Query {
me: User
users: [User!]
}
#---------------------------------------
# MUTATIONS
#---------------------------------------
extend type Mutation {
createUser(input: CreateUserInput!): User!
login(email: String!, password: String!): User!
logout: User!
}
#---------------------------------------
# MUTATIONS
#---------------------------------------
input CreateUserInput {
name: String!
email: String!
password: String!
}
`
You need to correct where option from
where: {
[Op.eq]: [{email}]
}
to
where: {
email
}
just like you did in the login mutation.
I managed to get db.user.findOne defined properly. I was not properly using sequelize.define() in db.js, and I have now rewritten the pesky section as such:
const modelPath = path.join(__dirname, '/models');
fs.readdirSync(path.join(modelPath))
.filter((file)=>
file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js'
)
.forEach((file)=>{
const modelFile = path.join(modelPath, file);
const modelExport = require(modelFile);
if (! modelExport) throw new Error ('Error accessing model declaration file: ', modelFile)
const model = modelExport.default(sequelize);
db[model.name] = model;
});
Related
Hello can somebody help me with this ? I was doing my controllers and I can access to my model like this "const { User } = require("../models/User");" but than when I send my request I had this message "TypeError: Cannot read property 'create' of undefined" so something was missing.
So I change my call model to this "const { User } = require("../models");".
And I went on my model index.js (so connection sequelize) and I add fs function and Objectif.key. After all those changes I have the error "No Sequelize instance passed".
So maybe somebody can help with this because I don't see the problem
So this is my model index.js
//sequelize importe
const fs = require("fs");
const path = require("path");
const Sequelize = require("sequelize");
const db = {};
const basename = path.basename(__filename);
let sequelize = new Sequelize("groupomania", "root", "root", {
host: "localhost",
dialect: "mysql",
});
sequelize
.authenticate()
.then(() => {
console.log("Connection has been established successfully!");
})
.catch((err) => {
console.log("Can't establish database connection:\n" + err);
});
fs.readdirSync(__dirname)
.filter((file) => {
console.log( file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js");
return (
file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js"
);
})
.forEach(file => {
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
db[model.name] = model;
});
Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
This is my model User.js
const { Model } = require("sequelize");
module.exports = (Sequelize, DataTypes) => {
class User extends Model {
toJSON() {
return {
...this.get(),
password: undefined,
};
}
}
User.init(
{
id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4 },
nom: { type: DataTypes.STRING, allowNull: false },
prenom: { type: DataTypes.STRING, allowNull: false },
email: {
type: DataTypes.STRING,
allowNull: false,
validate: { notNull: true, notEmpty: true, isEmail: true },
},
status: { type: DataTypes.STRING, allowNull: false },
password: { type: DataTypes.STRING, required: true },
},
{ Sequelize, tableName: "users", modelName: "User" }
);
return User;
};
My controllers/user.js
/*const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");*/
const { User } = require("../models/User");
module.exports.signup = async (req, res) => {
try {
const user = await User.create({
nom: "Jp",
prenom: "remy",
email: "remy#gmail.fr",
password: "motdepasse",
});
res.status(200);
throw Error("erreur est survenu");
} catch (erreur) {
console.log(erreur);
res.status(200).json({ erreur });
}
};
My route user
const express = require("express");
const router = express.Router();
const userCtrl = require("../controllers/user");
router.post("/signup", userCtrl.signup);
/*router.post("/login", userCtrl.login);*/
module.exports = router;
Thank you for any help! :)
The answer was that on my model user the "S" of sequelize must have an s minus
I am trying to implement signup, signin, getcurrentuser, getallusers functionalities.
except getllusers everything is working fine.
I have used JWT Token verification
help me out to find, how to query all users if a user is logged in
Resolvers
const { ApolloError, AuthenticationError } = require("apollo-server-express");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
const { generateToken } = require("../utils/index");
module.exports = {
Query: {
me(parent, args, { models, authUser }) {
return models.User.findByPk(authUser.id);
},
getAllUsers: async (parent, args, { models }) => {
const allUsers = await models.User.findAll();
console.log(allUsers);
return allUsers;
},
users: async (parent, args, { models }) => {
await models.User.findAll();
},
},
Mutation: {
async signUp(parent, { username, email, password }, { models }) {
const userExists = await models.User.findOne({ where: { email } });
if (userExists) {
throw new ApolloError("Email is already in use");
}
const user = await models.User.create({ username, email, password });
// ?console.log(token);
return { token: generateToken(user) };
},
async signIn(parent, { email, password }, context) {
const user = await context.models.User.findOne({ where: { email } });
if (!user) {
throw new AuthenticationError("Invalid Email");
}
const isPasswordValid = await bcrypt.compare(password, user.password);
if (!isPasswordValid) {
throw new AuthenticationError("Invalid Password");
}
return { token: generateToken(user) };
},
// async signIn(parent, { email, password }, { models }) {
// const user = await models.User.findOne({ where: { email } });
// if (!user) {
// throw new AuthenticationError("Invalid Email");
// }
// const isPasswordValid = await bcrypt.compare(password, user.password);
// if (!isPasswordValid) {
// throw new AuthenticationError("Invalid Password");
// }
// return { token: generateToken(user) };
// },
},
};
Type Defs
const { gql } = require("apollo-server-express");
module.exports = gql`
type User {
id: ID!
username: String!
email: String!
role: Role!
avatar: String
createdAt: DateTime!
updatedAt: DateTime!
}
enum Role {
ADMIN
USER
}
type Token {
token: String!
}
extend type Mutation {
signUp(username: String!, email: String!, password: String!): Token!
signIn(email: String!, password: String!): Token!
}
extend type Query {
getAllUsers: User
users: User
me: User!
}
`;
Here is my Index.JS file
My Headers
const express = require("express");
const { ApolloServer, gql } = require("apollo-server-express");
const models = require("./models");
const typeDefs = require("./typedefs");
const resolvers = require("./resolvers");
const { getAuthUser } = require("./utils");
const app = express();
const port = 5000;
Server Initializaation
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => {
const authUser = getAuthUser(req);
console.log("Auth User", authUser);
return { models, authUser };
},
});
server.applyMiddleware({ app, cors: true })
app.listen(port, () => console.log(`started at ${port} ${server.graphqlPath}`));
Not able to save the data in Google Datastore DB not getting any error, can somebody help me to find the fix
Console.log result as below
entityKey: Key { namespace: undefined, kind: 'User', path: [Getter] },
entityData:
{ firstname: 'Abcd',
lastname: 'Abcd',
email: 'abcd#gmail.com',
password: '123454',
createdOn: 'Abcd',
[Symbol(KEY)]: Key { namespace: undefined, kind: 'User', path: [Getter] } },
Ref - https://www.npmjs.com/package/gstore-node
const express = require('express');
const router = express.Router();
const { check, validationResult } = require('express-validator');
var User =require('../models/user');
//get register page
router.get('/register',function(req,res){
res.render('register')
});
//get login page
router.get('/login',function(req,res){
res.render('login')
});
router.post('/register', [
check('Name').isEmpty().withMessage('The Name is required'),
check('Email').isEmail().withMessage('Email is requried'),
//check('Password').isEmpty().withMessage('pass is requried'),
//check('Password','Password is Requried').isEmpty(),
// check('Password2','Password Not Match').equals('password2'),
], (req, res,next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
res.render('register',{
error:errors.mapped()
})
}else{
console.log()
const newUser = new User ({
firstname:req.body.name,
lastname:req.body.name,
email :req.body.Email,
password :req.body.Password,
createdOn:req.body.name
});
console.log("Data1",newUser)
const createUser = (req, res) => {
const entityData = User.sanitize(req.body);
const user = new User(entityData);
console.log("Data2",createUser)
user.save()
.then((entity) => {
res.json(entity.plain());
})
.catch((err) => {
// If there are any validation error on the schema
// they will be in this error object
res.status(400).json(err);
})
};
req.flash('success_msg','you are registered and can login now');
res.redirect('/users/login');
}
});
module.exports=router;
const { Gstore, instances } = require('gstore-node');
const { Datastore } = require('#google-cloud/datastore');
const gstore = new Gstore();
const datastore = new Datastore({
projectId: 'sinuous250616',
});
gstore.connect(datastore);
// Save the gstore instance
instances.set('unique-id', gstore);
const bcrypt = require('bcrypt');
// Retrieve the gstore instance
const ggstore = instances.get('unique-id');
const { Schema } = ggstore;
/**
* A custom validation function for an embedded entity
*/
const validateAccessList = (value, validator) => {
if (!Array.isArray(value)) {
return false;
}
return value.some((item) => {
const isValidIp = !validator.isEmpty(item.ip) && validator.isIP(item.ip, 4);
const isValidHostname = !validator.isEmpty(item.hostname);
return isValidHostname && isValidIp;
});
}
//Create the schema for the User Model
const userSchema = new Schema({
firstname: { type: String, required: true },
lastname: { type: String, optional: true },
email: { type: String, validate: 'isEmail', required: true },
password: { type: String, read: false, required: true },
createdOn: { type: String, default: gstore.defaultValues.NOW, write: false, read: false }
});
/**
* List entities query shortcut
*/
const listSettings = {
limit: 15,
order: { property: 'lastname' }
};
userSchema.queries('list', listSettings);
/**
* Pre "save" middleware
* Each time the entity is saved or updated, if there is a password passed, it will be hashed
*/
function hashPassword() {
// scope *this* is the entity instance
const _this = this;
const password = this.password;
if (!password) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
bcrypt.genSalt(5, function onSalt(err, salt) {
if (err) {
return reject(err);
};
bcrypt.hash(password, salt, null, function onHash(err, hash) {
if (err) {
// reject will *not* save the entity
return reject(err);
};
_this.password = hash;
// resolve to go to next middleware or save method
return resolve();
});
});
});
// add the "pre" middleware to the save method
userSchema.pre('save', hashPassword);
/**
* Export the User Model
* It will generate "User" entity kind in the Datastore
*/
module.exports = gstore.model('User', userSchema);
*I think there is a problem with User model **
You should have a User model like this in /models/user.js (put models at the root of your application) to define User:
const { instances } = require('gstore-node');
const bscrypt = require('bcrypt-nodejs');
// Retrieve the gstore instance
const gstore = instances.get('unique-id');
const { Schema } = gstore;
var usersSchema = new Schema({
firstname:{type:String},
lastname:{type:String},
email:{type:String},
password :{type:String},
createdOn: Date
})
var User = gstore.model('User', usersSchema);
module.exports = User;
And you forgot to use to save with save()
var newUser = new User ({
firstname:req.body.name,
lastname:req.body.name,
email :req.body.Email,
password :req.body.Password,
createdOn: new Date() // there is a problem here.... use new Date()
});
newUser.save(); //<======= it is abscent so it won't save
I am following this graphql tutorial, everything was going ok until I try to use dataloaders.
My server.js is:
const start = async () => {
const mongo = await connectMongo();
const buildOptions = async req => {
const user = await authenticate(req, mongo.Users);
return {
context: {
dataloaders: buildDataloaders(mongo),
mongo,
user
},
schema
};
};
app.use('/graphql', bodyParser.json(), graphqlExpress(buildOptions));
app.use(
'/graphiql',
graphiqlExpress({
endpointURL: '/graphql',
passHeader: `'Authorization': 'bearer token-name#email.com'`
})
);
app.use('/', expressStaticGzip('dist'));
app.use('/attendance', expressStaticGzip('dist'));
app.use('/login', expressStaticGzip('dist'));
spdy.createServer(sslOptions, app).listen(process.env.PORT || 8080, error => {
if (error) {
console.error(error);
return process.exit(1);
} else {
console.info(
`App available at https://localhost:${process.env.PORT || 3000}`
);
}
});
};
My copy and paste dataloaders.js:
const DataLoader = require('dataloader');
async function batchUsers(Users, keys) {
return await Users.find({ _id: { $in: keys } }).toArray();
}
module.exports = ({ Users }) => ({
userLoader: new DataLoader(keys => batchUsers(Users, keys), {
cacheKeyFn: key => key.toString()
})
});
And my resolvers.js:
export default {
Query: {
allLinks: async (root, data, { mongo: { Links } }) =>
Links.find({}).toArray()
},
Mutation: {
createLink: async (root, data, { mongo: { Links }, user }) => {
const newLink = Object.assign({ postedById: user && user._id }, data);
const response = await Links.insert(newLink);
return Object.assign({ id: response.insertedIds[0] }, newLink);
},
createUser: async (root, data, { mongo: { Users } }) => {
const newUser = {
name: data.name,
email: data.authProvider.email.email,
password: data.authProvider.email.password
};
const response = await Users.insert(newUser);
return Object.assign({ id: response.insertedIds[0] }, newUser);
},
signinUser: async (root, data, { mongo: { Users } }) => {
const user = await Users.findOne({ email: data.email.email });
if (data.email.password === user.password) {
return { token: `token-${user.email}`, user };
}
}
},
Link: {
id: root => root._id || root.id,
postedBy: async ({ postedById }, data, { dataloaders: { userLoader } }) => {
return await userLoader.load(postedById);
}
},
User: {
id: root => root._id || root.id
}
};
When I try get my allLinks I got the error:
TypeError: The loader.load() function must be called with a value,but
got: undefined.
Can anyone help me?
So I was able to reproduce the error by creating a link with a user, deleting the user from the Mongo database, and then querying for the postedBy attribute of the Link.
I would suggest dropping all your links and recreating your user (register + sign in), creating a new link, then querying for the postedBy field.
In my node app i am using sequelize as an ORM for my postgresql database.The following is my model:
User:
var bcrypt = require('bcrypt'),
crypto = require('crypto');
var authTypes = ['github', 'twitter', 'facebook', 'google'];
var map_attributes = function() {
var obj = new Object(),
ctx = this;
ctx.attributes.forEach(
function(attr) {
obj[attr] = ctx[attr];
});
return obj;
};
var validatePresenceOf = function(value) {
return value && value.length;
};
module.exports = function(sequelize, DataTypes) {
return sequelize.define('user', {
name: {
type: DataTypes.STRING,
validate: {
len: {
args: 1,
msg: "Name cannot be blank"
}
}
},
email: {
type: DataTypes.STRING,
validate: {
len: {
args: 1,
msg: "email cannot be blank"
}
}
},
username: {
type: DataTypes.STRING,
validate: {
len: {
args: 1,
msg: "username cannot be blank"
}
}
},
provider: DataTypes.STRING,
//hashed_password: String,
hashed_password: {
type: DataTypes.STRING,
set: function(v) {
var salt = bcrypt.genSaltSync(10);
var hash = bcrypt.hashSync(v, salt);
this.setDataValue('hashed_password', hash);
}
},
salt: DataTypes.STRING,
/*facebook: {},
twitter: {},
github: {},
google: {}*/
}, {
hooks: {
beforeValidate: function(next) {
if (!this.isNew) return next();
if (!validatePresenceOf(this.password) && authTypes.indexOf(this.provider) === -1) next(new Error('Invalid password'));
else next();
}
}
}, {
instanceMethods: {
authenticate: function(plainText) {
return this.encryptPassword(plainText) === this.hashed_password;
},
makeSalt: function() {
return Math.round((new Date().valueOf() * Math.random())) + '';
},
encryptPassword: function(password) {
if (!password) return '';
return crypto.createHmac('sha1', this.salt).update(password).digest('hex');
}
}
});
}
In this model i have to insert data into my database.How can i achieve this. I found this tutorial http://sequelizejs.com/docs/1.7.8/instances but its different from my design , here i am exporting the total model.Thanks in advance.
I tried for this:
index.js:
var Sequelize = require('sequelize');
var util = require('util');
var config = require('config').dbpostgres; // we use node-config to handle environments
// initialize database connection
var sequelize = new Sequelize(
config.dbname,
config.username,
config.password, {
dialect: 'postgres'
});
//var sequelize = new Sequelize('postgres://postgres:postgres#localhost:5432/Geocode', { dialect: 'postgres', protocol: 'postgres' });
// load models
var models = ['user'] //,'sciSphereModel', 'access_token', 'oauth_client', 'request_token', 'article'];
models.forEach(function(model) {
//console.log(model)
var sequelizeModel = sequelize.import(__dirname + '/' + model);
//console.log("seq=" + util.inspect(sequelizeModel));
//sequelizeModel.sync();
/*sequelizeModel.sync().success(function() {
console.log('DB error');
}).error(function(error) {
console.log(error);
})*/
sequelizeModel.sync();
//console.log("sequelizeModel=" + util.inspect(sequelizeModel))
var user = sequelizeModel.build({
name: 'kumar',
email: 'kumar#gmail.com',
username: 'kumar007',
provider: 'local',
hashed_password: 'tyegnaak',
salt: 'uopioann'
})
user.save().complete(function(err) {
console.log("Inside user save");
if ( !! err) {
console.log('The instance has not been saved:', err)
}
else {
console.log('We have a persisted instance now')
}
})
module.exports[model] = sequelizeModel; //Implement sync
});
// export connection
//sequelize.sync();
module.exports.sequelize = sequelize;
app.set('sequelize', sequelize);
Whether i am doing right?.Is this the way to achieve this?
Wouldn't it be sequelize.sync(); not sequelizeModel.sync(); because you'd want to syncronize any model changes with the db. You can also add force to your sync in case the table doesn't match your model.
sequelize.sync({ force: true }); // use to drop before create
I have never tried sync on a model, just create(), save(), find(), updateAttributes() etc.