Skip to content

Commit

Permalink
Handle unspecified types in queries. (#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
isoos authored Oct 13, 2023
1 parent 5b120c0 commit 4b02470
Show file tree
Hide file tree
Showing 7 changed files with 15 additions and 35 deletions.
4 changes: 3 additions & 1 deletion lib/src/binary_codec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ class PostgresBinaryEncoder<T extends Object> {
// ignore: unnecessary_cast
switch (_dataType as PgDataType<Object>) {
case PgDataType.unknownType:
case PgDataType.unspecified:
case PgDataType.voidType:
throw ArgumentError('Cannot encode into an unknown type or into void');
throw ArgumentError('Cannot encode into ${_dataType.name}.');
case PgDataType.boolean:
{
if (input is bool) {
Expand Down Expand Up @@ -621,6 +622,7 @@ class PostgresBinaryDecoder<T> {
}) as T;

case PostgreSQLDataType.unknownType:
case PostgreSQLDataType.unspecified:
{
// We'll try and decode this as a utf8 string and return that
// for many internal types, this is valid. If it fails,
Expand Down
4 changes: 2 additions & 2 deletions lib/src/query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,10 @@ class ParameterValue {
return ParameterValue(type, value);
}

bool get hasKnownType => _type != null;
late final hasKnownType = _type != null && _type != PgDataType.unspecified;

Uint8List? encodeAsBytes(Encoding encoding) {
if (_type != null) {
if (hasKnownType) {
final encoder = PostgresBinaryEncoder(_type!);
return encoder.convert(_value, encoding);
}
Expand Down
7 changes: 3 additions & 4 deletions lib/src/v3/connection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -522,10 +522,9 @@ class _PgResultStreamSubscription

connection._channel.sink.add(AggregatedClientMessage([
BindMessage(
[
for (final parameter in statement.parameters)
ParameterValue(parameter.type, parameter.value)
],
statement.parameters
.map((p) => ParameterValue(p.type, p.value))
.toList(),
portalName: _portalName,
statementName: statement.statement._name,
),
Expand Down
27 changes: 1 addition & 26 deletions lib/src/v3/query_description.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,33 +71,8 @@ class InternalQueryDescription implements PgSql {
return value;
} else if (knownType != null) {
return PgTypedParameter(knownType, value);
} else if (value == null) {
return PgTypedParameter(PgDataType.voidType, value);
} else if (value is String) {
return PgTypedParameter(PgDataType.varChar, value);
} else if (value is bool) {
return PgTypedParameter(PgDataType.boolean, value);
} else if (value is int && value.bitLength <= 16) {
return PgTypedParameter(PgDataType.smallInteger, value);
} else if (value is int && value.bitLength <= 32) {
return PgTypedParameter(PgDataType.integer, value);
} else if (value is int && value.bitLength <= 64) {
return PgTypedParameter(PgDataType.bigInteger, value);
} else if (value is double) {
return PgTypedParameter(PgDataType.double, value);
} else if (value is DateTime) {
return PgTypedParameter(PgDataType.timestampWithoutTimezone, value);
} else if (value is Map<String, dynamic>) {
return PgTypedParameter(PgDataType.jsonb, value);
} else if (value is PgPoint) {
return PgTypedParameter(PgDataType.point, value);
} else {
throw ArgumentError.value(
value,
name == null ? 'parameter' : '$name parameter',
'Is not a `PgTypedParameter` and appears in a location for which no '
'type could be inferred.',
);
return PgTypedParameter(PgDataType.unspecified, value);
}
}

Expand Down
3 changes: 3 additions & 0 deletions lib/src/v3/types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ enum PgDataType<Dart extends Object> {
/// Used to represent a type not yet understood by this package.
unknownType<Object>(null),

/// Used to represent value without any type representation.
unspecified<Object>(null),

/// Must be a [String].
text<String>(25, nameForSubstitution: 'text'),

Expand Down
1 change: 1 addition & 0 deletions test/interpolation_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:test/test.dart';
void main() {
test('Ensure all types/format type mappings are available and accurate', () {
const withoutMapping = {
PostgreSQLDataType.unspecified, // Can't bind into unspecified type
PostgreSQLDataType.unknownType, // Can't bind into unknown type
PostgreSQLDataType.voidType, // Can't assign to void
PostgreSQLDataType.bigSerial, // Can only be created from a table sequence
Expand Down
4 changes: 2 additions & 2 deletions test/variable_tokenizer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void main() {
expect(desc.bindParameters({'x': 4, 'y': true, 'z': 'z'}), [
PgTypedParameter(PgDataType.bigInteger, 4),
PgTypedParameter(PgDataType.boolean, true),
PgTypedParameter(PgDataType.varChar, 'z'),
PgTypedParameter(PgDataType.unspecified, 'z'),
]);

// Make sure we can still bind by index
Expand All @@ -48,7 +48,7 @@ void main() {
[
PgTypedParameter(PgDataType.bigInteger, 1),
PgTypedParameter(PgDataType.boolean, true),
PgTypedParameter(PgDataType.smallInteger, 3),
PgTypedParameter(PgDataType.unspecified, 3),
],
);
});
Expand Down

0 comments on commit 4b02470

Please sign in to comment.