0.0.19 • Published 6 months ago

loopback4-prisma v0.0.19

Weekly downloads
-
License
MIT
Repository
-
Last release
6 months ago

loopback4-prisma

This package enables Prisma integration with LoopBack 4.

Installation

To install loopback4-prisma:

$ [npm install | yarn add] loopback4-prisma

Integration Scope

This package adds the following integration capabilities:

  • Binding of Prisma models to context
  • Connection lifecycle integration
  • Integration with @loopback/logging

The following are not supported yet, but are being considered:

  • OpenAPI 3.0 schema generation
  • Prisma Middleware Providers
  • Prisma query filter like loopback4 query filter
  • Prisma generator for loopback models, repositories and crud controllers

Considerations

When using Prisma integration for LoopBack 4, there may be some important factors or changes that should be considered:

  • lazyConnect is disabled by default.

    This is to ensure that LoopBack fails fast with database connection issues.

  • Limited support for architectures or operating systems

    The Prisma engines are binary blobs that has its own list of supported platforms, separate from Node.js itself.

Basic Use

Configure and load LoopbackPrismaComponent in the application constructor as shown below.

import {PrismaComponent, PrismaOptions} from 'loopback4-prisma';

export class MyApplication extends RepositoryMixin(
  // This can be replaced with any `*Application`
  // (e.g. `RestApplication` if needed.
  Application
)) {
  constructor(options: ApplicationConfig = {}) {
    const opts: PrismaOptions = {/* Config here */}

    this.configure(PrismaBindings.COMPONENT).to(opts);
    this.component(PrismaComponent);
  }
}

Configuring Prisma Client and Component

The Prisma Component and Prisma Client accepts custom configuration, which can be configured as follows:

import {PrismaBindings, PrismaComponent, PrismaOptions} from 'loopback4-prisma';

export class MyApplication extends RepositoryMixin(RestApplication)) {
  constructor(options: ApplicationConfig = {}) {
    const opts: PrismaOptions = {
      prismaClient: {
        /* Prisma Client options go here */
      }

      // Prisma Component configuration
      enableLoggingIntegration: true,
      lazyConnect: false,
      models: {
        namespace: 'customPrismaModelNamespace',
        tags: ['customPrismaModelTag'],
      },
    };

    // The order does not matter as long as `app.init()` hasn't been called.
    this.configure(PrismaBindings.COMPONENT).to(opts);
    this.component(PrismaComponent);
    // ...
  }
}

After .init(), the configuration binding will be locked. Manual unlocking and modification will not be honored.

Registering Prisma middleware

Extension points are a LoopBack 4 concept which allows extending functionality through a common interface. In the case, it is also useful as a bill-of-material of registered Prisma middleware.

import {Binding, BindingKey} from '@loopback/core';
import {
  asPrismaMiddleware,
  PrismaBindings,
  PrismaComponent
} from 'loopback4-prisma';

// Replace this to import your own middleware.
import {myPrismaMiddleware} from '.';

export class MyApplication extends RepositoryMixin(RestApplication)) {
  constructor(options: ApplicationConfig = {}) {
    // BindingKey.generate() creates a unique binding key.
    // It can be replaced with your own binding key to allow identification of
    // the middleware.
    this.bind(new Binding(BindingKey.generate()))
      .to(myPrismaMiddleware)
      .apply(asPrismaMiddleware);

    this.component(LoopbackPrismaComponent);
    // ...
  }
}

Prisma middleware can be registered at any point in time (with some caveats), and its binding will be automatically locked immediately when and after .init().

Registering Prisma Middleware after init

When registerin Prisma Middleware After .init() is called, it is necessary to call process.nextTick() to guarantee that the middleware registation is complete. Otherwise, there is a risk of a race condition.

In asynchronous functions, it is possible to adapt process.nextTick() as follows:

// Avoid "callback hell" in asynchronous functions
await new Promise(resolve => process.nextTick(resolve));

Injecting Prisma models

During initialization, Prisma models are discovered and bound to Context as Constant Singletons.

For example, to constructor-inject a Prisma model named User into a Controller:

