Giter VIP home page Giter VIP logo

moleculer-db's Introduction

Moleculer logo

Build Status Coverage Status Codacy Badge Maintainability Known Vulnerabilities Join the chat at https://gitter.im/moleculerjs/moleculer

Official DB addons for Moleculer framework

Generals

Name Version Description
moleculer-db NPM version Moleculer service to store entities in database
moleculer-db-adapter-couchdb-nano NPM version CouchDB Nano adapter for Moleculer DB service.
moleculer-db-adapter-mongo NPM version MongoDB native adapter for Moleculer DB service.
moleculer-db-adapter-mongoose NPM version Mongoose adapter for Moleculer DB service
moleculer-db-adapter-sequelize NPM version SQL adapter (Postgres, MySQL, SQLite & MSSQL) for Moleculer DB service
moleculer-db-adapter-prisma NPM version Prisma adapter for Moleculer DB service

Contribution

Install dependencies

$ npm run setup

Development

Run the simple example in moleculer-db service with watching

$ npm run dev moleculer-db

Run the full example in moleculer-db service w/o watching

$ npm run demo moleculer-db full

Test

$ npm test

Create a new addon

$ npm run init moleculer-<modulename>

Publish new releases

$ npm run release

License

The project is available under the MIT license.

Contact

Copyright (c) 2016-2022 MoleculerJS

@moleculerjs @MoleculerJS

moleculer-db's People

Contributors

0x0a0d avatar andremaz avatar bzd2000 avatar cintolas avatar dependabot[bot] avatar devalexandre avatar dkuida avatar embraser01 avatar freezystem avatar gcareri avatar giovanni-bertoncelli avatar grinat avatar guilhermedalleprane avatar icebob avatar jjgumucio avatar mariusbackes avatar mikegin avatar molobala avatar moonrailgun avatar mrkutin avatar noluckjustskill avatar russ666 avatar rzvdaniel avatar saeedtabrizi avatar snyk-bot avatar someone635 avatar thib3113 avatar ttrolololll avatar wradgio avatar zeeshanalisyed avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

moleculer-db's Issues

How to handle Reconnecting loop?

Hi, i am using the sequelize adapter and when I was testing invalid connection option, the broker calls the started() from the service DbService and does not stop, and if I create a DbService that merges and overrides the started func and when I trigger a reject for n count of attempts the broker stops.

How do I handle such infinite loop connecting to resolve? and does returning a reject does not trigger circuit breaker? or maybe can a broker stop loading that service and not halt everything and saying cant load all services.

Bug: mongodb adapter was not stopped when broker stop

When I stop the broker, the mongodb adapter was not stopped correctly, so although the test run successfully, it doesn't exit. I have to add the workaround code to my service:

  async stopped() {
    await this.adapter.client.close(true)
  }

Populate should accept either an array or a string

When I am populating it through the query params I have to add an additional blank attribute to make it an array

http://[ip]:[port]/users?populate=client&populate=

Otherwise, it will throw a validation exception.

[FEATURE REQUEST] - Inlcude multiple data entities for a single service

At present moleculer-db allows only for a single data model per service. There might be use cases where a service needs to manage multiple data entities (tables in a data schema).

Example:
Service: Access Control Service - a service managing role based access control for the stack.
Data Entities:

  • Roles: Access roles (e.g. administrator, user, super user, etc)
  • Role Groups: Grouping access roles together (e.g. finance, technical, marketing, etc)
  • Functions: System functions that users might have access to (e.g. edit Customer, delete account, etc)
  • Role Functions: Mapping Roles to Functions

Currently, I would have to create a service for each data entity, i.e. role-service, roleGroup-service, function-service, roleRunction-service.

Each of these services will then link to the underlying data table, using the model property of the service, e.g.:

model: {
    name: "roles",
    define: {
        _id: Sequelize.INTEGER,
        title: Sequelize.STRING,
        status: Sequelize.STRING
    }
}

Accessing the model methods:

this.model.findById(ctx.params.id)

It would be great if the model property could accept an array of model objects. Accessing these from the service, would look something like:

