NestJs: How can I import one repository into another? - nestjs

I apologize for what is likely a very amateur question. Coming from Laravel, this is still quite confusing to me and I just don't understand what is needed.
I have a user.repository.ts file and a location.repository.ts file. Each have their own modules, controllers and services. I have successfully created CRUD operations for each entity but now am trying to work towards a Many to Many relationship.
In my user.repository.ts file, I am trying to save a related (many to many) repository:
// user.repository.ts
user.locations = await this.locationRepository.findByIds(locations);
...
await user.save();
I am not sure how to inject or import the location.repository.ts file. I have tried numerous variations of importing the service into each module. Or importing each module into the other module. I have tried different versions of this:
#EntityRepository(User)
#EntityRepository(Location)
Or importing the LocationService into the UserService.
In Laravel, this would be as "simple" as $model->sync($relationship);
How can I import/inject the locationRepository into my userRepository? Thank you for any suggestions!

I assume this question is related to your last question, the simplest way to implement it, Add Locationentity to your UserModule
#Module({
imports:[TypeOrmModule.forFeature([UserRepository,LocationRepository])], // or just Location entity [UserRepository,Location] if you didn't setup a custom LocationRepository
After that, inject it in your as what you did for userRepo... service
constructor(
#InjectRepository(LocationRepository)
private locationRepository: LocationRepository,
// or just private locationRepository: Repository<Location>,
) {}
In the create method service get your locations:
async createUser(createUserDto: CreateUserDto) { // usersSrvice
let locations = await this.locationRepository.findByIds(createUserDto.locations);
await this.userRepository.createMethodeName(createUserDto,locations) // add secand
params for your locations
don't hesitate to ask if you have any other questions

Related

NestJs instantiate class with dependencies

I'm completely new to Nestjs moving from Laravel, really enjoying it, but it's kinda more difficult to find answers online.
I got a base class with a dependency of the HttpService:
export abstract class BaseClass {
constructor(protected httpService: HttpService) {}
}
I got a couple of classes extending the base class, and I'm trying to instantiate them on the fly:
const bus = new BusClass([
new classNumber1(this.httpService),
new classNumber2(this.httpService),
]);
I want to find a way to NOT pass the httpService to the constructors,
just like NestJs doing it when we inject services on the constructors in the controllers for example.
I tried with factories and really any example from the docs, with no success.
Will be glad for any kind of help, thanks allot ahead!

How can I access a repository globally in loopback 4?

I used loopback 4 to bootstrap my API application and developed some parts of it.
Now I'm trying to access repositories outside the controllers and tried everything I could but didn't help. None of my searches did too. For example I have a controller in which I can access repo such way.
constructor(
#repository(UserRepository) public userRepository: UserRepository){}
But if it isn't a controller it won't work and I found out I had a wrong understanding about #repository and #inject decorators.
My Case:
I want to run a cron-job to perform an update operation on database every day at a specific time.
The thing is I think I should create a service or something like that to expose database operations so it can be accessible anywhere.
The issue you're trying to tackle comes down to dependency injection. It's described at https://loopback.io/doc/en/lb4/Dependency-injection.html but that article does not explain how to create a separate class that works with dependency injection.
In short, in order to perform the dependency injection through decorators, LoopBack needs to be the one to construct the class you're writing, so that it can pick what you need from its Context. So, instead of writing new ClassSomething, it has to be #inject(ClassSomething) or #service(ClassSomething), and those decorators only work in a class also instantiated by LoopBack. In other words, your class has to be in the "call tree" from the original application class (application.ts) for dependency injection to work.
The easiest way to do what you want to do is to use LoopBack's Cron component: see https://loopback.io/doc/en/lb4/Running-cron-jobs.html. You could convert your class to a CronJob if it has no other purpose, or let the CronJob create an instance of your class. In the latter case, you need to bind your class to the application Context so that the CronJob can access it through decorators. You can do so in two ways:
Convert your class to a Service (see https://loopback.io/doc/en/lb4/Service.html and https://loopback.io/doc/en/lb4/Service-generator.html). If what your class does can be thought of as a service, this is the way to go.
Inject your class with: #service(MyServiceClass) myService: MyServiceClass
Directly bind your class to the application context, in application.ts:
this.bind('MyClass').toClass(MyClass);
Inject your class with: #inject(MyClass) myClass: MyClass
The latter option is not best practice AFAIU as it does not adhere to IoC-principles (https://en.wikipedia.org/wiki/Inversion_of_control) - basically, by hard-coding the class binding in the application class, it is not exactly modular. When your class is converted to a service (and placed in src/services), it will automatically be added to the Context, meaning you can inject it everywhere using #service().
I also experience the same(cron word). I couldn't find any solution still in the documentation. But still, I have achieved this in this way.
just call repository as like class with dependency in it. do this in your index.ts file where you start the application.
async function startCronJobs(app: SawLoopbackApplication) {
const userRepo = app.repository(UserRepository);
const userRepoInstance = await userRepo.getValue(app);
const cron = new CronComponent(userInstance);
//---- Exicute your cron here
new CronJob('0 6 * * *', function () {
cron.sendMorningMail()
}).start();
//---- Exicute your Second Cron
new CronJob('0 8 * * 1', function () {
cron.weeklyAppraisalsToAgent()
}).start();
}
call your cron in the functional component and execute a raw query to get the details from DB etc...
import {MysqlDataSource} from '../../datasources'
const query = `select * from accounts where IP="${ipAddress}" ORDER By
createdAt DESC Limit 1`
const dataSource = new MysqlDataSource()
const accountDetails = await dataSource.execute(query)
console.log(accountDetails)
instead of a raw query. call your repository from the function component below
import {MysqlDataSource} from '../datasources'
import {ContactUsUserDetailsRepository} from '../repositories'
const contactUsUserDetailsRepository = new ContactUsUserDetailsRepository(new MysqlDataSource)
function saveContactDetails(){
const payload={UID:"Unique ID",name:"Durai"}
await contactUsUserDetailsRepository.create(payload)
}
I would prefer 2 because, if you have a lot of imports in your cron class constractor you need to pass all of them while calling a function like in the 3rd point.
Have fun:)

What is the best way to organize the code of a nodejs-express project, using TypeScript?

While trying to organize the code of my first NodeJS-express project, I ran into some doubts about the use of namespaces, modules and classes. When to choose one? When another?
For example, my project is structured (simplifying) in.
routers -> controllers -> services -> repositories.
The possibilities I thought of to manage these "entities" are the following:
Classes
Classes with static methods
Singletons
Simple module export
Namespaces
Classes
I thought of avoiding them right away, since the above-mentioned entities do not need to memorize any state. Furthermore, they would complicate the code due to the need to be instantiated.
Classes with static methods
They are correct? Or rather a simple namespace or simple export of the modules?
Class + Singletons
A way of organizing the code in a "nicer" way than the simple class, but which does not convince me, since reading on the net that the singleton in TypeScript is replaceable with the namespace.
Simple module export
The way I thought to implement immediately, for example in this way (file user.repository.ts):
const add = async (user: User): Promise<void> => {
if(await canBeAdded(user)) {
//save user;
} else {
// throw error
}
}
export const UserRepository = {
add
}
It's corrects? Or am I not properly using what TypeScript offers? Being the first time I use this language, I would like to be sure I chose the right path.
Namespaces
Are they a better choice to develop the code published above? Are you advised against?
Thank you in advance for the answers! Any advice is welcome!
P.S. I know that, once the TypeScript is compiled, in Javascript the classes are practically syntactic sugar. What I'm interested in knowing are the best practices for writing good code in TypeScript.

Stripe + TypeScript: How to extend #types/stripe definitions for stripe-node?

I'm working on project, where we're using Stripe library for Node. We also want to use TypeScript on this project.
I've figured out that Stripe isn't providing official TypeScript definitions but I've found some community definitions #types/stripe on NPM. So I installed them and after a while I got an error:
Property 'sources' does not exist on type 'Stripe'.
Well there are missing some definitions, for example for this stripe.sources-related functionality.
I want to add missing definitions locally. So I need to extend this file:
#types/stripe/index.d.ts
I think that for the problem above I need:
to add property sources: Stripe.resources.Sources; to class Stripe,
to add class Sources to namespace resources,
to add missing function declarations to class Sources.
The problem is that I really don't know how. How should the .d.ts file with extensions look like? I've made many attempts according some examples and TypeScript docs but it always doesn't work. Do you have any idea?
I don't believe there's a way to augment the export-assigned Stripe class; the problem is similar to this open issue about augmenting a default-exported class. At this time, since you can't use augmentation, you'll have to fork the #types/stripe definitions for your project, and then you may as well make all the desired changes that way.
I think my colleague has found a solution that works for me. Here is how he made it:
import ST from 'stripe'
declare module 'stripe' {
namespace sources {
interface ISource extends IResourceObject {
...
}
interface ISourceCreationData {
...
}
}
namespace resources {
class Sources {
create(data: sources.ISourceCreationData): Promise<sources.ISource>;
retrieve(source: string, client_secret?: string): Promise<sources.ISource>;
}
}
class Stripe extends ST {
sources: ST.resources.Sources;
}
}

Is it possible to group controllers in sails using subfolders?

I'm planning to organize my controllers in sails using subfolder but I'm not sure how to do it. When I tried using like admin/PageController.js and connect it with the route I keep getting a 404 error.
You can definitely do this. The trick is, the controller identity is its path, in your case admin/PageController. So a custom route in config/routes.js would be something like:
'GET /admin/page/foo': 'admin/PageController.foo'
The great thing is, automatic actions still work, so if you have an index action in the controller then browsing to /admin/page will automatically run it.
You can also create controllers like this with sails generate controller admin/page.
Edit
Since commit 8e57d61 you can do this to get blueprint routes and functionality on nested controllers, assuming there is an AdminPage model in your project:
// api/controllers/admin/PageController.js
module.exports = {
_config: {
model: 'adminpage'
}
}
or this:
// config/routes.js
module.exports.routes = {
'admin/page': {
model: 'adminpage'
}
}
Old Answer
Your options
Defining explicit routes to your grouped controllers in config/routes.js.
Look at Scott Gress' answer for more details.
(If you are a bit adventurous) As i had the exact same requirement for a project of mine I created a Pull Request on Sails that allows you to override the model - controller association. You could install it via
npm install -g git://github.com/marionebl/sails.git#override-controller-model
Assuming it is the api/models/Page.js model you want the blueprint methods for on api/controllers/admin/PageController.js you then could do:
// api/controllers/admin/PageController.js
...
module.exports = {
_config: {
model: 'page'
}
}
Explanation
While generating/creating grouped controllers like this is perfectly valid an possible, you will not get the default blueprint routes you'd expect for controllers accompanied by models with the same identity.
E.g. api/controllers/UserController.js and api/models/User.js share the same identity user, thus the blueprint routes are mounted if they are enabled in config/blueprints.js.
In fact at the moment it is not possible to group models into subfolders in a valid way. This means you won't be able to create a model that matches the identity admin/page of your controller api/controllers/admin/PageController.js - the blueprint routes are not mounted for PageController.
The source responsible for this behavior can be inspected on Github.
I made a diagram that shows how implicit routes, explicit policies, nested controllers, singular models and nested views are related. It does not show an overridden model-controller association as described by #marionebl.
It was mostly an exercise for me to understand this topic better, but I hope it helps somebody else too. Please let me know if I made any mistakes:
Thanks merionebl, its work fine for me and I want to share with all guys my answer derived from merionebl answer.
/config/routes.js
'get /admin/user' : {
controller: "Admin/UserController", action: "find",
model : 'user',
},
My aim is not repeat answer just have upgrade and clear example.
Thanks

Resources