Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependency injection without ts metadata #1080

Merged
merged 4 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"cSpell.words": [
"Biblatex",
"Nuxt",
"booktitle",
"codegen",
"datetime",
"esbuild",
"jiti",
"journaltitle",
"Nuxt",
"nuxtjs",
"transpiled",
"tsyringe",
Expand Down
5 changes: 2 additions & 3 deletions api/database/disconnect.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { container } from 'tsyringe'
import type { PrismaClient } from '@prisma/client'
import { resolve } from './../tsyringe'

export async function disconnect(): Promise<void> {
await container.resolve<PrismaClient>('PrismaClient').$disconnect()
await resolve('PrismaClient').$disconnect()
}
10 changes: 5 additions & 5 deletions api/documents/resolvers.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { container } from 'tsyringe'
import mocking from 'jest-mock-extended'
import { UserDocument } from '@prisma/client'
import { register, resolve } from '../tsyringe'
import { UserDocumentService } from './user.document.service'
import { Query, Mutation, DocumentResolver } from './resolvers'
import { DocumentResolver } from './resolvers'
import { createUnauthenticatedContext } from '~/test/context.helper'

const userDocumentService = mocking.mock<UserDocumentService>()
container.registerInstance(UserDocumentService, userDocumentService)
const query = container.resolve(Query)
const mutation = container.resolve(Mutation)
register('UserDocumentService', { useValue: userDocumentService })
const query = resolve('DocumentQuery')
const mutation = resolve('DocumentMutation')

const context = createUnauthenticatedContext()

Expand Down
26 changes: 16 additions & 10 deletions api/documents/resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { DocumentType, Prisma } from '@prisma/client'
import { container, injectable } from 'tsyringe'
import { Context } from '../context'
import {
AddJournalArticleInput,
Expand All @@ -17,6 +16,7 @@ import {
UpdateUserDocumentInput,
} from '../graphql'
import { ResolveType } from '../utils/extractResolveType'
import { resolve, injectable, inject } from './../tsyringe'
import { UserDocumentService, UserDocument } from './user.document.service'

// Fields that are stored as separate columns in the database
Expand Down Expand Up @@ -157,7 +157,10 @@ function convertDocumentInput(

@injectable()
export class Query {
constructor(private userDocumentService: UserDocumentService) {}
constructor(
@inject('UserDocumentService')
private userDocumentService: UserDocumentService
) {}

async userDocument(
_root: Record<string, never>,
Expand All @@ -170,7 +173,10 @@ export class Query {

@injectable()
export class Mutation {
constructor(private userDocumentService: UserDocumentService) {}
constructor(
@inject('UserDocumentService')
private userDocumentService: UserDocumentService
) {}

async addUserDocument(
_root: Record<string, never>,
Expand Down Expand Up @@ -308,12 +314,12 @@ export class OtherResolver extends DocumentResolver {}

export function resolvers(): Resolvers {
return {
Query: container.resolve(Query),
Mutation: container.resolve(Mutation),
Document: container.resolve(DocumentResolver),
JournalArticle: container.resolve(JournalArticleResolver),
ProceedingsArticle: container.resolve(ProceedingsArticleResolver),
Thesis: container.resolve(ThesisResolver),
Other: container.resolve(OtherResolver),
Query: resolve('DocumentQuery'),
Mutation: resolve('DocumentMutation'),
Document: resolve('DocumentResolver'),
JournalArticle: resolve('JournalArticleResolver'),
ProceedingsArticle: resolve('ProceedingsArticleResolver'),
Thesis: resolve('ThesisResolver'),
Other: resolve('OtherResolver'),
}
}
8 changes: 4 additions & 4 deletions api/documents/user.document.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { container } from 'tsyringe'
import { mockDeep, mockReset } from 'jest-mock-extended'
import type { PrismaClient } from '@prisma/client'
import { UserDocument, UserDocumentService } from './user.document.service'
import { register, resolve } from '../tsyringe'
import { UserDocument } from './user.document.service'

const prisma = mockDeep<PrismaClient>()
container.registerInstance('PrismaClient', prisma)
const userDocumentService = container.resolve(UserDocumentService)
register('PrismaClient', { useValue: prisma })
const userDocumentService = resolve('UserDocumentService')

const testDocument: UserDocument = {
id: 'test',
Expand Down
2 changes: 1 addition & 1 deletion api/documents/user.document.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import type {
JournalIssue,
Journal,
} from '@prisma/client'
import { inject, injectable } from 'tsyringe'
import { DocumentFilters, UserDocumentsConnection } from '../graphql'
import { inject, injectable } from './../tsyringe'

export type UserDocument = PlainUserDocument & {
other?: UserDocumentOtherField[]
Expand Down
14 changes: 7 additions & 7 deletions api/groups/resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { UserInputError } from 'apollo-server-errors'
import { container, injectable } from 'tsyringe'
import prisma from '@prisma/client'
import type { Group, GroupType as GroupTypeT } from '@prisma/client'
import { Context } from '../context'
Expand All @@ -9,6 +8,7 @@ import {
MutationUpdateGroupArgs,
MutationCreateGroupArgs,
} from '../graphql'
import { resolve, injectable, inject } from './../tsyringe'
import { GroupService } from './service'
const { GroupType, GroupHierarchyType } = prisma

Expand All @@ -21,7 +21,7 @@ export type GroupMaybeResolved = Group | GroupResolved

@injectable()
export class Query {
constructor(private groupService: GroupService) {}
constructor(@inject('GroupService') private groupService: GroupService) {}

async group(
_root: Record<string, never>,
Expand All @@ -34,7 +34,7 @@ export class Query {

@injectable()
export class Mutation {
constructor(private groupService: GroupService) {}
constructor(@inject('GroupService') private groupService: GroupService) {}

async createGroup(
_root: Record<string, never>,
Expand Down Expand Up @@ -153,7 +153,7 @@ export class Mutation {

@injectable()
export class GroupResolver {
constructor(private groupService: GroupService) {}
constructor(@inject('GroupService') private groupService: GroupService) {}

__resolveType(group: GroupMaybeResolved): GroupTypeT {
return group.type
Expand All @@ -178,8 +178,8 @@ export class GroupResolver {

export function resolvers(): Resolvers {
return {
Query: container.resolve(Query),
Mutation: container.resolve(Mutation),
Group: container.resolve(GroupResolver),
Query: resolve('GroupQuery'),
Mutation: resolve('GroupMutation'),
Group: resolve('GroupResolver'),
}
}
2 changes: 1 addition & 1 deletion api/groups/service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Group, Prisma, PrismaClient, User } from '@prisma/client'
import { inject, injectable } from 'tsyringe'
import { inject, injectable } from './../tsyringe'

@injectable()
export class GroupService {
Expand Down
5 changes: 2 additions & 3 deletions api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import http from 'http'
import express from 'express'
import { ApolloServer } from 'apollo-server-express'
import 'reflect-metadata' // Needed for tsyringe
import { container } from 'tsyringe'
import {
ApolloServerPluginDrainHttpServer,
ApolloServerPluginLandingPageLocalDefault,
} from 'apollo-server-core'
import { Environment } from '../config'
import { resolve } from './tsyringe'
import { configure as configureTsyringe } from './tsyringe.config'
import { buildContext } from './context'
import { loadSchema } from './schema'
import PassportInitializer from './user/passport-initializer'
import config from '#config'

// Create express instance
Expand All @@ -25,7 +24,7 @@ const httpServer = http.createServer(app)

// TODO: Replace this with await, once esbuild supports top-level await
void configureTsyringe().then(() => {
const passportInitializer = container.resolve(PassportInitializer)
const passportInitializer = resolve('PassportInitializer')
passportInitializer.initialize()
passportInitializer.install(app)

Expand Down
51 changes: 47 additions & 4 deletions api/tsyringe.config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,58 @@
import prisma from '@prisma/client'
import { container, instanceCachingFactory } from 'tsyringe'
import * as DocumentResolvers from './documents/resolvers'
import { UserDocumentService } from './documents/user.document.service'
import * as GroupResolvers from './groups/resolvers'
import { GroupService } from './groups/service'
import { instanceCachingFactory, register } from './tsyringe'
import { AuthService } from './user/auth.service'
import PassportInitializer from './user/passport-initializer'
import * as UserResolvers from './user/resolvers'
import { createRedisClient } from './utils/services.factory'

const { PrismaClient } = prisma

export async function configure(): Promise<void> {
container.register('PrismaClient', {
// Tools
register('PrismaClient', {
useFactory: instanceCachingFactory(() => new PrismaClient()),
})

container.register('RedisClient', {
register('RedisClient', {
useValue: await createRedisClient(),
})
registerClasses()
}

export function registerClasses(): void {
// Tools
register('PassportInitializer', PassportInitializer)

// Services
register('UserDocumentService', UserDocumentService)
register('AuthService', AuthService)
register('GroupService', GroupService)
// Resolvers
register('DocumentQuery', DocumentResolvers.Query)
register('DocumentMutation', DocumentResolvers.Mutation)
register('DocumentResolver', DocumentResolvers.DocumentResolver)
register('JournalArticleResolver', DocumentResolvers.JournalArticleResolver)
register(
'ProceedingsArticleResolver',
DocumentResolvers.ProceedingsArticleResolver
)
register('ThesisResolver', DocumentResolvers.ThesisResolver)
register('OtherResolver', DocumentResolvers.OtherResolver)

register('GroupQuery', GroupResolvers.Query)
register('GroupMutation', GroupResolvers.Mutation)
register('GroupResolver', GroupResolvers.GroupResolver)

register('UserQuery', UserResolvers.Query)
register('UserMutation', UserResolvers.Mutation)
register('UserResolver', UserResolvers.UserResolver)
register('LoginPayloadResolver', UserResolvers.LoginPayloadResolver)
register('SignupPayloadResolver', UserResolvers.SignupPayloadResolver)
register(
'ChangePasswordPayloadResolver',
UserResolvers.ChangePasswordPayloadResolver
)
}
Loading