npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@yamato-daiwa/prisma-schema-generator

v0.2.3

Published

Intended to be used for generating of "prisma.schema" file based on business rules defined by TypeScript.

Readme

Yamato Daiwa Prisma Schema Generator

Generates the prisma.schema based on a script intended to be executed by ts-node or tsx. Designed for the projects obeys to Clean Architecture principles one of which forbids the defining of the business rules using the frameworks.

Installation

npm i prisma-schema-generator -D -E

Peer Dependencies

| Package Name | Versions Range | |--------------|-----------------| | prisma | >=6.9.0 <6.10.0 |

Problem Overview

Prisma suggests to use prisma.schema file as business rules definition method. Although it has not been declared directly, de facto using just the Prisma you need either defined you business rules inside prisma.schema or additionally model the data on application level what it rarely practiced because it is the dual management impacting the application maintainability.

The defining of the business rules in prisma.schema is the gross violation of Clean Architecture.

Where should such ORM systems reside? In the database layer of course. Indeed, ORMs form another kind of Humble Object boundary between the gateway interfaces and the database.

— Robert C. Martin, Clean Architecture, Pearson Education, ISBN-10: 0-13-449416-4, Published in 2018.

The database layer mentioned above is the outermost layer of the Clean Architecture while the entities (enterprise business rules) are the innermost layer:

According to the Clean Architecture, each outer ring must respect the inner ones while the inner ones must know nothing about the outer ones:

Source code dependencies must point only inward, toward higher-level policies.

Nothing in an inner circle can know anything at all about something in an outer circle. In particular, the name of something declared in an outer circle must not be mentioned by the code in an inner circle. That includes classes, variables, or any other named software entity.

— Robert C. Martin, Clean Architecture, Pearson Education, ISBN-10: 0-13-449416-4, Published in 2018.

Solution

In general terms, the prisma-schema-generator has been designed as a part of the following approach.

  1. Define the business rules completely independently on any framework.
  2. For each entity create the mapper object according to which the Prisma model will be generated.
  3. Create the script generating the Prisma schema.

Example

Step 1: Define the Business Rules

There is no standards how to define the business rules. The author of prisma-schema-generator doing is as shown below. To make the example enough, three entities has been provided.

Sample Entity 1

import {
  EMAIL_ADDRESS_VALID_PATTERN,
  MAXIMAL_CHARACTERS_COUNT_OF_EMAIL_ADDRESS,
  MINIMAL_CHARACTERS_COUNT_OF_EMAIL_ADDRESS
} from "fundamental-constants";


type User = {
  emailAddress: string;
  displayingName: string;
  authorityRole: User.AuthorityRoles;
  hashedPassword: string;
};


namespace User {

  export const NAME: string = "User";

  export namespace EmailAddress {
    export const NAME: string = "emailAddress";
    export const TYPE: StringConstructor = String;
    export const REQUIRED: boolean = true;
    export const MINIMAL_CHARACTERS_COUNT: number = MINIMAL_CHARACTERS_COUNT_OF_EMAIL_ADDRESS;
    export const MAXIMAL_CHARACTERS_COUNT: number = MAXIMAL_CHARACTERS_COUNT_OF_EMAIL_ADDRESS;
    export const REGULAR_EXPRESSION: RegExp = EMAIL_ADDRESS_VALID_PATTERN;
  }


  export namespace DisplayingName {
    export const NAME: string = "displayingName";
    export const TYPE: StringConstructor = String;
    export const REQUIRED: boolean = true;
    export const MINIMAL_CHARACTERS_COUNT: number = 2;
    export const MAXIMAL_CHARACTERS_COUNT: number = 250;
  }


  export enum AuthorityRoles {
    admin = "admin",
    editor = "editor"
  }

  export namespace AuthorityRole {
    export const TYPE: StringConstructor = String;
    export const REQUIRED: boolean = true;
    export const ALLOWED_VALUES: Array<AuthorityRoles> = Object.values(AuthorityRoles);
  }


  export namespace HashedPassword {
    export const NAME: string = "hashedPassword";
    export const TYPE: StringConstructor = String;
    export const REQUIRED: boolean = true;
  }

}


export default User;

Sample Entity 2

import { FIXED_CHARACTERS_COUNT_IN_NANO_ID } from "fundamental-constants";


type ProductCategory = {
  readonly ID: ProductCategory.ID;
  name: string;
};


namespace ProductCategory {

  export const NAME: string = "ProductCategory";

