Coder Social home page Coder Social logo

prisma-client-js's Introduction

Prisma

Prisma

Discord

Quickstart   •   Website   •   Docs   •   Examples   •   Blog   •   Discord   •   Twitter

What is Prisma?

Prisma is a next-generation ORM that consists of these tools:

  • Prisma Client: Auto-generated and type-safe query builder for Node.js & TypeScript
  • Prisma Migrate: Declarative data modeling & migration system
  • Prisma Studio: GUI to view and edit data in your database

Prisma Client can be used in any Node.js or TypeScript backend application (including serverless applications and microservices). This can be a REST API, a GraphQL API, a gRPC API, or anything else that needs a database.

The Prisma ORM can also further be extended with these Prisma products:

Getting started

The fastest way to get started with Prisma is by following the Quickstart (5 min).

The Quickstart is based on a preconfigured SQLite database. You can also get started with your own database (PostgreSQL and MySQL) by following one of these guides:

How Prisma works

This section provides a high-level overview of how Prisma works and its most important technical components. For a more thorough introduction, visit the Prisma documentation.

The Prisma schema

Every project that uses a tool from the Prisma toolkit starts with a Prisma schema file. The Prisma schema allows developers to define their application models in an intuitive data modeling language. It also contains the connection to a database and defines a generator:

// Data source
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

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

// Data model
model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User?   @relation(fields:  [authorId], references: [id])
  authorId  Int?
}

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

In this schema, you configure three things:

  • Data source: Specifies your database connection (via an environment variable)
  • Generator: Indicates that you want to generate Prisma Client
  • Data model: Defines your application models

The Prisma data model

On this page, the focus is on the data model. You can learn more about Data sources and Generators on the respective docs pages.

Functions of Prisma models

The data model is a collection of models. A model has two major functions:

  • Represent a table in the underlying database
  • Provide the foundation for the queries in the Prisma Client API

Getting a data model

There are two major workflows for "getting" a data model into your Prisma schema:

  • Generate the data model from introspecting a database
  • Manually writing the data model and mapping it to the database with Prisma Migrate

