Skip to content

Commit f239799

Browse files
author
Isaque Neves
committed
extract method to create a PostgreSQL Epoch Base DateTime using the correct local timezone, restore original _messageTypeMap
1 parent ab75ea7 commit f239799

File tree

3 files changed

+52
-79
lines changed

3 files changed

+52
-79
lines changed

example/example.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,4 @@ void main() async {
8383
print(await subscription.schema);
8484

8585
await conn.close();
86-
}
86+
}

lib/src/message_window.dart

+24-62
Original file line numberDiff line numberDiff line change
@@ -15,74 +15,35 @@ const int _headerByteSize = 5;
1515
typedef _ServerMessageFn = ServerMessage Function(
1616
PgByteDataReader reader, int length);
1717

18-
// Map<int, _ServerMessageFn> _messageTypeMap = {
19-
// 49: (_, __) => ParseCompleteMessage(),
20-
// 50: (_, __) => BindCompleteMessage(),
21-
// 65: (r, _) => NotificationResponseMessage.parse(r),
22-
// 67: (r, _) => CommandCompleteMessage.parse(r),
23-
// 68: (r, _) => DataRowMessage.parse(r),
24-
// 69: ErrorResponseMessage.parse,
25-
// 75: (r, _) => BackendKeyMessage.parse(r),
26-
// 82: AuthenticationMessage.parse,
27-
// 83: (r, l) => ParameterStatusMessage.parse(r),
28-
// 84: (r, _) => RowDescriptionMessage.parse(r),
29-
// 87: (r, _) => CopyBothResponseMessage.parse(r),
30-
// 90: ReadyForQueryMessage.parse,
31-
// 100: _parseCopyDataMessage,
32-
// 110: (_, __) => NoDataMessage(),
33-
// 116: (r, _) => ParameterDescriptionMessage.parse(r),
34-
// $3: (_, __) => CloseCompleteMessage(),
35-
// $N: NoticeMessage.parse,
36-
// };
18+
Map<int, _ServerMessageFn> _messageTypeMap = {
19+
49: (_, __) => ParseCompleteMessage(),
20+
50: (_, __) => BindCompleteMessage(),
21+
65: (r, _) => NotificationResponseMessage.parse(r),
22+
67: (r, _) => CommandCompleteMessage.parse(r),
23+
68: (r, _) => DataRowMessage.parse(r),
24+
69: ErrorResponseMessage.parse,
25+
75: (r, _) => BackendKeyMessage.parse(r),
26+
82: AuthenticationMessage.parse,
27+
83: (r, l) => ParameterStatusMessage.parse(r),
28+
84: (r, _) => RowDescriptionMessage.parse(r),
29+
87: (r, _) => CopyBothResponseMessage.parse(r),
30+
90: ReadyForQueryMessage.parse,
31+
100: _parseCopyDataMessage,
32+
110: (_, __) => NoDataMessage(),
33+
116: (r, _) => ParameterDescriptionMessage.parse(r),
34+
$3: (_, __) => CloseCompleteMessage(),
35+
$N: NoticeMessage.parse,
36+
};
3737