  export type ID = string;
  export namespace ID {
    export const NAME: string = "ID";
    export const TYPE: StringConstructor = String;
    export const REQUIRED: boolean = true;
    export const FIXED_CHARACTERS_COUNT: number = FIXED_CHARACTERS_COUNT_IN_NANO_ID;
  }

  export namespace Name {
    export const NAME: string = "name";
    export const TYPE: StringConstructor = String;
    export const REQUIRED: boolean = true;
    export const MINIMAL_CHARACTERS_COUNT: number = 2;
    export const MAXIMAL_CHARACTERS_COUNT: number = 100;
  }

}


export default ProductCategory;

Sample Entity 3

import type ProductCategory from "./ProductCategory";
import { FIXED_CHARACTERS_COUNT_IN_NANO_ID } from "fundamental-constants";


type Product = {
  readonly ID: Product.ID;
  title: string;
  description?: string;
  category: ProductCategory;
  price__dollars__includingTax: number;
  quantityRemainInStock?: number;
};


namespace Product {

  export const NAME: string = "Product";

  export type ID = string;
  export namespace ID {
    export const NAME: string = "ID";
    export const TYPE: StringConstructor = String;
    export const REQUIRED: boolean = true;
    export const FIXED_CHARACTERS_COUNT: number = FIXED_CHARACTERS_COUNT_IN_NANO_ID;
  }

  export namespace Title {
    export const NAME: string = "title";
    export const TYPE: StringConstructor = String;
    export const REQUIRED: boolean = true;
    export const MINIMAL_CHARACTERS_COUNT: number = 2;
    export const MAXIMAL_CHARACTERS_COUNT: number = 200;
  }

  export namespace Description {
    export const NAME: string = "description";
    export const TYPE: StringConstructor = String;
    export const REQUIRED: boolean = true;
    export const MINIMAL_CHARACTERS_COUNT: number = 2;
    export const MAXIMAL_CHARACTERS_COUNT: number = 500;
  }

  export namespace Category {
    export const NAME: string = "category";
    export const TYPE: ObjectConstructor = Object;
    export const REQUIRED: boolean = false;
  }

  export namespace Price__Dollars__WithoutTax {
    export const NAME: string = "price__dollars__withoutTax";
    export const TYPE: NumberConstructor = Number;
    export const REQUIRED: boolean = true;
    export const MINIMAL_VALUE: number = 1;
    export const MAXIMAL_VALUE: number = Number.MAX_SAFE_INTEGER;
  }

  export namespace QuantityRemainInStock {
    export const NAME: string = "quantityRemainInStock";
    export const TYPE: NumberConstructor = Number;
    export const REQUIRED: boolean = false;
    export const MINIMAL_VALUE: number = 0;
    export const MAXIMAL_VALUE: number = Number.MAX_SAFE_INTEGER;
  }

}


export default Product;

Step 2 Define the Prisma Models Definition

Defining the prisma models, refer to business rules as much as possible.

Sample Entity 1

const userPrismaModelDefinition: PrismaSchemaGenerator.ModelDefinition = {
  modelName: User.NAME,
  tableName: "users",
  propertiesDefinitions: [
    {
      propertyName: User.EmailAddress.NAME,
      columnName: "email_address",
      type: User.EmailAddress.TYPE,
      isPrimaryKey: true,
      isNullable: !User.EmailAddress.REQUIRED,
      maximalCharactersCount: User.EmailAddress.MAXIMAL_CHARACTERS_COUNT
    },
    {
      propertyName: User.DisplayingName.NAME,
      columnName: "displaying_name",
      type: User.DisplayingName.TYPE,
      isNullable: !User.DisplayingName.REQUIRED,
      maximalCharactersCount: User.DisplayingName.MAXIMAL_CHARACTERS_COUNT
    },
    {
      propertyName: "authorityRoleCode",
      columnName: "authority_role_code",
      type: IntegerDataTypes.oneByte,
      isUnsigned: true,
      isNullable: !User.AuthorityRole.REQUIRED
    },
    {
      propertyName: User.HashedPassword.NAME,
      columnName: "hashed_password",
      type: User.HashedPassword.TYPE,
      isNullable: !User.HashedPassword.REQUIRED,
      fixedCharactersCount: 60
    }
  ]
};

Sample Entity 2

