Skip to content

Commit b7add8f

Browse files
authored
Preparing Type refactor. (#238)
1 parent 2df3120 commit b7add8f

File tree

10 files changed

+81
-32
lines changed

10 files changed

+81
-32
lines changed

lib/postgres.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import 'dart:convert';
33

44
import 'package:collection/collection.dart';
55
import 'package:meta/meta.dart';
6-
import 'package:postgres/src/types/type_registry.dart';
76
import 'package:stream_channel/stream_channel.dart';
87

98
import 'src/replication.dart';
109
import 'src/types.dart';
10+
import 'src/types/type_registry.dart';
1111
import 'src/v3/connection.dart';
1212
import 'src/v3/protocol.dart';
1313
import 'src/v3/query_description.dart';
@@ -16,6 +16,7 @@ export 'src/exceptions.dart';
1616
export 'src/pool/pool_api.dart';
1717
export 'src/replication.dart';
1818
export 'src/types.dart';
19+
export 'src/types/type_registry.dart' show TypeOid, TypeRegistry;
1920

2021
/// A description of a SQL query as interpreted by this package.
2122
///

lib/src/messages/client_messages.dart

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ class DescribeMessage extends ClientMessage {
172172
}
173173

174174
class BindMessage extends ClientMessage {
175-
final List<TypedValue> _parameters;
175+
final List<EncodeOutput?> _parameters;
176176
final String _portalName;
177177
final String _statementName;
178178

@@ -189,19 +189,12 @@ class BindMessage extends ClientMessage {
189189
final portalName = buffer.encodeString(_portalName);
190190
final statementName = buffer.encodeString(_statementName);
191191

192-
final encodedOutputs = _parameters
193-
.map((p) => p.value == null
194-
? null
195-
: p.type.encode(
196-
EncodeInput(value: p.value!, encoding: buffer.encoding)))
197-
.toList();
198-
final encodedBytes = encodedOutputs.map((e) {
192+
final encodedBytes = _parameters.map((e) {
199193
if (e == null) return null;
200194
return e.isBinary ? e.bytes! : buffer.encoding.encode(e.text!);
201195
}).toList();
202-
final binaryCount =
203-
encodedOutputs.where((p) => p?.isBinary ?? false).length;
204-
final isAllBinary = binaryCount == encodedOutputs.length;
196+
final binaryCount = _parameters.where((p) => p?.isBinary ?? false).length;
197+
final isAllBinary = binaryCount == _parameters.length;
205198
final isAllText = binaryCount == 0;
206199
final inputParameterElementCount =
207200
isAllBinary || isAllText ? 1 : _parameters.length;
@@ -232,7 +225,7 @@ class BindMessage extends ClientMessage {
232225
} else {
233226
// Well, we have some text and some binary, so we have to be explicit about each one
234227
buffer.writeUint16(_parameters.length);
235-
for (final p in encodedOutputs) {
228+
for (final p in _parameters) {
236229
buffer.writeUint16(p != null && p.isBinary
237230
? ClientMessageFormat.binary
238231
: ClientMessageFormat.text);

lib/src/types/text_codec.dart

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ class PostgresTextEncoder {
88
const PostgresTextEncoder();
99

1010
String convert(Object input, {bool escapeStrings = true}) {
11+
final value = tryConvert(input, escapeStrings: escapeStrings);
12+
if (value != null) {
13+
return value;
14+
}
15+
throw PgException("Could not infer type of value '$input'.");
16+
}
17+
18+
String? tryConvert(Object input, {bool escapeStrings = false}) {
1119
if (input is int) {
1220
return _encodeNumber(input);
1321
}
@@ -40,9 +48,7 @@ class PostgresTextEncoder {
4048
return _encodeList(input);
4149
}
4250

43-
// TODO: use custom type encoders
44-
45-
throw PgException("Could not infer type of value '$input'.");
51+
return null;
4652
}
4753

4854
String _encodeString(String text, bool escapeStrings) {

lib/src/types/type_registry.dart

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
import 'dart:convert';
2+
import 'dart:typed_data';
3+
14
import 'package:meta/meta.dart';
25

36
import '../types.dart';
47

58
import 'generic_type.dart';
69

10+
typedef TypeEncoderFn = EncodeOutput Function(EncodeInput input);
11+
typedef TypeDecoderFn = Object? Function(DecodeInput input);
12+
713
/// See: https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat
814
class TypeOid {
915
static const bigInteger = 20;
@@ -110,3 +116,32 @@ class TypeRegistry {
110116
@internal
111117
Iterable<Type> get registered => _byTypeOid.values;
112118
}
119+
120+
extension TypeRegistryExt on TypeRegistry {
121+
EncodeOutput? encodeValue(
122+
Object? value, {
123+
Type? type,
124+
required Encoding encoding,
125+
}) {
126+
if (value == null) return null;
127+
return type?.encode(EncodeInput(value: value, encoding: encoding));
128+
}
129+
130+
Object? decodeBytes(
131+
Uint8List? bytes, {
132+
required int typeOid,
133+
required bool isBinary,
134+
required Encoding encoding,
135+
}) {
136+
if (bytes == null) {
137+
return null;
138+
}
139+
final type = resolveOid(typeOid);
140+
return type.decode(DecodeInput(
141+
bytes: bytes,
142+
isBinary: isBinary,
143+
encoding: encoding,
144+
typeRegistry: this,
145+
));
146+
}
147+
}

lib/src/v2/query.dart

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ class Query<T> {
9191
final messages = [
9292
ParseMessage(sqlString, statementName: statementName),
9393
DescribeMessage(statementName: statementName),
94-
BindMessage(parameterList, statementName: statementName),
94+
BindMessage(_toEncodedOutput(parameterList),
95+
statementName: statementName),
9596
ExecuteMessage(),
9697
SyncMessage(),
9798
];
@@ -104,6 +105,17 @@ class Query<T> {
104105
.add(_aggregateClientMessages(messages, encoding: connection.encoding));
105106
}
106107

108+
late final _typeRegistry = TypeRegistry();
109+
List<EncodeOutput?> _toEncodedOutput(List<ParameterValue> values) {
110+
return values
111+
.map((e) => _typeRegistry.encodeValue(
112+
e.value,
113+
type: e.type,
114+
encoding: connection.encoding,
115+
))
116+
.toList();
117+
}
118+
107119
void sendCachedQuery(Socket socket, CachedQuery cacheQuery,
108120
Map<String, dynamic>? substitutionValues) {
109121
final statementName = cacheQuery.preparedStatementName;
@@ -114,7 +126,8 @@ class Query<T> {
114126

115127
final bytes = _aggregateClientMessages(
116128
[
117-
BindMessage(parameterList, statementName: statementName!),
129+
BindMessage(_toEncodedOutput(parameterList),
130+
statementName: statementName!),
118131
ExecuteMessage(),
119132
SyncMessage()
120133
],

lib/src/v3/connection.dart

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:async/async.dart' as async;
77
import 'package:charcode/ascii.dart';
88
import 'package:meta/meta.dart';
99
import 'package:pool/pool.dart' as pool;
10+
import 'package:postgres/src/types/type_registry.dart';
1011
import 'package:stream_channel/stream_channel.dart';
1112

1213
import '../../postgres.dart';
@@ -568,7 +569,13 @@ class _PgResultStreamSubscription
568569

569570
connection._channel.sink.add(AggregatedClientMessage([
570571
BindMessage(
571-
statement.parameters,
572+
statement.parameters
573+
.map((e) => connection._settings.typeRegistry.encodeValue(
574+
e.value,
575+
type: e.type,
576+
encoding: connection.encoding,
577+
))
578+
.toList(),
572579
portalName: _portalName,
573580
statementName: statement.statement._name,
574581
),
@@ -674,16 +681,14 @@ class _PgResultStreamSubscription
674681
for (var i = 0; i < message.values.length; i++) {
675682
final field = schema.columns[i];
676683

677-
final type = field.type;
678684
final input = message.values[i];
679-
final value = input == null
680-
? null
681-
: type.decode(DecodeInput(
682-
bytes: input,
683-
isBinary: field.isBinaryEncoding,
684-
encoding: session.encoding,
685-
typeRegistry: session._connection._settings.typeRegistry,
686-
));
685+
final value =
686+
session._connection._settings.typeRegistry.decodeBytes(
687+
input,
688+
typeOid: field.typeOid,
689+
isBinary: field.isBinaryEncoding,
690+
encoding: session.encoding,
691+
);
687692
columnValues.add(value);
688693
}
689694

lib/src/v3/resolved_settings.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import 'dart:convert';
22

33
import 'package:postgres/messages.dart';
4-
import 'package:postgres/src/types/type_registry.dart';
54
import 'package:stream_channel/stream_channel.dart';
65

76
import '../../postgres.dart';

test/decode_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import 'package:buffer/buffer.dart';
44
import 'package:postgres/legacy.dart';
55
import 'package:postgres/postgres.dart';
66
import 'package:postgres/src/types/binary_codec.dart';
7-
import 'package:postgres/src/types/type_registry.dart';
87
import 'package:test/test.dart';
98

109
import 'docker.dart';

test/encoding_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import 'package:postgres/legacy.dart';
66
import 'package:postgres/postgres.dart';
77
import 'package:postgres/src/types/binary_codec.dart';
88
import 'package:postgres/src/types/text_codec.dart';
9-
import 'package:postgres/src/types/type_registry.dart';
109
import 'package:test/test.dart';
1110

1211
import 'docker.dart';

test/interpolation_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import 'dart:convert';
22

33
import 'package:postgres/legacy.dart';
44
import 'package:postgres/postgres.dart';
5-
import 'package:postgres/src/types/type_registry.dart';
65
import 'package:postgres/src/v2/query.dart';
76
import 'package:test/test.dart';
87

0 commit comments

Comments
 (0)