Once the data model is defined, you can generate Prisma Client which will expose CRUD and more queries for the defined models. If you're using TypeScript, you'll get full type-safety for all queries (even when only retrieving the subsets of a model's fields).


Accessing your database with Prisma Client

Generating Prisma Client

The first step when using Prisma Client is installing its npm package:

npm install @prisma/client

Note that the installation of this package invokes the prisma generate command which reads your Prisma schema and generates the Prisma Client code. The code will be located in node_modules/.prisma/client, which is exported by node_modules/@prisma/client/index.d.ts.

After you change your data model, you'll need to manually re-generate Prisma Client to ensure the code inside node_modules/.prisma/client gets updated:

npx prisma generate

Refer to the documentation for more information about "generating the Prisma client".

Using Prisma Client to send queries to your database

Once the Prisma Client is generated, you can import it in your code and send queries to your database. This is what the setup code looks like.

Import and instantiate Prisma Client

You can import and instantiate Prisma Client as follows:

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

or

const { PrismaClient } = require('@prisma/client')

const prisma = new PrismaClient()

Now you can start sending queries via the generated Prisma Client API, here are a few sample queries. Note that all Prisma Client queries return plain old JavaScript objects.

Learn more about the available operations in the Prisma Client docs or watch this demo video (2 min).

Retrieve all User records from the database
// Run inside `async` function
const allUsers = await prisma.user.findMany()
Include the posts relation on each returned User object
// Run inside `async` function
const allUsers = await prisma.user.findMany({
  include: { posts: true },
})
Filter all Post records that contain "prisma"
// Run inside `async` function
const filteredPosts = await prisma.post.findMany({
  where: {
    OR: [{ title: { contains: 'prisma' } }, { content: { contains: 'prisma' } }],
  },
})
Create a new User and a new Post record in the same query
// Run inside `async` function
const user = await prisma.user.create({
  data: {
    name: 'Alice',
    email: '[email protected]',
    posts: {
      create: { title: 'Join us for Prisma Day 2021' },
    },
  },
})
Update an existing Post record
// Run inside `async` function
const post = await prisma.post.update({
  where: { id: 42 },
  data: { published: true },
})

Usage with TypeScript

Note that when using TypeScript, the result of this query will be statically typed so that you can't accidentally access a property that doesn't exist (and any typos are caught at compile-time). Learn more about leveraging Prisma Client's generated types on the Advanced usage of generated types page in the docs.

Community

Prisma has a large and supportive community of enthusiastic application developers. You can join us on Discord and here on GitHub.

Security

If you have a security issue to report, please contact us at [email protected].

Support

Ask a question about Prisma

You can ask questions and initiate discussions about Prisma-related topics in the prisma repository on GitHub.

👉 Ask a question

Create a bug report for Prisma

If you see an error message or run into an issue, please make sure to create a bug report! You can find best practices for creating bug reports (like including additional debugging output) in the docs.

👉 Create bug report

Submit a feature request

If Prisma currently doesn't have a certain feature, be sure to check out the roadmap to see if this is already planned for the future.

If the feature on the roadmap is linked to a GitHub issue, please make sure to leave a 👍 reaction on the issue and ideally a comment with your thoughts about the feature!

👉 Submit feature request

Contributing

Refer to our contribution guidelines and Code of Conduct for contributors.

Tests Status

  • Prisma Tests Status:
    Prisma Tests Status
  • Ecosystem Tests Status:
    Ecosystem Tests Status

prisma-client-js's People

Contributors

0xflotus avatar aliedp avatar ctrlplusb avatar ejoebstl avatar errorname avatar ghashtag avatar gihrig avatar idkjs avatar janpio avatar jolg42 avatar kripod avatar kuldar avatar leonardopliski avatar matthewmueller avatar mfix22 avatar murajun1978 avatar neilime avatar nikolasburk avatar orzfly avatar pantharshit00 avatar prisma-bot avatar rafaelkr avatar schickling avatar steebchen avatar timsuchanek avatar tnunes avatar tomitrescak avatar trufa avatar wardpeet avatar weakky 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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

prisma-client-js's Issues

Life-cycle hooks

Middleware (blocking)

function beforeUserCreate(user: UserCreateProps): UserCreateProps {
  return {
    ...user,
    email: user.email.toLowerCase(),
  }
}

type UserCreateProps = { name: string }
type UserCreateCallback = (userStuff: UserCreateProps) => Promiselike<UserCreateProps>

const beforeUserCreateCallback: UserCreateCallback = user => ({
  name: 'Tim',
})

function afterUserCreate(user) {
  datadog.log(`User Created ${JSON.stringify(user)}`)
}

const prisma = new Prisma({
  middlewares: { beforeUserCreate, afterUserCreate },
})

Events (non-blocking)

const prisma = new Prisma()
prisma.on('User:beforeCreate', user => {
  stripe.createUser(user)
})

Prisma Client JS apis for browser

It would be great If prisma2 can generate photon api for the browser. We can use Postgres row based permissions for security. The browser apis will allow developers to quickly build an application without using rest/graphql endpoint.

Group By

Problem

Most database support ways to indicate how to group results, especially in combination with usage of aggregators.
Prisma 2 currently doesn't offer any way to group results, and requires to fall back to using raw SQL queries. This defeats the benefits of having a type-safe client, and hurts code maintainability.

Suggested solution

Add support for ways to group results

Initial API example proposal:

type DynamicResult4 = {
  lastName: string
  records: User[]
  aggregate: { age: { avg: number } }
}
const groupByResult: DynamicResult4 = await prisma.users.groupBy({
  key: 'lastName',
  having: { age: { avgGt: 10 } },
  where: { isActive: true },
  first: 100,
  orderBy: { lastName: 'ASC' },
  select: {
    records: { take: 100 },
    aggregate: { age: { avg: true } },
  },
})

type DynamicResult5 = {
  raw: any
  records: User[]
  aggregate: { age: { avg: number } }
}
const groupByResult2: DynamicResult5 = await prisma.users.groupBy({
  raw: { key: 'firstName || lastName', having: 'AVG(age) > 50' },
  select: {
    records: { $first: 100 },
    aggregate: { age: { avg: true } },
  },
})

Next steps

  • Define scope of the kinds of group by statement we want to support first
  • Agree on API design
  • Implement in engines
  • Implement in client

Disallow returning data from delete operations

// Change from ...
const deletedUser: User = await prisma.users.delete('bobs-id')
// to ...
const deletedUser: User = await prisma.users.findOne('bobs-id')
const nothing: void = await prisma.users.delete('bobs-id')

Is pluralization still needed on `photon.<model_name>` ?

Description

Let's assume a User model.
Since we're planning to drop support for the shortcut photon.users({ ... }), I don't see the reason anymore to have pluralization.

It feels especially weird to me when doing photon.users.findOne({ ... })

Proposal

Remove pluralization and always use the model names lowercased.

photon.user.findOne()
photon.user.findMany()

ENOENT Error: Error in lift engine: [ Windows OS]

Execution of below command or any Lift related command is giving error in Windows (happening for most of the examples provided) No other logs provided except the below error message. Please help !

Command> prisma2 lift save --name 'init'
Error Message: ENOENT Error: Error in lift engine:

Split up `select` into `select` and `include`

Based on early user feedback for the new select API, I suggest the split up the select API into 2 parts:

  • select: { ... } explicitly select fields (by default empty selection set)
  • include: { ... } add fields to default selection set

Here's an example:

model Genre {
  id: String
  name: String
  popularity: Int
  tracks: Track[]
}

model Track {
  id: String
  name: String
  genre: Genre
}
// explicitly select some fields
const result = await photon.genres.findMany({
  first: 10,
  select: { id: true, name: true }
})

// all scalars and include all scalars of first 10 tracks
const result = await photon.genres.findMany({
  first: 10,
  include: {
    tracks: { first: 10 }
  }
})

Loose connection with MySQL

When running a lot of operation at "the same time" against the database using a single instance of Photon, connections get refused.

Here a sample with debug: true

  engine request to http://localhost:52107/status failed, reason: connect ECONNREFUSED 127.0.0.1:52107 +0ms
  engine request to http://localhost:52108/status failed, reason: connect ECONNREFUSED 127.0.0.1:52108 +0ms
  engine request to http://localhost:52107/status failed, reason: connect ECONNREFUSED 127.0.0.1:52107 +58ms
  engine request to http://localhost:52108/status failed, reason: connect ECONNREFUSED 127.0.0.1:52108 +1ms
  engine request to http://localhost:52108/status failed, reason: connect ECONNREFUSED 127.0.0.1:52108 +57ms
  engine request to http://localhost:52107/status failed, reason: connect ECONNREFUSED 127.0.0.1:52107 +1ms
  engine request to http://localhost:52107/status failed, reason: connect ECONNREFUSED 127.0.0.1:52107 +54ms
  engine request to http://localhost:52108/status failed, reason: connect ECONNREFUSED 127.0.0.1:52108 +1ms
  engine request to http://localhost:52107/status failed, reason: connect ECONNREFUSED 127.0.0.1:52107 +78ms
  engine request to http://localhost:52108/status failed, reason: connect ECONNREFUSED 127.0.0.1:52108 +1ms
  engine request to http://localhost:52108/status failed, reason: connect ECONNREFUSED 127.0.0.1:52108 +54ms
  engine request to http://localhost:52107/status failed, reason: connect ECONNREFUSED 127.0.0.1:52107 +0ms
  engine request to http://localhost:52107/status failed, reason: connect ECONNREFUSED 127.0.0.1:52107 +57ms

TypeError: cb.apply is not a function

For some reason this copy breaks:

https://github.com/prisma/photon-js/blob/9507d5219ff2729a0a41cb3eef64382ec4d609c0/packages/photon/src/generation/generateClient.ts#L125

My guess is that when typescript compiles async/await into yield statements, fs-extra doesn't properly handle it.

Workaround (in transpiles code):

    yield fs_extra_1.default.copy(
      path_1.default.join(__dirname, '../../runtime'),
      path_1.default.join(outputDir, '/runtime'),
    )

to

    fs_extra_1.default.copySync(
      path_1.default.join(__dirname, '../../runtime'),
      path_1.default.join(outputDir, '/runtime'),
    )

I'd suggest we use: https://github.com/sindresorhus/cpy

@unique is not enforced with SQLite

I'm using this project file:

datasource db {
  provider = "sqlite"
  url      = "file:my.db"
}

generator nexus_prisma {
  provider = "nexus-prisma"
  output   = "node_modules/@generated/nexus-prisma"
}

generator photon {
  provider = "photonjs"
  output   = "node_modules/@generated/photon"
}

model User {
  id    String  @default(cuid()) @id
  email String  @unique
  name  String?
  posts Post[]
}
  
model Post {
  id        String   @default(cuid()) @id
  published Boolean
  title     String
  content   String?
  author    User?
}

Then I'm running this script:

import Photon from '@generated/photon'

const photon = new Photon()

async function main() {

  await photon.connect()

  const newUser = await  photon.users.create({
    data: { 
      email: '[email protected]', 
      name: 'Nikolas'
    },
    select: { id: true }
  })
  console.log(`Create a new user with ID: ${newUser.id}`)

  photon.disconnect()
}

main().catch(e => {
  console.error(e)
  photon.disconnect()
})

I can run it multiple times in a row and the DB happily creates new User records with the same email not enforcing the unique constraint that I specified on the email field.

image

Generated typings are not working properly with JavaScript

Currently, you won't get proper typing unless you manually add .default to you photon instance.

const Photon = require('@generated/photon');
const photon = new Photon.default();

What I will suggest is also to export a named model Photon. Otherwise, even though Babel will transform .default interop exports but we will lose typing information using default exports. Named exports solve this completely.

Problem with the typescript auth demo project.

Using this example repo: https://github.com/prisma/photonjs/tree/master/examples/typescript/graphql-auth

I experience an error when I call the createDraft mutation.

Error: Cannot return null for non-nullable field Mutation.createDraft.
    at completeValue (/Users/sjensen/dev/prisma-simple-demo/node_modules/graphql/execution/execute.js:579:13)
    at /Users/sjensen/dev/prisma-simple-demo/node_modules/graphql/execution/execute.js:511:16
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)

