Giter VIP home page Giter VIP logo

prisma-util's Introduction

Hi there, I'm David ๐Ÿ‘‹

I'm an aspiring Java Developer and student who strives to code useful open-source stuff that can help people.

Software I use

  • โ˜• Java, C#, Maven
  • ๐Ÿ“š MySQL, MariaDB, PostgreSQL
  • ๐ŸŒ JavaScript, Node.js, Next.js, React.js, Typescript
  • ๐Ÿ”— PHP

You can reach me via...

My Stats

My Stats

Top Langs

prisma-util's People

Contributors

davidhancu avatar dependabot[bot] avatar imlunahey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

imlunahey

prisma-util's Issues

Custom functions for @default - Accepted Proposal

Scope

The aim of this proposal is to provide a sneak-peek for the new feature that will be added to Prisma Util v2.0. In this issue, I'll be outlining the process of defining a function and how the configuration will look like, so you can make preparations in advance.

Introduction

This feature will be released under the customAttributeFunctions flag and will require manual activation.

Configuration

To set a default function for a field, we can just do this:

function generateDefault(dmmf) {
    // Generate your default value based on the DMMF data of this field
    const defaultValue = "";
    return defaultValue;
}
export default {
    // Other configuration values
    defaultFunctions: {
        "path/to/file:ModelName.field": generateDefault
    }
}

The function will then be grabbed by Prisma Util and added to a function map. To copy the function over, Prisma Util will use .toString() on the provided function and wrap the code in another function, as such:

const columnMappings = {
    "ModelName.field": function() {
        const func = function generateDefault(dmmf) {
            // Generate your default value based on the DMMF data of this field
            const defaultValue = "";
            return defaultValue;
        }
        return func;
    }(),
}

Middleware

This feature makes use of Project Toolchain's Middleware API and defines a middleware called attributeFunctions. To use it, you have to import it like this and add it to your Prisma middleware chain:

import attributeFunctions from "prisma-util/toolchain/middleware/customAttributeFunctions";
prisma.$use(attributeFunctions(prisma));

And that's it! Now everything will function correctly whenever you create a new model.

Final Words

Please let us know if this is suitable for you and if you would like any changes to be made.

Middleware Context API - Accepted Proposal

Scope

The aim of this proposal is to provide a sneak-peek for the new feature that will be added to Prisma Util v2.0. In this issue, I'll be outlining the process of how Middleware Context can be used for passing down metadata to middleware.

Introduction

This feature will be released under the middlewareContext flag and will require manual activation. Because this feature uses Project Toolchain's Generation API, it will create the typings necessary for configuring context.

Code Example

prisma.user.findMany({
    where: {
        name: "David"
    },
    // The new Context API
    context: {
        anyKey: "anyValue",
        anotherKey: 2
    }
});

Then, in your middleware:

const middleware = async (params, next) => {
    if(params.args.context && params.args.context.anotherKey == 2)
    {
        // do something
    }
    return next(params);
}

Middleware

This feature makes use of Project Toolchain's Middleware API and defines a middleware called contextRemover. To use it, you have to import it like this and add it to your Prisma middleware chain:

import contextRemover from "prisma-util/toolchain/middleware/middlewareContext";
prisma.$use(contextRemover(prisma));

And that's it! Now everything will function correctly whenever you create a new model.

Caveat

This context remover middleware must be the last one in the chain, otherwise you'll be removing the context from further middleware. This must be done to ensure that the context parameter isn't sent to Prisma.

Enhanced Introspection - Accepted Proposal

Scope

The aim of this proposal is to provide a sneak-peek for the new feature that will be added to Prisma Util v2.0. In this issue, I'll be outlining the process of how you can use the new Enhanced Introspection features to manipulate your schema.

Introduction

This feature will be released under the enhancedIntrospection flag and will require manual activation. Because this feature uses Project Toolchain's Generation API, it will create the typings necessary for configuring the fields of this object. All Enhanced Introspection steps will be ran before the schema is generated, to allow you to modify the models before they are written to the final file.

Configuration

To configure the Enhanced Introspection feature, you're going to have to add an introspection property to your configuration object like this:

export default {
    // Other configuration options
    introspection: {
        modelPatterns: {
            // We'll come back to this option later on.
        }
    }
}

We've created a separate introspection object to facilitate a fieldPatterns option coming in the future.

Model Patterns

Model Patterns are used for defining rules that models should follow. To offer more granular control for your schema, we've implemented the following class that will be passed to your functions:

abstract class Model {
    /**
     * The name of this model. If this parameter hasn't been modified before, it will be the table name from the database.
     */
    public abstract get name();
    /**
     * Set the name for this model.
     */
    public abstract set name(name: string);
    /**
     * Add an attribute to this model.
     * @param attribute The attribute to add. You can use the `schema-creator` module for a list of attributes.
     */
    public abstract addAttribute(attribute: string);
}

The rules for Model Patterns are split into 3 categories:

  • Static Changes

Static changes edit models based on their name and are placed under the $static key. These can be configured in 2 ways:

  1. Using a String

Using a String is the easiest way to remap a table. To do it, add the following object to your introspection block:

export default {
    // Other configuration options
    introspection: {
        modelPatterns: {
            $static: {
                "table_name": "ModelName"
            }
        }
    }
}

In this example, ModelName will map to table_name.

  1. Using a Function

Using a function allows more granular control for this table. To do it, add the following object to your introspection block:

import { Constraints } from "prisma-util/schema-creator";

export default {
    // Other configuration options
    introspection: {
        modelPatterns: {
            $static: {
                "table_name": async (model: Model) => {
                    model.name = "ModelName";
                    model.addAttribute(Constraints.Model.UNIQUE(["name", "email"]));
                    return model;
                }
            }
        }
    }
}

In this example, ModelName will map to table_name and will add the @@unique([name, email]) attribute to the model.

  • Regex Changes

Regex changes use regexes to match model names. These regexes are ran with the gims flags and are placed under the $regex key. To configure a regex replacer, add a function like this:

export default {
    // Other configuration options
    introspection: {
        modelPatterns: {
            $regex: {
                "model_name(\\d)": async (model: Model, match: string, ...groups: string[]) => {
                    model.name = `ModelName${groups[1]}`;
                    return model;
                }
            }
        }
    }
}

One regex replacer can be called for multiple tables and will pass the correct model as a parameter. In this example, all tables that match the regex will have the underscore removed and will be changed to PascalCase.

  • Catch-all Changes

Catch-all replacers will be ran for all models. To configure a catch-all replacer, add a function like this:

export default {
    // Other configuration options
    introspection: {
        modelPatterns: {
            $all: async (model: Model) => {
                model.name = model.name.replace(/_/gims, "");
                return model;
            }
        }
    }
}

In this example, all tables will have the underscore removed.

Handling Conflicts

Because the Enhanced Introspection step is ran before the Conflict Manager has a chance to run, all models that will trigger a naming conflict will be flagged and the normal rename/skip dialog will be shown.

Prioritizing Changes

Replacers will be ran from the first key to the last key. A table can trigger multiple replacers, if the latter ones match the new name set by the previous replacers. You can use this to your advantage: by reordering the $static, $regex and $all keys you can create a powerful workflow that fits your use-case. One example of such workflow would be leaving the $all key as the last property of the object to enforce default naming conventions on all models.

[Proposal] pg_trgm Support

pg_trgm Support

Hey everyone! I've recently seen an issue in the official Prisma GitHub repository asking for pg_trgm support, then encountered the same necessity with my use-cases of Prisma, so I thought about implementing it in Prisma Util.

Design

As all features that modify the way that Prisma Util processes files, this feature will be marked as Experimental as well (or opt-in if you will). To get started, you'd need to add the following to your configuration file (using the new .mjs syntax coming in v1.3.0):

{
    pg_trgm: true,
    ftsIndexes: {
        "schema.prisma:User.name": "GIN"
    }
}

In this case, Prisma Util will create a GIN index for the model User in the file named schema.prisma for the name column.

Implementation

Prisma Util is already capable of enhanced parsing, so my idea was to add an @Unsupported("TSVECTOR") field to the schema, as well as install pg_trgm and create GIN or GiST (configured per field via the configuration file) indexes.

Code