const productCategoryPrismaModelDefinition: PrismaSchemaGenerator.ModelDefinition = {
  modelName: ProductCategory.NAME,
  tableName: "product_categories",
  propertiesDefinitions: [
    {
      propertyName: ProductCategory.ID.NAME,
      columnName: "id",
      type: ProductCategory.ID.TYPE,
      isPrimaryKey: true,
      isNullable: !ProductCategory.ID.REQUIRED,
      fixedCharactersCount: ProductCategory.ID.FIXED_CHARACTERS_COUNT
    },
    {
      propertyName: ProductCategory.Name.NAME,
      columnName: "name",
      type: ProductCategory.Name.TYPE,
      isNullable: !ProductCategory.Name.REQUIRED,
      maximalCharactersCount: ProductCategory.Name.MAXIMAL_CHARACTERS_COUNT
    },
    {
      propertyName: "products",
      type: PrismaSchemaGenerator.PropertyDefinition.List.TYPE,
      elementType: Product.NAME
    }
  ]
};

Sample Entity 3

const PRODUCT_CATEGORY_EXTERNAL_KEY_NAME: string = `${ Product.Category.NAME }ID`;


const productPrismaModelDefinition: PrismaSchemaGenerator.ModelDefinition = {
  modelName: Product.NAME,
  tableName: "products",
  propertiesDefinitions: [
    {
      propertyName: Product.ID.NAME,
      columnName: "id",
      type: Product.ID.TYPE,
      isPrimaryKey: true,
      isNullable: !Product.ID.REQUIRED,
      fixedCharactersCount: Product.ID.FIXED_CHARACTERS_COUNT
    },
    {
      propertyName: Product.Title.NAME,
      columnName: "title",
      type: Product.Title.TYPE,
      isNullable: !Product.Title.REQUIRED,
      maximalCharactersCount: Product.Title.MAXIMAL_CHARACTERS_COUNT
    },
    {
      propertyName: Product.Description.NAME,
      columnName: "description",
      type: Product.Description.TYPE,
      isNullable: !Product.Description.REQUIRED,
      maximalCharactersCount: Product.Description.MAXIMAL_CHARACTERS_COUNT
    },
    {
      propertyName: Product.Category.NAME,
      type: PrismaSchemaGenerator.PropertyDefinition.AnotherModel.TYPE,
      targetModelName: ProductCategory.NAME,
      isNullable: !Product.Category.REQUIRED,
      relation: {
        fields: [ PRODUCT_CATEGORY_EXTERNAL_KEY_NAME ],
        references: [ ProductCategory.ID.NAME ]
      }
    },
    {
      propertyName: PRODUCT_CATEGORY_EXTERNAL_KEY_NAME,
      type: Product.ID.TYPE,
      isForeignKey: true,
      fixedCharactersCount: ProductCategory.ID.FIXED_CHARACTERS_COUNT,
      isNullable: !Product.Category.REQUIRED
    },
    {
      propertyName: Product.Price__Dollars__WithoutTax.NAME,
      columnName: "price__dollars__includingTax",
      type: Integer,
      minimalValue: Product.Price__Dollars__WithoutTax.MINIMAL_VALUE,
      maximalValue: Product.Price__Dollars__WithoutTax.MAXIMAL_VALUE,
      isNullable: !Product.Price__Dollars__WithoutTax.REQUIRED
    },
    {
      propertyName: Product.QuantityRemainInStock.NAME,
      columnName: "quantity_remain_in_stock",
      type: Integer,
      minimalValue: Product.QuantityRemainInStock.MINIMAL_VALUE,
      maximalValue: Product.QuantityRemainInStock.MAXIMAL_VALUE,
      isNullable: !Product.QuantityRemainInStock.REQUIRED
    }
  ]
};

Step 3 Create and Run the Script

/* ─── Data ───────────────────────────────────────────────────────────────────────────────────────────────────────── */
import productPrismaModelDefinition from "./PrismaModelsDefinitions/ProductPrismaModelDefinition";
import productCategoryPrismaModelDefinition from "./PrismaModelsDefinitions/ProductCategoryPrismaModelDefinition";
import userPrismaModelDefinition from "./PrismaModelsDefinitions/UserPrismaModelDefinition";


/* ─── Utils ──────────────────────────────────────────────────────────────────────────────────────────────────────── */
import PrismaSchemaGenerator from "prisma-schema-generator";
import Path from "path";
import { Logger, FileWritingFailedError } from "@yamato-daiwa/es-extensions";
import { ConsoleApplicationLogger } from "@yamato-daiwa/es-extensions-nodejs";


// TODO Correct the otuput directory path
const OUTPUT_DIRECTORY_ABSOLUTE_PATH: string = Path.join(
  process.cwd(), "Tests", "Manual", "Minimal", "_Generated"
);


Logger.setImplementation(ConsoleApplicationLogger);