this.model.roles.findById(ctx.params.id)

Add support for upsert and upsertMany

In many cases it's desireable to have idemponent opreations that can be done against the database. Supporting upsert and upsertMany would blur the distinction between an insert and an update. To do this we also can't rely on the presence of an "ID" field to determine if a record already exists in the database or not. An alternate key is needed.

Warning: A promise was created but not returned from it

Hi

On line x498 in your moleculer-db/src/index.js file you do not return from the promise in case the if statement fails. Could you please add the following:

if (this.schema[eventName] != null) {
  return this.schema[eventName].call(this, json, ctx);
}
return; // <--- this

so that we do not get the warnings?

Thanks and best,
Michael

Getting error with updateById

When I call updateById method on mongo adpater , I get this error
Request error! MongoError : The _id field cannot be changed from {_id: ObjectId('5aa1785f6fabc20dccdaaabf')} to {_id: "5aa1785f6fabc20dccdaaabf"}.
Actually we need to passe _is without converting it to objectID
I did that in my code and the error disapeared but no update is done:

this.adapter.collection.findOneAndUpdate({ _id: (currentFolder._id/*string*/) }, currentFolder, { returnOriginal : false })

[moleculer-db] Error: Invalid value when I set search attribute in list method

var data = this.actions.list({	
	query: {
		role: ctx.params.role,
	},	
	fields: ["id", "username", 'firstName', 'lastName', 'birthday', 'idNumber', 'city' , 'district', 'ward', 		'address', 'email', 'managerId', 'companyId', 'typeUser', 'allowModule'],
	page: Number(ctx.params.page),
	pageSize: SETTING.Paginate.LIMIT_RECORD,
	search: 'Customer',	
	searchFields: ["username"]
})

I want to set search attribute and I have this error. I don't know how to fix?

Error: Invalid value { username: { '$like': '%Customer%' } }

how do i find a query?

I find moleculer-db is very confusing and frustrating, I am not sure but i can't make the database work as it's documented, i have to search for a domain in database but i am not getting the results i need:

this.broker.call('$database.service.get',{host : domain.params}).then(resolve) -> Unhandled rejection ValidationError: Parameters validation error!

tried this:
this.adapter.find({ host : domain.params }).then(resolve) - > return all list of hosts in array that looks like this:
[{host:'host1.com'},{host:''hotst2.com}] but i need to find one host not all of them.

tried this:
this.find({ query: { host: domain.params } }).then(resolve)
UnhandledPromiseRejectionWarning: TypeError: this.find is not a function

here is my service:

module.exports = {
    name      : "$database.service",
    adapter  : new db.MemoryAdapter({ filename :  'hosts.db' }),
    actions: {
        init (domain) {
          return new Promise((resolve) => {
            this.adapter.insert(domain.params);
            resolve();
          });
        },
        getDomain(domain){
          return new Promise((resolve) => {
             this.adapter.find({ host : domain.params }).then(resolve);
             //`this.broker.call('$database.service.get',{host : domain.params}).then(resolve) -> Unhandled rejection ValidationError: Parameters validation error!`;
             //this.find({ query: { host: domain.params } }).then(resolve) UnhandledPromiseRejectionWarning: TypeError: this.find is not a function
          });
        }
    }
}

Thank you

Moleculer with Cassandra

Hi,
I'm new in Moleculer. I want to build my project with Moleculer and Cassandra.
Is there any examples to create a DB Service which connect to Cassandra?
Thank you.

Mongo/Mongoose Adapter

It'd be really nice if I could create Mongo/Mongoose Adapters using a connection object instead of a connection string.

I want to create some mocha tests and today I have to keep a database running (in memory or full) to be able to connect to it.
By being able to initialise mongoose adapter using a connection, I could use mongoose-mock or some other mock api.

Relations in moleculer-sequelize?

I am just wondering how moleculer-sequelize adapter implements the relations for Sequelize?

As I understand the moleculer-db module, it only takes care of the CRUD operations to the DB, and everything else is taken care of in the service level (relationships). Is this true? if not, is there a way that this is handled by the adapter?

