diff --git a/wrestling_scoreboard_server/lib/controllers/bout_action_controller.dart b/wrestling_scoreboard_server/lib/controllers/bout_action_controller.dart index 1389bd03..de35c24c 100644 --- a/wrestling_scoreboard_server/lib/controllers/bout_action_controller.dart +++ b/wrestling_scoreboard_server/lib/controllers/bout_action_controller.dart @@ -1,5 +1,5 @@ import 'package:wrestling_scoreboard_common/common.dart'; -import 'package:postgres/postgres.dart'; +import 'package:postgres/postgres.dart' as psql; import 'entity_controller.dart'; @@ -13,9 +13,9 @@ class BoutActionController extends EntityController { BoutActionController._internal() : super(tableName: 'bout_action'); @override - Map getPostgresDataTypes() { + Map getPostgresDataTypes() { return { - 'point_count': PostgreSQLDataType.smallInteger, + 'point_count': psql.Type.smallInteger, 'bout_role': null, 'action_type': null, }; diff --git a/wrestling_scoreboard_server/lib/controllers/bout_config_controller.dart b/wrestling_scoreboard_server/lib/controllers/bout_config_controller.dart index bcc5218e..c21f7fa1 100644 --- a/wrestling_scoreboard_server/lib/controllers/bout_config_controller.dart +++ b/wrestling_scoreboard_server/lib/controllers/bout_config_controller.dart @@ -1,5 +1,5 @@ import 'package:wrestling_scoreboard_common/common.dart'; -import 'package:postgres/postgres.dart'; +import 'package:postgres/postgres.dart' as psql; import 'package:wrestling_scoreboard_server/controllers/entity_controller.dart'; class BoutConfigController extends EntityController { @@ -12,9 +12,9 @@ class BoutConfigController extends EntityController { BoutConfigController._internal() : super(tableName: 'bout_config'); @override - Map getPostgresDataTypes() { + Map getPostgresDataTypes() { return { - 'period_count': PostgreSQLDataType.smallInteger, + 'period_count': psql.Type.smallInteger, }; } } diff --git a/wrestling_scoreboard_server/lib/controllers/bout_controller.dart b/wrestling_scoreboard_server/lib/controllers/bout_controller.dart index 82732152..0264b8a5 100644 --- a/wrestling_scoreboard_server/lib/controllers/bout_controller.dart +++ b/wrestling_scoreboard_server/lib/controllers/bout_controller.dart @@ -1,5 +1,5 @@ import 'package:wrestling_scoreboard_common/common.dart'; -import 'package:postgres/postgres.dart'; +import 'package:postgres/postgres.dart' as psql; import 'package:shelf/shelf.dart'; import 'entity_controller.dart'; @@ -20,7 +20,7 @@ class BoutController extends EntityController { } @override - Map getPostgresDataTypes() { + Map getPostgresDataTypes() { return { 'winner_role': null, 'bout_result': null, diff --git a/wrestling_scoreboard_server/lib/controllers/competition_controller.dart b/wrestling_scoreboard_server/lib/controllers/competition_controller.dart index d8e5cc20..3463d5d5 100644 --- a/wrestling_scoreboard_server/lib/controllers/competition_controller.dart +++ b/wrestling_scoreboard_server/lib/controllers/competition_controller.dart @@ -1,5 +1,5 @@ import 'package:wrestling_scoreboard_common/common.dart'; -import 'package:postgres/postgres.dart'; +import 'package:postgres/postgres.dart' as psql; import 'package:shelf/shelf.dart'; import 'entity_controller.dart'; @@ -24,7 +24,7 @@ class CompetitionController extends EntityController { } @override - Map getPostgresDataTypes() { - return {'comment': PostgreSQLDataType.text}; + Map getPostgresDataTypes() { + return {'comment': psql.Type.text}; } } diff --git a/wrestling_scoreboard_server/lib/controllers/entity_controller.dart b/wrestling_scoreboard_server/lib/controllers/entity_controller.dart index 28f15d9c..c7fc5131 100644 --- a/wrestling_scoreboard_server/lib/controllers/entity_controller.dart +++ b/wrestling_scoreboard_server/lib/controllers/entity_controller.dart @@ -1,12 +1,14 @@ import 'dart:convert'; -import 'package:postgres/postgres.dart'; +import 'package:postgres/legacy.dart'; +import 'package:postgres/postgres.dart' as psql; import 'package:shelf/shelf.dart'; import 'package:wrestling_scoreboard_common/common.dart'; -import 'package:wrestling_scoreboard_server/controllers/bout_config_controller.dart'; -import 'package:wrestling_scoreboard_server/controllers/club_controller.dart'; import 'package:wrestling_scoreboard_server/controllers/bout_action_controller.dart'; +import 'package:wrestling_scoreboard_server/controllers/bout_config_controller.dart'; import 'package:wrestling_scoreboard_server/controllers/bout_controller.dart'; +import 'package:wrestling_scoreboard_server/controllers/club_controller.dart'; +import 'package:wrestling_scoreboard_server/controllers/competition_controller.dart'; import 'package:wrestling_scoreboard_server/controllers/league_controller.dart'; import 'package:wrestling_scoreboard_server/controllers/league_team_participation_controller.dart'; import 'package:wrestling_scoreboard_server/controllers/league_weight_class_controller.dart'; @@ -16,42 +18,41 @@ import 'package:wrestling_scoreboard_server/controllers/participant_state_contro import 'package:wrestling_scoreboard_server/controllers/participation_controller.dart'; import 'package:wrestling_scoreboard_server/controllers/person_controller.dart'; import 'package:wrestling_scoreboard_server/controllers/team_controller.dart'; -import 'package:wrestling_scoreboard_server/controllers/team_match_controller.dart'; import 'package:wrestling_scoreboard_server/controllers/team_match_bout_controller.dart'; -import 'package:wrestling_scoreboard_server/controllers/competition_controller.dart'; +import 'package:wrestling_scoreboard_server/controllers/team_match_controller.dart'; import 'package:wrestling_scoreboard_server/controllers/websocket_handler.dart'; import 'package:wrestling_scoreboard_server/controllers/weight_class_controller.dart'; import 'package:wrestling_scoreboard_server/services/postgres_db.dart'; -Map typeDartToCodeMap = { - String: PostgreSQLDataType.varChar, - // 'int2': PostgreSQLDataType.smallInteger, - int: PostgreSQLDataType.integer, - // 'int8': PostgreSQLDataType.bigInteger, - // 'float4': PostgreSQLDataType.real, - double: PostgreSQLDataType.double, - bool: PostgreSQLDataType.boolean, - DateTime: PostgreSQLDataType.date, - // 'timestamp': PostgreSQLDataType.timestampWithoutTimezone, - // 'timestamptz': PostgreSQLDataType.timestampWithTimezone, - // 'interval': PostgreSQLDataType.interval, - PgPoint: PostgreSQLDataType.point, - // 'jsonb': PostgreSQLDataType.jsonb, - // 'bytea': PostgreSQLDataType.byteArray, - // 'name': PostgreSQLDataType.name, - // 'uuid': PostgreSQLDataType.uuid, - // 'json': PostgreSQLDataType.json, - // 'point': PostgreSQLDataType.point, - List: PostgreSQLDataType.integerArray, - List: PostgreSQLDataType.textArray, - List: PostgreSQLDataType.doubleArray, - // 'varchar': PostgreSQLDataType.varChar, - // '_jsonb': PostgreSQLDataType.jsonbArray, +Map typeDartToCodeMap = { + String: psql.Type.varChar, + // 'int2': psql.Type.smallInteger, + int: psql.Type.integer, + // 'int8': psql.Type.bigInteger, + // 'float4': psql.Type.real, + double: psql.Type.double, + bool: psql.Type.boolean, + DateTime: psql.Type.date, + // 'timestamp': psql.Type.timestampWithoutTimezone, + // 'timestamptz': psql.Type.timestampWithTimezone, + // 'interval': psql.Type.interval, + // PgPoint: psql.Type.point, + // 'jsonb': psql.Type.jsonb, + // 'bytea': psql.Type.byteArray, + // 'name': psql.Type.name, + // 'uuid': psql.Type.uuid, + // 'json': psql.Type.json, + // 'point': psql.Type.point, + List: psql.Type.integerArray, + List: psql.Type.textArray, + List: psql.Type.doubleArray, + // 'varchar': psql.Type.varChar, + // '_jsonb': psql.Type.jsonbArray, }; class PostgresMap { Map map; - Map types; + Map types; PostgresMap(this.map, [this.types = const {}]); } @@ -83,13 +84,14 @@ abstract class EntityController { return DataObject.fromRaw(single, getSingleFromDataType); } + late final getSingleRawStmt = + PostgresDb().connection.prepare(psql.Sql.named('SELECT * FROM $tableName WHERE $primaryKeyName = @id;')); + Future?> getSingleRaw(int id) async { - final res = await PostgresDb() - .connection - .mappedResultsQuery('SELECT * FROM $tableName WHERE $primaryKeyName = @id;', substitutionValues: {'id': id}); - final many = mapToTable(res); - if (many.isEmpty) return Future.value(null); - return many.first; + final res = (await getSingleRawStmt).bind({'id': id}); + final many = res.toColumnMap(); + if (await many.isEmpty) return Future.value(null); + return await many.first; } Future createSingle(T dataObject) async { @@ -104,19 +106,24 @@ abstract class EntityController { final postgresType = postgresTypes.containsKey(e.key) ? postgresTypes[e.key] : typeDartToCodeMap[e.value.runtimeType]; // Trim all strings before inserting into db - if (postgresType == PostgreSQLDataType.varChar || postgresType == PostgreSQLDataType.text) { + if (postgresType == psql.Type.varChar || postgresType == psql.Type.text) { data[e.key] = e.value != null ? (e.value as String).trim() : e.value; } return PostgreSQLFormat.id(e.key, type: postgresType); }).join(', ')}) RETURNING $primaryKeyName; '''; try { - final res = await PostgresDb().connection.query(sql, substitutionValues: data); - return res.last[0] as int; - } on PostgreSQLException catch (e) { + final stmt = await PostgresDb().connection.prepare(sql); + final res = stmt.bind(data); + if (await res.isEmpty || (await res.last).isEmpty) { + throw InvalidParameterException( + 'The data object of table $tableName could not be updated. Check the attributes: $data'); + } + return (await res.last)[0] as int; + } on psql.PgException catch (e) { throw InvalidParameterException( 'The data object of table $tableName could not be created. Check the attributes: $data\n' - 'PostgreSQLException: {"code": ${e.code}}'); + 'PgException: {"message": ${e.message}}'); } } @@ -132,7 +139,7 @@ abstract class EntityController { final postgresType = postgresTypes.containsKey(e.key) ? postgresTypes[e.key] : typeDartToCodeMap[e.value.runtimeType]; // Trim all strings before inserting into db - if (postgresType == PostgreSQLDataType.varChar || postgresType == PostgreSQLDataType.text) { + if (postgresType == psql.Type.varChar || postgresType == psql.Type.text) { data[e.key] = e.value != null ? (e.value as String).trim() : e.value; } return '${e.key} = ${PostgreSQLFormat.id(e.key, type: postgresType)}'; @@ -140,25 +147,28 @@ abstract class EntityController { WHERE $primaryKeyName = ${data[primaryKeyName]} RETURNING $primaryKeyName; '''; try { - final res = await PostgresDb().connection.query(sql, substitutionValues: data); - if (res.isEmpty || res.last.isEmpty) { + final stmt = await PostgresDb().connection.prepare(sql); + final res = stmt.bind(data); + if (await res.isEmpty || (await res.last).isEmpty) { throw InvalidParameterException( 'The data object of table $tableName could not be updated. Check the attributes: $data'); } - return res.last[0] as int; - } on PostgreSQLException catch (e) { + return (await res.last)[0] as int; + } on psql.PgException catch (e) { throw InvalidParameterException( 'The data object of table $tableName could not be updated. Check the attributes: $data' - '\nPostgreSQLException: {"code": ${e.code}'); + '\nPgException: {"message": ${e.message}'); } } + late final deleteSingleStmt = + PostgresDb().connection.prepare(psql.Sql.named('DELETE FROM $tableName WHERE $primaryKeyName = @id;')); + Future deleteSingle(int id) async { try { - await PostgresDb() - .connection - .query('DELETE FROM $tableName WHERE $primaryKeyName = @id;', substitutionValues: {'id': id}); - } on PostgreSQLException catch (_) { + final res = (await deleteSingleStmt).bind({'id': id}); + await res.drain(); + } on psql.PgException catch (_) { return false; } return true; @@ -182,7 +192,9 @@ abstract class EntityController { } Future setManyRawFromQuery(String sqlQuery, {Map? substitutionValues}) async { - await PostgresDb().connection.mappedResultsQuery(sqlQuery, substitutionValues: substitutionValues); + final stmt = await PostgresDb().connection.prepare(psql.Sql.named(sqlQuery)); + final res = stmt.bind(substitutionValues); + return await res.drain(); } Future requestMany(Request request) async { @@ -220,8 +232,9 @@ abstract class EntityController { Future>> getManyRawFromQuery(String sqlQuery, {Map? substitutionValues}) async { - final res = await PostgresDb().connection.mappedResultsQuery(sqlQuery, substitutionValues: substitutionValues); - return mapToTable(res); + final stmt = await PostgresDb().connection.prepare(psql.Sql.named(sqlQuery)); + final res = stmt.bind(substitutionValues); + return await res.toColumnMap().toList(); } Future> mapToEntity(List>> res) async { @@ -231,18 +244,15 @@ abstract class EntityController { })); } - List> mapToTable(List>> res) { - return res.map((row) => row[tableName]!).toList(); - } - - Map getPostgresDataTypes() => {}; + Map getPostgresDataTypes() => {}; bool isRaw(Request request) { return (request.url.queryParameters['isRaw'] ?? '').parseBool(); } - static Future> query(String sqlQuery, {Map? substitutionValues}) async { - return (await PostgresDb().connection.mappedResultsQuery(sqlQuery, substitutionValues: substitutionValues)).single; + static Future> query(psql.Statement stmt, {Map? substitutionValues}) async { + final res = stmt.bind(substitutionValues); + return res.toColumnMap().single; } static Future handlePostSingleOfController(EntityController controller, Map json) async { @@ -315,8 +325,8 @@ abstract class EntityController { static Future> getManyFromDataType( {List? conditions, Conjunction conjunction = Conjunction.and, Map? substitutionValues}) { - return getControllerFromDataType() - .getMany(conditions: conditions, conjunction: conjunction, substitutionValues: substitutionValues); + return getControllerFromDataType().getMany( + conditions: conditions, conjunction: conjunction, substitutionValues: substitutionValues) as Future>; } static EntityController getControllerFromDataType() { @@ -371,3 +381,23 @@ class InvalidParameterException implements Exception { InvalidParameterException(this.message); } + +extension on Map { + /// Parse custom postgres types + /// https://github.com/isoos/postgresql-dart/issues/276 + Map parse() { + return map((key, value) => MapEntry(key, value is psql.UndecodedBytes ? value.asString : value)); + } +} + +extension on psql.ResultStream { + /// Parse custom postgres types + /// https://github.com/isoos/postgresql-dart/issues/276 + Stream> parse() { + return map((row) => row.map((value) => value is psql.UndecodedBytes ? value.asString : value)); + } + + Stream> toColumnMap() { + return map((row) => row.toColumnMap().parse()); + } +} diff --git a/wrestling_scoreboard_server/lib/controllers/lineup_controller.dart b/wrestling_scoreboard_server/lib/controllers/lineup_controller.dart index 8d30329d..78c0606f 100644 --- a/wrestling_scoreboard_server/lib/controllers/lineup_controller.dart +++ b/wrestling_scoreboard_server/lib/controllers/lineup_controller.dart @@ -1,5 +1,6 @@ -import 'package:wrestling_scoreboard_common/common.dart'; import 'package:shelf/shelf.dart'; +import 'package:wrestling_scoreboard_common/common.dart'; +import 'package:wrestling_scoreboard_server/services/postgres_db.dart'; import 'entity_controller.dart'; import 'participation_controller.dart'; @@ -11,7 +12,7 @@ class LineupController extends EntityController { return _singleton; } - static final teamIdQuery = 'SELECT team_id FROM lineup WHERE id = @id'; + static final teamIdStmt = PostgresDb().connection.prepare('SELECT team_id FROM lineup WHERE id = @id'); LineupController._internal() : super(tableName: 'lineup'); diff --git a/wrestling_scoreboard_server/lib/controllers/participant_state_controller.dart b/wrestling_scoreboard_server/lib/controllers/participant_state_controller.dart index 7f4d2ebb..85e5cc96 100644 --- a/wrestling_scoreboard_server/lib/controllers/participant_state_controller.dart +++ b/wrestling_scoreboard_server/lib/controllers/participant_state_controller.dart @@ -1,5 +1,5 @@ import 'package:wrestling_scoreboard_common/common.dart'; -import 'package:postgres/postgres.dart'; +import 'package:postgres/postgres.dart' as psql; import 'entity_controller.dart'; @@ -13,7 +13,7 @@ class ParticipantStateController extends EntityController { ParticipantStateController._internal() : super(tableName: 'participant_state'); @override - Map getPostgresDataTypes() { - return {'classification_points': PostgreSQLDataType.smallInteger}; + Map getPostgresDataTypes() { + return {'classification_points': psql.Type.smallInteger}; } } diff --git a/wrestling_scoreboard_server/lib/controllers/participation_controller.dart b/wrestling_scoreboard_server/lib/controllers/participation_controller.dart index e214a836..9901620f 100644 --- a/wrestling_scoreboard_server/lib/controllers/participation_controller.dart +++ b/wrestling_scoreboard_server/lib/controllers/participation_controller.dart @@ -1,5 +1,5 @@ import 'package:wrestling_scoreboard_common/common.dart'; -import 'package:postgres/postgres.dart'; +import 'package:postgres/postgres.dart' as psql; import 'entity_controller.dart'; @@ -13,7 +13,7 @@ class ParticipationController extends EntityController { ParticipationController._internal() : super(tableName: 'participation'); @override - Map getPostgresDataTypes() { - return {'weight': PostgreSQLDataType.numeric}; + Map getPostgresDataTypes() { + return {'weight': psql.Type.numeric}; } } diff --git a/wrestling_scoreboard_server/lib/controllers/person_controller.dart b/wrestling_scoreboard_server/lib/controllers/person_controller.dart index 25f8043e..aedbc5e7 100644 --- a/wrestling_scoreboard_server/lib/controllers/person_controller.dart +++ b/wrestling_scoreboard_server/lib/controllers/person_controller.dart @@ -1,5 +1,5 @@ import 'package:wrestling_scoreboard_common/common.dart'; -import 'package:postgres/postgres.dart'; +import 'package:postgres/postgres.dart' as psql; import 'entity_controller.dart'; @@ -13,7 +13,7 @@ class PersonController extends EntityController { PersonController._internal() : super(tableName: 'person'); @override - Map getPostgresDataTypes() { + Map getPostgresDataTypes() { return { 'gender': null, }; diff --git a/wrestling_scoreboard_server/lib/controllers/team_match_controller.dart b/wrestling_scoreboard_server/lib/controllers/team_match_controller.dart index 823aed41..64f471ac 100644 --- a/wrestling_scoreboard_server/lib/controllers/team_match_controller.dart +++ b/wrestling_scoreboard_server/lib/controllers/team_match_controller.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:postgres/postgres.dart'; +import 'package:postgres/postgres.dart' as psql; import 'package:shelf/shelf.dart'; import 'package:wrestling_scoreboard_common/common.dart'; import 'package:wrestling_scoreboard_server/controllers/league_controller.dart'; @@ -10,8 +10,8 @@ import 'package:wrestling_scoreboard_server/controllers/team_match_bout_controll import 'package:wrestling_scoreboard_server/controllers/websocket_handler.dart'; import 'package:wrestling_scoreboard_server/services/postgres_db.dart'; -import 'entity_controller.dart'; import 'bout_controller.dart'; +import 'entity_controller.dart'; class TeamMatchController extends EntityController { static final TeamMatchController _singleton = TeamMatchController._internal(); @@ -83,23 +83,20 @@ class TeamMatchController extends EntityController { bout = bout.copyWith(b: bout.b!.copyWithId(await ParticipantStateController().createSingle(bout.b!))); } bout = bout.copyWithId(await BoutController().createSingle(bout)); - await TeamMatchBoutController() - .createSingle(TeamMatchBout(teamMatch: teamMatch, bout: bout, pos: entry.key)); + await TeamMatchBoutController().createSingle(TeamMatchBout(teamMatch: teamMatch, bout: bout, pos: entry.key)); bouts[entry.key] = bout; } else { bout = bout.copyWithId(res.first['id']); bouts[entry.key] = await Bout.fromRaw(res.first, EntityController.getSingleFromDataType); - await PostgresDb() - .connection - .query('UPDATE team_match_bout SET pos = ${entry.key} WHERE bout_id = ${bout.id};'); + final conn = PostgresDb().connection; + await conn.execute('UPDATE team_match_bout SET pos = ${entry.key} WHERE bout_id = ${bout.id};'); } }); if (isReset) { await Future.forEach(oldBouts, (Bout bout) async { if (bout.id != null) { // TODO may also delete boutActions, participantState etc. - await TeamMatchBoutController() - .deleteMany(conditions: ['bout_id=@id'], substitutionValues: {'id': bout.id}); + await TeamMatchBoutController().deleteMany(conditions: ['bout_id=@id'], substitutionValues: {'id': bout.id}); await BoutController().deleteSingle(bout.id!); } }); @@ -109,19 +106,19 @@ class TeamMatchController extends EntityController { await Future.forEach(unusedBouts, (Bout bout) async { if (bout.id != null) { // TODO may also delete boutActions, participantState etc. - await TeamMatchBoutController() - .deleteMany(conditions: ['bout_id=@id'], substitutionValues: {'id': bout.id}); + await TeamMatchBoutController().deleteMany(conditions: ['bout_id=@id'], substitutionValues: {'id': bout.id}); await BoutController().deleteSingle(bout.id!); } }); } - broadcast(jsonEncode(manyToJson(bouts, Bout, CRUD.update, isRaw: false, filterType: TeamMatch, filterId: teamMatch.id))); + broadcast( + jsonEncode(manyToJson(bouts, Bout, CRUD.update, isRaw: false, filterType: TeamMatch, filterId: teamMatch.id))); return Response.ok('{"status": "success"}'); } @override - Map getPostgresDataTypes() { - return {'comment': PostgreSQLDataType.text}; + Map getPostgresDataTypes() { + return {'comment': psql.Type.text}; } } diff --git a/wrestling_scoreboard_server/lib/controllers/websocket_handler.dart b/wrestling_scoreboard_server/lib/controllers/websocket_handler.dart index fbf02957..e721a59e 100644 --- a/wrestling_scoreboard_server/lib/controllers/websocket_handler.dart +++ b/wrestling_scoreboard_server/lib/controllers/websocket_handler.dart @@ -208,13 +208,13 @@ void broadcastSingleRaw(Map single) async } else if (T == TeamMatch) { final teamMatchController = TeamMatchController(); - final homeTeamId = (await EntityController.query(LineupController.teamIdQuery, + final homeTeamId = (await EntityController.query(await LineupController.teamIdStmt, substitutionValues: {'id': single['home_id']}))['team_id']; final homeMatches = await teamMatchController .getManyRawFromQuery(TeamController.teamMatchesQuery, substitutionValues: {'id': homeTeamId}); broadcast(jsonEncode(manyToJson(homeMatches, TeamMatch, CRUD.update, isRaw: true, filterType: Team, filterId: homeTeamId))); - final guestTeamId = (await EntityController.query(LineupController.teamIdQuery, + final guestTeamId = (await EntityController.query(await LineupController.teamIdStmt, substitutionValues: {'id': single['guest_id']}))['team_id']; final guestMatches = await teamMatchController .getManyRawFromQuery(TeamController.teamMatchesQuery, substitutionValues: {'id': guestTeamId}); diff --git a/wrestling_scoreboard_server/lib/controllers/weight_class_controller.dart b/wrestling_scoreboard_server/lib/controllers/weight_class_controller.dart index 839048fb..04af9a39 100644 --- a/wrestling_scoreboard_server/lib/controllers/weight_class_controller.dart +++ b/wrestling_scoreboard_server/lib/controllers/weight_class_controller.dart @@ -1,5 +1,5 @@ import 'package:wrestling_scoreboard_common/common.dart'; -import 'package:postgres/postgres.dart'; +import 'package:postgres/postgres.dart' as psql; import 'entity_controller.dart'; @@ -13,9 +13,9 @@ class WeightClassController extends EntityController { WeightClassController._internal() : super(tableName: 'weight_class'); @override - Map getPostgresDataTypes() { + Map getPostgresDataTypes() { return { - 'weight': PostgreSQLDataType.smallInteger, + 'weight': psql.Type.smallInteger, 'style': null, 'unit': null, }; diff --git a/wrestling_scoreboard_server/lib/server.dart b/wrestling_scoreboard_server/lib/server.dart index d8ebff9c..da8fed89 100644 --- a/wrestling_scoreboard_server/lib/server.dart +++ b/wrestling_scoreboard_server/lib/server.dart @@ -5,13 +5,13 @@ import 'dart:io'; import 'package:dotenv/dotenv.dart' show DotEnv; -import 'package:wrestling_scoreboard_server/controllers/websocket_handler.dart'; -import 'package:wrestling_scoreboard_server/routes/api_route.dart'; -import 'package:wrestling_scoreboard_server/services/postgres_db.dart'; import 'package:shelf/shelf.dart'; import 'package:shelf/shelf_io.dart' as shelf_io; import 'package:shelf_router/shelf_router.dart' as shelf_router; import 'package:shelf_static/shelf_static.dart' as shelf_static; +import 'package:wrestling_scoreboard_server/controllers/websocket_handler.dart'; +import 'package:wrestling_scoreboard_server/routes/api_route.dart'; +import 'package:wrestling_scoreboard_server/services/postgres_db.dart'; import 'middleware/cors.dart'; @@ -45,7 +45,7 @@ Future init() async { port, ); - await PostgresDb().connection.open(); + await PostgresDb().open(); final serverUrl = 'http://${server.address.host}:${server.port}'; print('Serving API at $serverUrl/api'); diff --git a/wrestling_scoreboard_server/lib/services/postgres_db.dart b/wrestling_scoreboard_server/lib/services/postgres_db.dart index a6204822..ffa2a556 100644 --- a/wrestling_scoreboard_server/lib/services/postgres_db.dart +++ b/wrestling_scoreboard_server/lib/services/postgres_db.dart @@ -1,6 +1,8 @@ -import 'package:postgres/postgres.dart'; +import 'package:postgres/postgres.dart' as psql; import 'package:wrestling_scoreboard_server/server.dart'; +const _isReleaseMode = bool.fromEnvironment("dart.vm.product"); + class PostgresDb { final String postgresHost = env['DATABASE_HOST'] ?? 'localhost'; final int postgresPort = int.parse(env['DATABASE_PORT'] ?? '5432'); @@ -9,14 +11,26 @@ class PostgresDb { final String postgresDatabaseName = env['DATABASE_NAME'] ?? 'wrestling_scoreboard'; static final PostgresDb _singleton = PostgresDb._internal(); - late final PostgreSQLConnection connection; + late final psql.Connection connection; factory PostgresDb() { return _singleton; } - PostgresDb._internal() { - connection = - PostgreSQLConnection(postgresHost, postgresPort, postgresDatabaseName, username: dbUser, password: dbPW); + PostgresDb._internal(); + + /// Only call this once! + Future open() async { + connection = await psql.Connection.open( + psql.Endpoint( + host: postgresHost, + port: postgresPort, + database: postgresDatabaseName, + username: dbUser, + password: dbPW, + ), + settings: psql.ConnectionSettings( + sslMode: _isReleaseMode ? psql.SslMode.require : psql.SslMode.disable, + )); } } diff --git a/wrestling_scoreboard_server/pubspec.lock b/wrestling_scoreboard_server/pubspec.lock index 8e2e1ced..1c081216 100644 --- a/wrestling_scoreboard_server/pubspec.lock +++ b/wrestling_scoreboard_server/pubspec.lock @@ -261,10 +261,10 @@ packages: dependency: "direct main" description: name: postgres - sha256: fce8406bbe8b7018c768e76816be24adf302f44c06d7176c912d2501ea6aac2a + sha256: d384c0cce2c30f9b349a133812f976ca16fa916fd567882bb6a01741b194c22a url: "https://pub.dev" source: hosted - version: "2.6.3" + version: "3.0.6" pub_semver: dependency: transitive description: diff --git a/wrestling_scoreboard_server/pubspec.yaml b/wrestling_scoreboard_server/pubspec.yaml index ccbefd18..7136c810 100644 --- a/wrestling_scoreboard_server/pubspec.yaml +++ b/wrestling_scoreboard_server/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: shelf_static: ^1.0.0 wrestling_scoreboard_common: path: ../wrestling_scoreboard_common - postgres: ^2.4.0 + postgres: ^3.0.6 web_socket_channel: ^2.1.0 shelf_web_socket: ^1.0.3