From e25f6831130f72adb22a4ac8694bcca07792f235 Mon Sep 17 00:00:00 2001 From: gmpassos Date: Wed, 5 Mar 2025 04:51:52 -0300 Subject: [PATCH 01/10] v1.9.3 - Upgrade to `postgres` API v3. - postgres: ^3.5.4 - project_template: ^1.1.1 - archive: ^4.0.4 --- CHANGELOG.md | 8 ++ lib/src/bones_api_base.dart | 2 +- lib/src/bones_api_db_module.dart | 2 +- lib/src/bones_api_entity_db_postgres.dart | 131 +++++++++++++++------- pubspec.yaml | 10 +- 5 files changed, 106 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2856e863..d46fc50a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 1.9.3 + +- Upgrade to `postgres` API v3. + +- postgres: ^3.5.4 +- project_template: ^1.1.1 +- archive: ^4.0.4 + ## 1.9.2 - `FieldsFromMap`: diff --git a/lib/src/bones_api_base.dart b/lib/src/bones_api_base.dart index 3e941522..0148a595 100644 --- a/lib/src/bones_api_base.dart +++ b/lib/src/bones_api_base.dart @@ -42,7 +42,7 @@ typedef APILogger = void Function(APIRoot apiRoot, String type, String? message, /// Bones API Library class. class BonesAPI { // ignore: constant_identifier_names - static const String VERSION = '1.9.2'; + static const String VERSION = '1.9.3'; static bool _boot = false; diff --git a/lib/src/bones_api_db_module.dart b/lib/src/bones_api_db_module.dart index 85289b93..a234b0ca 100644 --- a/lib/src/bones_api_db_module.dart +++ b/lib/src/bones_api_db_module.dart @@ -842,7 +842,7 @@ class APIDBModule extends APIModule { var zipEncoder = ZipEncoder(); - var encode = zipEncoder.encode(archive)!; + var encode = zipEncoder.encode(archive); var zipData = encode is Uint8List ? encode : Uint8List.fromList(encode); var zipFileName = '$zipName.zip'; diff --git a/lib/src/bones_api_entity_db_postgres.dart b/lib/src/bones_api_entity_db_postgres.dart index 67de53fb..651d7c24 100644 --- a/lib/src/bones_api_entity_db_postgres.dart +++ b/lib/src/bones_api_entity_db_postgres.dart @@ -1,6 +1,6 @@ import 'package:async_extension/async_extension.dart'; import 'package:logging/logging.dart' as logging; -import 'package:postgres/postgres.dart'; +import 'package:postgres/postgres.dart' hide Time, Type; import 'package:reflection_factory/reflection_factory.dart'; import 'package:statistics/statistics.dart'; @@ -34,7 +34,7 @@ class DBPostgreSQLAdapter extends DBSQLAdapter DBSQLAdapter.boot(); - Transaction.registerErrorFilter((e, s) => e is PostgreSQLException); + Transaction.registerErrorFilter((e, s) => e is PgException); DBSQLAdapter.registerAdapter([ 'sql.postgres', @@ -232,8 +232,8 @@ class DBPostgreSQLAdapter extends DBSQLAdapter Object? previousError) { if (error is DBPostgreSQLAdapterException) { return error; - } else if (error is PostgreSQLException) { - if (error.severity == PostgreSQLSeverity.error) { + } else if (error is ServerException) { + if (error.severity == Severity.error) { if (error.code == '23505') { return EntityFieldInvalid("unique", error.detail, fieldName: error.columnName, @@ -272,7 +272,8 @@ class DBPostgreSQLAdapter extends DBSQLAdapter var count = ++_connectionCount; for (var i = 0; i < 3; ++i) { - var timeout = i == 0 ? 3 : (i == 1 ? 10 : 30); + final timeoutSec = i == 0 ? 3 : (i == 1 ? 10 : 30); + final timeout = Duration(seconds: timeoutSec); var connection = await _createConnectionImpl(password, timeout); @@ -298,7 +299,7 @@ class DBPostgreSQLAdapter extends DBSQLAdapter return _createConnectionImpl(password, timeout).then((conn) { if (conn == null) { - var error = PostgreSQLException( + var error = PgException( "Error connecting to: $databaseName@$host:$port"); _log.severe( @@ -313,8 +314,7 @@ class DBPostgreSQLAdapter extends DBSQLAdapter } } - var error = - PostgreSQLException("Error connecting to: $databaseName@$host:$port"); + var error = PgException("Error connecting to: $databaseName@$host:$port"); _log.severe("Can't connect to PostgreSQL: $databaseName@$host:$port"); @@ -322,25 +322,33 @@ class DBPostgreSQLAdapter extends DBSQLAdapter } Future _createConnectionImpl( - String password, int timeout) async { - var connection = PostgreSQLConnection(host, port, databaseName, - username: username, password: password, timeoutInSeconds: timeout); - var ok = await tryCallMapped(() => connection.open(), - onSuccessValue: true, onErrorValue: false); + String password, Duration timeout) async { + final endpoint = Endpoint( + host: host, + port: port, + database: databaseName, + username: username, + password: password); + + final connectionSettings = ConnectionSettings(connectTimeout: timeout); + + var connection = await tryCall( + () => Connection.open(endpoint, settings: connectionSettings), + ); - if (ok == null || !ok) return null; + if (connection == null) return null; - var connWrapper = PostgreSQLConnectionWrapper(connection); + var connWrapper = PostgreSQLConnectionWrapper(connection, endpoint); _connectionFinalizer.attach(connWrapper, connection); return connWrapper; } - late final Finalizer _connectionFinalizer = + late final Finalizer _connectionFinalizer = Finalizer(_finalizeConnection); - void _finalizeConnection(PostgreSQLConnection connection) { + void _finalizeConnection(Connection connection) { try { // ignore: discarded_futures connection.close(); @@ -1129,33 +1137,52 @@ class DBPostgreSQLAdapter extends DBSQLAdapter } /// A [DBPostgreSQLAdapter] connection wrapper. -class PostgreSQLConnectionWrapper - extends DBConnectionWrapper { - PostgreSQLConnectionWrapper(super.nativeConnection); +class PostgreSQLConnectionWrapper extends DBConnectionWrapper { + final Endpoint _endpoint; + + PostgreSQLConnectionWrapper(super.nativeConnection, this._endpoint); @override String get connectionURL { - var c = nativeConnection as PostgreSQLConnection; - return 'postgresql://${c.username}@${c.host}:${c.port}/${c.databaseName}'; + return 'postgresql://${_endpoint.username}@${_endpoint.host}:${_endpoint.port}/${_endpoint.database}'; } Future>>> mappedResultsQuery(String sql, - {Map? substitutionValues}) { + {Map? substitutionValues}) async { updateLastAccessTime(); - return nativeConnection.mappedResultsQuery(sql, - substitutionValues: substitutionValues); + + var rs = await nativeConnection.execute( + Sql.named(sql), + parameters: substitutionValues, + ); + + var tablesColumnsMap = rs.map((e) => e.toTablesColumnMap()).toList(); + + var mappedResult = tablesColumnsMap + .map((e) => e.map((k, v) => MapEntry('$k', v))) + .toList(); + + return mappedResult; } - Future query(String sql, - {Map? substitutionValues}) { + Future query(String sql, + {Map? substitutionValues}) async { updateLastAccessTime(); - return nativeConnection.query(sql, substitutionValues: substitutionValues); + return nativeConnection.execute( + Sql.named(sql), + parameters: substitutionValues, + ); } - Future execute(String sql, {Map? substitutionValues}) { + Future execute(String sql, + {Map? substitutionValues}) async { updateLastAccessTime(); - return nativeConnection.execute(sql, - substitutionValues: substitutionValues); + var rs = await nativeConnection.execute( + Sql.named(sql), + parameters: substitutionValues, + ignoreRows: true, + ); + return rs.affectedRows; } Future openTransaction( @@ -1163,23 +1190,26 @@ class PostgreSQLConnectionWrapper queryBlock, { int? commitTimeoutInSeconds, }) { - var conn = nativeConnection as PostgreSQLConnection; + var conn = nativeConnection as Connection; updateLastAccessTime(); - return conn.transaction((transactionContext) => queryBlock( - PostgreSQLConnectionTransactionWrapper(this, transactionContext))); + + return conn.runTx( + (tx) => queryBlock( + PostgreSQLConnectionTransactionWrapper(this, tx, _endpoint), + ), + ); } @override bool isClosedImpl() { final nativeConnection = this.nativeConnection; - return nativeConnection is PostgreSQLConnection && - nativeConnection.isClosed; + return nativeConnection is Connection && !nativeConnection.isOpen; } @override void closeImpl() { final nativeConnection = this.nativeConnection; - if (nativeConnection is PostgreSQLConnection) { + if (nativeConnection is Connection) { try { // ignore: discarded_futures nativeConnection.close(); @@ -1196,7 +1226,8 @@ class PostgreSQLConnectionTransactionWrapper extends PostgreSQLConnectionWrapper { final PostgreSQLConnectionWrapper parent; - PostgreSQLConnectionTransactionWrapper(this.parent, super.nativeConnection); + PostgreSQLConnectionTransactionWrapper( + this.parent, super.nativeConnection, super.endpoint); @override Future openTransaction( @@ -1206,8 +1237,10 @@ class PostgreSQLConnectionTransactionWrapper {int? commitTimeoutInSeconds}) => queryBlock(this); - void cancelTransaction({String? reason}) => - nativeConnection.cancelTransaction(reason: reason); + void cancelTransaction({String? reason}) { + var tx = nativeConnection as TxSession; + unawaited(tx.rollback()); + } @override String get runtimeTypeNameSafe => 'PostgreSQLConnectionTransactionWrapper'; @@ -1227,3 +1260,21 @@ class DBPostgreSQLAdapterException extends DBSQLAdapterException { super.operation, super.previousError}); } + +extension on ResultRow { + Map> toTablesColumnMap() { + final tablesMap = >{}; + + for (final (i, col) in schema.columns.indexed) { + var map = tablesMap[col.tableOid ?? 0] ??= {}; + + if (col.columnName case final String name) { + map[name] = this[i]; + } else { + map['[$i]'] = this[i]; + } + } + + return tablesMap; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 8a3a57f0..a624e9d2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: bones_api description: Bones_API - A powerful API backend framework for Dart. It comes with a built-in HTTP Server, route handler, entity handler, SQL translator, and DB adapters. -version: 1.9.2 +version: 1.9.3 homepage: https://github.com/Colossus-Services/bones_api environment: @@ -23,7 +23,7 @@ dependencies: dart_spawner: ^1.1.0 yaml_writer: ^2.1.0 mercury_client: ^2.3.0 - project_template: ^1.1.0 + project_template: ^1.1.1 resource_portable: ^3.1.2 docker_commander: ^2.1.7 args_simple: ^1.1.0 @@ -38,13 +38,13 @@ dependencies: logging: ^1.3.0 collection: ^1.19.0 mime: ^1.0.6 - postgres: ^2.6.4 + postgres: ^3.5.4 mysql1: ^0.20.0 gcloud: ^0.8.18 yaml: ^3.1.3 crypto: ^3.0.6 path: ^1.9.1 - archive: ^3.6.1 + archive: ^4.0.4 stream_channel: ^2.1.4 http: ^1.3.0 googleapis_auth: ^1.6.0 @@ -59,7 +59,7 @@ dev_dependencies: pubspec: ^2.3.0 dependency_validator: ^4.1.2 coverage: ^1.11.1 - vm_service: ^13.0.0 + vm_service: ^15.0.0 #dependency_overrides: # shared_map: From bef8aff8eb3c12bac5064bff89f2d5e2432cdefa Mon Sep 17 00:00:00 2001 From: gmpassos Date: Wed, 5 Mar 2025 04:53:49 -0300 Subject: [PATCH 02/10] =?UTF-8?q?=F0=9F=94=84=20Upgrade=20GitHub=20Actions?= =?UTF-8?q?=20checkout=20to=20v4=20in=20dart.yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/dart.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 929420bc..a27056d4 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -10,7 +10,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dart-lang/setup-dart@v1 - name: Dart version run: | @@ -32,7 +32,7 @@ jobs: test_vm: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dart-lang/setup-dart@v1 - name: Dart version run: | @@ -63,7 +63,7 @@ jobs: test_chrome: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dart-lang/setup-dart@v1 - name: Dart version run: | From bd6677059d95847d4c8632dfe06f8c0d1ae8acdd Mon Sep 17 00:00:00 2001 From: gmpassos Date: Wed, 5 Mar 2025 04:57:11 -0300 Subject: [PATCH 03/10] =?UTF-8?q?=F0=9F=90=9B=20fix:=20Add=20SSL=20mode=20?= =?UTF-8?q?requirement=20for=20Postgres=20connection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/bones_api_entity_db_postgres.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/bones_api_entity_db_postgres.dart b/lib/src/bones_api_entity_db_postgres.dart index 651d7c24..efb43f5e 100644 --- a/lib/src/bones_api_entity_db_postgres.dart +++ b/lib/src/bones_api_entity_db_postgres.dart @@ -330,7 +330,10 @@ class DBPostgreSQLAdapter extends DBSQLAdapter username: username, password: password); - final connectionSettings = ConnectionSettings(connectTimeout: timeout); + final connectionSettings = ConnectionSettings( + connectTimeout: timeout, + sslMode: SslMode.require, + ); var connection = await tryCall( () => Connection.open(endpoint, settings: connectionSettings), From 4b0e8f080cd2da309181071d8555efcfa0467e28 Mon Sep 17 00:00:00 2001 From: gmpassos Date: Wed, 5 Mar 2025 19:18:12 -0300 Subject: [PATCH 04/10] v1.9.3 - `DBPostgreSQLAdapter`: - Upgrade to `postgres` API v3. - Allow SSL connections. - `Time.parse`: accept format `Time(hh:mm:ss.sss)` - postgres: ^3.5.4 - project_template: ^1.1.1 - archive: ^4.0.4 --- CHANGELOG.md | 6 +- lib/src/bones_api_entity_db_postgres.dart | 175 ++++++++++--------- lib/src/bones_api_types.dart | 4 + test/bones_api_enitity_db_postgres_test.dart | 28 +-- test/bones_api_entity_db_tests_base.dart | 1 - 5 files changed, 119 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d46fc50a..05b3748e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ ## 1.9.3 -- Upgrade to `postgres` API v3. +- `DBPostgreSQLAdapter`: + - Upgrade to `postgres` API v3. + - Allow SSL connections. + +- `Time.parse`: accept format `Time(hh:mm:ss.sss)` - postgres: ^3.5.4 - project_template: ^1.1.1 diff --git a/lib/src/bones_api_entity_db_postgres.dart b/lib/src/bones_api_entity_db_postgres.dart index efb43f5e..f537e484 100644 --- a/lib/src/bones_api_entity_db_postgres.dart +++ b/lib/src/bones_api_entity_db_postgres.dart @@ -15,7 +15,6 @@ import 'bones_api_logging.dart'; import 'bones_api_sql_builder.dart'; import 'bones_api_types.dart'; import 'bones_api_utils.dart'; -import 'bones_api_utils_call.dart'; import 'bones_api_utils_timedmap.dart'; final _log = logging.Logger('DBPostgreSQLAdapter')..registerAsDbLogger(); @@ -330,14 +329,9 @@ class DBPostgreSQLAdapter extends DBSQLAdapter username: username, password: password); - final connectionSettings = ConnectionSettings( - connectTimeout: timeout, - sslMode: SslMode.require, - ); - - var connection = await tryCall( - () => Connection.open(endpoint, settings: connectionSettings), - ); + var connection = await (_lastConnectSSLSupported + ? _connectSSLImpl(endpoint, timeout) + : _connectNoSSLImpl(endpoint, timeout)); if (connection == null) return null; @@ -348,6 +342,72 @@ class DBPostgreSQLAdapter extends DBSQLAdapter return connWrapper; } + var _lastConnectSSLSupported = true; + + Future _connectSSLImpl( + Endpoint endpoint, Duration timeout) async { + try { + var connection = await Connection.open( + endpoint, + settings: ConnectionSettings( + connectTimeout: timeout, + sslMode: SslMode.require, + ), + ); + _lastConnectSSLSupported = true; + return connection; + } on PgException catch (e) { + if (e.severity == Severity.error && + e.message.contains('not support SSL')) { + try { + var connection = await Connection.open( + endpoint, + settings: ConnectionSettings( + connectTimeout: timeout, + sslMode: SslMode.disable, + ), + ); + _lastConnectSSLSupported = false; + return connection; + } catch (_) {} + } + + return null; + } + } + + Future _connectNoSSLImpl( + Endpoint endpoint, Duration timeout) async { + try { + var connection = await Connection.open( + endpoint, + settings: ConnectionSettings( + connectTimeout: timeout, + sslMode: SslMode.disable, + ), + ); + _lastConnectSSLSupported = false; + return connection; + } on PgException catch (e) { + if (e.severity == Severity.error && + e.message.contains('not support SSL')) { + try { + var connection = await Connection.open( + endpoint, + settings: ConnectionSettings( + connectTimeout: timeout, + sslMode: SslMode.require, + ), + ); + _lastConnectSSLSupported = true; + return connection; + } catch (_) {} + } + + return null; + } + } + late final Finalizer _connectionFinalizer = Finalizer(_finalizeConnection); @@ -412,9 +472,7 @@ class DBPostgreSQLAdapter extends DBSQLAdapter var sql = "SELECT column_name, data_type, column_default, is_updatable FROM information_schema.columns WHERE table_name = '$table'"; - var results = await connection.mappedResultsQuery(sql); - - var scheme = results.map((e) => e['']!).toList(growable: false); + var scheme = await connection.mappedResultsQuery(sql); await releaseIntoPool(connection); @@ -445,9 +503,7 @@ class DBPostgreSQLAdapter extends DBSQLAdapter var sql = "SELECT column_name, data_type, column_default, is_updatable FROM information_schema.columns WHERE table_name = '$table'"; - var results = await connection.mappedResultsQuery(sql); - - var scheme = results.map((e) => e['']!).toList(growable: false); + var scheme = await connection.mappedResultsQuery(sql); if (scheme.isEmpty) { await releaseIntoPool(connection); @@ -506,11 +562,7 @@ class DBPostgreSQLAdapter extends DBSQLAdapter tbl.relname = '$table'; '''; - var results = await connection.mappedResultsQuery(sql); - - var columns = results.map((r) { - return Map.fromEntries(r.values.expand((e) => e.entries)); - }).toList(growable: false); + var columns = await connection.mappedResultsQuery(sql); var constraintsDefinitions = columns.map((m) => m['constraint_definition'].toString()).toList(); @@ -595,11 +647,7 @@ class DBPostgreSQLAdapter extends DBSQLAdapter constraint_type = 'PRIMARY KEY' and tc.table_name = '$table'; '''; - var results = await connection.mappedResultsQuery(sql); - - var columns = results.map((r) { - return Map.fromEntries(r.values.expand((e) => e.entries)); - }).toList(growable: false); + var columns = await connection.mappedResultsQuery(sql); var primaryFields = Map.fromEntries(columns .map((m) => MapEntry(m['column_name'].toString(), m['data_type']))); @@ -745,13 +793,7 @@ class DBPostgreSQLAdapter extends DBSQLAdapter var results = await connection.mappedResultsQuery(sql); - var names = results - .map((e) { - var v = e.values.first; - return v.values.first; - }) - .map((e) => '$e') - .toList(); + var names = results.map((e) => e.values.first).map((e) => '$e').toList(); return names; } @@ -806,11 +848,7 @@ class DBPostgreSQLAdapter extends DBSQLAdapter o.contype = 'f' AND m.relname = '$table' AND o.conrelid IN (SELECT oid FROM pg_class c WHERE c.relkind = 'r') '''; - var results = await connection.mappedResultsQuery(sql); - - var referenceFields = results.map((r) { - return Map.fromEntries(r.values.expand((e) => e.entries)); - }).toList(growable: false); + var referenceFields = await connection.mappedResultsQuery(sql); var map = Map.fromEntries(referenceFields.map((e) { @@ -882,9 +920,8 @@ class DBPostgreSQLAdapter extends DBSQLAdapter substitutionValues: sql.parametersByPlaceholder) .resolveMapped((results) { var count = results - .map((e) { - var tableResults = e[table] ?? e['']; - var count = tableResults?['count'] ?? 0; + .map((row) { + var count = row['count'] ?? 0; return count is int ? count : int.tryParse(count.toString().trim()); }) .whereType() @@ -906,11 +943,7 @@ class DBPostgreSQLAdapter extends DBSQLAdapter .mappedResultsQuery(sql.sql, substitutionValues: sql.parametersByPlaceholder) .resolveMapped((results) { - var ids = results - .map((e) => e[table]) - .whereType>() - .map((e) => e['id']); - + var ids = results.map((row) => _resolveReturningID(row, sql)); return parseIDs(ids); }); } @@ -924,17 +957,8 @@ class DBPostgreSQLAdapter extends DBSQLAdapter PostgreSQLConnectionWrapper connection) { if (sql.isDummy) return >[]; - return connection - .mappedResultsQuery(sql.sql, - substitutionValues: sql.parametersByPlaceholder) - .resolveMapped((results) { - var entries = results - .map((e) => e[table]) - .whereType>() - .toList(); - - return entries; - }); + return connection.mappedResultsQuery(sql.sql, + substitutionValues: sql.parametersByPlaceholder); } @override @@ -946,17 +970,8 @@ class DBPostgreSQLAdapter extends DBSQLAdapter PostgreSQLConnectionWrapper connection) { if (sql.isDummy) return >[]; - return connection - .mappedResultsQuery(sql.sql, - substitutionValues: sql.parametersByPlaceholder) - .resolveMapped((results) { - var entries = results - .map((e) => e[table]) - .whereType>() - .toList(); - - return entries; - }); + return connection.mappedResultsQuery(sql.sql, + substitutionValues: sql.parametersByPlaceholder); } @override @@ -1050,14 +1065,18 @@ class DBPostgreSQLAdapter extends DBSQLAdapter } dynamic _resolveResultID( - List>> results, String table, SQL sql) { + List> results, String table, SQL sql) { if (results.isEmpty) { return null; } - var returning = results.first[table]; + var returning = results.first; - if (returning == null || returning.isEmpty) { + return _resolveReturningID(returning, sql); + } + + dynamic _resolveReturningID(Map returning, SQL sql) { + if (returning.isEmpty) { return null; } else if (returning.length == 1) { var id = returning.values.first; @@ -1150,7 +1169,7 @@ class PostgreSQLConnectionWrapper extends DBConnectionWrapper { return 'postgresql://${_endpoint.username}@${_endpoint.host}:${_endpoint.port}/${_endpoint.database}'; } - Future>>> mappedResultsQuery(String sql, + Future>> mappedResultsQuery(String sql, {Map? substitutionValues}) async { updateLastAccessTime(); @@ -1159,11 +1178,7 @@ class PostgreSQLConnectionWrapper extends DBConnectionWrapper { parameters: substitutionValues, ); - var tablesColumnsMap = rs.map((e) => e.toTablesColumnMap()).toList(); - - var mappedResult = tablesColumnsMap - .map((e) => e.map((k, v) => MapEntry('$k', v))) - .toList(); + var mappedResult = rs.map((e) => e.toResultsMap()).toList(); return mappedResult; } @@ -1265,12 +1280,10 @@ class DBPostgreSQLAdapterException extends DBSQLAdapterException { } extension on ResultRow { - Map> toTablesColumnMap() { - final tablesMap = >{}; + Map toResultsMap() { + final map = {}; for (final (i, col) in schema.columns.indexed) { - var map = tablesMap[col.tableOid ?? 0] ??= {}; - if (col.columnName case final String name) { map[name] = this[i]; } else { @@ -1278,6 +1291,6 @@ extension on ResultRow { } } - return tablesMap; + return map; } } diff --git a/lib/src/bones_api_types.dart b/lib/src/bones_api_types.dart index 66424a9f..54e2497a 100644 --- a/lib/src/bones_api_types.dart +++ b/lib/src/bones_api_types.dart @@ -183,6 +183,10 @@ class Time implements Comparable