[moleculer-db] Add hooks support

All default action in moleculer-db try to call a before hook from the schema. If the action result promise resolved, try to call after hook from the schema.

{
    name: "project",

    settings: {...},

    actions: { ... },

    hooks: {
        before: {
            update(ctx) {
                // It will be called before `update` action called.
                // It can be return with Promise. If the returned promise 
                // rejected( or thrown an Error ), the `update` action 
                // won't be called!
            }
        },

        after: {
            create(ctx, model) {
                // It will be called after a project created.
            },

            remove(ctx, model) {
                // It will be called after a project removed.
            }
        }
    },

    methods: { ... }
}

Unable to get moleculer-db mongoose working

I'm running a very simple service, and I just can't get it to work, it just stops after 'Connected successfully...', no errors, it just stops, and I can't for the life of me figure out what is going on. Here's my test repo any help would be much appreciated.

$ node -v
v9.11.1
$ npm -v
5.8.0

Checking if value in array

Hi,
I'm fairly new to MoleculerDB, in my database I have a field like so participants: ["person 1 id", "person 2 id"] how would I check if a id is in the array?

Thanks,
Jamie

HTTP2 Support

Hello,
I would like add a request for enhancement HTTP 2 support protocol
Congratulations for this framework!

Not convenient to know what fields are updated in entityUpdated hook

I would like to use entityUpdated hook to define some side logic, such as 'auto set statusUpdatedAt status if status is changed', but the problem is, there is no right way to get the previous doc and diff out if status was changed.

By now I used a workaround looking for ctx.params, but that is not safe since there may be other update actions in the future which have different params definitions.

Every collection should has his service?

Hi @icebob
I just start new project and has question about using database with your framework.
How use moleculer-db correctly? I will have many services and some service should take some information from mongo store, but collections can be different.

How i can see when use this module i should make many services for every collection. No way for use one db service?

add multi tenant support

Allow support of multi tenants

In settings

{
  // this could be specific to the adapters
  tenantStrategy: {
    // if these keys are not preset we throw validation error
    // and based on tenant strategy we might have to add these to every query we make to db
    tenantKeys: ['accountId'], // or (config, params) => ['accountId']

    // for mongo adapter return new db
    getDB: (config, params) => config.client.db(`${config.collection}-${params.accountId}`),

    // for mongo adapter return new collection
    getCollection: (config, params) => config.db.collection(`${config.collection}-${params.accountId}`),

    // for mongoose
    getModel: (config, params) => config.model,

    // if exists will override the adapter find or update the params and call adapter's find
    find: () => null
    // ... other methods
  }
}

And tenant strategies can be implemented by the adapters itself, example incase of mongoose, whether to use that as shardKey or use a separate collection or use a separate db

moleculer-db-adapter-mongoose connect function resolves the Promise even when there is no connection established

The problem comes when the adapter-mongoose is used with multiple services which doesnt have dependencies between each other.

Service A

module.exports = {
	 name: "testA",
	  mixins: [DbService],
	  adapter: new MongooseAdapter("mongodb://localhost/test"),
	  model: ModelForServiceA,
	  afterConnected() {
		  this.logger.info("Connected successfully A...");
	  }
}

Service B

module.exports = {
   name: "testB",
   mixins: [DbService],
   adapter: new MongooseAdapter("mongodb://localhost/test"),
   model: ModelForServiceB,
   afterConnected() {
		this.logger.info("Connected successfully B...");
   }
}

if the mongodb server is down then Service B is going to report wrongly "Connected successfully B..." .
The reason was nailed to the connect function of MongooseDbAdapter :

connect() {
		let conn
		if (this.model) {
			if (mongoose.connection.readyState != 0) {
				this.db = mongoose.connection;
				return Promise.resolve();
			}

			conn = mongoose.connect(this.uri, this.opts);
		} else if (this.schema) {
			conn = mongoose.createConnection(this.uri, this.opts);
			this.model = conn.model(this.modelName, this.schema);
		}

		return conn.then(result => {
			this.db = result.connection || result.db;

			this.db.on("disconnected", function mongoDisconnected() {
				/* istanbul ignore next */
				this.service.logger.warn("Disconnected from MongoDB.");
			}.bind(this));
		});
}

