Giter Site home page Giter Site logo

moleculer-decorators's People

Contributors

colonelbundy avatar d0whc3r avatar davidfrtala avatar dependabot[bot] avatar dkuida 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

Watchers

 avatar  avatar  avatar  avatar  avatar

moleculer-decorators's Issues

moleculer-db lifecycle functions are excluded

I have a problem, with moleculer-db mixed into one of my services. moleculer-db contains lifecycle entity functions, that aren't actions, methods or events. They are global in the same way as created(), started() and stopped() functions.

Namely

    afterConnected() {
        ...
    },

    entityCreated(json, ctx) {
        ...
    },

    entityUpdated(json, ctx) {
        ...
    },

    entityRemoved(json, ctx) {
        ...
    },  

And the problem is, that when I use db adapter, the moment when it connects to database, it's calling a function, which doesn't exists in the schema under this.schema.afterConnected

https://github.com/moleculerjs/moleculer-db/blob/b80c01bf1e4f6e4aae38f67b203bb58e428632b7/packages/moleculer-db/src/index.js#L389

and therefore, this service and its lifecycle db event won't trigger

@Service({
  name: "users",
  mixins: [DbService],
  adapter: new MongooseDbAdapter(process.env.MONGO_URI),
  model: UserModel
})
class UsersService extends BaseSchema {
  ...

  public async afterConnected() {
    const count = await this.adapter.count();
    if (count === 0) {
      await this.seedDB();
    } else {
      this.logger.info(`${count} users in DB. Skipping seed...`);
    }
  }
}

tsc npm package

image

Hi @ColonelBundy , I think you forgot to compile the package for couple of recent releases?

Nice work on this project btw, thanks for your contribution.

Please respect the semver versioning scheme

Hi @ColonelBundy this is not an bug issue but just wanna ask you to follow the right semver versioning scheme when releasing breaking changes, such as the recent merged PR from #13.

This PR created breaking change, released under patches 1.0.21 -> 1.0.22, causing our CI/CD process to fail....

Again thanks for the hard work on this module but respect the versioning scheme pls <3

Error while run unit test with moleculer-cli generated project