I found that I can fix it by adding an async await in the resolver but it doesn't make any sense to me why this would work.

Before:

  t.field('createDraft', {
      type: 'Post',
      args: {
        title: stringArg(),
        content: stringArg({ nullable: true })
      },
      resolve: (parent, { title, content }, ctx) => {
        const userId = getUserId(ctx);
        return  ctx.photon.posts.create({
          data: {
            title,
            content,
            published: false,
            author: { connect: { id: userId } }
          }
        });
      }
    });

After:
This fixes it- first awaiting the response, saving it as the variable draft and then returning that works just fine.

    t.field('createDraft', {
      type: 'Post',
      args: {
        title: stringArg(),
        content: stringArg({ nullable: true })
      },
      resolve: async (parent, { title, content }, ctx) => {
        const userId = getUserId(ctx);
        const draft = await ctx.photon.posts.create({
          data: {
            title,
            content,
            published: false,
            author: { connect: { id: userId } }
          }
        });
        return draft;
      }
    });

Support for selecting relations of relations (and more sophisticated queries in general)

Perhaps I'm missing something in the documentation, but I can't find anything that describes how to select relations that are more than one layer deep. The example I found is this:

// The returned posts objects will have all scalar fields of the `Post` model and additionally all the categories for each post
const allPosts: Post[] = await photon.posts.findMany({
  include: ["categories"]
})