This is the biggest problem right now and I'd love some feedback on how you'd want this feature to operate. I would say that a middleware is best, as it requires the least amount of setup and it's pretty easy to implement as well.

Wrapping Up

Please let me know what you expect from this feature and how you think that it should be used.

[v1.4.0] Creating schemas using JavaScript

Creating schemas with JavaScript and TypeScript

Hey everyone! I've recently got an idea from seeing how many people requested this, so here is my proposal.

Design

My aim is to make this system as easy as possible and as such I thought about this feature as a perfect fit for the Experimental tag. To use it, you'd have to add 2 more keys in your configuration file:

{
    "codeSchemas": true,
    "codeGenerators": ["file.generator.js"]
}

As with any experimental feature, you have to add codeSchemas to enable the feature. The codeGenerators array provides a list of relative paths for the config generators.

Code

This is an example of how I thought the code part could work:

import { SchemaCreator, Constraints } from "@prisma-util/schema-creator";

export default async function createSchema()
{
    SchemaCreator.model("User")
                             .column("id", "Int", Constraints.ID, Constraints.DEFAULT("autoincrement"))
                             .column("name", "String", Constraints.UNIQUE)
                             .column("posts", "Post[]");
    SchemaCreator.model("Post")
                             .column("id", "Int", Constraints.ID, Constraints.DEFAULT("autoincrement"))
                             .column("title", "String", Constraints.UNIQUE)
                             .column("userId", "Int")
                             .column("user", "User", Constraints.RELATION(["userId"], ["id"]);             
    return SchemaCreator.build();
}

This would create the schema:

model User {
    id Int @id @default(autoincrement())
    name String @unique
    posts Post[]
}

model Post {
    id Int @id @default(autoincrement())
    title String @unique
    userId Int
    user User @relation(fields: [userId], references: [id])
}

As you can see, everything you need is under the Constraints object. Some values (like DEFAULT and RELATION in this example) are callable, and the value you provide will be passed as an argument in your schema.

Wrapping Up

Let me know what you think about this proposal and any improvements you'd like to see!

[v1.4.0] Additional ways of configuring your schema (YAML and XML)

Additional ways of configuring schemas without the use of .env files

As with the code-generated schemas proposal, I've seen many people interested in this feature. Basically, allow the DATABASE_URL environment variable to be used from another file, such as YAML and XML.

Design

My aim is to make this system as easy as possible and as such I thought about this feature as a perfect fit for the Experimental tag. To use it, you'd have to add 2 more keys in your configuration file:

{
    "additionalFormats": true,
    "configurations": ["configuration.yml", "another.yml"]
}

As with any experimental feature, you have to add additionalFormats to enable the feature. The configurations array provides a list of relative paths for the YAML and XML files (by the way, you can suggest more formats!).

In this example, the another.yml file would take priority and override configuration.yml, as it's the one set at the end.

Example

As with all proposals, here's what I think that this configuration could look like:

datasource:
    provider: "postgresql"
    url: "DATABASE_URL"

Wrapping Up

Let me know what you think about this proposal and any improvements you'd like to see!

Support Multiple Inheritance

Problem

I have the following config.mjs:

export default {
  optionalFeatures: ["crossFileRelations"],
  baseSchema: BaseSchema,
  includeFiles: [...globModels(BaseSchema, "prisma/models/**/*.prisma")],
  extended: {
    "user.prisma:User": "vendor.prisma:Vendor"
  },
}

I would like to be able to extend multiple models, as such:

  extended: {
    "user.prisma:User": ["vendor.prisma:Vendor", "vendor.prisma:Customer", ...]
  },

This is currently not possible.

Suggested solution

The extended config parameter should support a string or list of strings as the type, such that a model can extend multiple other models.

Alternatives

Honestly, the current DX for defining cross-file relations and extensions both are quite bad. This package should move long-term to support the following syntax in .prisma files:

# import './Project.prisma'

model User extends Vendor, Customer {
   ....

  projects          Project[]
}

The import statement can be completed by plugging in the graphql-import NPM package or a similar alternative.

Additional context

This package is much needed, great job building it. There are multiple issues open on Prisma's Github for multiple years that this package resolves!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.