diff --git a/.travis.yml b/.travis.yml index 9d14a9a..af90a1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: dart sudo: required dart: - - stable + - beta addons: postgresql: "9.6" services: diff --git a/CHANGELOG.md b/CHANGELOG.md index ca20fdc..08e1fa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 2.3.0 + +- Migrate to null safety + ## 2.2.0 - Supporting Unix socket connections. (Thanks to [grillbiff](https://github.com/grillbiff), diff --git a/lib/src/binary_codec.dart b/lib/src/binary_codec.dart index 89c75ce..aa4c75b 100644 --- a/lib/src/binary_codec.dart +++ b/lib/src/binary_codec.dart @@ -28,13 +28,13 @@ final _hex = [ 'f', ]; -class PostgresBinaryEncoder extends Converter { +class PostgresBinaryEncoder extends Converter { final PostgreSQLDataType _dataType; const PostgresBinaryEncoder(this._dataType); @override - Uint8List convert(dynamic value) { + Uint8List? convert(dynamic value) { if (value == null) { return null; } @@ -169,7 +169,7 @@ class PostgresBinaryEncoder extends Converter { 'Invalid type for parameter value. Expected: String Got: ${value.runtimeType}'); } - final hexBytes = (value as String) + final hexBytes = value .toLowerCase() .codeUnits .where((c) => c != _dashUnit) @@ -199,9 +199,9 @@ class PostgresBinaryEncoder extends Converter { } return outBuffer; } + default: + throw PostgreSQLException('Unsupported datatype'); } - - throw PostgreSQLException('Unsupported datatype'); } } @@ -211,13 +211,13 @@ class PostgresBinaryDecoder extends Converter { final int typeCode; @override - dynamic convert(Uint8List value) { - final dataType = typeMap[typeCode]; - + dynamic convert(Uint8List? value) { if (value == null) { return null; } + final dataType = typeMap[typeCode]; + final buffer = ByteData.view(value.buffer, value.offsetInBytes, value.lengthInBytes); @@ -277,16 +277,18 @@ class PostgresBinaryDecoder extends Converter { return buf.toString(); } - } - - // We'll try and decode this as a utf8 string and return that - // for many internal types, this is valid. If it fails, - // we just return the bytes and let the caller figure out what to - // do with it. - try { - return utf8.decode(value); - } catch (_) { - return value; + default: + { + // We'll try and decode this as a utf8 string and return that + // for many internal types, this is valid. If it fails, + // we just return the bytes and let the caller figure out what to + // do with it. + try { + return utf8.decode(value); + } catch (_) { + return value; + } + } } } diff --git a/lib/src/client_messages.dart b/lib/src/client_messages.dart index e072c07..c085657 100644 --- a/lib/src/client_messages.dart +++ b/lib/src/client_messages.dart @@ -42,11 +42,11 @@ void _applyStringToBuffer(UTF8BackedString string, ByteDataWriter buffer) { } class StartupMessage extends ClientMessage { - final UTF8BackedString _username; + final UTF8BackedString? _username; final UTF8BackedString _databaseName; final UTF8BackedString _timeZone; - StartupMessage(String databaseName, String timeZone, {String username}) + StartupMessage(String databaseName, String timeZone, {String? username}) : _databaseName = UTF8BackedString(databaseName), _timeZone = UTF8BackedString(timeZone), _username = username == null ? null : UTF8BackedString(username); @@ -58,7 +58,7 @@ class StartupMessage extends ClientMessage { if (_username != null) { fixedLength += 5; - variableLength += _username.utf8Length + 1; + variableLength += _username!.utf8Length + 1; } buffer.writeInt32(fixedLength + variableLength); @@ -66,7 +66,7 @@ class StartupMessage extends ClientMessage { if (_username != null) { buffer.write(UTF8ByteConstants.user); - _applyStringToBuffer(_username, buffer); + _applyStringToBuffer(_username!, buffer); } buffer.write(UTF8ByteConstants.database); @@ -83,7 +83,7 @@ class StartupMessage extends ClientMessage { } class AuthMD5Message extends ClientMessage { - UTF8BackedString _hashedAuthString; + UTF8BackedString? _hashedAuthString; AuthMD5Message(String username, String password, List saltBytes) { final passwordHash = md5.convert('$password$username'.codeUnits).toString(); @@ -96,9 +96,9 @@ class AuthMD5Message extends ClientMessage { @override void applyToBuffer(ByteDataWriter buffer) { buffer.writeUint8(ClientMessage.PasswordIdentifier); - final length = 5 + _hashedAuthString.utf8Length; + final length = 5 + _hashedAuthString!.utf8Length; buffer.writeUint32(length); - _applyStringToBuffer(_hashedAuthString, buffer); + _applyStringToBuffer(_hashedAuthString!, buffer); } } @@ -157,14 +157,14 @@ class BindMessage extends ClientMessage { final List _parameters; final UTF8BackedString _statementName; final int _typeSpecCount; - int _cachedLength; + int _cachedLength = -1; BindMessage(this._parameters, {String statementName = ''}) : _typeSpecCount = _parameters.where((p) => p.isBinary).length, _statementName = UTF8BackedString(statementName); int get length { - if (_cachedLength == null) { + if (_cachedLength == -1) { var inputParameterElementCount = _parameters.length; if (_typeSpecCount == _parameters.length || _typeSpecCount == 0) { inputParameterElementCount = 1; @@ -221,7 +221,7 @@ class BindMessage extends ClientMessage { buffer.writeInt32(-1); } else { buffer.writeInt32(p.length); - buffer.write(p.bytes); + buffer.write(p.bytes!); } }); diff --git a/lib/src/connection.dart b/lib/src/connection.dart index ba3455e..09c8250 100644 --- a/lib/src/connection.dart +++ b/lib/src/connection.dart @@ -67,10 +67,10 @@ class PostgreSQLConnection extends Object final String databaseName; /// Username for authenticating this connection. - final String username; + final String? username; /// Password for authenticating this connection. - final String password; + final String? password; /// Whether or not this connection should connect securely. final bool useSSL; @@ -113,18 +113,18 @@ class PostgreSQLConnection extends Object final _cache = QueryCache(); final _oidCache = _OidCache(); - Socket _socket; + Socket? _socket; MessageFramer _framer = MessageFramer(); - int _processID; + late int _processID; // ignore: unused_field - int _secretKey; - List _salt; + late int _secretKey; + late List _salt; bool _hasConnectedPreviously = false; - _PostgreSQLConnectionState _connectionState; + late _PostgreSQLConnectionState _connectionState; @override - PostgreSQLExecutionContext get _transaction => null; + PostgreSQLExecutionContext get _transaction => this; @override PostgreSQLConnection get _connection => this; @@ -156,11 +156,12 @@ class PostgreSQLConnection extends Object _framer = MessageFramer(); if (useSSL) { - _socket = await _upgradeSocketToSSL(_socket, timeout: timeoutInSeconds); + _socket = + await _upgradeSocketToSSL(_socket!, timeout: timeoutInSeconds); } final connectionComplete = Completer(); - _socket.listen(_readData, onError: _close, onDone: _close); + _socket!.listen(_readData, onError: _close, onDone: _close); _transitionToState( _PostgreSQLConnectionStateSocketConnected(connectionComplete)); @@ -214,7 +215,7 @@ class PostgreSQLConnection extends Object /// default query timeout will be used. Future transaction( Future Function(PostgreSQLExecutionContext connection) queryBlock, { - int commitTimeoutInSeconds, + int? commitTimeoutInSeconds, }) async { if (isClosed) { throw PostgreSQLException( @@ -229,7 +230,7 @@ class PostgreSQLConnection extends Object } @override - void cancelTransaction({String reason}) { + void cancelTransaction({String? reason}) { // Default is no-op } @@ -249,13 +250,15 @@ class PostgreSQLConnection extends Object _connectionState.connection = this; } - Future _close([dynamic error, StackTrace trace]) async { + Future _close([dynamic error, StackTrace? trace]) async { _connectionState = _PostgreSQLConnectionStateClosed(); - await _socket?.close(); - await _notifications?.close(); + if (_socket != null) { + await _socket!.close(); + } + await _notifications.close(); - _queue?.cancel(error, trace); + _queue.cancel(error, trace); } void _readData(List bytes) { @@ -355,16 +358,16 @@ class _OidCache { Future> _resolveTableNames( _PostgreSQLExecutionContextMixin c, - List columns) async { - if (columns == null) return null; + List? columns) async { + if (columns == null) return []; //todo (joeconwaystk): If this was a cached query, resolving is table oids is unnecessary. // It's not a significant impact here, but an area for optimization. This includes // assigning resolvedTableName final unresolvedTableOIDs = columns - .map((f) => f.tableID) + .where((f) => f != null) + .map((f) => f!.tableID) .toSet() - .where((oid) => - oid != null && oid > 0 && !_tableOIDNameMap.containsKey(oid)) + .where((oid) => oid > 0 && !_tableOIDNameMap.containsKey(oid)) .toList() ..sort(); @@ -373,7 +376,7 @@ class _OidCache { } return columns - .map((c) => c.change(tableName: _tableOIDNameMap[c.tableID])) + .map((c) => c!.change(tableName: _tableOIDNameMap[c.tableID])) .toList(); } @@ -387,6 +390,10 @@ class _OidCache { resolveOids: false, ); + if (orderedTableNames == null) { + return; + } + final iterator = oids.iterator; orderedTableNames.forEach((tableName) { iterator.moveNext(); @@ -409,11 +416,11 @@ abstract class _PostgreSQLExecutionContextMixin int get queueSize => _queue.length; @override - Future query( + Future query( String fmtString, { - Map substitutionValues, - bool allowReuse, - int timeoutInSeconds, + Map? substitutionValues, + bool allowReuse = true, + int? timeoutInSeconds, }) => _query( fmtString, @@ -422,16 +429,14 @@ abstract class _PostgreSQLExecutionContextMixin timeoutInSeconds: timeoutInSeconds, ); - Future _query( + Future _query( String fmtString, { - Map substitutionValues, - bool allowReuse, - int timeoutInSeconds, - bool resolveOids, + Map? substitutionValues, + required bool allowReuse, + int? timeoutInSeconds, + bool resolveOids = true, }) async { - allowReuse ??= true; timeoutInSeconds ??= _connection.queryTimeoutInSeconds; - resolveOids ??= true; if (_connection.isClosed) { throw PostgreSQLException( @@ -451,34 +456,41 @@ abstract class _PostgreSQLExecutionContextMixin columnDescriptions = await _connection._oidCache ._resolveTableNames(this, columnDescriptions); } - final metaData = _PostgreSQLResultMetaData(columnDescriptions); - - return _PostgreSQLResult( - queryResult.affectedRowCount, - metaData, - queryResult.value - .map((columns) => _PostgreSQLResultRow(metaData, columns)) - .toList()); + final metaData = _PostgreSQLResultMetaData(columnDescriptions!); + + return queryResult != null + ? _PostgreSQLResult( + queryResult.affectedRowCount, + metaData, + queryResult.value! + .map((columns) => _PostgreSQLResultRow(metaData, columns)) + .toList()) + : null; } @override - Future>>> mappedResultsQuery( + Future>>> mappedResultsQuery( String fmtString, - {Map substitutionValues, - bool allowReuse, - int timeoutInSeconds}) async { + {Map substitutionValues = const {}, + bool allowReuse = false, + int? timeoutInSeconds}) async { final rs = await query( fmtString, substitutionValues: substitutionValues, allowReuse: allowReuse, timeoutInSeconds: timeoutInSeconds, ); + + if (rs == null) { + return Future.value(); + } return rs.map((row) => row.toTableColumnMap()).toList(); } @override - Future execute(String fmtString, - {Map substitutionValues, int timeoutInSeconds}) async { + Future execute(String fmtString, + {Map substitutionValues = const {}, + int? timeoutInSeconds}) async { timeoutInSeconds ??= _connection.queryTimeoutInSeconds; if (_connection.isClosed) { throw PostgreSQLException( @@ -490,13 +502,13 @@ abstract class _PostgreSQLExecutionContextMixin onlyReturnAffectedRowCount: true); final result = await _enqueue(query, timeoutInSeconds: timeoutInSeconds); - return result.affectedRowCount; + return result != null ? result.affectedRowCount : null; } @override void cancelTransaction({String reason}); - Future> _enqueue(Query query, + Future?> _enqueue(Query query, {int timeoutInSeconds = 30}) async { if (_queue.add(query)) { _connection._transitionToState(_connection._connectionState.awake()); @@ -521,18 +533,19 @@ abstract class _PostgreSQLExecutionContextMixin } } - Future _onQueryError(Query query, dynamic error, [StackTrace trace]) async {} + Future _onQueryError(Query query, dynamic error, [StackTrace? trace]) async {} } class _PostgreSQLResultMetaData { - final List columnDescriptions; - List _tableNames; + final List columnDescriptions; + late List _tableNames; - _PostgreSQLResultMetaData(this.columnDescriptions); + _PostgreSQLResultMetaData(this.columnDescriptions) { + _tableNames = + columnDescriptions.map((column) => column!.tableName).toSet().toList(); + } - List get tableNames { - _tableNames ??= - columnDescriptions.map((column) => column.tableName).toSet().toList(); + List get tableNames { return _tableNames; } } @@ -548,7 +561,7 @@ class _PostgreSQLResult extends UnmodifiableListView : super(rows); @override - List get columnDescriptions => + List get columnDescriptions => _metaData.columnDescriptions; } @@ -559,18 +572,18 @@ class _PostgreSQLResultRow extends UnmodifiableListView _PostgreSQLResultRow(this._metaData, List columns) : super(columns); @override - List get columnDescriptions => + List get columnDescriptions => _metaData.columnDescriptions; @override - Map> toTableColumnMap() { - final rowMap = >{}; + Map> toTableColumnMap() { + final rowMap = >{}; _metaData.tableNames.forEach((tableName) { rowMap[tableName] = {}; }); for (var i = 0; i < _metaData.columnDescriptions.length; i++) { final col = _metaData.columnDescriptions[i]; - rowMap[col.tableName][col.columnName] = this[i]; + rowMap[col!.tableName]![col.columnName] = this[i]; } return rowMap; } @@ -580,7 +593,7 @@ class _PostgreSQLResultRow extends UnmodifiableListView final rowMap = {}; for (var i = 0; i < _metaData.columnDescriptions.length; i++) { final col = _metaData.columnDescriptions[i]; - rowMap[col.columnName] = this[i]; + rowMap[col!.columnName] = this[i]; } return rowMap; } diff --git a/lib/src/connection_fsm.dart b/lib/src/connection_fsm.dart index 3dbb2b4..11e939a 100644 --- a/lib/src/connection_fsm.dart +++ b/lib/src/connection_fsm.dart @@ -1,7 +1,7 @@ part of postgres.connection; abstract class _PostgreSQLConnectionState { - PostgreSQLConnection connection; + PostgreSQLConnection? connection; _PostgreSQLConnectionState onEnter() { return this; @@ -48,10 +48,10 @@ class _PostgreSQLConnectionStateSocketConnected @override _PostgreSQLConnectionState onEnter() { final startupMessage = StartupMessage( - connection.databaseName, connection.timeZone, - username: connection.username); + connection!.databaseName, connection!.timeZone, + username: connection!.username); - connection._socket.add(startupMessage.asBytes()); + connection!._socket!.add(startupMessage.asBytes()); return this; } @@ -73,7 +73,7 @@ class _PostgreSQLConnectionStateSocketConnected if (authMessage.type == AuthenticationMessage.KindOK) { return _PostgreSQLConnectionStateAuthenticated(completer); } else if (authMessage.type == AuthenticationMessage.KindMD5Password) { - connection._salt = authMessage.salt; + connection!._salt = authMessage.salt; return _PostgreSQLConnectionStateAuthenticating(completer); } @@ -98,9 +98,9 @@ class _PostgreSQLConnectionStateAuthenticating @override _PostgreSQLConnectionState onEnter() { final authMessage = AuthMD5Message( - connection.username, connection.password, connection._salt); + connection!.username!, connection!.password!, connection!._salt); - connection._socket.add(authMessage.asBytes()); + connection!._socket!.add(authMessage.asBytes()); return this; } @@ -117,10 +117,10 @@ class _PostgreSQLConnectionStateAuthenticating @override _PostgreSQLConnectionState onMessage(ServerMessage message) { if (message is ParameterStatusMessage) { - connection.settings[message.name] = message.value; + connection!.settings[message.name] = message.value; } else if (message is BackendKeyMessage) { - connection._processID = message.processID; - connection._secretKey = message.secretKey; + connection!._processID = message.processID; + connection!._secretKey = message.secretKey; } else if (message is ReadyForQueryMessage) { if (message.state == ReadyForQueryMessage.StateIdle) { return _PostgreSQLConnectionStateIdle(openCompleter: completer); @@ -153,10 +153,10 @@ class _PostgreSQLConnectionStateAuthenticated @override _PostgreSQLConnectionState onMessage(ServerMessage message) { if (message is ParameterStatusMessage) { - connection.settings[message.name] = message.value; + connection!.settings[message.name] = message.value; } else if (message is BackendKeyMessage) { - connection._processID = message.processID; - connection._secretKey = message.secretKey; + connection!._processID = message.processID; + connection!._secretKey = message.secretKey; } else if (message is ReadyForQueryMessage) { if (message.state == ReadyForQueryMessage.StateIdle) { return _PostgreSQLConnectionStateIdle(openCompleter: completer); @@ -174,11 +174,11 @@ class _PostgreSQLConnectionStateAuthenticated class _PostgreSQLConnectionStateIdle extends _PostgreSQLConnectionState { _PostgreSQLConnectionStateIdle({this.openCompleter}); - Completer openCompleter; + Completer? openCompleter; @override _PostgreSQLConnectionState awake() { - final pendingQuery = connection._queue.pending; + final pendingQuery = connection!._queue.pending; if (pendingQuery != null) { return processQuery(pendingQuery); } @@ -189,18 +189,18 @@ class _PostgreSQLConnectionStateIdle extends _PostgreSQLConnectionState { _PostgreSQLConnectionState processQuery(Query q) { try { if (q.onlyReturnAffectedRowCount) { - q.sendSimple(connection._socket); + q.sendSimple(connection!._socket!); return _PostgreSQLConnectionStateBusy(q); } - final cached = connection._cache[q.statement]; - q.sendExtended(connection._socket, cacheQuery: cached); + final cached = connection!._cache[q.statement]; + q.sendExtended(connection!._socket!, cacheQuery: cached); return _PostgreSQLConnectionStateBusy(q); } catch (e, st) { scheduleMicrotask(() { q.completeError(e, st); - connection._transitionToState(_PostgreSQLConnectionStateIdle()); + connection!._transitionToState(_PostgreSQLConnectionStateIdle()); }); return _PostgreSQLConnectionStateDeferredFailure(); @@ -228,7 +228,7 @@ class _PostgreSQLConnectionStateBusy extends _PostgreSQLConnectionState { _PostgreSQLConnectionStateBusy(this.query); Query query; - PostgreSQLException returningException; + PostgreSQLException? returningException; int rowsAffected = 0; @override @@ -256,13 +256,12 @@ class _PostgreSQLConnectionStateBusy extends _PostgreSQLConnectionState { if (message is ReadyForQueryMessage) { if (message.state == ReadyForQueryMessage.StateTransactionError) { - query.completeError(returningException); + query.completeError(returningException!); return _PostgreSQLConnectionStateReadyInTransaction( query.transaction as _TransactionProxy); } - if (returningException != null) { - query.completeError(returningException); + query.completeError(returningException!); } else { query.complete(rowsAffected); } @@ -318,12 +317,12 @@ class _PostgreSQLConnectionStateReadyInTransaction _PostgreSQLConnectionState processQuery(Query q) { try { if (q.onlyReturnAffectedRowCount) { - q.sendSimple(connection._socket); + q.sendSimple(connection!._socket!); return _PostgreSQLConnectionStateBusy(q); } - final cached = connection._cache[q.statement]; - q.sendExtended(connection._socket, cacheQuery: cached); + final cached = connection!._cache[q.statement]; + q.sendExtended(connection!._socket!, cacheQuery: cached); return _PostgreSQLConnectionStateBusy(q); } catch (e, st) { diff --git a/lib/src/exceptions.dart b/lib/src/exceptions.dart index 44e6a00..33952e0 100644 --- a/lib/src/exceptions.dart +++ b/lib/src/exceptions.dart @@ -42,71 +42,71 @@ class PostgreSQLException implements Exception { PostgreSQLException._(List errorFields, {this.stackTrace}) { final finder = (int identifer) => (errorFields.firstWhere( (ErrorField e) => e.identificationToken == identifer, - orElse: () => null)); + orElse: () => ErrorField(null, null))); severity = ErrorField.severityFromString( finder(ErrorField.SeverityIdentifier).text); code = finder(ErrorField.CodeIdentifier).text; message = finder(ErrorField.MessageIdentifier).text; - detail = finder(ErrorField.DetailIdentifier)?.text; - hint = finder(ErrorField.HintIdentifier)?.text; - - internalQuery = finder(ErrorField.InternalQueryIdentifier)?.text; - trace = finder(ErrorField.WhereIdentifier)?.text; - schemaName = finder(ErrorField.SchemaIdentifier)?.text; - tableName = finder(ErrorField.TableIdentifier)?.text; - columnName = finder(ErrorField.ColumnIdentifier)?.text; - dataTypeName = finder(ErrorField.DataTypeIdentifier)?.text; - constraintName = finder(ErrorField.ConstraintIdentifier)?.text; - fileName = finder(ErrorField.FileIdentifier)?.text; - routineName = finder(ErrorField.RoutineIdentifier)?.text; - - var i = finder(ErrorField.PositionIdentifier)?.text; + detail = finder(ErrorField.DetailIdentifier).text; + hint = finder(ErrorField.HintIdentifier).text; + + internalQuery = finder(ErrorField.InternalQueryIdentifier).text; + trace = finder(ErrorField.WhereIdentifier).text; + schemaName = finder(ErrorField.SchemaIdentifier).text; + tableName = finder(ErrorField.TableIdentifier).text; + columnName = finder(ErrorField.ColumnIdentifier).text; + dataTypeName = finder(ErrorField.DataTypeIdentifier).text; + constraintName = finder(ErrorField.ConstraintIdentifier).text; + fileName = finder(ErrorField.FileIdentifier).text; + routineName = finder(ErrorField.RoutineIdentifier).text; + + var i = finder(ErrorField.PositionIdentifier).text; position = (i != null ? int.parse(i) : null); - i = finder(ErrorField.InternalPositionIdentifier)?.text; + i = finder(ErrorField.InternalPositionIdentifier).text; internalPosition = (i != null ? int.parse(i) : null); - i = finder(ErrorField.LineIdentifier)?.text; + i = finder(ErrorField.LineIdentifier).text; lineNumber = (i != null ? int.parse(i) : null); } /// The severity of the exception. - PostgreSQLSeverity severity; + PostgreSQLSeverity? severity; /// The PostgreSQL error code. /// /// May be null if the exception was not generated by the database. - String code; + String? code; /// A message indicating the error. - String message; + String? message; /// Additional details if provided by the database. - String detail; + String? detail; /// A hint on how to remedy an error, if provided by the database. - String hint; + String? hint; /// An index into an executed query string where an error occurred, if by provided by the database. - int position; + int? position; /// An index into a query string generated by the database, if provided. - int internalPosition; - - String internalQuery; - String trace; - String schemaName; - String tableName; - String columnName; - String dataTypeName; - String constraintName; - String fileName; - int lineNumber; - String routineName; + int? internalPosition; + + String? internalQuery; + String? trace; + String? schemaName; + String? tableName; + String? columnName; + String? dataTypeName; + String? constraintName; + String? fileName; + int? lineNumber; + String? routineName; /// A [StackTrace] if available. - StackTrace stackTrace; + StackTrace? stackTrace; @override String toString() { diff --git a/lib/src/execution_context.dart b/lib/src/execution_context.dart index c5f0e0e..a37d388 100644 --- a/lib/src/execution_context.dart +++ b/lib/src/execution_context.dart @@ -29,10 +29,10 @@ abstract class PostgreSQLExecutionContext { /// By default, instances of this class will reuse queries. This allows significantly more efficient transport to and from the database. You do not have to do /// anything to opt in to this behavior, this connection will track the necessary information required to reuse queries without intervention. (The [fmtString] is /// the unique identifier to look up reuse information.) You can disable reuse by passing false for [allowReuse]. - Future query(String fmtString, + Future query(String fmtString, {Map substitutionValues, bool allowReuse, - int timeoutInSeconds}); + int? timeoutInSeconds}); /// Executes a query on this context. /// @@ -41,8 +41,8 @@ abstract class PostgreSQLExecutionContext { /// This method returns the number of rows affected and no additional information. This method uses the least efficient and less secure command /// for executing queries in the PostgreSQL protocol; [query] is preferred for queries that will be executed more than once, will contain user input, /// or return rows. - Future execute(String fmtString, - {Map substitutionValues, int timeoutInSeconds}); + Future execute(String fmtString, + {Map substitutionValues, int? timeoutInSeconds}); /// Cancels a transaction on this context. /// @@ -80,7 +80,7 @@ abstract class PostgreSQLExecutionContext { /// "company: {"name": "stable|kernel"} /// } /// ] - Future>>> mappedResultsQuery( + Future>>> mappedResultsQuery( String fmtString, {Map substitutionValues, bool allowReuse, @@ -93,18 +93,18 @@ abstract class ColumnDescription { String get columnName; /// The resolved name of the referenced table. - String get tableName; + String? get tableName; } /// A single row of a query result. /// /// Column values can be accessed through the `[]` operator. abstract class PostgreSQLResultRow implements List { - List get columnDescriptions; + List get columnDescriptions; /// Returns a two-level map that on the first level contains the resolved /// table name, and on the second level the column name (or its alias). - Map> toTableColumnMap(); + Map> toTableColumnMap(); /// Returns a single-level map that maps the column name (or its alias) to the /// value returned on that position. @@ -117,5 +117,5 @@ abstract class PostgreSQLResultRow implements List { abstract class PostgreSQLResult implements List { /// How many rows did this query affect? int get affectedRowCount; - List get columnDescriptions; + List get columnDescriptions; } diff --git a/lib/src/message_window.dart b/lib/src/message_window.dart index c40129a..91c47d6 100644 --- a/lib/src/message_window.dart +++ b/lib/src/message_window.dart @@ -30,8 +30,8 @@ class MessageFramer { final _reader = ByteDataReader(); final messageQueue = Queue(); - int _type; - int _expectedLength; + int? _type; + int _expectedLength = 0; bool get _hasReadHeader => _type != null; bool get _canReadHeader => _reader.remainingLength >= _headerByteSize; @@ -59,7 +59,7 @@ class MessageFramer { msgMaker == null ? UnknownMessage(_type, data) : msgMaker(data); messageQueue.add(msg); _type = null; - _expectedLength = null; + _expectedLength = 0; evaluateNextMessage = true; } } diff --git a/lib/src/query.dart b/lib/src/query.dart index 26bd2d5..008f4fa 100644 --- a/lib/src/query.dart +++ b/lib/src/query.dart @@ -24,26 +24,26 @@ class Query { final bool onlyReturnAffectedRowCount; - String statementIdentifier; + String? statementIdentifier; - Future> get future => _onComplete.future; + Future?> get future => _onComplete.future; final String statement; - final Map substitutionValues; + final Map? substitutionValues; final PostgreSQLExecutionContext transaction; final PostgreSQLConnection connection; - List _specifiedParameterTypeCodes; + late List _specifiedParameterTypeCodes; final rows = >[]; - CachedQuery cache; + CachedQuery? cache; - final _onComplete = Completer>.sync(); - List _fieldDescriptions; + final _onComplete = Completer?>.sync(); + List? _fieldDescriptions; - List get fieldDescriptions => _fieldDescriptions; + List? get fieldDescriptions => _fieldDescriptions; - set fieldDescriptions(List fds) { + set fieldDescriptions(List? fds) { _fieldDescriptions = fds; cache?.fieldDescriptions = fds; } @@ -56,9 +56,9 @@ class Query { socket.add(queryMessage.asBytes()); } - void sendExtended(Socket socket, {CachedQuery cacheQuery}) { + void sendExtended(Socket socket, {CachedQuery? cacheQuery}) { if (cacheQuery != null) { - fieldDescriptions = cacheQuery.fieldDescriptions; + fieldDescriptions = cacheQuery.fieldDescriptions!; sendCachedQuery(socket, cacheQuery, substitutionValues); return; @@ -89,21 +89,21 @@ class Query { ]; if (statementIdentifier != null) { - cache = CachedQuery(statementIdentifier, formatIdentifiers); + cache = CachedQuery(statementIdentifier!, formatIdentifiers); } socket.add(ClientMessage.aggregateBytes(messages)); } void sendCachedQuery(Socket socket, CachedQuery cacheQuery, - Map substitutionValues) { + Map? substitutionValues) { final statementName = cacheQuery.preparedStatementName; - final parameterList = cacheQuery.orderedParameters + final parameterList = cacheQuery.orderedParameters! .map((identifier) => ParameterValue(identifier, substitutionValues)) .toList(); final bytes = ClientMessage.aggregateBytes([ - BindMessage(parameterList, statementName: statementName), + BindMessage(parameterList, statementName: statementName!), ExecuteMessage(), SyncMessage() ]); @@ -111,7 +111,7 @@ class Query { socket.add(bytes); } - PostgreSQLException validateParameters(List parameterTypeIDs) { + PostgreSQLException? validateParameters(List parameterTypeIDs) { final actualParameterTypeCodeIterator = parameterTypeIDs.iterator; final parametersAreMismatched = _specifiedParameterTypeCodes.map((specifiedType) { @@ -134,12 +134,12 @@ class Query { return null; } - void addRow(List rawRowData) { - if (onlyReturnAffectedRowCount) { + void addRow(List rawRowData) { + if (onlyReturnAffectedRowCount || fieldDescriptions == null) { return; } - final iterator = fieldDescriptions.iterator; + final iterator = fieldDescriptions!.iterator; final lazyDecodedData = rawRowData.map((bd) { iterator.moveNext(); return iterator.current.converter.convert(bd); @@ -161,7 +161,7 @@ class Query { _onComplete.complete(QueryResult(rowsAffected, rows as T)); } - void completeError(dynamic error, [StackTrace stackTrace]) { + void completeError(Object error, [StackTrace? stackTrace]) { if (_onComplete.isCompleted) { return; } @@ -175,7 +175,7 @@ class Query { class QueryResult { final int affectedRowCount; - final T value; + final T? value; const QueryResult(this.affectedRowCount, this.value); } @@ -183,9 +183,9 @@ class QueryResult { class CachedQuery { CachedQuery(this.preparedStatementName, this.orderedParameters); - final String preparedStatementName; - final List orderedParameters; - List fieldDescriptions; + final String? preparedStatementName; + final List? orderedParameters; + List? fieldDescriptions; bool get isValid { return preparedStatementName != null && @@ -196,13 +196,13 @@ class CachedQuery { class ParameterValue { factory ParameterValue(PostgreSQLFormatIdentifier identifier, - Map substitutionValues) { + Map? substitutionValues) { if (identifier.type == null) { - return ParameterValue.text(substitutionValues[identifier.name]); + return ParameterValue.text(substitutionValues?[identifier.name]); } return ParameterValue.binary( - substitutionValues[identifier.name], identifier.type); + substitutionValues?[identifier.name], identifier.type!); } factory ParameterValue.binary( @@ -214,7 +214,7 @@ class ParameterValue { } factory ParameterValue.text(dynamic value) { - Uint8List bytes; + Uint8List? bytes; if (value != null) { final converter = PostgresTextEncoder(); bytes = castBytes( @@ -227,7 +227,7 @@ class ParameterValue { ParameterValue._(this.isBinary, this.bytes, this.length); final bool isBinary; - final Uint8List bytes; + final Uint8List? bytes; final int length; } @@ -244,7 +244,7 @@ class FieldDescription implements ColumnDescription { final int formatCode; @override - final String tableName; + final String? tableName; FieldDescription._( this.converter, @@ -285,7 +285,7 @@ class FieldDescription implements ColumnDescription { ); } - FieldDescription change({String tableName}) { + FieldDescription change({String? tableName}) { return FieldDescription._(converter, columnName, tableID, columnID, typeID, dataTypeSize, typeModifier, formatCode, tableName ?? this.tableName); } @@ -328,8 +328,8 @@ class PostgreSQLFormatIdentifier { factory PostgreSQLFormatIdentifier(String t) { String name; - PostgreSQLDataType type; - String typeCast; + PostgreSQLDataType? type; + String? typeCast; final components = t.split('::'); if (components.length > 1) { @@ -343,12 +343,11 @@ class PostgreSQLFormatIdentifier { name = variableComponents.first; final dataTypeString = variableComponents.last; - if (dataTypeString != null) { - type = typeStringToCodeMap[dataTypeString]; - if (type == null) { - throw FormatException( - "Invalid type code in substitution variable '$t'"); - } + try { + type = typeStringToCodeMap[dataTypeString]!; + } catch (e) { + throw FormatException( + "Invalid type code in substitution variable '$t'"); } } else { throw FormatException( @@ -363,6 +362,6 @@ class PostgreSQLFormatIdentifier { PostgreSQLFormatIdentifier._(this.name, this.type, this.typeCast); final String name; - final PostgreSQLDataType type; - final String typeCast; + final PostgreSQLDataType? type; + final String? typeCast; } diff --git a/lib/src/query_cache.dart b/lib/src/query_cache.dart index 2acf5d9..4fa4690 100644 --- a/lib/src/query_cache.dart +++ b/lib/src/query_cache.dart @@ -12,12 +12,12 @@ class QueryCache { return; } - if (query.cache.isValid) { - _queries[query.statement] = query.cache; + if (query.cache!.isValid) { + _queries[query.statement] = query.cache!; } } - CachedQuery operator [](String statementId) { + CachedQuery? operator [](String? statementId) { if (statementId == null) { return null; } @@ -28,7 +28,7 @@ class QueryCache { String identifierForQuery(Query query) { final existing = _queries[query.statement]; if (existing != null) { - return existing.preparedStatementName; + return existing.preparedStatementName!; } final string = '$_idCounter'.padLeft(12, '0'); diff --git a/lib/src/query_queue.dart b/lib/src/query_queue.dart index 29514cb..42ac683 100644 --- a/lib/src/query_queue.dart +++ b/lib/src/query_queue.dart @@ -13,14 +13,14 @@ class QueryQueue extends ListBase> PostgreSQLException get _cancellationException => PostgreSQLException( 'Query cancelled due to the database connection closing.'); - Query get pending { + Query? get pending { if (_inner.isEmpty) { return null; } return _inner.first; } - void cancel([dynamic error, StackTrace stackTrace]) { + void cancel([Object? error, StackTrace? stackTrace]) { _isCancelled = true; error ??= _cancellationException; final existing = _inner; @@ -30,8 +30,8 @@ class QueryQueue extends ListBase> // get the error and not the close message, since completeError is // synchronous. scheduleMicrotask(() { - existing?.forEach((q) { - q.completeError(error, stackTrace); + existing.forEach((q) { + q.completeError(error!, stackTrace); }); }); } diff --git a/lib/src/server_messages.dart b/lib/src/server_messages.dart index 4ee1f9a..709a659 100644 --- a/lib/src/server_messages.dart +++ b/lib/src/server_messages.dart @@ -14,8 +14,8 @@ class ErrorResponseMessage implements ServerMessage { ErrorResponseMessage(Uint8List bytes) { final reader = ByteDataReader()..add(bytes); - int identificationToken; - StringBuffer sb; + int? identificationToken; + StringBuffer? sb; while (reader.remainingLength > 0) { final byte = reader.readUint8(); @@ -27,7 +27,7 @@ class ErrorResponseMessage implements ServerMessage { identificationToken = null; sb = null; } else { - sb.writeCharCode(byte); + sb!.writeCharCode(byte); } } if (identificationToken != null && sb != null) { @@ -54,9 +54,9 @@ class AuthenticationMessage implements ServerMessage { factory AuthenticationMessage(Uint8List bytes) { final reader = ByteDataReader()..add(bytes); final type = reader.readUint32(); - List salt; + final salt = []; if (type == KindMD5Password) { - salt = reader.read(4, copy: true); + salt.addAll(reader.read(4, copy: true)); } return AuthenticationMessage._(type, salt); } @@ -115,7 +115,7 @@ class RowDescriptionMessage extends ServerMessage { } class DataRowMessage extends ServerMessage { - final values = []; + final values = []; DataRowMessage(Uint8List bytes) { final reader = ByteDataReader()..add(bytes); @@ -168,7 +168,7 @@ class CommandCompleteMessage extends ServerMessage { final str = utf8.decode(bytes.sublist(0, bytes.length - 1)); final match = identifierExpression.firstMatch(str); var rowsAffected = 0; - if (match.end < str.length) { + if (match != null && match.end < str.length) { rowsAffected = int.parse(str.split(' ').last); } return CommandCompleteMessage._(rowsAffected); @@ -210,8 +210,8 @@ class NoDataMessage extends ServerMessage { } class UnknownMessage extends ServerMessage { - final int code; - final Uint8List bytes; + final int? code; + final Uint8List? bytes; UnknownMessage(this.code, this.bytes); @@ -223,11 +223,11 @@ class UnknownMessage extends ServerMessage { @override bool operator ==(dynamic other) { if (bytes != null) { - if (bytes.length != other.bytes.length) { + if (bytes!.length != other.bytes.length) { return false; } - for (var i = 0; i < bytes.length; i++) { - if (bytes[i] != other.bytes[i]) { + for (var i = 0; i < bytes!.length; i++) { + if (bytes![i] != other.bytes[i]) { return false; } } @@ -259,7 +259,7 @@ class ErrorField { static const int LineIdentifier = 76; static const int RoutineIdentifier = 82; - static PostgreSQLSeverity severityFromString(String str) { + static PostgreSQLSeverity severityFromString(String? str) { switch (str) { case 'ERROR': return PostgreSQLSeverity.error; @@ -277,13 +277,13 @@ class ErrorField { return PostgreSQLSeverity.info; case 'LOG': return PostgreSQLSeverity.log; + default: + return PostgreSQLSeverity.unknown; } - - return PostgreSQLSeverity.unknown; } - final int identificationToken; - final String text; + final int? identificationToken; + final String? text; ErrorField(this.identificationToken, this.text); } diff --git a/lib/src/substituter.dart b/lib/src/substituter.dart index 0d7f647..472383f 100644 --- a/lib/src/substituter.dart +++ b/lib/src/substituter.dart @@ -5,7 +5,7 @@ import 'types.dart'; class PostgreSQLFormat { static final int _atSignCodeUnit = '@'.codeUnitAt(0); - static String id(String name, {PostgreSQLDataType type}) { + static String id(String name, {PostgreSQLDataType? type}) { if (type != null) { return '@$name:${dataTypeStringForDataType(type)}'; } @@ -13,7 +13,7 @@ class PostgreSQLFormat { return '@$name'; } - static String dataTypeStringForDataType(PostgreSQLDataType dt) { + static String? dataTypeStringForDataType(PostgreSQLDataType? dt) { switch (dt) { case PostgreSQLDataType.text: return 'text'; @@ -47,19 +47,19 @@ class PostgreSQLFormat { return 'name'; case PostgreSQLDataType.uuid: return 'uuid'; + default: + return null; } - - return null; } - static String substitute(String fmtString, Map values, - {SQLReplaceIdentifierFunction replace}) { + static String substitute(String fmtString, Map? values, + {SQLReplaceIdentifierFunction? replace}) { final converter = PostgresTextEncoder(); - values ??= {}; - replace ??= (spec, index) => converter.convert(values[spec.name]); + values ??= const {}; + replace ??= (spec, index) => converter.convert(values![spec.name]); final items = []; - PostgreSQLFormatToken currentPtr; + PostgreSQLFormatToken? currentPtr; final iterator = RuneIterator(fmtString); while (iterator.moveNext()) { @@ -115,13 +115,13 @@ class PostgreSQLFormat { } else { final identifier = PostgreSQLFormatIdentifier(t.buffer.toString()); - if (!values.containsKey(identifier.name)) { + if (values != null && !values.containsKey(identifier.name)) { // Format string specified identifier with name ${identifier.name}, // but key was not present in values. return t.buffer; } - final val = replace(identifier, idx); + final val = replace!(identifier, idx); idx++; if (identifier.typeCast != null) { diff --git a/lib/src/text_codec.dart b/lib/src/text_codec.dart index 852f986..8eca302 100644 --- a/lib/src/text_codec.dart +++ b/lib/src/text_codec.dart @@ -110,7 +110,7 @@ class PostgresTextEncoder { return value ? 'TRUE' : 'FALSE'; } - String _encodeDateTime(DateTime value, {bool isDateOnly}) { + String _encodeDateTime(DateTime value, {bool isDateOnly = false}) { var string = value.toIso8601String(); if (isDateOnly) { diff --git a/lib/src/transaction_proxy.dart b/lib/src/transaction_proxy.dart index 67ea2b1..077345f 100644 --- a/lib/src/transaction_proxy.dart +++ b/lib/src/transaction_proxy.dart @@ -13,12 +13,12 @@ class _TransactionProxy extends Object _beginQuery.future.then(startTransaction).catchError((err, StackTrace st) { Future(() { - _completer.completeError(err, st); + _completer.completeError(err as Object, st); }); }); } - Query _beginQuery; + late Query _beginQuery; final _completer = Completer(); Future get future => _completer.future; @@ -30,13 +30,13 @@ class _TransactionProxy extends Object PostgreSQLExecutionContext get _transaction => this; final _TransactionQuerySignature executionBlock; - final int commitTimeoutInSeconds; + final int? commitTimeoutInSeconds; bool _hasFailed = false; bool _hasRolledBack = false; @override - void cancelTransaction({String reason}) { - throw _TransactionRollbackException(reason); + void cancelTransaction({String? reason}) { + throw _TransactionRollbackException(reason ?? 'Reason not given.'); } Future startTransaction(dynamic _) async { @@ -70,7 +70,7 @@ class _TransactionProxy extends Object } } - Future _cancelAndRollback(dynamic object, [StackTrace trace]) async { + Future _cancelAndRollback(dynamic object, [StackTrace? trace]) async { if (_hasRolledBack) { return; } @@ -102,11 +102,11 @@ class _TransactionProxy extends Object if (object is _TransactionRollbackException) { _completer.complete(PostgreSQLRollback._(object.reason)); } else { - _completer.completeError(object, trace); + _completer.completeError(object as Object, trace); } } - Future _transactionFailed(dynamic error, [StackTrace trace]) async { + Future _transactionFailed(dynamic error, [StackTrace? trace]) async { if (_hasFailed) { return; } @@ -117,7 +117,7 @@ class _TransactionProxy extends Object } @override - Future _onQueryError(Query query, dynamic error, [StackTrace trace]) { + Future _onQueryError(Query query, dynamic error, [StackTrace? trace]) { return _transactionFailed(error, trace); } } diff --git a/lib/src/utf8_backed_string.dart b/lib/src/utf8_backed_string.dart index 360344d..f8612e8 100644 --- a/lib/src/utf8_backed_string.dart +++ b/lib/src/utf8_backed_string.dart @@ -3,7 +3,7 @@ import 'dart:convert'; class UTF8BackedString { UTF8BackedString(this.string); - List _cachedUTF8Bytes; + List? _cachedUTF8Bytes; bool get hasCachedBytes => _cachedUTF8Bytes != null; @@ -11,11 +11,11 @@ class UTF8BackedString { int get utf8Length { _cachedUTF8Bytes ??= utf8.encode(string); - return _cachedUTF8Bytes.length; + return _cachedUTF8Bytes!.length; } List get utf8Bytes { _cachedUTF8Bytes ??= utf8.encode(string); - return _cachedUTF8Bytes; + return _cachedUTF8Bytes!; } } diff --git a/pubspec.yaml b/pubspec.yaml index 48ef18e..8de7278 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,16 +1,16 @@ name: postgres description: PostgreSQL database driver. Supports statement reuse and binary protocol. -version: 2.2.0 +version: 2.3.0 homepage: https://github.com/stablekernel/postgresql-dart environment: - sdk: ">=2.8.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" dependencies: - buffer: ^1.0.6 - crypto: ^2.0.0 + buffer: ^1.1.0-nullsafety.0 + crypto: ^3.0.0 dev_dependencies: - pedantic: ^1.0.0 - test: ^1.3.0 + pedantic: ^1.10.0 + test: ^1.16.3 coverage: any diff --git a/test/connection_test.dart b/test/connection_test.dart index d95b7d0..48c87a7 100644 --- a/test/connection_test.dart +++ b/test/connection_test.dart @@ -10,10 +10,10 @@ import 'package:postgres/postgres.dart'; void main() { group('Connection lifecycle', () { - PostgreSQLConnection conn; + late PostgreSQLConnection conn; tearDown(() async { - await conn?.close(); + await conn.close(); }); test('Connect with md5 auth required', () async { @@ -70,8 +70,6 @@ void main() { final underlyingSocket = reflect(conn).getField(socketMirror.simpleName).reflectee as Socket; expect(await underlyingSocket.done, isNotNull); - - conn = null; }); test('SSL Closing idle connection succeeds, closes underlying socket', @@ -88,8 +86,6 @@ void main() { final underlyingSocket = reflect(conn).getField(socketMirror.simpleName).reflectee as Socket; expect(await underlyingSocket.done, isNotNull); - - conn = null; }); test( @@ -148,7 +144,7 @@ void main() { }); group('Successful queries over time', () { - PostgreSQLConnection conn; + late PostgreSQLConnection conn; setUp(() async { conn = PostgreSQLConnection('localhost', 5432, 'dart_test', @@ -157,7 +153,7 @@ void main() { }); tearDown(() async { - await conn?.close(); + await conn.close(); }); test( @@ -224,12 +220,12 @@ void main() { }); group('Unintended user-error situations', () { - PostgreSQLConnection conn; - Future openFuture; + late PostgreSQLConnection conn; + late Future openFuture; tearDown(() async { await openFuture; - await conn?.close(); + await conn.close(); }); test('Sending queries to opening connection triggers error', () async { @@ -348,7 +344,6 @@ void main() { await conn.execute('CREATE TEMPORARY TABLE t (i int unique)'); await conn.execute('INSERT INTO t (i) VALUES (1)'); - //ignore: unawaited_futures conn.execute('INSERT INTO t (i) VALUES (1)').catchError((err) { // ignore }); @@ -393,7 +388,6 @@ void main() { final orderEnsurer = []; // this will emit a query error - //ignore: unawaited_futures conn.execute('INSERT INTO t (i) VALUES (1)').catchError((err) { orderEnsurer.add(1); // ignore @@ -449,12 +443,16 @@ void main() { }); group('Network error situations', () { - ServerSocket serverSocket; - Socket socket; + ServerSocket? serverSocket; + Socket? socket; tearDown(() async { - await serverSocket?.close(); - await socket?.close(); + if (serverSocket != null) { + await serverSocket!.close(); + } + if (socket != null) { + await socket!.close(); + } }); test( @@ -493,7 +491,7 @@ void main() { () async { serverSocket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 5433); - serverSocket.listen((s) { + serverSocket!.listen((s) { socket = s; // Don't respond on purpose s.listen((bytes) {}); @@ -517,7 +515,7 @@ void main() { () async { serverSocket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 5433); - serverSocket.listen((s) { + serverSocket!.listen((s) { socket = s; // Don't respond on purpose s.listen((bytes) {}); @@ -541,7 +539,7 @@ void main() { final openCompleter = Completer(); serverSocket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 5433); - serverSocket.listen((s) { + serverSocket!.listen((s) { socket = s; // Don't respond on purpose s.listen((bytes) {}); @@ -567,7 +565,7 @@ void main() { final openCompleter = Completer(); serverSocket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 5433); - serverSocket.listen((s) { + serverSocket!.listen((s) { socket = s; // Don't respond on purpose s.listen((bytes) {}); diff --git a/test/decode_test.dart b/test/decode_test.dart index 27096fb..f492f0b 100644 --- a/test/decode_test.dart +++ b/test/decode_test.dart @@ -2,7 +2,7 @@ import 'package:postgres/postgres.dart'; import 'package:test/test.dart'; void main() { - PostgreSQLConnection connection; + late PostgreSQLConnection connection; setUp(() async { connection = PostgreSQLConnection('localhost', 5432, 'dart_test', username: 'dart', password: 'dart'); @@ -34,13 +34,13 @@ void main() { 'VALUES (null, null, null, null, null, null, null, null, null, null, null, null, null)'); }); tearDown(() async { - await connection?.close(); + await connection.close(); }); test('Fetch em', () async { final res = await connection.query('select * from t'); - final row1 = res[0]; + final row1 = res![0]; final row2 = res[1]; final row3 = res[2]; diff --git a/test/encoding_test.dart b/test/encoding_test.dart index edfc81e..3566d7e 100644 --- a/test/encoding_test.dart +++ b/test/encoding_test.dart @@ -9,7 +9,7 @@ import 'package:postgres/src/text_codec.dart'; import 'package:postgres/src/types.dart'; import 'package:postgres/src/utf8_backed_string.dart'; -PostgreSQLConnection conn; +late PostgreSQLConnection conn; void main() { group('Binary encoders', () { @@ -21,7 +21,6 @@ void main() { tearDown(() async { await conn.close(); - conn = null; }); // expectInverse ensures that: @@ -394,7 +393,7 @@ Future expectInverse(dynamic value, PostgreSQLDataType dataType) async { final result = await conn.query( 'INSERT INTO t (v) VALUES (${PostgreSQLFormat.id('v', type: dataType)}) RETURNING v', substitutionValues: {'v': value}); - expect(result.first.first, equals(value)); + expect(result!.first.first, equals(value)); final encoder = PostgresBinaryEncoder(dataType); final encodedValue = encoder.convert(value); @@ -404,7 +403,7 @@ Future expectInverse(dynamic value, PostgreSQLDataType dataType) async { } else if (dataType == PostgreSQLDataType.bigSerial) { dataType = PostgreSQLDataType.bigInteger; } - int code; + late int code; PostgresBinaryDecoder.typeMap.forEach((key, type) { if (type == dataType) { code = key; diff --git a/test/framer_test.dart b/test/framer_test.dart index 77a3996..064c54e 100644 --- a/test/framer_test.dart +++ b/test/framer_test.dart @@ -8,7 +8,7 @@ import 'package:postgres/src/message_window.dart'; import 'package:postgres/src/server_messages.dart'; void main() { - MessageFramer framer; + late MessageFramer framer; setUp(() { framer = MessageFramer(); }); diff --git a/test/json_test.dart b/test/json_test.dart index cee5b27..c045c32 100644 --- a/test/json_test.dart +++ b/test/json_test.dart @@ -2,7 +2,7 @@ import 'package:postgres/postgres.dart'; import 'package:test/test.dart'; void main() { - PostgreSQLConnection connection; + late PostgreSQLConnection connection; setUp(() async { connection = PostgreSQLConnection('localhost', 5432, 'dart_test', @@ -15,7 +15,7 @@ void main() { }); tearDown(() async { - await connection?.close(); + await connection.close(); }); group('Storage', () { diff --git a/test/map_return_test.dart b/test/map_return_test.dart index b0135ed..ac2e222 100644 --- a/test/map_return_test.dart +++ b/test/map_return_test.dart @@ -4,7 +4,7 @@ import 'package:postgres/postgres.dart'; import 'package:test/test.dart'; void main() { - PostgreSQLConnection connection; + late PostgreSQLConnection connection; setUp(() async { connection = PostgreSQLConnection('localhost', 5432, 'dart_test', @@ -31,7 +31,7 @@ void main() { }); tearDown(() async { - await connection?.close(); + await connection.close(); }); test('Get row map without specifying columns', () async { diff --git a/test/notification_test.dart b/test/notification_test.dart index d6cb5d9..d12aaae 100644 --- a/test/notification_test.dart +++ b/test/notification_test.dart @@ -5,9 +5,7 @@ import 'package:test/test.dart'; void main() { group('Successful notifications', () { - var connection = PostgreSQLConnection('localhost', 5432, 'dart_test', - username: 'dart', password: 'dart'); - + late PostgreSQLConnection connection; setUp(() async { connection = PostgreSQLConnection('localhost', 5432, 'dart_test', username: 'dart', password: 'dart'); diff --git a/test/query_reuse_test.dart b/test/query_reuse_test.dart index 44ebbae..929cb6a 100644 --- a/test/query_reuse_test.dart +++ b/test/query_reuse_test.dart @@ -11,7 +11,7 @@ String sid(String id, PostgreSQLDataType dt) => void main() { group('Retaining type information', () { - PostgreSQLConnection connection; + late PostgreSQLConnection connection; setUp(() async { connection = PostgreSQLConnection('localhost', 5432, 'dart_test', @@ -281,7 +281,7 @@ void main() { }); group('Mixing prepared statements', () { - PostgreSQLConnection connection; + late PostgreSQLConnection connection; setUp(() async { connection = PostgreSQLConnection('localhost', 5432, 'dart_test', @@ -440,8 +440,7 @@ void main() { }); group('Failure cases', () { - var connection = PostgreSQLConnection('localhost', 5432, 'dart_test', - username: 'dart', password: 'dart'); + late PostgreSQLConnection connection; setUp(() async { connection = PostgreSQLConnection('localhost', 5432, 'dart_test', diff --git a/test/query_test.dart b/test/query_test.dart index 9627632..8ee2244 100644 --- a/test/query_test.dart +++ b/test/query_test.dart @@ -4,8 +4,7 @@ import 'package:postgres/src/types.dart'; void main() { group('Successful queries', () { - var connection = PostgreSQLConnection('localhost', 5432, 'dart_test', - username: 'dart', password: 'dart'); + late PostgreSQLConnection connection; setUp(() async { connection = PostgreSQLConnection('localhost', 5432, 'dart_test', @@ -39,9 +38,9 @@ void main() { expect(result, [expectedRow]); result = await connection.query('select t from t'); - expect(result.columnDescriptions, hasLength(1)); - expect(result.columnDescriptions.single.tableName, 't'); - expect(result.columnDescriptions.single.columnName, 't'); + expect(result!.columnDescriptions, hasLength(1)); + expect(result.columnDescriptions.single!.tableName, 't'); + expect(result.columnDescriptions.single!.columnName, 't'); expect(result, [expectedRow]); }); @@ -155,11 +154,11 @@ void main() { {'a': 'b'}, '01234567-89ab-cdef-0123-0123456789ab' ]; - expect(result.columnDescriptions, hasLength(14)); - expect(result.columnDescriptions.first.tableName, 't'); - expect(result.columnDescriptions.first.columnName, 'i'); - expect(result.columnDescriptions.last.tableName, 't'); - expect(result.columnDescriptions.last.columnName, 'u'); + expect(result!.columnDescriptions, hasLength(14)); + expect(result.columnDescriptions.first!.tableName, 't'); + expect(result.columnDescriptions.first!.columnName, 'i'); + expect(result.columnDescriptions.last!.tableName, 't'); + expect(result.columnDescriptions.last!.columnName, 'u'); expect(result, [expectedRow]); result = await connection.query( 'select i,s, bi, bs, bl, si, t, f, d, dt, ts, tsz, j, u from t'); @@ -332,8 +331,7 @@ void main() { }); group('Unsuccesful queries', () { - var connection = PostgreSQLConnection('localhost', 5432, 'dart_test', - username: 'dart', password: 'dart'); + late PostgreSQLConnection connection; setUp(() async { connection = PostgreSQLConnection('localhost', 5432, 'dart_test', @@ -365,13 +363,13 @@ void main() { () async { final rs1 = await connection .query('SELECT * FROM (VALUES (\'user@domain.com\')) t1 (col1)'); - expect(rs1.first.toColumnMap(), {'col1': 'user@domain.com'}); + expect(rs1!.first.toColumnMap(), {'col1': 'user@domain.com'}); final rs2 = await connection.query( 'SELECT * FROM (VALUES (\'user@domain.com\')) t1 (col1) WHERE col1 > @u1', substitutionValues: {'u1': 'hello@domain.com'}, ); - expect(rs2.first.toColumnMap(), {'col1': 'user@domain.com'}); + expect(rs2!.first.toColumnMap(), {'col1': 'user@domain.com'}); }); test('Wrong type for parameter in substitution values fails', () async { diff --git a/test/timeout_test.dart b/test/timeout_test.dart index 5ff8f32..610db5f 100644 --- a/test/timeout_test.dart +++ b/test/timeout_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; import 'package:postgres/postgres.dart'; void main() { - PostgreSQLConnection conn; + late PostgreSQLConnection conn; setUp(() async { conn = PostgreSQLConnection('localhost', 5432, 'dart_test', @@ -15,7 +15,7 @@ void main() { }); tearDown(() async { - await conn?.close(); + await conn.close(); }); test( diff --git a/test/transaction_test.dart b/test/transaction_test.dart index e588032..5bee2ef 100644 --- a/test/transaction_test.dart +++ b/test/transaction_test.dart @@ -7,7 +7,7 @@ import 'package:postgres/postgres.dart'; void main() { group('Transaction behavior', () { - PostgreSQLConnection conn; + late PostgreSQLConnection conn; setUp(() async { conn = PostgreSQLConnection('localhost', 5432, 'dart_test', @@ -17,7 +17,7 @@ void main() { }); tearDown(() async { - await conn?.close(); + await conn.close(); }); test('Rows are Lists of column values', () async { @@ -248,8 +248,12 @@ void main() { () async { final errs = []; await conn.transaction((ctx) async { - ctx.query('INSERT INTO t (id) VALUES (1)').catchError(errs.add); - ctx.query('INSERT INTO t (id) VALUES (2)').catchError(errs.add); + final errsAdd = (e) { + errs.add(e); + return null; + }; + ctx.query('INSERT INTO t (id) VALUES (1)').catchError(errsAdd); + ctx.query('INSERT INTO t (id) VALUES (2)').catchError(errsAdd); ctx.cancelTransaction(); ctx.query('INSERT INTO t (id) VALUES (3)').catchError((e) {}); }); @@ -295,7 +299,7 @@ void main() { // After a transaction fails, the changes must be rolled back, it should continue with pending queries, pending transactions, later queries, later transactions group('Transaction:Query recovery', () { - PostgreSQLConnection conn; + late PostgreSQLConnection conn; setUp(() async { conn = PostgreSQLConnection('localhost', 5432, 'dart_test', @@ -305,7 +309,7 @@ void main() { }); tearDown(() async { - await conn?.close(); + await conn.close(); }); test('Is rolled back/executes later query', () async { @@ -396,7 +400,7 @@ void main() { }); group('Transaction:Exception recovery', () { - PostgreSQLConnection conn; + late PostgreSQLConnection conn; setUp(() async { conn = PostgreSQLConnection('localhost', 5432, 'dart_test', @@ -406,7 +410,7 @@ void main() { }); tearDown(() async { - await conn?.close(); + await conn.close(); }); test('Is rolled back/executes later query', () async { @@ -542,7 +546,7 @@ void main() { }); group('Transaction:Rollback recovery', () { - PostgreSQLConnection conn; + late PostgreSQLConnection conn; setUp(() async { conn = PostgreSQLConnection('localhost', 5432, 'dart_test', @@ -552,7 +556,7 @@ void main() { }); tearDown(() async { - await conn?.close(); + await conn.close(); }); test('Is rolled back/executes later query', () async {