Okay, this gets me the categories on each returned post, but what if I want to also grab one or more relations of each returned category? I can't see any way to do that right now since include just takes a string array, not any kind of JSON object where i could specify what fields on each category I'd want returned (and iteratively go deeper if needed)

The GraphQL equivalent of what I'd like to be able to do is something like this:

{
 posts {
   id
   categories {
      id
      x {
        id
      } 
      y {
        id
      }
    }
 }
}

I stayed away from Prisma Client (and stuck with Bindings) precisely because it seemed to offer no support for these kinds of sophisticated queries; the fluid API was kind of neat for extremely simple use cases, but hopeless for anything beyond that. Is Photon limited in the same fashion?

I'd really like it if I could select data with Photon in a way similar to this:

// The returned posts objects will have all scalar fields of the `Post` model and additionally all the categories for each post
const allPosts: Post[] = await photon.posts.findMany({
  include: {
    id: true,
    categories: {
      id: true,
      x: {
        id: true
      },
      y: {
        id: true
      }
    }
  }
})

Cannot find module '@generated/photon'

when i use prisma2 init to generate a new project and run:

yarn run v1.17.0
$ ts-node prisma/seed.ts

/Users/a/Downloads/prisma2/node_modules/ts-node/src/index.ts:245
    return new TSError(diagnosticText, diagnosticCodes)
           ^
TSError: ⨯ Unable to compile TypeScript:
prisma/seed.ts:1:20 - error TS2307: Cannot find module '@generated/photon'.

1 import Photon from '@generated/photon'

`updateMany` should return count of updated records

I have this User model:

model User {
  id: Int @id
  name: String
}

The updateMany method for this model has the following signature:

 updateMany<T extends UserUpdateManyArgs>(args: Subset<T, UserUpdateManyArgs>): 'select' extends keyof T ? PromiseLike<UserGetPayload<ExtractUserUpdateManyArgsSelect<T>>> : UserClient<User>;

This means I'm just getting a single User object back. It should return the number records that have been updated in the database.

The same problem seems to exist for deleteMany.

image

Nested create is not working

Might be related to #30

Given this datamodel:

datasource db {
  provider = "sqlite"
  url      = "file:dev.db"
  default  = true
}

generator photon {
  provider = "photonjs"
}

model User {
  id       Int    @id
  username String @unique
  posts    Post[]
}

model Post {
  id   Int    @id
  data String
  user User
}

This mutation doesn't work:

 const testData = await photon.users.create({
    data: {
      username: 'harshit',
      posts: {
        create: {
          data: 'test',
        },
      },
    },
  })

Reproduction repo: https://github.com/pantharshit00/p2-nested-create

Support for JSON/JSONB

Does Prisma Client support these types? If not, what are the plans to support them going forward?

createdAt with default doesn't work

Datamodel

model Post {
  id Int @id
  createdAt DateTime  @default(now())
  updatedAt DateTime @updatedAt
  published Boolean @default(false)
  title String
  content String?
  author User
}