3838
class MessageFramer {
3939
final Encoding _encoding;
4040
TimeZoneSettings timeZone;
41-
late final _reader = PgByteDataReader(encoding: _encoding, timeZone: timeZone);
41+
late final _reader =
42+
PgByteDataReader(encoding: _encoding, timeZone: timeZone);
4243
final messageQueue = Queue<ServerMessage>();
4344

4445
MessageFramer(this._encoding, this.timeZone);
4546

46-
_ServerMessageFn? _messageTypeMap(int? messageType) {
47-
switch (messageType) {
48-
case 49:
49-
return (_, __) => ParseCompleteMessage();
50-
case 50:
51-
return (_, __) => BindCompleteMessage();
52-
case 65:
53-
return (r, _) => NotificationResponseMessage.parse(r);
54-
case 67:
55-
return (r, _) => CommandCompleteMessage.parse(r);
56-
case 68:
57-
return (r, _) => DataRowMessage.parse(r);
58-
case 69:
59-
return ErrorResponseMessage.parse;
60-
case 75:
61-
return (r, _) => BackendKeyMessage.parse(r);
62-
case 82:
63-
return AuthenticationMessage.parse;
64-
case 83:
65-
return (r, l) => ParameterStatusMessage.parse(r);
66-
case 84:
67-
return (r, _) => RowDescriptionMessage.parse(r);
68-
case 87:
69-
return (r, _) => CopyBothResponseMessage.parse(r);
70-
case 90:
71-
return ReadyForQueryMessage.parse;
72-
case 100:
73-
return _parseCopyDataMessage;
74-
case 110:
75-
return (_, __) => NoDataMessage();
76-
case 116:
77-
return (r, _) => ParameterDescriptionMessage.parse(r);
78-
case $3:
79-
return (_, __) => CloseCompleteMessage();
80-
case $N:
81-
return NoticeMessage.parse;
82-
}
83-
return null;
84-
}
85-
8647
int? _type;
8748
int _expectedLength = 0;
8849

@@ -111,7 +72,7 @@ class MessageFramer {
11172
}
11273

11374
if (_hasReadHeader && _isComplete) {
114-
final msgMaker = _messageTypeMap(_type);
75+
final msgMaker = _messageTypeMap[_type];
11576
if (msgMaker == null) {
11677
_addMsg(UnknownMessage(_type!, _reader.read(_expectedLength)));
11778
continue;
@@ -158,7 +119,8 @@ ServerMessage _parseCopyDataMessage(PgByteDataReader reader, int length) {
158119
if (code == ReplicationMessageId.primaryKeepAlive) {
159120
return PrimaryKeepAliveMessage.parse(reader);
160121
} else if (code == ReplicationMessageId.xLogData) {
161-
return XLogDataMessage.parse(reader.read(length - 1), reader.encoding, reader.timeZone);
122+
return XLogDataMessage.parse(
123+
reader.read(length - 1), reader.encoding, reader.timeZone);
162124
} else {
163125
final bb = BytesBuffer();
164126
bb.addByte(code);

lib/src/types/binary_codec.dart

+27-16
Original file line numberDiff line numberDiff line change
@@ -796,14 +796,8 @@ class PostgresBinaryDecoder {
796796
if (dinput.timeZone.forceDecodeDateAsUTC) {
797797
return DateTime.utc(2000).add(Duration(days: value));
798798
}
799-
// https://github.com/dart-lang/sdk/issues/56312
800-
// ignore past timestamp transitions and use only current timestamp in local datetime
801-
final nowDt = DateTime.now();
802-
var baseDt = DateTime(2000);
803-
if (baseDt.timeZoneOffset != nowDt.timeZoneOffset) {
804-
final difference = baseDt.timeZoneOffset - nowDt.timeZoneOffset;
805-
baseDt = baseDt.add(difference);
806-
}
799+
800+
final baseDt = _getPostgreSQLEpochBaseDate();
807801
return baseDt.add(Duration(days: value));
808802
case TypeOid.timestampWithoutTimezone:
809803
final value = buffer.getInt64(0);
@@ -815,14 +809,8 @@ class PostgresBinaryDecoder {
815809
if (dinput.timeZone.forceDecodeTimestampAsUTC) {
816810
return DateTime.utc(2000).add(Duration(microseconds: value));
817811
}
818-
// https://github.com/dart-lang/sdk/issues/56312
819-
// ignore previous timestamp transitions and use only the current system timestamp in local date and time so that the behavior is correct on Windows and Linux
820-
final nowDt = DateTime.now();
821-
var baseDt = DateTime(2000);
822-
if (baseDt.timeZoneOffset != nowDt.timeZoneOffset) {
823-
final difference = baseDt.timeZoneOffset - nowDt.timeZoneOffset;
824-
baseDt = baseDt.add(difference);
825-
}
812+
813+
final baseDt = _getPostgreSQLEpochBaseDate();
826814
return baseDt.add(Duration(microseconds: value));
827815

828816
case TypeOid.timestampWithTimezone:
@@ -1054,6 +1042,29 @@ class PostgresBinaryDecoder {
10541042
);
10551043
}
10561044

1045+
/// Returns a base DateTime object representing the PostgreSQL epoch
1046+
/// (January 1, 2000), adjusted to the current system's timezone offset.
1047+
///
1048+
/// This method ensures that the base DateTime object is consistent across
1049+
/// different system environments (e.g., Windows, Linux) by adjusting the
1050+
/// base DateTime's timezone offset to match the current system's timezone
1051+
/// offset. This adjustment is necessary due to potential differences in
1052+
/// how different operating systems handle timezone transitions.
1053+
/// Returns:
1054+
/// - A `DateTime` object representing January 1, 2000, adjusted to the
1055+
/// current system's timezone offset.
1056+
DateTime _getPostgreSQLEpochBaseDate() {
1057+
// https://github.com/dart-lang/sdk/issues/56312
1058+
// ignore past timestamp transitions and use only current timestamp in local datetime
1059+
final nowDt = DateTime.now();
1060+
var baseDt = DateTime(2000);
1061+
if (baseDt.timeZoneOffset != nowDt.timeZoneOffset) {
1062+
final difference = baseDt.timeZoneOffset - nowDt.timeZoneOffset;
1063+
baseDt = baseDt.add(difference);
1064+
}
1065+
return baseDt;
1066+
}
1067+
10571068
List<V> readListBytes<V>(Uint8List data,
10581069
V Function(ByteDataReader reader, int length) valueDecoder) {
10591070
if (data.length < 16) {

0 commit comments

Comments
 (0)