Skip to content

Commit

Permalink
refactor(client, $raw): Adapting to the new raw protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
medz committed Sep 15, 2024
1 parent 1d6679a commit 0b60312
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 117 deletions.
6 changes: 3 additions & 3 deletions docs/getting-started/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ Install Prisma Dart Client, you need to create a `prisma/schema.prisma` file in
::: code-group

```bash [Bun.js]
bun prisma init --generator-provider="dart run orm"
bun prisma init
```

```bash [NPM]
npx prisma init --generator-provider="dart run orm"
npx prisma init
```

```bash [pnpm]
pnpx prisma init --generator-provider="dart run orm"
pnpx prisma init
```

:::
Expand Down
33 changes: 30 additions & 3 deletions examples/with_sqlite/bin/with_sqlite.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,44 @@ import 'package:orm/orm.dart';
import 'package:with_sqlite/with_sqlite.dart';

final prisma = PrismaClient(log: {
(LogLevel.info, LogEmit.stdout),
(LogLevel.query, LogEmit.stdout),
});

Future<void> main() async {
try {
final games = await prisma.$transaction((prisma) async {
// With transaction run query
final gamesWithTransaction = await prisma.$transaction((prisma) async {
final result = await prisma.game.aggregate(
select: AggregateGameSelect(
$count: PrismaUnion.$2(
AggregateGameCountArgs(
select: GameCountAggregateOutputTypeSelect(id: true),
),
),
),
);
if (result.$count!.id! <= 3) {
await prisma.game.create(
data: PrismaUnion.$2(
GameUncheckedCreateInput(name: 'Game ${result.$count?.id}'),
),
);
}

return await prisma.game.findMany();
});
print(gamesWithTransaction.map((e) => e.toJson()));

// final games = await prisma.game.findMany();
// Find many
final games = await prisma.game.findMany();
print(games.map((e) => e.toJson()));

// SQL query all rows.
final result = await prisma.$raw.query('SELECT * FROM games');
print(result);

// Delete a `game_id` eq "1" row, DB not found "1", returns `0`
print(await prisma.$raw.execute(r'delete from games where game_id = "1"'));
} finally {
await prisma.$disconnect();
}
Expand Down
27 changes: 22 additions & 5 deletions packages/orm/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
## v5.0.7
## v5.1.0

To install Prisma ORM for Dart v5.0.7 run this command
To install Prisma ORM for Dart v5.1.0 run this command

```bash
dart pub add orm:^5.0.7
dart pub add orm:^5.1.0
```

Or update your `pubspec.yaml` file:

```yaml
dependencies:
orm: ^5.0.7
orm: ^5.1.0
```
### What's Changed
- **upstream**: Starting from Prisma v5.17.0, the new RAW raw SQL protocol has been enabled.
- **$raw**: Now `$raw.query` returns the correct data type front, instead of `dynamic`.
- **$raw**: `$raw.execute` now returns the number of rows affected as an `int`.
- **docs**: Removed param from docs that are no longer supported by the Prisma CLI

#### QueryRaw performance improvements

We’ve changed the response format of queryRaw to decrease its average size which reduces serialization CPU overhead.

When querying large data sets, we expect you to see improved memory usage and up to 2x performance improvements.

## ‼️Important Tips

Starting from version v5.1.0, only Prisma CLI v5.17.0 or higher is supported!

## v5.0.6

To install Prisma ORM for Dart v5.0.6 run this command
Expand All @@ -28,7 +45,7 @@ dependencies:
orm: ^5.0.6
```

## What's Changed
### What's Changed

- **deps**: Upgrade the Dart SDK min version to `^3.4.0`
- **deps**: Upgrade `path` package version to `^1.9.0`
Expand Down
46 changes: 46 additions & 0 deletions packages/orm/lib/src/runtime/raw/_deserialize_raw_results.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import 'dart:convert';

import '../decimal.dart';

extension type _TypedRawResult._(Map _) {
Iterable<String> get columns => (_['columns'] as Iterable).cast<String>();
Iterable<String> get types => (_['types'] as Iterable).cast<String>();
Iterable<Iterable> get rows => (_['rows'] as Iterable).cast<Iterable>();
}

List<Map<String, Object?>> deserializeRawResult(Map result) {
final _TypedRawResult(:columns, :types, :rows) = _TypedRawResult._(result);
final deserialized = <Map<String, Object?>>[];

for (final row in rows) {
final mapped = <String, Object?>{};
for (final (index, value) in row.indexed) {
mapped[columns.elementAt(index)] = _decode(types.elementAt(index), value);
}

deserialized.add(mapped);
}

return deserialized;
}

Object? _decode(String type, Object? value) {
return switch (type) {
'bigint' => BigInt.parse(value.toString()),
'bytes' => base64.decode(value.toString()),
'decimal' => Decimal.parse(value.toString()),
'datetime' || 'date' => DateTime.parse(value.toString()),
'time' => DateTime.parse('1970-01-01T${value}Z'),
'bigint-array' => _decodeIterable('bigint', value as Iterable),
'bytes-array' => _decodeIterable('bytes', value as Iterable),
'decimal-array' => _decodeIterable('decimal', value as Iterable),
'datetime-array' => _decodeIterable('datetime', value as Iterable),
'date-array' => _decodeIterable('date', value as Iterable),
'time-array' => _decodeIterable('time', value as Iterable),
_ => value,
};
}

List _decodeIterable(String type, Iterable values) {
return values.map((value) => _decode(type, value)).toList(growable: false);
}

This file was deleted.

38 changes: 38 additions & 0 deletions packages/orm/lib/src/runtime/raw/_serialize_raw_params.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'dart:convert';
import 'dart:typed_data';

import '../decimal.dart';
import '../json_convertible.dart';
import '../prisma_null.dart';

/// Serialize RAW params.
String serializeRawParams(Iterable<Object?> params) {
return json.encode(
params.map(_encode).toList(growable: false),
);
}

Object? _encode(Object? value) {
return switch (value) {
PrismaNull() => null,
BigInt value => _createTypedValue('bigint', value.toString()),
DateTime value =>
_createTypedValue('date', value.toUtc().toIso8601String()),
Decimal value => _createTypedValue('decimal', value.toString()),
Uint8List bytes => _createTypedValue('bytes', base64.encode(bytes)),
TypedData typedData => _encode(typedData.buffer),
ByteBuffer byteBuffer => _encode(byteBuffer.asUint8List()),
JsonConvertible value => _createTypedValue('json', value.toJson()),
Iterable iterable => iterable.map(_encode).toList(growable: false),
Map value =>
value.map((key, value) => MapEntry(key.toString(), _encode(value))),
_ => value,
};
}

Map<String, Object> _createTypedValue(String type, Object value) {
return {
'prisma__type': type,
'prisma__value': value,
};
}
47 changes: 27 additions & 20 deletions packages/orm/lib/src/runtime/raw/raw_client.dart
Original file line number Diff line number Diff line change
@@ -1,36 +1,45 @@
import 'dart:convert';

import '../../base_prisma_client.dart';
import '../json_protocol/protocol.dart';
import '../json_protocol/serialize.dart';
import '_internal/raw_parameter_codec.dart';
import '_serialize_raw_params.dart';
import '_deserialize_raw_results.dart';

class RawClient<Client extends BasePrismaClient<Client>> {
final Client _client;

const RawClient(Client client) : _client = client;

Future<dynamic> query(String sql, [Iterable<dynamic>? parameters]) => _inner(
action: JsonQueryAction.queryRaw,
sql: sql,
parameters: parameters?.toList(growable: false),
);
Future<List<Map<String, Object?>>> query(
String sql, [
Iterable<Object>? parameters,
]) async {
final results = await _innerRunSQL(
action: JsonQueryAction.queryRaw,
sql: sql,
parameters: parameters,
);

return deserializeRawResult(results[JsonQueryAction.queryRaw.name]);
}

Future<int> execute(String sql, [Iterable<Object>? parameters]) async {
final results = await _innerRunSQL(
action: JsonQueryAction.executeRaw,
sql: sql,
parameters: parameters,
);

Future<dynamic> execute(String sql, [Iterable<dynamic>? parameters]) =>
_inner(
action: JsonQueryAction.executeRaw,
sql: sql,
parameters: parameters?.toList(growable: false),
);
return results[JsonQueryAction.executeRaw.name];
}

Future<dynamic> _inner({
Future<Map> _innerRunSQL({
required String sql,
required JsonQueryAction action,
List<dynamic>? parameters,
Iterable<Object>? parameters,
}) async {
final args = {
'query': sql,
'parameters': json.encode(rawParameter.encode(parameters ?? const [])),
'parameters': serializeRawParams(parameters ?? const []),
};

final query = serializeJsonQuery(
Expand All @@ -39,12 +48,10 @@ class RawClient<Client extends BasePrismaClient<Client>> {
args: args,
);

final result = await _client.$engine.request(
return _client.$engine.request(
query,
headers: _client.$transaction.headers,
transaction: _client.$transaction.transaction,
);

return rawParameter.decode(result[action.name]);
}
}
2 changes: 1 addition & 1 deletion packages/orm/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: orm
description: Next-generation ORM for Dart & Flutter | PostgreSQL, MySQL, MariaDB, SQL Server, SQLite, MongoDB and CockroachDB.
version: 5.0.7
version: 5.1.0
homepage: https://prisma.pub
repository: https://github.com/medz/prisma-dart
funding:
Expand Down

0 comments on commit 0b60312

Please sign in to comment.