medz / prisma-dart

Prisma Client Dart is an auto-generated type-safe ORM. It uses Prisma Engine as the data access layer and is as consistent as possible with the Prisma Client JS/TS APIs.
https://prisma.pub
BSD 3-Clause "New" or "Revised" License
436 stars 29 forks source link

P2021: Prisma Dart trying to find the wrong table name #376

Closed SunP04 closed 3 weeks ago

SunP04 commented 3 weeks ago

Model Setup

model Game {
  id String @id @default(uuid()) @map("game_id")

  leftTeam  String
  leftScore  Int    @default(0)

  rightTeam String
  rightScore  Int    @default(0)

  @@map("games")
}

Problem

When querying any model, prisma throws a P2021 error.

Stacktrace

Information got from my recoverer

Exception: [{error: KnownError { message: "The table `main.games` does not exist in the current database.", meta: Object {"table": String("main.games")}, error_code: "P2021" }, user_facing_error: {is_panic: false, message: The table `main.games` does not exist in the current database., meta: {table: main.games}, error_code: P2021}}]

Expected

Additional Info

Thanks for any help, Sun.

medz commented 3 weeks ago

@SunP04 Okay, may I ask which database you are using? So that I can investigate, it would be best to post the query statement.

SunP04 commented 3 weeks ago

@medz using sqlite right now.

it would be best to post the query statement.

Any query is causing that issue, so any should work as example.

For future reference, that's my generator/provider setup

generator client {
  provider = "dart run orm"
  output = "../lib/providers/prisma"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}
SunP04 commented 3 weeks ago

New context and resolutions:

Repo: LiveScore

Path issues:

When using prisma dart, I assumed it also got the path from .env but it didn't, so it created the shown error here (searching for the wrong table).

Aftermath:

Another error showed up when I corrected that problem, the BinaryEngine is never considered to be "ready" and when I call any method or query or just call PrismaClient#$connect.

Stacktrace:

Unhandled exception:
Exception: Prisma binary query engine not ready
#0      BinaryEngine._serverEndpoint.<anonymous closure> (package:orm/engines/binary.dart:114:13)
#1      RetryOptions.retry (package:retry/retry.dart:131:24)
<asynchronous suspension>
#2      BinaryEngine._serverReady (package:orm/engines/binary.dart:121:18)
<asynchronous suspension>
#3      BinaryEngine._internalStart (package:orm/engines/binary.dart:99:19)
<asynchronous suspension>
#4      BinaryEngine.start (package:orm/engines/binary.dart:60:18)
<asynchronous suspension>
#5      main (file:///C:/Users/pedro/Desktop/Coding/Dart/livescore/bin/server.dart:26:3)
<asynchronous suspension>
medz commented 3 weeks ago

@SunP04

import 'dart:io';

import 'env.dart';
import 'package:livescore/providers/prisma/client.dart';
import 'package:path/path.dart' as p;

final class PrismaConfig {
  final PrismaClient client;

  const PrismaConfig({required this.client});

  factory PrismaConfig.connect(EnvConfig env) {
    final fullPath = p.join(Directory.current.path, "prisma", env.dbPath);
    final path = p.normalize(fullPath);

    final client = PrismaClient(datasourceUrl: path);

    return PrismaConfig(client: client);
  }
}

You made a serious mistake, that is, you did not follow the Prisma Connection URL protocol rules. 👉 https://www.prisma.io/docs/orm/overview/databases/sqlite  I think the URL you finally completed on the Window should be in the style of C:\\a/b/c/d.db, ​​but it actually needs to be file:C:\\a/b/c/d.db  According to your code, you only need to change line 16 to: 

++ final client = PrismaClient(datasourceUrl: 'file:$path');
-- final client = PrismaClient(datasourceUrl: path);

 Then make sure env.dbPath is a path relative to the prisma/ directory.

medz commented 3 weeks ago

@SunP04

import 'dart:io' show File;

String resolvePrismaConnectURL(String datasourceUrl) {
  final url = Uri.tryParse(datasourceUrl);
  const ptotocols = ['file', 'mysql', 'mongodb', 'sqlserver'];

  if (url == null || !ptotocols.contains(url.scheme)) {
    throw StateError('Invalid Prisma connection URL');
  } else if (url.scheme == 'file') {
    final sqliteDatabaseFile = File.fromUri(url);
    if (sqliteDatabaseFile.existsSync()) {
      return 'file:${sqliteDatabaseFile.path}';
    }

    throw StateError('SQLite database file not found');
  }

  return url.toString();
}

I'll give you a method I often use to verify the URL, which can ensure that your database URL is correct.

SunP04 commented 3 weeks ago

@medz

aaah, didn't know I actually needed to add the scheme on it, I thought it inferred from the provider type

Just pushed those changes to git and they're running now, it was just that error.

I'll give you a method I often use to verify the URL, which can ensure that your database URL is correct.

I added that method in my lib/shared/path/resolve_protocol.dart and there is a reference to you there, since I didn't write the code :d

Thanks for all the help

SunP04 commented 3 weeks ago

Since the problem is resolved, I'll just close the issue and I don't know if there is a solved tag or not, but it's solved too.

medz commented 3 weeks ago

@SunP04 https://gitlab.com/SunP04/livescore/-/blob/dev/bin/config/prisma.dart?ref_type=heads#L13

I observed that you used the Prisma Datasource URL incorrectly. resolvePrismaFileProtocol function will return the correct Prisma Connection URL, you don't need to deal with it.

import 'package:livescore/shared/path/resolve_protocol.dart';

import 'env.dart';
import 'package:livescore/providers/prisma/client.dart';

final class PrismaConfig {
    final PrismaClient client;

    const PrismaConfig({required this.client});

    factory PrismaConfig.connect(EnvConfig env) {
--     final path = resolvePrismaFileProtocol(env.dbPath);
++     final path = resolvePrismaFileProtocol(env.DATABASE_URL);
--     final client = PrismaClient(datasourceUrl: "file:$path");
++     final client = PrismaClient(datasourceUrl: url);

       return PrismaConfig(client: client);
    }
}