Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server 6 updates #45

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions lib/edgeql_codegen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import 'package:build/build.dart';
import 'package:code_builder/code_builder.dart';
import 'package:dart_style/dart_style.dart';
import 'package:pub_semver/pub_semver.dart';
import 'package:edgedb/src/base_proto.dart';
import 'package:edgedb/src/client.dart';
import 'package:edgedb/src/codecs/codecs.dart';
Expand Down Expand Up @@ -107,6 +108,7 @@ class EdgeqlCodegenBuilder implements Builder {
final holder = await connPool.acquireHolder(Options.defaults());
try {
parseResult = await (await holder.getConnection()).parse(
language: Language.edgeql,
query: query,
outputFormat: OutputFormat.binary,
expectedCardinality: Cardinality.many,
Expand Down Expand Up @@ -228,10 +230,11 @@ class EdgeqlCodegenBuilder implements Builder {
.statement;
}))));

final generatedCode = DartFormatter().format(file
.build()
.accept(DartEmitter.scoped(useNullSafetySyntax: true))
.toString());
final generatedCode = DartFormatter(languageVersion: Version(3, 6, 0))
.format(file
.build()
.accept(DartEmitter.scoped(useNullSafetySyntax: true))
.toString());

await buildStep.writeAsString(
inputId.addExtension('.dart'),
Expand Down
36 changes: 31 additions & 5 deletions lib/src/base_proto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import 'primitives/transport.dart';
import 'primitives/types.dart';
import 'utils/indent.dart';

const protoVer = ProtocolVersion(2, 0);
const protoVer = protoV3;
const minProtoVer = ProtocolVersion(1, 0);

enum Capabilities {
Expand Down Expand Up @@ -242,8 +242,13 @@ abstract class BaseProtocol {
final errorType = resolveErrorCode(errCode);
final err = errorType(errMessage);

final attrs = message.readHeaders().map((key, value) => MapEntry(
errorAttrsByCode[key] ?? ErrorAttr.unknown, utf8.decode(value)));
var numAttrs = message.readInt16();
final attrs = <ErrorAttr, String>{};
while (numAttrs > 0) {
final key = message.readUint16();
attrs[errorAttrsByCode[key] ?? ErrorAttr.unknown] = message.readString();
numAttrs--;
}
setErrorAttrs(err, attrs);

message.finishMessage();
Expand Down Expand Up @@ -340,6 +345,7 @@ abstract class BaseProtocol {

void _encodeParseParams(
{required WriteMessageBuffer buffer,
required Language language,
required String query,
required OutputFormat outputFormat,
required Cardinality expectedCardinality,
Expand All @@ -351,7 +357,11 @@ abstract class BaseProtocol {
..writeFlags(
privilegedMode ? Capabilities.all.value : restrictedCapabilities)
..writeFlags(0)
..writeInt64(0)
..writeInt64(0);
if (protocolVersion >= protoV3) {
buffer.writeUint8(language.value);
}
buffer
..writeUint8(outputFormat.value)
..writeUint8(expectedCardinality == Cardinality.one ||
expectedCardinality == Cardinality.atMostOne
Expand Down Expand Up @@ -381,7 +391,8 @@ abstract class BaseProtocol {
// protocol flow

Future<dynamic> fetch<T>(
{required String query,
{Language language = Language.edgeql,
required String query,
String? queryName,
dynamic args,
required OutputFormat outputFormat,
Expand All @@ -390,6 +401,12 @@ abstract class BaseProtocol {
Codec? inCodec,
Codec? outCodec,
bool privilegedMode = false}) async {
if (language != Language.edgeql && protoV3 > protocolVersion) {
throw UnsupportedFeatureError(
'the server does not support SQL queries, upgrade to 6.0 or newer',
);
}

final requiredOne = expectedCardinality == Cardinality.one;
final expectOne =
requiredOne || expectedCardinality == Cardinality.atMostOne;
Expand All @@ -404,6 +421,7 @@ abstract class BaseProtocol {
if ((inCodec == null && cacheItem == null && args != null) ||
(stateCodec == invalidCodec && state != Session.defaults())) {
parseResult = await parse(
language: language,
query: query,
outputFormat: outputFormat,
expectedCardinality: expectedCardinality,
Expand All @@ -412,6 +430,7 @@ abstract class BaseProtocol {
}
try {
await execute(
language: language,
query: query,
queryName: queryName,
args: args,
Expand Down Expand Up @@ -442,6 +461,7 @@ abstract class BaseProtocol {
}
}
await execute(
language: language,
query: query,
queryName: queryName,
args: args,
Expand Down Expand Up @@ -482,6 +502,7 @@ abstract class BaseProtocol {
}

Future<ParseResult> parse({
required Language language,
required String query,
required OutputFormat outputFormat,
required Cardinality expectedCardinality,
Expand All @@ -496,6 +517,7 @@ abstract class BaseProtocol {

_encodeParseParams(
buffer: wb,
language: language,
query: query,
outputFormat: outputFormat,
expectedCardinality: expectedCardinality,
Expand Down Expand Up @@ -557,6 +579,7 @@ abstract class BaseProtocol {
if (error != null) {
if (error is StateMismatchError) {
return parse(
language: language,
query: query,
outputFormat: outputFormat,
expectedCardinality: expectedCardinality,
Expand All @@ -570,6 +593,7 @@ abstract class BaseProtocol {
}

Future<void> execute({
required Language language,
required String query,
String? queryName,
dynamic args,
Expand All @@ -590,6 +614,7 @@ abstract class BaseProtocol {

_encodeParseParams(
buffer: wb,
language: language,
query: query,
outputFormat: outputFormat,
expectedCardinality: expectedCardinality,
Expand Down Expand Up @@ -691,6 +716,7 @@ abstract class BaseProtocol {
if (error != null) {
if (error is StateMismatchError) {
return execute(
language: language,
query: query,
queryName: queryName,
args: args,
Expand Down
54 changes: 53 additions & 1 deletion lib/src/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ class ClientConnectionHolder<Connection extends BaseProtocol> {
}

Future<dynamic> _retryingFetch<T>(
{required String query,
{Language language = Language.edgeql,
required String query,
String? queryName,
dynamic args,
required OutputFormat outputFormat,
Expand All @@ -155,6 +156,7 @@ class ClientConnectionHolder<Connection extends BaseProtocol> {
final conn = await getConnection();
try {
result = await conn.fetch<T>(
language: language,
query: query,
queryName: queryName,
args: args,
Expand Down Expand Up @@ -193,6 +195,15 @@ class ClientConnectionHolder<Connection extends BaseProtocol> {
expectedCardinality: Cardinality.noResult);
}

Future<void> executeSQL(String query, [dynamic args]) async {
await _retryingFetch(
language: Language.sql,
query: query,
args: args,
outputFormat: OutputFormat.none,
expectedCardinality: Cardinality.noResult);
}

Future<List<dynamic>> query(String query, [dynamic args]) async {
return await _retryingFetch(
query: query,
Expand All @@ -201,6 +212,15 @@ class ClientConnectionHolder<Connection extends BaseProtocol> {
expectedCardinality: Cardinality.many) as List<dynamic>;
}

Future<List<dynamic>> querySQL(String query, [dynamic args]) async {
return await _retryingFetch(
language: Language.sql,
query: query,
args: args,
outputFormat: OutputFormat.binary,
expectedCardinality: Cardinality.many) as List<dynamic>;
}

Future<String> queryJSON(String query, [dynamic args]) async {
return await _retryingFetch(
query: query,
Expand Down Expand Up @@ -430,12 +450,24 @@ abstract class Executor {
/// [docs page](../edgedb-library.html).
Future<void> execute(String query, [dynamic args]);

/// Executes a SQL query, returning no result.
///
/// For details on [args] see the `edgedb` library
/// [docs page](../edgedb-library.html).
Future<void> executeSQL(String query, [dynamic args]);

/// Executes a query, returning a `List` of results.
///
/// For details on result types and [args] see the `edgedb` library
/// [docs page](../edgedb-library.html).
Future<List<dynamic>> query(String query, [dynamic args]);

/// Executes a SQL query, returning a `List` of results.
///
/// For details on result types and [args] see the `edgedb` library
/// [docs page](../edgedb-library.html).
Future<List<dynamic>> querySQL(String query, [dynamic args]);

/// Executes a query, returning the result as a JSON encoded `String`.
///
/// For details on [args] see the `edgedb` library
Expand Down Expand Up @@ -689,6 +721,16 @@ class Client implements Executor {
}
}

@override
Future<void> executeSQL(String query, [dynamic args]) async {
final holder = await _pool.acquireHolder(_options);
try {
return await holder.executeSQL(query, args);
} finally {
await holder.release();
}
}

@override
Future<List<dynamic>> query(String query, [dynamic args]) async {
final holder = await _pool.acquireHolder(_options);
Expand All @@ -699,6 +741,16 @@ class Client implements Executor {
}
}

@override
Future<List<dynamic>> querySQL(String query, [dynamic args]) async {
final holder = await _pool.acquireHolder(_options);
try {
return await holder.querySQL(query, args);
} finally {
await holder.release();
}
}

@override
Future<String> queryJSON(String query, [dynamic args]) async {
final holder = await _pool.acquireHolder(_options);
Expand Down
3 changes: 2 additions & 1 deletion lib/src/codecs/object.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ class ObjectCodec extends Codec {
}

void encodeArgs(WriteBuffer buf, dynamic args) {
if (fields[0].name == '0') {
// EdgeQL query parameters start at 0, SQL start at 1.
if (fields[0].name == "0" || fields[0].name == "1") {
_encodePositionalArgs(buf, args);
} else {
_encodeNamedArgs(buf, args);
Expand Down
74 changes: 74 additions & 0 deletions lib/src/codecs/record.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import '../errors/errors.dart';
import '../primitives/buffer.dart';
import '../utils/indent.dart';
import 'codecs.dart';

class SQLRecordColumn {
final String name;
final Codec codec;

SQLRecordColumn(this.name, this.codec);
}

class SQLRecordCodec extends Codec {
final List<SQLRecordColumn> columns;
final ReturnTypeConstructor? returnType;

SQLRecordCodec(super.tid, List<Codec> codecs, List<String> names,
{this.returnType})
: columns = List.generate(codecs.length, (i) {
return SQLRecordColumn(names[i], codecs[i]);
});

@override
void encode(WriteBuffer buf, dynamic object) {
throw ArgumentError("SQL records cannot be passed as arguments");
}

@override
dynamic decode(ReadBuffer buf) {
final els = buf.readUint32();
if (els != columns.length) {
throw ProtocolError(
'cannot decode SQL record: expected ${columns.length} elements, got $els');
}

final result = <String, dynamic>{};
for (var col in columns) {
buf.discard(4); // reserved
final elemLen = buf.readInt32();
final name = col.name;
if (elemLen == -1) {
result[name] = null;
} else {
final elemBuf = buf.slice(elemLen);
result[name] = col.codec.decode(elemBuf);
elemBuf.finish();
}
}

return returnType != null ? returnType!(result) : result;
}

@override
String toString() {
return 'SQLRecordCodec ($tid) {\n'
'${columns.map((field) => ' ${field.name}:'
' ${indent(field.codec.toString())}\n').join('')}'
'}';
}

@override
bool compare(Codec codec) {
if (codec is! SQLRecordCodec || codec.columns.length != columns.length) {
return false;
}
for (var i = 0; i < columns.length; i++) {
if (columns[i].name != codec.columns[i].name ||
!columns[i].codec.compare(codec.columns[i].codec)) {
return false;
}
}
return true;
}
}
Loading
Loading