while executing service B it checks for mongoose.connection.readyState and after readyState 2 = connecting the Promise resolves simply because the status is connecting.
However under normal connection behavior this function resolves only when the connection is established.
This provokes the function afterConnected to be executed while there is no connection established.
Is there any different way to solve this issue without setting a dependency between services or using the schema instead of the model ?

how can i use $and like mongodb ?

when i use this code :
this.adapter.find({ $and: [{ from: { $lt: 1005 } }, { to: { $gt: 1005 } }] });
returns all of objects in db but when i run this query in robomongo give me one object that i want. please help me I want just one object to return to me

Populate

Hello,

I'm trying to run this code sniped:

user.service.js

module.exports = {
    name: "user",
    mixins: [DbService],
    settings: {
        fields: ["name", "email", "_id"]
    },

    afterConnected() {
            this.broker.call("user.find").then((resp)=>{
                if (resp.length!=0) return;
                this.logger.info("Seed User Collection...");
                return this.adapter.insertMany(
                    [
                        { name: "John", email: "[email protected]", _id: '1' },
                        { name: "Adam", email: "[email protected]", _id: '2' },
                        { name: "Jane", email: "[email protected]", _id: '3' },
                        { name: "Susan", email: "[email protected]", _id: '4' },
                        { name: "Bill", email: "[email protected]", _id: '5' }
                    ])
            })
    }
}

permission.service.js

module.exports = {
    name: "permission",
    mixins: [DbService],
    settings: {
        fields: ["name", "level", "_id"]
    },

    afterConnected() {
        this.broker.call("permission.find").then((resp)=>{
            if (resp.length!=0) return;
            this.logger.info("Seed Permission Collection...");
            return this.adapter.insertMany(
                [
                    { name: 'Level 02', level: '2', _id: '1' },
                    { name: 'Level 01', level: '1', _id: '2' },
                    { name: 'Level 03', level: '3', _id: '3' }
                ])
        })
    }
}

user_x_permission.service.js

module.exports = {
    name: "user_x_permission",
    mixins: [DbService],
    settings: {
        fields: ["user_id", "permission_id"]
    },

    populates: {
        "user_id": {
            action: "user.get",
            params: {
                fields: ["name", "email"]
            }
        },
        "permission_id": {
            action: "permission.get",
            params: {
                fields: ["name", "level"]
            }
        }
    },

    afterConnected() {
        this.broker.call("user_x_permission.find").then((resp)=>{
            if (resp.length!=0) return;
            this.logger.info("Seed UserPermission Collection...");
            return this.adapter.insertMany(
                [
                    { user_id: "2", permission_id: "1" },
                    { user_id: "1", permission_id: "2" },
                    { user_id: "3", permission_id: "3" }
                ])
        });
    }
}

And then:

broker.call("user_x_permission.find",{populate:["user_id"]}).then((resp)=>{ console.log(resp); }

And my response is:

[ { user_id: '3', permission_id: '3' }, { user_id: '1', permission_id: '2' }, { user_id: '2', permission_id: '1' } ]

Should not 'user_id' be populated? What I'm missing? I ran your sample and the result is correct, but on my service didn't get the populate to work.

Missing typings for `moleculer-db` packages

Hi @icebob .

I see there is no d.ts files in the repo. Also, there are no @types/* packages for that.

I've bootstrapped them in my project via dts-gen but they look not really well.

Will you mind to add them? Or should I create a PR with those crappy dts-gen samples?

How to Populating one to many in mysql

Suppose I have a user and post table. The post will contain the user's foreign key
I want to retrieve a user record with all the users' post

AND

How can I change properties populate when merging?
I want to populate by author_id. however after merging I want to change author_id to author

origin

{
 "title":"this is title post",
 "author_id":{ ... }
}

expect

{
 "title":"this is title post",
 "author":{ ... }
}

Import model from model folder

With node and sequelize a can define all my models in another folder in different files and it's extremely comfortable.
Could I import my model.js and use it in service.js file? like model: myModel ? How to do it? I don't want to keep my models and logic in one trash file.

Issue with ObjectId fields

Hello,

I have not found any smart issue to manage this problem, the adapter changes the _id field as string, but I have also other ObjectId fields (some references to other collections) and they are not converted to string, so I need to call a toString() for doing other queries, but moleculer validation prevents to call service.getusing an object id or with null values.

My database has some optional references to other entities, so there are null values. I think that is not possible to manage directly, because validator throws an error...

Example

Thanks to everyone :)

[2018-07-10T11:11:26.843Z] INFO  mac-mini-di-andrea.local-20730/TEST: test.save STARTING...
[2018-07-10T11:11:26.853Z] INFO  mac-mini-di-andrea.local-20730/TEST: test.save: { _id: '5b44945e0362e150fa37a60d', _idType: 'string', field: 000000000000000000000001, fieldType: 'object', fieldString: '000000000000000000000001', fieldStringType: 'string' }
[2018-07-10T11:11:26.857Z] INFO  mac-mini-di-andrea.local-20730/TEST: test.save - forcing validation error, using an object for doing: broker.call("test.get", { _id: test.field });
Error occured! Parameters validation error!

"populateDocs" function incorrectly validates "docs" parameter type

In src/index.js, the populateDocs(ctx, docs, populateFields) function validates the docs parameter using:
if (docs == null || !_.isObject(docs) || !Array.isArray(docs))

This makes it so that docs must be an Array, not accepting docs as an Object.
I believe the correct validation should be something like:
if (docs == null || !_.isObject(docs) && !Array.isArray(docs))

Reverse populate?

Hi,
We can populate by using a value from a particular field, how would we populate if we didn't have that field? E.g. I have two databases conversations and messages where messages references a conversation although if I wanted to get the messages for a conversation that is a different story.
Is there a way around this?

Thanks,
Jamie

Sequelize methods support

Right now, if I define a class method inside the options object of my model (say a search method), it throws an exception when I try to access it through this.model.search.

Am I missing something or using it incorrectly way?

Custom entityValidator with function

I'm using a custom Joi validator that not just validate the instance but also fix the object with defaults, conversions and etc.

I'm trying to create the entityValidator using a function, like...

entityValidator: function(entity) {
  // do whatever
  return entity;
},

However it's not respecting the custom function because a function is a subtype of object, following the snippet.

if (this.broker.validator && _.isObject(this.settings.entityValidator)) {
  const check = this.broker.validator.compile(this.settings.entityValidator);
  this.settings.entityValidator = entity => {
    const res = check(entity);
    if (res === true)
      return Promise.resolve();
    else
      return Promise.reject(new ValidationError("Entity validation error!", null, res));
  };
}

Then, it creates a function wrapping my custom function, which of course is wrong.

EDITED
I believe it's necessary to add !_.isFunction(this.settings.entityValidator) and keep the _.isObject(this.settings.entityValidator) for compatibility reasons

Tks

[Proposal] transform in settings

Currently there are populate and entityValidator which could be used for similar purpose, but it looks like kind of a hack to use it to transform entities.

The general idea here is to be able:

  1. To transform input object to object like how it should look in DB. Example, user object, it might arrive with password, but what we want to save to DB is salt and hash and not password field. This is possible with entityValidator, but this sounds like a hack. - I was able to figure it out by looking into source code of entityValidator since it is using .map on array, but it should use .every.

  2. To transform output object to something else. Example to remove hash and salt fields could be achieved by filtering fields, which is cool, but in case we just want to transform it somehow differently its getting hard and using populate for it is more like a hack.


Proposal is to:

  1. Make entityValidator(or just validator) only do validation, and not transforming
  2. Add entityTransformer(or just transformer): { in: function, out: function }

Not sure what exactly needs to be done, but can write some proposal.

moleculer-db + moleculer-web

Hi. I've encountered an issue when using fields param through moleculer-webs query: it seems it's not possible to pass only one field into fields - that leads to an error

{
    "name": "ValidationError",
    "message": "Parameters validation error!",
    "code": 422,
    "type": "VALIDATION_ERROR",
    "data": [
        {
            "type": "array",
            "field": "fields",
            "message": "The 'fields' field must be an array!"
        }
    ]
}

To avoid that client can use something like http://my.host/endpoint?fields=foo&fields
but that doesn't look right.

That is caused by the fact that fields are defined as array and how the qs is parsing the query string.

Any thoughts on that?

Multiple Execute

Hi, Is multiple query execute normal? 2 tables, executes total of 12 which is repeated. Just wondering what if this has 20+ tables then it would "probably" executes total of 120? Sorry for being such a noob :) Please, see log below:

> [email protected] dev /Volumes/KB/projects/t1/micro
> moleculer-runner --repl --hot services

[2018-09-08T00:41:27.667Z] INFO  dev-macbook-pro.local-40732/BROKER: Moleculer v0.12.8 is starting...
[2018-09-08T00:41:27.670Z] INFO  dev-macbook-pro.local-40732/BROKER: Node ID: dev-macbook-pro.local-40732
[2018-09-08T00:41:27.671Z] INFO  dev-macbook-pro.local-40732/BROKER: Namespace: <not defined>
[2018-09-08T00:41:27.671Z] INFO  dev-macbook-pro.local-40732/REGISTRY: Strategy: RoundRobinStrategy
[2018-09-08T00:41:27.685Z] INFO  dev-macbook-pro.local-40732/REGISTRY: '$node' service is registered.
[2018-09-08T00:41:27.821Z] INFO  dev-macbook-pro.local-40732/REGISTRY: 'api' service is registered.
[2018-09-08T00:41:27.822Z] INFO  dev-macbook-pro.local-40732/API: Register route to '/'
[2018-09-08T00:41:27.855Z] INFO  dev-macbook-pro.local-40732/API: API Gateway created!
[2018-09-08T00:41:27.857Z] INFO  dev-macbook-pro.local-40732/REGISTRY: 'greeter' service is registered.
[2018-09-08T00:41:28.086Z] INFO  dev-macbook-pro.local-40732/REGISTRY: 'profiles' service is registered.
[2018-09-08T00:41:28.087Z] INFO  dev-macbook-pro.local-40732/REGISTRY: 'server' service is registered.
[2018-09-08T00:41:28.099Z] INFO  dev-macbook-pro.local-40732/REGISTRY: 'users' service is registered.

sequelize deprecated String based operators are now deprecated. Please use Symbol based operators for better security, read more at http://docs.sequelizejs.com/manual/tutorial/querying.html#operators node_modules/sequelize/lib/sequelize.js:242:13
[2018-09-08T00:41:28.217Z] INFO  dev-macbook-pro.local-40732/API: API Gateway listening on http://0.0.0.0:3000
Executing (default): SELECT 1+1 AS result
Executing (default): SELECT 1+1 AS result
Executing (default): CREATE TABLE IF NOT EXISTS `account_profiles` (`id` INTEGER NOT NULL auto_increment , `user_id` INTEGER, `firstname` VARCHAR(255), `lastname` VARCHAR(255), `phone` VARCHAR(255), `gender` VARCHAR(255), `dob` DATETIME, `address` VARCHAR(255), `city` VARCHAR(255), `state` VARCHAR(255), `zipcode` VARCHAR(255), `timezone` VARCHAR(255), `avatar` VARCHAR(255), `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): CREATE TABLE IF NOT EXISTS `users` (`id` INTEGER NOT NULL auto_increment , `name` VARCHAR(255), `email` VARCHAR(255), `deleted_at` DATETIME, `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `account_profiles`
Executing (default): SHOW INDEX FROM `users`
Executing (default): SELECT 1+1 AS result
Executing (default): SELECT 1+1 AS result
Executing (default): CREATE TABLE IF NOT EXISTS `account_profiles` (`id` INTEGER NOT NULL auto_increment , `user_id` INTEGER, `firstname` VARCHAR(255), `lastname` VARCHAR(255), `phone` VARCHAR(255), `gender` VARCHAR(255), `dob` DATETIME, `address` VARCHAR(255), `city` VARCHAR(255), `state` VARCHAR(255), `zipcode` VARCHAR(255), `timezone` VARCHAR(255), `avatar` VARCHAR(255), `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): CREATE TABLE IF NOT EXISTS `users` (`id` INTEGER NOT NULL auto_increment , `name` VARCHAR(255), `email` VARCHAR(255), `deleted_at` DATETIME, `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `account_profiles`
Executing (default): SHOW INDEX FROM `users`

[2018-09-08T00:41:28.318Z] INFO  dev-macbook-pro.local-40732/BROKER: ServiceBroker with 6 service(s) is started successfully.
mol $ q
mol $ [2018-09-08T00:41:31.157Z] INFO  dev-macbook-pro.local-40732/API: API Gateway stopped!
[2018-09-08T00:41:31.159Z] INFO  dev-macbook-pro.local-40732/BROKER: ServiceBroker is stopped successfully. Good bye.

Problems with cache

When I have a version in my service the clearCache doesn't work anymore.

The problem in the code

/**
 * Clear cached entities
 *
 * @methods
 * @returns {Promise}
 */
clearCache() {
    var version = this.version ? this.version + '.' : '';
    this.broker.broadcast(`cache.clean.${version}${this.name}`);
    if (this.broker.cacher) {
        // version is missing
        
        this.broker.cacher.clean(`${version}${this.name}.*`);
    }
    return Promise.resolve();
},

Misleading connection options documentation

In your README.md file you describe the Example with connection options as follows:

new MongooseAdapter({
    uri: "mongodb://db-server-hostname/my-db",
    options: {
        user: process.env.MONGO_USERNAME,
        pass: process.env.MONGO_PASSWORD
        server: {
            socketOptions: {
                keepAlive: 1
            }
        }
    })

However, in your source code you access the options as opts:

	/**
	 * Connect to database
	 *
	 * @returns {Promise}
	 *
	 * @memberof MongooseDbAdapter
	 */
	connect() {
		let uri, opts, conn;
		if (_.isObject(this.opts) && this.opts.uri != null) {
			uri = this.opts.uri;
			opts = this.opts.opts; // opts or options???
		} else {
			uri = this.opts;
		}

		if (this.model) {
			/* istanbul ignore next */
			if (mongoose.connection.readyState != 0) {
				this.db = mongoose.connection;
				return Promise.resolve();
			}

			conn = mongoose.connect(uri, opts);
		} else if (this.schema) {
			conn = mongoose.createConnection(uri, opts);
			this.model = conn.model(this.modelName, this.schema);
		}

		return conn.then(result => {
			this.db = conn.connection || result.db;

			this.db.on("disconnected", function mongoDisconnected() {
				/* istanbul ignore next */
				this.service.logger.warn("Disconnected from MongoDB.");
			}.bind(this));
		});
	}

Please consolidate the documentation.

Thank you.

Setting `idField`is not working properly

The setting idFieldis not working properly.

Steps to reproduce

'use strict'

const { ServiceBroker } = require('moleculer')
const DbService = require('moleculer-db')

const broker = new ServiceBroker()

// Create a DB service for `user` entities
broker.createService({
  name: 'users',
  mixins: [DbService],

  settings: {
    idField: 'myCustomIDField'
  }
})

let newEntry = {
  myCustomIDField: '123456789',
  username: 'john',
  name: 'John Doe',
  status: 1
}

broker.start()
  .then(() => broker.call('users.create', { ...newEntry }))
  .then(() => broker.call('users.find', {}))
  .then(res => console.log(res))

Exptected Result

[ { "username": "john",
    "name": "John Doe",
    "status": 1,
    "myCustomIDField": "123456789'"} ]

Actual Result

[ { "myCustomIDField": "123456789",
    "username": "john",
    "name": "John Doe",
    "status": 1,
    "_id": "ch1O9ghyjFYStlpW" } ]

Problem Location
In actions.create the entity is inserted without checking if it has any idField as ID

create: {
handler(ctx) {
let entity = ctx.params;
return this.validateEntity(entity)
.then(entity => this.adapter.insert(entity))

In methods.transformDocuments the _id field is not transformed into the idField

// Encode IDs
.then(docs => docs.map(doc => {
doc[this.settings.idField] = this.encodeID(doc[this.settings.idField]);
return doc;
}))

Merge adapter codes to the main repo

Due to #21, we should remove adapter dependencies (mongodb, mongoose, sequelize), because it doesn't work with different versions (when you use a version which is not exactly what adapter uses).

In this case, we can merge short adapter codes to the moleculer-db repo.

Example to use DB service with mongoose adapter:

$ npm install moleculer-db mongoose
const DbService = require("moleculer-db");
const MongooseAdapter = DbService.Adapters.Mongoose;
const mongoose = require("mongoose");

module.exports = {
	name: "posts",
	mixins: [DBService],
	adapter: MongooseAdapter("mongodb://..."),
	model: mongoose.model("Post", mongoose.Schema({
        title: { type: String },
        content: { type: String },
        votes: { type: Number, default: 0}
    }))
}

ctx params not updated in async update in before hooks

The ctx values are updated inside the update hook but the ctx changes are not reflected on the update action. Hence, the data written to DB is not updated.

hooks: {
  before: {
    update: async function (ctx) {
      /** await call here **/
      ctx.params.data = { foo: 'bar' }
      return
    }
  }
}

Extend with custom actions use sequelize adapter

Examples of extend with custom actions in moleculer manual is:

const DbService = require("moleculer-db");

module.exports = {
    name: "posts",
    mixins: [DbService],

    settings: {
        fields: ["_id", "title", "content", "votes"]
    },

    actions: {
        // Increment `votes` field by post ID
        vote(ctx) {
            return this.adapter.updateById(ctx.params.id, { $inc: { votes: 1 } });
        },

        // List posts of an author
        byAuthors(ctx) {
            return this.find({
                query: {
                    author: ctx.params.authorID
                },
                limit: ctx.params.limit || 10,
                sort: "-createdAt"
            });
        }
    }
}

Examples of Sequelize Adapter in moleculer manual is:

"use strict";

const { ServiceBroker } = require("moleculer");
const DbService = require("moleculer-db");
const SqlAdapter = require("moleculer-db-adapter-sequelize");
const Sequelize = require("sequelize");

const broker = new ServiceBroker();

// Create a Sequelize service for `post` entities
broker.createService({
    name: "posts",
    mixins: [DbService],
    adapter: new SqlAdapter("sqlite://:memory:"),
    model: {
        name: "post",
        define: {
            title: Sequelize.STRING,
            content: Sequelize.TEXT,
            votes: Sequelize.INTEGER,
            author: Sequelize.INTEGER,
            status: Sequelize.BOOLEAN
        },
        options: {
            // Options from http://docs.sequelizejs.com/manual/tutorial/models-definition.html
        }
    },
});


broker.start()
// Create a new post
.then(() => broker.call("posts.create", {
    title: "My first post",
    content: "Lorem ipsum...",
    votes: 0
}))

// Get all posts
.then(() => broker.call("posts.find").then(console.log));

If I want extend with custom actions use sequelize adapter, what should we do?

global broker / when i start my project with runner

i was looking a way to get a global broker to use it in Model pre/post hooks, after i ran the project with the moleculer-runner which is the recommended way to do it so. I have not found how to get to the broker, since when i create a new one it cant see the other nodes even with the same namespace and transport.

is there a way?.

How to populate by default?

Hello,

can I populate without explicit set populate in find, list and get actions?

Populate fields already in settings, i want to populate this fields by default.

Mongoose Adapter / Timeout on unique duplicate.

I have this problem, i ran my microservices ecosystem with mongo-db-mongoose-adapter and, whenever i try to save a document with an existent unique key, it logs an error, but the api never responds.

captura de pantalla 2019-03-04 a la s 2 46 45

is there a way to catch it ?.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.