i am trying to make an es7 template project with moleculer-cli generated project .now it can run with npm run dev without error,
but it can't pass npm test , with errors:

   Test 'products' service  Test hooks  encountered a declaration exception

    ServiceSchemaError: Service name can't be empty! Maybe it is not a valid Service schema. Maybe is it not a service schema?

      4 | const DbMixin = require("../mixins/db.mixin");
      5 | 
    > 6 | @Service({
        | ^
      7 |       name: 'products',
      8 |       // constructOverride: false,
      9 |       // skipHandler: true,

      at Object.parseServiceSchema (../node_modules/moleculer/src/service.js:92:10)
      at new Service (../node_modules/moleculer/src/service.js:63:9)
      at new ProductsService (products.service.js:6:1)
      at new <anonymous> (../node_modules/moleculer-decorators/dist/index.js:128:9)
      at ServiceBroker.createService (../node_modules/moleculer/src/service-broker.js:801:14)
      at Suite.<anonymous> (../test/unit/services/products.spec.js:149:10)
      at Suite.<anonymous> (../test/unit/services/products.spec.js:146:2)
      at Object.<anonymous> (../test/unit/services/products.spec.js:9:1)

the error was begin from :

products.spec.js

...
describe("Test hooks", () => {
		const broker = new ServiceBroker({ logger: false });
		const createActionFn = jest.fn();
		broker.createService(TestService, { // <- error start from here, while it try to merge mock action to TestService Schema
			actions: {
				create: {
					handler: createActionFn
				}
			}
		});
...
}

and createService run into :

...
createService(schema, schemaMods) {
		let service;
		schema = this.normalizeSchemaConstructor(schema);
		if (Object.prototype.isPrototypeOf.call(this.ServiceFactory, schema)) {
			service = new schema(this, schemaMods); // <- run into here to new Decoratored Schema, but it with schemaMods, this is why it throws error , beacause `new service(broker, schemaMods)` will call parseServiceSchema, it will check name of schemaMods , but shemaMods don't have name properties. see bellow code . 
		} else {
			let s = schema;
			
			if (schemaMods)
				s = this.ServiceFactory.mergeSchemas(schema, schemaMods);
			console.log('s', s);
			service = new this.ServiceFactory(this, s);
		}
}
...

i notice that , moleculer-decorators return Service as :

return class extends parentService.constructor {
      constructor(broker, schema) { //  <- new schema(this, schemaMods) 
        super(broker, schema); // <- here, it will call `Moleculer.Service`, with params broker and schemaMods  
        this.parseServiceSchema(base);
      }
    };
  };

ref

class Service {

...
	constructor(broker, schema) {
		if (!isObject(broker))
			throw new ServiceSchemaError("Must set a ServiceBroker instance!");

		this.broker = broker;

		if (broker)
			this.Promise = broker.Promise;

		if (schema)
			this.parseServiceSchema(schema); // <- ran into here 
	}

	/**
	 * Parse Service schema & register as local service
	 *
	 * @param {Object} schema of Service
	 */
	parseServiceSchema(schema) {
		if (!isObject(schema))
			throw new ServiceSchemaError("The service schema can't be null. Maybe is it not a service schema?");

		this.originalSchema = _.cloneDeep(schema);

		if (schema.mixins) {
			schema = Service.applyMixins(schema);
		}

		if (isFunction(schema.merged)) {
			schema.merged.call(this, schema);
		} else if (Array.isArray(schema.merged)) {
			schema.merged.forEach(fn => fn.call(this, schema));
		}

		this.broker.callMiddlewareHookSync("serviceCreating", [this, schema]);

		if (!schema.name) { // <- error throws here
			
			console.error("Service name can't be empty! Maybe it is not a valid Service schema. Maybe is it not a service schema?", { schema });
			throw new ServiceSchemaError("Service name can't be empty! Maybe it is not a valid Service schema. Maybe is it not a service schema?", { schema });
		}
         ...

Action decorator wrong implementation (but working)

I have a doubt with Action decorator, here is the source code:

export function Action(options: ActionOptions = {}) {
  return function(target, key: string, descriptor: PropertyDescriptor) {
    if (!options.skipHandler) {
      options.handler = descriptor.value;
    } else {
      delete options.skipHandler;
    }

    (target.actions || (target.actions = {}))[key] = options
      ? {
          ...options
        }
      : options.skipHandler
      ? ""
      : descriptor.value;
  };
}

first if:

  • if options.skipHandler exists, it will be deleted, fair enough

target.actions assignation:

  • if options exists, then { ...options } ELSE check options.skipHandler here is the error, because if options.skipHandler exist is deleted in previous if and you are checking the "else" condition of "if (options)" then, the else condition is that "options" is not defined, then it is not possible that "options.skipHandler" could be defined.

This is giving me a typescript error:

TS2339: Property 'skipHandler' does not exist on type 'never'.

There are some other errors with "noImplicitAny: true" in tsconfig.json that avoid build in projects that are using moleculer-decorators with that config in tsconfig.json, maybe could be useful to add this compilerOptions:

    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noImplicitThis": false,
    "noStrictGenericChecks": true,
    "noUnusedLocals": true,
    "noUnusedParameters": false,
    "resolveJsonModule": true,
    "strict": true,
    "strictNullChecks": true,

Error testing use jest

I use moleculer 0.13, and I can't either loadService and createService from service that written using molecular decorator.

 Test 'user_session' service › encountered a declaration exception

    Invalid '[object Object]' type in validator schema!

      4 | describe(`Test 'user_session' service`, () => {
      5 | 	let broker = new ServiceBroker()
    > 6 | 	broker.loadService('./user_session/service.ts')
        | 	       ^
      7 | 
      8 | 	beforeAll(() => broker.start())
      9 | 	afterAll(() => broker.stop())

Using moleculer-web as mixin creates type error

I followed the exact tutorial in the Moleculer documentation, this is the code:

import moleculer from 'moleculer';
import ApiGateway from 'moleculer-web';
import { Service } from 'moleculer-decorators';


@Service({
    mixins: [ApiGateway]
})
class ApiService extends moleculer.Service {

    settings = {
        port: process.env.PORT || 8080,
    };
}

export = ApiService;

I'm getting the following error at mixins: [ApiGateway]:

Type 'ServiceSchema<ServiceSettingSchema> & { Errors: ApiGatewayErrors; }' is not assignable to type 'ServiceSchema<ServiceSettingSchema>'.
  Types of property 'dependencies' are incompatible.
    Type 'string | GenericObject | string[] | GenericObject[]' is not assignable to type 'string | ServiceDependency | (string | ServiceDependency)[]'.
      Type 'GenericObject' is not assignable to type 'string | ServiceDependency | (string | ServiceDependency)[]'.
        Type 'GenericObject' is not assignable to type 'string'.

Am I doing anything wrong?

No actions

Hi,

The following program works with moleculer-decorators 1.0.21, but fails with 1.1.0:

/*
tsconfig.json:
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true
  }
}

package.json:
{
  "name": "wobble",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "build": "tsc"
  },
  "dependencies": {
    "@types/node": "*",
    "moleculer": "0.13.7",
    "moleculer-decorators": "1.1.0",
    "typescript": "^3.5.2"
  }
}
*/
import { ServiceBroker } from "moleculer";
import { Service, Action } from 'moleculer-decorators';

@Service({
    version: 'v1',
})
class MyService {
    @Action()
    test() {
        return "Yep it works";
    }
}

const broker = new ServiceBroker();
broker.createService(MyService);

async function run() {
    await broker.start();

    const result = await broker.call('v1.MyService.test');
    console.log(result);
    await broker.stop();
}

run();

Output with 1.1.0:

ServiceNotFoundError: Service 'v1.MyService.test' is not found.

Expected output, as produced by earlier versions:

Yep it works

moleculer-0.14 support?

moleculer-0.14 is about to be released (it is at 0.14-rc1). Does this package need to be updated for the new version?

mixins are not applied properly


name: mixins are not applied properly


Prerequisites

Please answer the following questions for yourself before submitting an issue.

  • I am running the latest version
  • I checked the documentation and found no answer
  • I checked to make sure that this issue has not already been filed
  • I'm reporting the issue to the correct repository

Expected Behavior

FooService has action foo
image

MainService mixins[ServiceFoo]... so expecting main.foo to exist

Current Behavior

not found
image

Failure Information

Reproduce code snippet

//foo.service
'use strict';
const moleculer = require('moleculer');
const { Service, Action, Method, Event } = require('moleculer-decorators');

@Service({})
class foo extends moleculer.Service {
  // Optional constructor
  constructor(broker,s?) {
    super(broker,s);
  }

  @Action()
  foo() {
     return 'baz'; 
   }

   @Method
   foo2(){
     return 'baz2';
   }
}

module.exports = foo;
//main.service
"use strict";

const moleculer = require('moleculer');
const { Service, Action, Event, Method } = require('moleculer-decorators');
const foo = require('./foo.service');

@Service({
  mixins: [foo],
  settings: {
  }
})
class main extends moleculer.Service {

  // Optional constructor
  constructor(broker, s) {
    super(broker, s)
    this.settings = { // Overrides above by default, to prevent this, add "constructOverride: false" to @Service
      foo: "mainbaz"
    }
  }

  // @Action({
  //   skipHandler: true // Any options will be merged with the mixin's action.
  // })
  // foo() { // this function will never be called since a mixin will override it, unless you specify skipHandler: false.

  // }

  // With options
  // No need for "handler:{}" here
  @Action()
  yo(ctx) {
    return "yo"
  }

}


const broker = new moleculer.ServiceBroker({
  namespace: "test",
  logger: console,
  logLevel: "debug",
});
broker.createService(main);
broker.start();
broker.repl();
export {}

Context

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

  • Moleculer version: 0.13.8
  • Moleculer-decorators": 1.0.22
  • NodeJS version: 10
  • Operating System: centos

Failure Logs


TypeError when using ServiceSchema and moleculer v0.14.7

Because of different moleculer type versions the following type error occours:

Type 'ActionSchema' is not assignable to type 'boolean | ActionSchema | ActionHandler<any>'.

Upgrading moleculer dependency to 0.14.7 solves this issue

Workaround: Add moleculer as peerDependency

ActionOptions Typescript Typedef missing some options?

Hi There,

I'm trying to use decorators with Typescript. In your README.md example, we can set cache value per action:

  // With options
  // No need for "handler:{}" here
  @Action({
    cache: false,
    params: {
      a: "number",
      b: "number"
    }
  })

But when defining an @Action the type checking complains as it isn't defined:

export interface ActionOptions extends Partial<Action> {
  name?: string,
  handler?: ActionHandler<any>, // Not really used
  skipHandler?: boolean
}

It appears, "cache" should be defined in the Typescript typedef? Or perhaps I'm missing something key?

Services is called twice when started

Current Behavior

I was doing some tests on my services and noticed that the service is started 2 times and it seems to me the second instance replaces the first one, I put a console.log in the class constructor and it was fired 2 times.

Expected Behavior

The expected behavior was that the class's constructor was called only once, which is more strange is that if you have to add other parameters to the constructor (DI) the first time the constructor is called the additional parameters are undefined and only exist on the second call .

Failure Information

image

Steps to Reproduce

Please provide detailed steps for reproducing the issue.

Create a service using TS and classes;
Put a console.log inside the constructor;
Export the class with a function decorator;

Reproduce code snippet

import { Context, Service as MoleculerService, ServiceBroker } from 'moleculer'
import { Action, Service } from 'moleculer-decorators'
import { verify, sign } from 'jsonwebtoken'

import { IAuth } from '@Interfaces'
import { TimeInSeconds } from '../../src/helpers/enums/time'

@Service({ name: 'Auth' })
class AuthService extends MoleculerService {
  public constructor(broker: ServiceBroker) {
    super(broker)
    console.log('Called At: ', new Date())
  }

  @Action({
    cache: {
      enabled: true,
      ttl: TimeInSeconds.FiveMinutes,
    },
    params: {
      token: 'string'
    }
  })
  public async DecodeJWT(ctx: Context<{token: string}>): Promise<IAuth.JwtPayload | string | null> {
    try {
      return verify(ctx.params.token, process.env.JWT_SECRET)
    } catch (error) {
      return null
    }
  }

  @Action({
    params: {
      id: 'string',
      email: { type: 'string', optional: true },
      name: 'string'
    }
  })
  public async GenerateJWT(ctx: Context<IAuth.JwtDto>): Promise<string | null> {
    try {
      const { id, email, name } = ctx.params
      return sign({id, email, name}, process.env.JWT_SECRET)
    } catch (error) {
      return null
    }
  }
}

export default (broker: ServiceBroker): MoleculerService => new AuthService(broker)

Context

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

  • Moleculer Decorator version: 1.3.0
  • Moleculer version: 0.14.16
  • NodeJS version: v14.16.1
  • Operating System: MacOS BigSur 11.4

Failure Logs

$ ts-node ./node_modules/moleculer/bin/moleculer-runner.js --env --repl --hot services/**/*.ts services/**/*.js
[2021-08-19T13:41:43.652Z] INFO  nmac-1381.local-46462/BROKER: Moleculer v0.14.16 is starting...
[2021-08-19T13:41:43.654Z] INFO  nmac-1381.local-46462/BROKER: Namespace: <not defined>
[2021-08-19T13:41:43.654Z] INFO  nmac-1381.local-46462/BROKER: Node ID: nmac-1381.local-46462
[2021-08-19T13:41:43.655Z] INFO  nmac-1381.local-46462/REGISTRY: Strategy: RoundRobinStrategy
[2021-08-19T13:41:43.655Z] INFO  nmac-1381.local-46462/REGISTRY: Discoverer: LocalDiscoverer
[2021-08-19T13:41:43.656Z] INFO  nmac-1381.local-46462/BROKER: Serializer: JSONSerializer
[2021-08-19T13:41:43.669Z] INFO  nmac-1381.local-46462/BROKER: Validator: FastestValidator
[2021-08-19T13:41:43.671Z] INFO  nmac-1381.local-46462/BROKER: Registered 14 internal middleware(s).
Called At:  2021-08-19T13:41:49.022Z
Called At:  2021-08-19T13:41:49.023Z

Typeorm - reflect-metadata

When i'm trying to use typeorm together with moleculer-decorators i throws an error decorating Service

TypeError in node_modules/reflect-metadata/Reflect.js:544:31

@Service() class-decorator implementation throws TypeError

Reflect metadata throws an error when trying to use the @service() decorator on a class

import { Service, Action } from 'moleculer-decorators';

@Service()
export default class DemoController {
    @Action({
        rest: 'GET /welcome',
    })
    welcome(ctx) {
        return 'Hello'
    }
}

node_modules/reflect-metadata/Reflect.js

        function DecorateConstructor(decorators, target) {
            for (var i = decorators.length - 1; i >= 0; --i) {
                var decorator = decorators[i];
                var decorated = decorator(target);

                if (!IsUndefined(decorated) && !IsNull(decorated)) {
                    //Throws error because decorated is not a function but an object
                    if (!IsConstructor(decorated)) throw new TypeError();
                    target = decorated;
                }
            }
            return target;
        }

On closer inspection of decorator i see it returns an object. A class decorator should return nothing or a new function constructor.

function (constructor) {
        let base = {
            name: ''
        };
        const _options = Object.assign({}, defaultServiceOptions, options);
        Object.defineProperty(base, 'name', {
            value: options.name || constructor.name,
            writable: false,
            enumerable: true
        });
        if (options.name) {
            delete options.name;
        }
        Object.assign(base, _.omit(options, Object.keys(defaultServiceOptions)));
        const parentService = constructor.prototype;
        const vars = [];
        Object.getOwnPropertyNames(parentService).forEach(function (key) {
            if (key === 'constructor') {
                if (_options.constructOverride) {
                    const ServiceClass = new parentService.constructor(mockServiceBroker);
                    Object.getOwnPropertyNames(ServiceClass).forEach(function (key) {
                        if (blacklist.indexOf(key) === -1 &&
                            !_.isFunction(ServiceClass[key])) {
                            base[key] = Object.getOwnPropertyDescriptor(ServiceClass, key).value;
                            if (blacklist2.indexOf(key) === -1) {
                                vars[key] = Object.getOwnPropertyDescriptor(ServiceClass, key).value;
                            }
                        }
                    });
                    const bypass = Object.defineProperty;
                    const obj = {};
                    bypass(obj, 'created', {
                        value: function created(broker) {
                            for (let key in vars) {
                                this[key] = vars[key];
                            }
                            if (Object.getOwnPropertyDescriptor(parentService, 'created') !=
                                null) {
                                Object.getOwnPropertyDescriptor(parentService, 'created').value.call(this, broker);
                            }
                        },
                        writable: true,
                        enumerable: true,
                        configurable: true
                    });
                    base['created'] = obj.created;
                }
                return;
            }
            const descriptor = Object.getOwnPropertyDescriptor(parentService, key);
            if (key === 'created' && !_options.constructOverride) {
                base[key] = descriptor.value;
            }
            if (key === 'started' || key === 'stopped') {
                base[key] = descriptor.value;
                return;
            }
            if (key === 'events' || key === 'methods' || key === 'actions') {
                base[key]
                    ? Object.assign(base[key], descriptor.value)
                    : (base[key] = descriptor.value);
                return;
            }
            if (key === 'afterConnected' ||
                key === 'entityCreated' ||
                key === 'entityUpdated' ||
                key === 'entityRemoved') {
                base[key] = descriptor.value;
                return;
            }
        });
        return base;
    }

Typescript methods declaration

Good day, everyone! Firstly, thank you for your package!
I have a small question: how I can define decorators methods and properties for my class?

For example:

import { Action, Service } from 'moleculer-decorators'

@Service({ name: 'users' })
export class UsersService {
  @Action()
  sample() {
    this.logger.info('What?')
  }
}

The TS compiler doesn't know about logger property, I can define it manually, but... Can I have beauty solution for all properties and service methods? And also how I can define mixin implementation of some methods?

Thank you!

Typesupport for mixins

Is there a plan to add a typesupport for mixins?
At the moment I can't call methods which were created in a mixin. Instead Of casting to any.

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.