Express + knex + Objection Base service class - node.js

I'm looking for solution to use BaseService for common Objection model methods. it is working properly on UserService. but i want to write some methods in BaseService class.
base.service.ts
class BaseService<Models>{
public m: Models;
constructor(model: Models) {
this.m = model;
}
//Not working
public find(): Promise<any> {
return await this.m.query().findAll();
}
}
user.service.ts
class UserService extends BaseService<typeof UserMoodel> {
constructor() {
super(UserModel)
}
getUsers() : Promise<User> {
return await this.m.query().findAll().toCast<User>();
}
}
user.model.ts
class UserMoodel extends Model {}

You should try out feathers It has good community, It has some learning curve but since you know knex then you can easily adopt it.

Related

How to create common source for different services with NestJS?

For example, this is book.service.ts
import { Injectable } from "#nestjs/common";
import { Book } from '../interfaces/book.interface'
#Injectable()
export class BooksService {
private readonly books: Book[] = [];
private create(book: Book) {
console.log(book)
this.books.push(book);
}
private findAll(): Book[] {
return this.books;
}
}
Another buy.service.ts
import { Injectable } from "#nestjs/common";
import { Book } from '../interfaces/book.interface'
#Injectable()
export class BuyService {
private readonly books: Book[] = [];
private findAll(): Book[] {
return this.books;
}
}
The private findAll() methods are the same in the two files. How to create a common logic for them?
If I were you, I'd inject the BookService into the BuyService and not make the findAll() method private. This way you can call this.bookService.findAll() from within the BuyService. Otherwise, you'll need to abstract up another layer and inject that abstraction into both BookService and BuyService.
Sounds like overall tightly coupling code, so be cautious you don't end up with crossed domain lines and tightly coupled dependencies

Property-based injection with an Abstract Class

I am trying to add an Abstract method to serialize my response objects in order to hash the id's. That would require to have a property-based injection in order to not pass lots of variables through the constructor.
The class that will be used to Serialize :
import { AbstractHash } from 'src/global/abstract.hash';
import { IItems } from '../items.interface';
import { Injectable } from '#nestjs/common';
#Injectable()
export class ResponseItem extends AbstractHash implements IItems {
name: string;
price: number;
type: string;
constructor(partial: Partial<IItems>) {
super();
Object.assign(this, partial);
}
}
The abstract class :
import { HashIdHelper } from 'src/hash-id.helper';
import { Exclude, Expose } from 'class-transformer';
import { Inject, Injectable } from '#nestjs/common';
#Injectable()
export abstract class AbstractHash {
#Exclude()
id: number;
//#Inject('HASHID_HELPER') // Neither works
#Inject(HashIdHelper)
public readonly hashIdHelper: HashIdHelper;
#Expose({ name: 'id' })
encodedId() {
console.log(this.hashIdHelper); // -> undefined
console.log(HashIdHelper);
return this.hashIdHelper.encode(this.id);
}
}
The controller :
// imports
#UseInterceptors(ClassSerializerInterceptor)
#Controller('items')
export class ItemsController {
constructor(
private readonly itemsService: ItemsService,
#Inject('HASHID_HELPER') private readonly hash: HashIdHelper, // <-- Ok
) {}
#Get(':id')
async findOne(#Param('id') id: string) {
console.log(this.hash.encode(+id)); // <-- Ok
const item = await this.itemsService.findOne(parseInt(id));
console.log(new ResponseItem(item));
return new ResponseItem(item); // <-- undefined attribute, see above
}
}
The repository : https://github.com/befabry/caddie/tree/hash_id
Thanks for the help
You're calling new ClassInstance() so you are 100% in control of the class and it's properties. Nest will not inject anything on a manually instantiated class, because it's not managed by Nest's lifecycle in the first place. You can use moduleRef.create to have Nest create an instance for you, but once you use the keyword new you are in charge of that instance.

Unable to spy on a class instance inside another class

I'm instantiating the service class inside the controller class, and the log method of the service is been used in the controller.
In spec file, I'm adding spy on the log method but the spy is not been called.
Here is my code
test.service.ts
export class TestService {
public log(msg: string): void {
console.log(msg);
}
}
test.controller.ts
import { TestService } from "../service/cart.service";
export class CartController {
private testService: TestService;
constructor() {
this.testService = new TestService();
}
public testFx():void {
this.testService.log("Here is a dummy msg.")
}
}
test.controller.spec.ts
import { TestController } from "./test.controller";
import { TestService } from "./test.service";
describe("Testing controller", () => {
private testController: TestController = new TestController();
private testService: TestService = new TestService();
it ("test function", () => {
spyOn(testService, "log");
testController.testFx();
expect(testService.log).toHaveBeenCalled();
});
})
Error: - Expected spy log to have been called.
Instead of creating a new class instance,
private testController: TestController = new TestController();
private testService: TestService = new TestService();
it ("test function", () => {
spyOn(testService, "log");
you can use escape hatch for it.
Try this:
private testController: TestController = new TestController();
it ("test function", () => {
spyOn(testController["testService"], "log");
Since the private, protected and public are the concept of typescript's syntactic sugar it has nothing to do when code compiles to javascript.
The more explaining answer is here.

Dynamic typing of child of abstract class

I have an abstract class defined statically and an implementation of it retrieved dynamically
Ie
export abstract class Foo {
abstract get();
}
const dynamicClass: typeof Foo = ( function() {
return class Bar {
get: function() {
console.log('get');
}
constructor() {
super();
console.log('cons');
}
}
}();
This is working fine exept one thing : I cannot call the constructor without "cheating"
IE
new Bar() output cannot instantiate abstract class
I have resolved that by doing
// #ts-ignore
new Bar();
But I feel i could do better.
The whole usecase for that is that the funciton that create the class at runtime will act differently based on the system it is (dynamiccally loading extra libraries that i removed for the sake of simplicity)
The easiest thing you can do is to not use an explicit type annotation, let the compiler infer what it will for dynamicClass:
export abstract class Foo {
abstract get(): void;
}
const dynamicClass = (function() {
return class Bar extends Foo {
get() {
console.log('get');
}
constructor() {
super();
console.log('cons');
}
}
})();
new dynamicClass();
Playground Link
If you want to go the explicit route you can use a constructor signature that returns Foo, this should mostly remove the abstarctness of the constructor:
export abstract class Foo {
abstract get(): void;
}
const dynamicClass: new () => Foo = (function() {
return class Bar extends Foo {
get() {
console.log('get');
}
constructor() {
super();
console.log('cons');
}
}
})();
new dynamicClass();
Playground Link

NeDB + Typescript

How can I get a datastore with NeDB using typescrip classes syntax?
namespace NamespaceName {
"use strict";
export class Persistence {
private attrs: Type;
public static $inject: Array<string> = [];
constructor(
) {
this.attr1 = "";
}
// Public Methods
public method1() {
...
}
// Private Methods
private method1() {
...
}
}
}
Where should I create and instantiate my datastore?
I was spinning my wheels on this myself for a while and I was able to do get the database to generate with the following:
import NeDB = require('nedb');
//test class
class duck{
body: string;
constructor(body: string)
{
this.body = body;
}
}
//method from where I init my database.
testdb() {
var db:any = new NeDB("./file.db");
var obj:duck= new duck("A normal duck body");
db.loadDatabase();
db.insert(obj);
}
Notes:
I do have the #typings installed for NeDB see NeDB
Typings
If you look at the above link they provide the tests they used to verify the typings.

Resources