Photon (doesn't allow adding createdAt manually)

const result = await photon.posts.create({
    data: {
      title: title,
      content: content,
      author: { connect: { email: authorEmail } }
    }
  });

Query sent to query engine

  photon mutation {
  photon   createPost(data: {
  photon     title: "Title 1"
  photon     content: "Content 1"
  photon     author: {
  photon       connect: {
  photon         email: "[email protected]"
  photon       }
  photon     }                                                                                                                                                             photon   }) {
  photon     id                                                                                                                                                            photon     createdAt
  photon     updatedAt
  photon     published
  photon     title
  photon     content
  photon   }
  photon } +0ms

Where to put generated code

Problem

  • VSCode doesn't reload generated types when they are updated. While this problem is the most pressing for TS, this is also a problem for JS.

Strategies

Strategy A: VSCode Plugin

Approaches:

  • Override file exclusion for VSC (see this tweet)
  • VSC Plugin to hook into TS language server via an "embedded TS plugin" to tell TS server to reload on file changes

Notes:

  • Which files to look for should be derived from Prisma project file by collecting all output paths from all generators.

Strategy B: Combination of "hashed node_module" + generated entry point in user land

Notes:

  • We need a heuristic where to put the generated entrypoint file (e.g. by reading the rootDir value from tsconfig.json)
  • Just needed for TS version. For JS version we can directly import from node_modules.

Cons:

  • No convenience of non-relative imports (i.e. no more import Photon from '@prisma/photon')
  • Complicated to build
  • Requires to split things up into JS/TS generator version

Strategy C: Require user to add allowJS: true to tsconfig.json

Cons:

  • No longer supports tsc -d

Some types are not working (DateTime and self declared ENUM on Postgres)

When introspecting my Postgres database, the schema is perfect. However, Photon will throw errors if types DateTime or some custom ENUM are present in the requested objects (even is those specific fields are not requested by graphql).

Commenting out the fields in the project.prisma and regenerating obviously makes the error go away.

Errors seems to come form the Rust library. Are these part of the early preview limitations ?

DateTime error below :

Error in Photonselect,cover: 
[
  {
    \"error\": \"ConnectorError(QueryError(Error { kind: FromSql, cause: Some(WrongType(Type(Timestamptz))) }\
\
stack backtrace:\
   0: failure::backtrace::internal::InternalBacktrace::new::h84e0252f893b7b0e (0x55a8a0489290)\
   1: failure::backtrace::Backtrace::new::h381a1eb507d04e2c (0x55a8a0489440)\
   2: <sql_connector::error::SqlError as core::convert::From<tokio_postgres::error::Error>>::from::h34ff4340a0dd5b3f (0x55a89febbc67)\
   3: sql_connector::database::postgresql::<impl sql_connector::row::ToSqlRow for tokio_postgres::row::Row>::to_sql_row::convert::h178249b965d8493a (0x55a89fe2686b)\
   4: sql_connector::database::postgresql::<impl sql_connector::row::ToSqlRow for tokio_postgres::row::Row>::to_sql_row::h3875436f09b0556f (0x55a89fe368ff)\
   5: sql_connector::database::postgresql::<impl sql_connector::transactional::Transaction for postgres::transaction::Transaction>::filter::h498f6550aa3967b1 (0x55a89fe9156a)\
   6: <sql_connector::database::postgresql::PostgreSql as sql_connector::transactional::Transactional>::with_transaction::hd5f1950fe91ab7e3 (0x55a89fbe22a8)\
   7: sql_connector::transactional::database_reader::<impl connector::database_reader::DatabaseReader for sql_connector::database::SqlDatabase<T>>::get_related_records::h291c7a1f45dc7434 (0x55a89fb52ab8)\
   8: core::executor::read::ReadQueryExecutor::execute_internal::hf955377e18499bf9 (0x55a89ff8d4fd)\
   9: core::executor::read::ReadQueryExecutor::execute_internal::hf955377e18499bf9 (0x55a89ff8f60c)\
  10: core::executor::Executor::exec_all::h019661aa466552b2 (0x55a89ffa4f55)\
  11: <prisma::req_handlers::graphql::GraphQlRequestHandler as prisma::req_handlers::RequestHandler>::handle::hd901880e604ba7f3 (0x55a89fc6494d)\
  12: prisma::http_handler::h574a96a3df5ad7b2 (0x55a89fc00499)\
  13: <F as actix_web::with::FnWith<T,R>>::call_with::h8921e8f777cf5423 (0x55a89fc5955e)\
  14: <actix_web::with::WithHandlerFut<T,S,R> as futures::future::Future>::poll::hd0405f55c326258c (0x55a89fc63271)\
  15: actix_web::pipeline::PipelineState<S,H>::poll::h05fe08bd6589e38c (0x55a89fb44610)\
  16: <actix_web::pipeline::Pipeline<S,H> as actix_web::server::handler::HttpHandlerTask>::poll_io::hf988cbba155aa2c2 (0x55a89fb33af0)\
  17: actix_web::server::h1::Http1Dispatcher<T,H>::poll_handler::h0e2de2e2f0e85c3b (0x55a89fb0afeb)\
  18: actix_web::server::h1::Http1Dispatcher<T,H>::poll::h7c512f9208c70f65 (0x55a89fbd73f7)\
  19: <actix_web::server::channel::HttpChannel<T,H> as futures::future::Future>::poll::h3fda956b624b7067 (0x55a89fbd39b9)\
  20: <actix_web::server::channel::HttpChannel<T,H> as futures::future::Future>::poll::h3fda956b624b7067 (0x55a89fbd48e6)\
  21: <actix_net::service::and_then::AndThenFuture<A,B> as futures::future::Future>::poll::hb1978ee7b706a005 (0x55a89fb3350d)\
  22: futures::future::chain::Chain<A,B,C>::poll::h4dcce436324a17dd (0x55a89fc7fe59)\
  23: futures::task_impl::std::set::hb6a916396ab13c6e (0x55a89fd4f262)\
  24: futures::task_impl::Spawn<T>::poll_future_notify::ha13909c8cd98d4fe (0x55a89fd69c66)\
  25: tokio_current_thread::CurrentRunner::set_spawn::hcab1a55dd9f5caaf (0x55a89fd49f74)\
  26: tokio_current_thread::scheduler::Scheduler<U>::tick::h1f8b6bf060538e24 (0x55a89fd566ca)\
  27: tokio_current_thread::Entered<P>::block_on::hd80cde5490457c04 (0x55a89fd4a92a)\
  28: std::thread::local::LocalKey<T>::with::h66e6fccf026a2b83 (0x55a89fd61138)\
  29: std::thread::local::LocalKey<T>::with::h7b6b9e8e24d2b1ae (0x55a89fd61f68)\
  30: std::thread::local::LocalKey<T>::with::h4efe62e0c4ca0fb4 (0x55a89fd6042f)\
  31: std::thread::local::LocalKey<T>::with::h1aefc504c0a5187d (0x55a89fd5f825)\
  32: tokio::runtime::current_thread::runtime::Runtime::block_on::h573894b7abc600ef (0x55a89fd4e180)\
  33: std::sys_common::backtrace::__rust_begin_short_backtrace::h027e6ea9ab4c2090 (0x55a89fd67687)\
  34: std::panicking::try::do_call::hbc22e41bfc445835 (0x55a89fd4c736)\
  35: __rust_maybe_catch_panic (0x55a8a04bce2a)\
             at src/libpanic_unwind/lib.rs:87\
  36: core::ops::function::FnOnce::call_once{{vtable.shim}}::hf39704692fc5ef53 (0x55a89fd67f26)\
  37: call_once<(),FnBox<()>> (0x55a8a04a325f)\
             at /rustc/3c235d5600393dfe6c36eeed34042efad8d4f26e/src/liballoc/boxed.rs:702\
  38: call_once<(),alloc::boxed::Box<FnBox<()>>> (0x55a8a04bc240)\
             at /rustc/3c235d5600393dfe6c36eeed34042efad8d4f26e/src/liballoc/boxed.rs:702\
      start_thread\
             at src/libstd/sys_common/thread.rs:14\
      thread_start\
             at src/libstd/sys/unix/thread.rs:80\
  39: start_thread (0x7f807e39b182)\
  40: __clone (0x7f807e2a8b1f)\
  41: <unknown> (0x0)))\"
  }
]

Enum error below (enum is a custom ROLES enum) :

Error in Photonselect,author: 
[
  {
    \"error\": \"ConnectorError(QueryError(Error { kind: FromSql, cause: Some(WrongType(Type(Other(Other { name: \\\"roles\\\", oid: 17089, kind: Enum([\\\"anonymous\\\", \\\"registered\\\", \\\"editor\\\", \\\"admin\\\", \\\"superadmin\\\"]), schema: \\\"public\\\" })))) }\
\
stack backtrace:\
   0: failure::backtrace::internal::InternalBacktrace::new::h84e0252f893b7b0e (0x5564cd836290)\
   1: failure::backtrace::Backtrace::new::h381a1eb507d04e2c (0x5564cd836440)\
   2: <sql_connector::error::SqlError as core::convert::From<tokio_postgres::error::Error>>::from::h34ff4340a0dd5b3f (0x5564cd268c67)\
   3: sql_connector::database::postgresql::<impl sql_connector::row::ToSqlRow for tokio_postgres::row::Row>::to_sql_row::convert::h178249b965d8493a (0x5564cd1d34cb)\
   4: sql_connector::database::postgresql::<impl sql_connector::row::ToSqlRow for tokio_postgres::row::Row>::to_sql_row::h3875436f09b0556f (0x5564cd1e38ff)\
   5: sql_connector::database::postgresql::<impl sql_connector::transactional::Transaction for postgres::transaction::Transaction>::filter::h498f6550aa3967b1 (0x5564cd23e56a)\
   6: <sql_connector::database::postgresql::PostgreSql as sql_connector::transactional::Transactional>::with_transaction::hd5f1950fe91ab7e3 (0x5564ccf8f2a8)\
   7: sql_connector::transactional::database_reader::<impl connector::database_reader::DatabaseReader for sql_connector::database::SqlDatabase<T>>::get_related_records::h291c7a1f45dc7434 (0x5564cceffab8)\
   8: core::executor::read::ReadQueryExecutor::execute_internal::hf955377e18499bf9 (0x5564cd33a4fd)\
   9: core::executor::read::ReadQueryExecutor::execute_internal::hf955377e18499bf9 (0x5564cd33c60c)\
  10: core::executor::Executor::exec_all::h019661aa466552b2 (0x5564cd351f55)\
  11: <prisma::req_handlers::graphql::GraphQlRequestHandler as prisma::req_handlers::RequestHandler>::handle::hd901880e604ba7f3 (0x5564cd01194d)\
  12: prisma::http_handler::h574a96a3df5ad7b2 (0x5564ccfad499)\
  13: <F as actix_web::with::FnWith<T,R>>::call_with::h8921e8f777cf5423 (0x5564cd00655e)\
  14: <actix_web::with::WithHandlerFut<T,S,R> as futures::future::Future>::poll::hd0405f55c326258c (0x5564cd010271)\
  15: actix_web::pipeline::PipelineState<S,H>::poll::h05fe08bd6589e38c (0x5564ccef1610)\
  16: <actix_web::pipeline::Pipeline<S,H> as actix_web::server::handler::HttpHandlerTask>::poll_io::hf988cbba155aa2c2 (0x5564ccee0af0)\
  17: actix_web::server::h1::Http1Dispatcher<T,H>::poll_handler::h0e2de2e2f0e85c3b (0x5564cceb7feb)\
  18: actix_web::server::h1::Http1Dispatcher<T,H>::poll::h7c512f9208c70f65 (0x5564ccf843f7)\
  19: <actix_web::server::channel::HttpChannel<T,H> as futures::future::Future>::poll::h3fda956b624b7067 (0x5564ccf809b9)\
  20: <actix_web::server::channel::HttpChannel<T,H> as futures::future::Future>::poll::h3fda956b624b7067 (0x5564ccf818e6)\
  21: <actix_net::service::and_then::AndThenFuture<A,B> as futures::future::Future>::poll::hb1978ee7b706a005 (0x5564ccee050d)\
  22: futures::future::chain::Chain<A,B,C>::poll::h4dcce436324a17dd (0x5564cd02ce59)\
  23: futures::task_impl::std::set::hb6a916396ab13c6e (0x5564cd0fc262)\
  24: futures::task_impl::Spawn<T>::poll_future_notify::ha13909c8cd98d4fe (0x5564cd116c66)\
  25: tokio_current_thread::CurrentRunner::set_spawn::hcab1a55dd9f5caaf (0x5564cd0f6f74)\
  26: tokio_current_thread::scheduler::Scheduler<U>::tick::h1f8b6bf060538e24 (0x5564cd1036ca)\
  27: tokio_current_thread::Entered<P>::block_on::hd80cde5490457c04 (0x5564cd0f792a)\
  28: std::thread::local::LocalKey<T>::with::h66e6fccf026a2b83 (0x5564cd10e138)\
  29: std::thread::local::LocalKey<T>::with::h7b6b9e8e24d2b1ae (0x5564cd10ef68)\
  30: std::thread::local::LocalKey<T>::with::h4efe62e0c4ca0fb4 (0x5564cd10d42f)\
  31: std::thread::local::LocalKey<T>::with::h1aefc504c0a5187d (0x5564cd10c825)\
  32: tokio::runtime::current_thread::runtime::Runtime::block_on::h573894b7abc600ef (0x5564cd0fb180)\
  33: std::sys_common::backtrace::__rust_begin_short_backtrace::h027e6ea9ab4c2090 (0x5564cd114687)\
  34: std::panicking::try::do_call::hbc22e41bfc445835 (0x5564cd0f9736)\
  35: __rust_maybe_catch_panic (0x5564cd869e2a)\
             at src/libpanic_unwind/lib.rs:87\
  36: core::ops::function::FnOnce::call_once{{vtable.shim}}::hf39704692fc5ef53 (0x5564cd114f26)\
  37: call_once<(),FnBox<()>> (0x5564cd85025f)\
             at /rustc/3c235d5600393dfe6c36eeed34042efad8d4f26e/src/liballoc/boxed.rs:702\
  38: call_once<(),alloc::boxed::Box<FnBox<()>>> (0x5564cd869240)\
             at /rustc/3c235d5600393dfe6c36eeed34042efad8d4f26e/src/liballoc/boxed.rs:702\
      start_thread\
             at src/libstd/sys_common/thread.rs:14\
      thread_start\
             at src/libstd/sys/unix/thread.rs:80\
  39: start_thread (0x7f0c57c0a182)\
  40: __clone (0x7f0c57b17b1f)\
  41: <unknown> (0x0)))\"
  }
]
`

Add `findOrNull` method

Using the demo project 'graphql-apollo-server' typescript project, I query on post and use a dummy id argument and expect to get a null post obj back, but instead I get an internal server error.

t.field('post', {
      type: 'Post',
      nullable: true,
      args: { id: idArg() },
      resolve: (parent, { id }, ctx) => {
        return ctx.photon.posts.findOne({
          where: {
            id,
          },
        })
      },
    })
Query:

{
 post(id: "123") {
   id
   author {
     id
   }
 }
}

Result: Error in Photon: \n[\n  {\n \"error\": \"ConnectorError(RecordDoesNotExist)\"\n  }\n]"

Is there a way to tell photon to just send back null or is this a bug?

Enum from MySQL are undefined

Introspecting MySQL database works well, but when using a generated Photon client, if a column is an Enum, it will return undefined.

Blacklist model names

Nonexhaustive List:

  • String
  • Int
  • Float
  • Subscription
  • DateTime
  • WhereInput
  • IDFilter
  • StringFilter

Alllow for array-based `select` syntax

Currently I can select fields in a Photon API call using the select syntax like so:

const allPosts: Post[] = await photon.posts.findMany({
  select: { id: true, author: true}
})

I think it would be great to provide an array-based API as well:

const allPosts: Post[] = await photon.posts.findMany({
  select: ["id", "author"]
})

Route /filterPosts of rest-express example fails validation

A type-safe query fails at runtime validation

app.get('/filterPosts', async (req, res) => {
  const { searchString } = req.query
  const draftPosts = await photon.posts.findMany({
    where: {
      OR: [
        {
          title: {
            contains: searchString,
          },
        },
        {
          content: {
            contains: searchString,
          },
        },
      ],
    },
  })
  res.json(draftPosts)
})

Invalid `photon.posts.findMany()` invocation in /Users/divyendusingh/Documents/prisma/photon-js/examples/typescript/rest-express/src/index.ts:68:41

{
  where: {
    OR: {
      '0': {
        title: {
?         contains?: String,
?         equals?: String,
?         not?: String | StringFilter,
?         in?: String,                                                                                                                                                   ?         notIn?: String,
?         lt?: String,
?         lte?: String,
?         gt?: String,
?         gte?: String,
?         startsWith?: String,
?         endsWith?: String
        }
      },
      '1': {
        content: {
?         contains?: String,
?         equals?: String | null,
?         not?: String | null | NullableStringFilter,
?         in?: String,
?         notIn?: String,
?         lt?: String,
?         lte?: String,
?         gt?: String,
?         gte?: String,
?         startsWith?: String,
?         endsWith?: String
        }
      }
    }
  }
}

photonJs example where is prisma.yml

I'm following the instructions to a tee but it gets weird here

After having updated the datamodel, you need to deploy the changes:

prisma deploy

Note that this also invokes prisma generate (because of the post-deploy hook in prisma.yml) which regenerates the Prisma client in ./src/generated/prisma-client.

But i have no prisma.yml file?
I also don't have a /generated/prisma.graphlql, when were these meant to be created?

as this is prisma2 . should we not be using prisma2 deploy ??

Generated code has an absolute path

This line prints the cwd in generated code which is an absolute path.

This breaks the assumption that generated code (even in node_modules) can be moved around across machines (for developers or build systems).

findOne returns Error when no record was found.

Yesterday I noticed the following bug:

let user = await context.photon.users.findOne({ where: { email: args.email } });

When the findOne function cannot find a record, it doesn't return null, which I believe would be the expected behaviour but instead it returns an error:

Screenshot 2019-07-04 at 08 35 25

Inconsistent type generation

Are we treating the field name id somehow special? For model Blog { id Int @id } I don’t have the provide id in Photon but for model PostNews { new Int @id } I do have to provide the new field.

image
image

Enable creation of record if not already present - `findOrCreate`

Problem

Whenever making use of database-stored configuration data, it is often wanted to check whether such data is available, and creating it if it’s not.
Doing that with the current client requires to add code which performs the check and creates the record if it’s not present.
Having a more concise way of performing these tasks would improve the overall developer experience.

Solution

Implement a findOrCreate function taking an object as input that performs the following:

  • looks for the input object using its primary key,
  • if not found, it goes ahead and creates it.

Connection fails if module has been bundled via Parcel

Howdy!

First off—great work here. This project feels like a game changer. I'm so excited to be a part of it's evolution however possible.

I've been experimenting with using Photon in a monorepo, and using parcel to bundle certain pages for deployment out to lambdas. As such, there are some path changes and other things that get moved around a bit in the process.

When testing the package independently, Photon works as expected, however after the package contents get bundled into a singular file, it is no longer able to connect.

My entry point for the package consuming Photon returns a promise with the connected photon object:

index.ts

import Photon from '@generated/photon'
import { inspect } from 'util';

function initPhoton(photonConfig: any = {}) {
  const photon = new Photon(photonConfig);
  return photon.connect()
    .then(() => {
      console.log('photon connected');
      return photon;
    })
    .catch(error => {
      console.error('photon connection error', error);
      console.log(inspect(photon, { depth: 3, colors: true }));
      return false;
    });
}

export default initPhoton;
export { default as Photon } from '@generated/photon';

The file above is compiled via tsc and consumed by other packages within the project. I wrote a small test file within the same package to validate that it behaves as expected. This file simple imports the module as it is exported from the compiled artifact of the file above.

test.js

const initPhoton = require('./dist/index').default;

initPhoton()
  .then(photon => photon && photon.organizations.create({
    data: {
      access_token: '126', scope: '126', team_id: '126', team_name: '126', user_id: '126',
    },
  }))
  .then(console.log)
  .catch(console.error)
  .then(() => process.exit());

When I run the file above, via node test.js, it appears to execute as expected. Returning the entry as it is written to the database.

However, if I bundle the the test.js file using the command below, invoking the same file no longer works.

 npx parcel build test.js --target node --bundle-node-modules -d testDist

node testDist/test.js

I've been having trouble determining an actual source of the connection error. The connect() promise usually rejects with a value of 1 however if I copy the prisma folder into the testDist directory, the connectionPromise rejects with:

{ Error: spawn EACCES
    at ChildProcess.spawn (internal/child_process.js:313:11)
    at Object.exports.spawn (child_process.js:508:9)
    at t.default.start (/Users/eschoellhorn/Repos/praisely-slackbot/packages/praisely-data/testDist/test.js:50:110668)
    at y.start (/Users/eschoellhorn/Repos/praisely-slackbot/packages/praisely-data/testDist/test.js:50:21187)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:189:7)
    at Function.Module.runMain (module.js:696:11)
    at startup (bootstrap_node.js:204:16)
    at bootstrap_node.js:625:3 errno: 'EACCES', code: 'EACCES', syscall: 'spawn' }

I have experimented with trying to alter the cwd prop for the engine to point to an existing prisma folder but haven't been able to affect much meaningful change. Happy to keep trying, but could use some pointers...

Thanks and, again, awesome work!!

Aggregations

type DynamicResult2 = (User & { aggregate: { age: { avg: number } } })[]
const dynamicResult2: DynamicResult2 = await prisma.users({
  select: { aggregate: { age: { avg: true } } },
})

type DynamicResult3 = User & {
  posts: (Post & { aggregate: { count: number } })[]
}
const dynamicResult3: DynamicResult3 = await prisma.users.findOne({
  where: 'bobs-id',
  select: { posts: { select: { aggregate: { count: true } } } },
})

const deletedCount: number = await prisma.users.deleteMany()

Split up `select` into `select` and `include`

Based on early user feedback for the new select API, I suggest the split up the select API into 2 parts:

  • select: { ... } explicitly select fields (by default empty selection set)
  • include: { ... } add fields to default selection set

Here's an example:

model Genre {
  id: String
  name: String
  popularity: Int
  tracks: Track[]
}

model Track {
  id: String
  name: String
  genre: Genre
}
// explicitly select some fields
const result = await photon.genres.findMany({
  first: 10,
  select: { id: true, name: true }
})

// all scalars and include all scalars of first 10 tracks
const result = await photon.genres.findMany({
  first: 10,
  include: {
    tracks: { first: 10 }
  }
})

Adjust default generation path to `@prisma/photon`

Currently the default output path for the generated Photon library is @generated/photon. While this is working well from a technical perspective, we've received the feedback that this might be potentially problematic as we don't own the @generated NPM organization.

A safer alternative would be @prisma/generated/photon or @prisma/photon.

More ideas welcome! 💡

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.