PrismaSchemaGenerator.generate({

  generatorProvider: "prisma-client-js",

  /** [ WARNING ] DO NOT hardcode it if your project intended to be published. */
  databaseConnectionURI_EnvironmentVariableName: "mysql://root:example@localhost:3306/PrismaSchemaGenerator-MinimalExample",

  databaseProvider: PrismaSchemaGenerator.SupportedDatabaseProviders.MySQL,
  outputFileAbsolutePath: OUTPUT_DIRECTORY_ABSOLUTE_PATH,
  modelsDefinitions: [
    productPrismaModelDefinition,
    productCategoryPrismaModelDefinition,
    userPrismaModelDefinition
  ]

}).

  then(
    (): void => {
      Logger.logSuccess({
        title: "schema.prisma has been generated",
        description: `${ OUTPUT_DIRECTORY_ABSOLUTE_PATH }${ Path.sep }schema.prisma`
      });
    }
  ).

  catch(
    (error: unknown): void => {
      Logger.logError({
        errorType: FileWritingFailedError.NAME,
        title: FileWritingFailedError.localization.defaultTitle,
        description: "prisma.schema",
        occurrenceLocation: "PrismaSchemaGenerator.generate",
        caughtError: error
      });
    }
  );

Now you can run this script to generate the schema.prisma. For ts-node case, it will be something like (you need to correct the path to script):

ts-node generatePrismaSchema.ts

As result, the following schema.prisma will be generated:

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url      = env("mysql://root:example@localhost:3306/PrismaSchemaGenerator-MinimalExample")
}

model Product {
  ID                         String           @id @map("id") @db.VarChar(21)
  title                      String           @db.TinyText
  description                String           @db.Text
  category                   ProductCategory? @relation(fields: [categoryID], references: [ID])
  categoryID                 String?          @db.Char(21)
  price__dollars__withoutTax BigInt           @map("price__dollars__includingTax") @db.UnsignedBigInt
  quantityRemainInStock      BigInt?          @map("quantity_remain_in_stock") @db.UnsignedBigInt

  @@map("products")
}

model ProductCategory {
  ID       String    @id @map("id") @db.VarChar(21)
  name     String    @db.TinyText
  products Product[]

  @@map("product_categories")
}

model User {
  emailAddress      String @id @map("email_address") @db.VarChar(320)
  displayingName    String @map("displaying_name") @db.TinyText
  authorityRoleCode Int    @map("authority_role_code") @db.UnsignedTinyInt
  hashedPassword    String @map("hashed_password") @db.Char(60)

  @@map("users")
}

The prisma-schema-generator's turn ends here. You will need to update and rerun this script when make some changes in business rules and/r prisma model definitions.

Also, you may want to generate the schema.prisma and prisma client at once. If so, add to your package.json the script similar to following one (correct the paths before launch):

{
  "scripts": {
    "Prisma Schema And Client Generating": "ts-node generatePrismaSchema.ts && prisma generate --schema _Generated/schema.prisma"
  }
}

API

PrismaSchemaGenerator Class / Namespace

Has only one public member, the static generate method.

generate Static Method

(
  options: Readonly<{
    generatorProvider: string;
    clientOutputPathRelativeToSchemaFile?: string;
    binaryTargets?: ReadonlyArray<string>;
    databaseProvider: PrismaSchemaGenerator.SupportedDatabaseProviders;
    databaseConnectionURI_EnvironmentVariableName: string;
    modelsDefinitions: ReadonlyArray<PrismaSchemaGenerator.ModelDefinition>;
    outputFileAbsolutePath: string;
  }>
): Promise<void>

Generates the prisma.schema file according the specified options.

Options

Properties Definition (PrismaSchemaGenerator.PropertyDefinition)

For each model definition (PrismaSchemaGenerator.ModelDefinition) the properties definitions must be specified via propertiesDefinitions, the array of PrismaSchemaGenerator.PropertyDefinition. The PrismaSchemaGenerator.PropertyDefinition is the (discriminated union) currently included the following subtypes:

  • PropertyDefinition.String
  • PropertyDefinition.Integer
  • PropertyDefinition.DateWithoutTime
  • PropertyDefinition.DateAndTime
  • PropertyDefinition.List
  • PropertyDefinition.AnotherModel
  • PropertyDefinition.JSON

Common Properties

Each subtype of PrismaSchemaGenerator.PropertyDefinition discriminated union has the following properties.

String Properties

For the string-like columns, in addition to common properties, the following one can be (must be for required ones) specified.