import {inject} from '@loopback/core';
import {DefaultPrismaCrudRepository, PrismaBindings} from 'loopback4-prisma';
import {Prisma, PrismaClient} from '@prisma/client';

export class MyController {
  constructor(
    @inject(`${PrismaBindings.PRISMA_MODEL_NAMESPACE}.${Prisma.ModelName.User}`)
    private _userModel: PrismaClient.prototype.user,
  ) {}
}

Injecting PrismaClient instance

After initialization, a PrismaClient instance will be bound to Context. To retrieve the instance:

class MyClass {
  constructor(
    @inject(PrismaBindings.PRISMA_CLIENT_INSTANCE)
    private _prismaClient: PrismaClient,
  ) {}
}

It is usually not recommended to inject the PrismaClient instance unless if the API is not exposed through this extension. Please consider submitting it as a new GitHub "Idea" Discussion.

@loopback/logging integration

The @loopback/logging integration a quick bootstrap helper that configures and binds event listeners to PrismaClient.

Quick start

  • Install a compatible version of @loopback/logging:

    $ [npm install | yarn add] @loopback/logging
  • Register LoggingComponent:

    import {LoggingComponent} from '@loopback/logging';
    // ...
    app.component(LoggingComponent);
  • Register and configure PrismaComponent:

    import {
      PrismaBindings,
      PrismaComponent,
      PrismaOptions,
    } from 'loopback4-prisma';
    // ...
    app.component(PrismaComponent);
    app.configure<PrismaOptions>(PrismaBindings.COMPONENT).to({
      enableLoggingIntegration: true,
    });

Advanced Use

Custom Prisma Client instance

Before .init() is called, it is possible to provide a custom instance of the Prisma Client:

import {PrismaBindings, PrismaComponent} from 'loopback4-prisma';
import {PrismaClient} from '@prisma/client';

export class MyApplication extends RepositoryMixin(RestApplication)) {
  constructor(options: ApplicationConfig = {}) {
    const prismaClient = new PrismaClient();

    this.bind(PrismaBindings.PRISMA_CLIENT_INSTANCE).to(prismaClient);
    this.component(LoopbackPrismaComponent);
    // ...
  }
}

In most cases, it's usually not necessary to provide your own instance of the Prisma Client. Also note that the instance MUST be bound as a constant (i.e. using Binding.to()); Otherwise, an error will be thrown during .init() and .start().

Informational

This section is for deeper, informational reference.

Pre- & Post-initialization Restrictions

Before .init() is called, the configuration and Prisma Client instance binding can be modified, and it is not necessary to call .configure() before .component().

After initialization, both bindings will be locked and any changes (even after manual unlocking) will not be honored.

Bad Binding Protections

At certain stages, this extension will check and validate if the relevant bound Bindings meet their respective requirements (e.g. Binding scope, binding type, etc.). Afterwards, these Bindings will be locked (i.e. through Binding.lock()) to discourage unwanted modifications and allow for quick, easy-to-spot errors.

After the bindings are locked, no additional checks will be performed, and Binding modification may cause additional unhandled errors deeper within the code.

Furthermore, behavior on interactions on the Bindings and the Bindings themselves are not tested or documented.

Hence, it is strongly discouraged to modify Bindings after they're locked, of which they should be considered "read-only".

Please refer to this documentation for more information on when certain Bindings are locked.

0.0.19

6 months ago

0.0.18

2 years ago

0.0.15

2 years ago

0.0.16

2 years ago

0.0.17

2 years ago

0.0.11

2 years ago

0.0.12

2 years ago

0.0.13

2 years ago

0.0.14

2 years ago

0.0.10

2 years ago

0.0.9

2 years ago

0.0.8

2 years ago

0.0.7

2 years ago

0.0.61

2 years ago

0.0.5

2 years ago

0.0.6

2 years ago

0.0.4-alpha5

3 years ago

0.0.4-alpha4

3 years ago

0.0.4-alpha3

3 years ago

0.0.4-alpha

3 years ago

0.0.3-alpha

3 years ago

0.0.4-alpha2

3 years ago

0.0.4-alpha1

3 years ago

0.0.2-alpha

3 years ago

0.0.1-alpha

3 years ago