How to get access to entity by his name? - node.js

I've got two projects based on single database. In the first project I've got every entities classes (with annotations like #Entity) but in second I don't have it and I can't use it. But I need to make an CRUD operations based on this entities.
So, how to use this entities based only on tables names?
I try like this:
this.entityManger.getRepository('user')
but it throw me this:
UnhandledPromiseRejectionWarning: EntityMetadataNotFoundError: No metadata for "user" was found.
my TypeORMConfig looks like this:
type: 'postgres',
url: this.dbURL(),
migrationsTransactionMode: 'each',
migrationsRun: true,
synchronize: true,
keepConnectionAlive: true,
can someone tell me how to connect to entity by only his name?
thanks for any help!

i'm not sure nest supports such a thing out of the box, but you can surly use the underlying TypeORM to do so:
import {getRepository} from "typeorm";
// later in your code
const userRepo = getRepository('users'); // assuming your table name is indeed 'users'
with the repo object you can do whatever you want as it is a TypeORM repository.
note that the type on this example is unknown so every object that comes from it will be of unknown type.
you can simply supply it with a type of your choice (or interface or simply any) to avoid further typing issues.

Related

Why is loopback throwing the error: The `ModelDefinition` instance is not valid

I am taking Strongloop for a spin. I am just trying the "Getting Started" tutorials, and the basic functionality one would typically want/need.
I am using Windows and PostgresSQL, so I created a new datasource and edited the model-config.json to change the built-in models datasource to this new one, lets call it lbdev.
After that I followed the docs section about creating the tables for the built-in models. The tables were created (everything looks fine in PgAdmin). I ran the explorer and the only public API (Users) is there, so far so good.
Next, using Arc I am trying to discover the models from the lbdev schema (with empty tables) but I get the following error for each table that is there:
Oops! Something is wrong
The ModelDefinition instance is not valid.
Details: name is not unique (value: "User").
Name: ValidationError
Message: The ModelDefinition instance is not valid. Details: name is not unique (value: "User").
Details: {"context":"ModelDefinition","codes":{"name":["uniqueness"]},"messages":{"name":["is not unique"]}}
Request: /workspace/api/DataSourceDefinitions/server.lbdev/createModel
status: 422
It is like it has already been done, but the Models tree in Arc is empty. Can someone shed some light over what is going on here?
Note: There is another post with a similar problem but very little info is provided so I created a new one.
Copying my comments into an answer...
I'm not sure why you are trying to discover models on that schema... are there other tables that already existed? If so, then you want to only pull those in, and not the tables that were auto-created from the built-in LoopBack models. If you try to "discover" the models that you just generated the tables from, then you will naturally have duplicate models (they are built-in, they already exist).
If you want to manage, extend, alter, whatever the built-in models then you need to create a new model and use whatever built-in model as the base:
// common/models/visitor.json
{
"name": "Visitor",
"base": "User",
// ... other options
"properties": {
// ... additional properties to those already on User
},
"acls": [
// ... additional ACLs to those on User... careful, these might overwrite built-in restrictions!
],
// ... other overwrites/additions
}

Associations in Sequelize migrations

My app currently uses the Sequelize sync() method to create the database, and I want to change it to use the migrations system.
One of my model has belongsTo() associations with other models, and I don't really know how to make the initial migration code for these associations.
Do I have to manually create the foreign key with SQL queries, or is there some methods available?
Case 1: Database initialization
If your purpose is to add relations during initialization of database structure it is better to just use sync method instead of manually adding them using migrations. If your models are properly designed and have relations defined, they will be created automatically during execution of sync method.
Take a look at sequelize express example. In models directory you have three files:
index.js - which includes all models
task.js - task model
user.js - user model
Look at task.js content, starting from line 7 the following code creates a relation between User and Task models:
classMethods: {
associate: function(models) {
Task.belongsTo(models.User, {
onDelete: "CASCADE",
foreignKey: {
allowNull: false
}
});
}
}
If you correctly prepare your relations in model files, sync will create the foreign keys for you. Migrations aren't necessary in this case.
I encourage you to read the whole express-example readme.md and browse repository files to see how the things work with express and sequelize.
Case 2: Database structure migration
In case you already have some data which you want to keep, you need to use migration script, because the only way for sync to restructure your database is to destroy it completely alongside with all its data.
You can read about basic migrations in the sequelize docs. Unfortunately docs do not cover creating a relation. Let's assume you want to create the following relation: User belongs to Group. To create column on the user side of relation, you may use addColumn method.
queryInterface.addColumn(
'user',
'group_id',
{
type: Sequelize.INTEGER,
allowNull: true
}
)
Unfortunately there isn't a nice function (yet) to create the foreign key constraint for you, but you can do it manually using sequelize query method. Postgresql example:
queryInterface.sequelize.query("ALTER TABLE user
ADD CONSTRAINT user_group_id_fkey FOREIGN KEY (group_id)
REFERENCES group (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE;");
Edit: Added database structure migration case
Adding this as an answer instead of a comment (not enough rep) for #aryeh-armon answer above. It's the table name that you need to make sure exists rather than the model name. i.e. if your model is named Job and your db table is named Jobs then the migration would look look like this instead.
jobId: {
type: Sequelize.INTEGER,
references: {
model: "Jobs",
key: "id"
}
},
you can add references to the migrations
Exmaple:
user_id: {
type: Sequelize.BIGINT,
references: {
model: "users",
key: "id"
}
},
Just make sure the model you are referencing exists.
After lots of searching, I found a couple of blog posts explaining what I wanted to do. The first one no longer exists, and here's the second one
Apparently it's not really the common way to do it, but it seems more logical to me. If you want to use only the migrations, you have to use SQL queries to create the initial migration.
But anyway, I think that ezpn is right about creating the initial database with sync, and then migrate. It seems easier than using umzug and only use migrations.

Using sequelize.js to interface against existing database?

I'm currently working in a project where our Node.js server will perform a lot of interactions against an existing MySQL database. Thus I'm wondering if Sequelize is a good library to interface the database. From what I've read about it, it is most often used as a master of the database. But in my case it will only have select,insert,delete access and not access to modify and create tables and so on. Does Sequelize support this method of interaction with a database?
If Sequelize does indeed work good for this, what settings do i need to disable to not run into much trouble? After reading their documentation i could not find any global settings to turn it into a simple interface tool. Timestamps and such could be disabled on table definition but not globally what I saw. Any input is greatly appreciated.
There are a lot of questions in this post, I'll try to answer them all:
Disable timestamps globally:
new Sequelize(... ,{
define: {
timestamps: false
}
});
You can pass any define options to the sequelize constructor and they will be applied to all calls to sequelize.define
Mapping to an existing database
I'll try to describe some common cases here:
I want my model to have a different name to my database table:
sequelize.define('name of model', attributes, {
tableName: 'name of table'
});
My database columns are called something different than the attributes in my model:
sequelize.define('name of model', {
name_of_attribute_in_model: {
type: ...
field: 'name of field in table'
}
});
My primary key is not called id:
sequelize.define('name of model', {
a_field_totally_not_called_id: {
primaryKey: true // also allows for composite primary keys, even though the support for composite keys accross associations is spotty
autoIncrement: true
}
});
My foreign keys are called something different
X.belongsTo(Y, { foreignKey: 'something_bla' });
disclaimer: I am a sequelize maintainer :). Overall I think we have pretty good support for working with legacy DBs. Feel free to ask more questions here or on irc://irc.freenode.net#sequelizejs

Database schema with sails.js and sails-postgresql

Is there any way to set database schema with sails-postgresql waterline adapter?
By default postgres adapter allways choose default public schema in database but I want to connect it to another schema.
For example I have database dev, schema test in database dev and table users in schema test.
Now I want to select all data from table users, in sql syntax I can simply write:
SELECT * FROM test.users
How to make it work in sails ?
When I write a model that uses postgres adapter, method Users.find() will look for the table users in default public schema. I want to change it to look in schema test without interactions with my postgres database.
Is it possible?
There is support for this, although it is as-yet undocumented. You can set the schema name for a model using the meta.schemaName property, eg:
module.exports = {
tableName: 'users',
meta: {
schemaName: 'test'
},
attributes: {
...
}
};
Update
It turns out this functionality was essentially broken for several versions, but it has been revamped and released in Sails-Postgresql v0.11.0. The syntax is the same as above. The main caveat is that it will not work with multiple Waterline models sharing the same tableName.
It appears that this is a bit buggy on the latest 1.0.3 version, but I found a way to accomplish it, by doing :
postgresql: {
adapter: require('sails-postgresql'),
url: 'postgresql://postgres:blablabla#localhost:5432/simplerp',
schemaName: 'radius',
}
On your config/datastores.js file.
Peace, out!

using _.omit on mongoose User in node.js

I have a mongoose User schema built like this:
var UserSchema = new Schema({
username: { type: String, required: true, index: { unique: true } },
password: { type: String, required: true },
salt: { type: String, required: true}
});
I want to be able to send this user object to the client side of my application but I don't want to sned the password or salt fields.
So I added he following code to my user model module
U
serSchema.methods.forClientSide = function() {
console.log('in UserSchema.methods.forClientSide');
console.log(this);
//var userForClientSide=_.omit(this,'passsword','salt');
var userForClientSide={_id:this._id, username:this.username };
console.log(userForClientSide);
return userForClientSide;
}
I have required the underscore module (its installed locally via a dependency in my package.js).
not the commented out line - I was expecting it to omit the password and salt fields of the user object but it did not do anything :( the logged object had the full set of properties.
when replaced with the currently used like var userForClientSide={_id:this._id, username:this.username }; it gets the results I want but:
1) I want to know why does the _.omit not work.
2) I don't like my current workaround very much because it actually selects some properties instead of omitting the ones I don't like so if I will add any new propertes to the scema I will have to add them here as well.
This is my first attempt at writing something using node.js/express/mongodb/mongoose etc. so It is very possible hat I am missing some other better solution to this issue (possibly some feature of mongoose ) feel free to educate me of the right way to do things like this.
so basically I want to know both what is the right way to do this and why did my way not work.
thanks
1) I want to know why does the _.omit not work.
Mongoose uses defineProperty and some heavy metaprogramming. If you want to use underscore, first call user.toJSON() to get a plain old javascript object that will work better with underscore without all the metaprogramming fanciness, functions, etc.
A better solution is to use mongo/mongoose's fields object and pass the string "-password -salt" and therefore just omit getting these back from mongo at all.
Another approach is to use the mongoose Transform (search for "tranform" on that page). Your use case is the EXACT use case the documentation uses as an example.
You can also make your mongoose queries "lean" by calling .lean() on your query, in which case you will get back plain javascript objects instead of mongoose model instances.
However, after trying each of these things, I'm personally coming to the opinion that there should be a separate collection for Account that has the login details and a User collection, which will make leaking the hashes extremely unlikely even by accident, but any of the above will work.

Resources