Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/spotty-buckets-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/mysql-zongji': minor
---

Export date and time values as structured fields.
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ The `ZongJi` constructor accepts one argument of either:

If a `Connection` or `Pool` object is passed to the constructor, it will not be destroyed/ended by Zongji's `stop()` method.

If there is a `dateStrings` `mysql` configuration option in the connection details or connection, `ZongJi` will follow it.

Each instance includes the following methods:

| Method Name | Arguments | Description |
Expand Down Expand Up @@ -139,7 +137,6 @@ Neither method requires any arguments.
- :star2: [All types allowed by `mysql`](https://github.com/mysqljs/mysql#type-casting) are supported by this package.
- :speak_no_evil: 64-bit integer is supported via package big-integer(see #108). If an integer is within the safe range of JS number (-2^53, 2^53), a Number object will returned, otherwise, will return as String.
- :point_right: `TRUNCATE` statement does not cause corresponding `DeleteRows` event. Use unqualified `DELETE FROM` for same effect.
- When using fractional seconds with `DATETIME` and `TIMESTAMP` data types in MySQL > 5.6.4, only millisecond precision is available due to the limit of Javascript's `Date` object.

## Run Tests

Expand Down
99 changes: 40 additions & 59 deletions lib/common.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const iconv = require('iconv-lite');
const decodeJson = require('./json_decode');
const dtDecode = require('./datetime_decode');
const bigInt = require('big-integer');

const MysqlTypes = (exports.MysqlTypes = {
Expand Down Expand Up @@ -332,27 +331,14 @@ const parseGeometryValue = function (buffer) {
// Returns false, or an object describing the fraction of a second part of a
// TIME, DATETIME, or TIMESTAMP.
const readTemporalFraction = function (parser, fractionPrecision) {
if (!fractionPrecision) return false;
if (!fractionPrecision) return undefined;
let fractionSize = Math.ceil(fractionPrecision / 2);
let fraction = readIntBE(parser._buffer, parser._offset, fractionSize);
parser._offset += fractionSize;
if (fractionPrecision % 2 !== 0) fraction /= 10; // Not using full space
if (fraction < 0) fraction *= -1; // Negative time, fraction not negative

let milliseconds;
if (fractionPrecision > 3) {
milliseconds = Math.floor(fraction / Math.pow(10, fractionPrecision - 3));
} else if (fractionPrecision < 3) {
milliseconds = fraction * Math.pow(10, 3 - fractionPrecision);
} else {
milliseconds = fraction;
}

return {
value: fraction, // the integer after the decimal place
precision: fractionPrecision, // the number of digits after the decimal
milliseconds: milliseconds // the unrounded 3 digits after the decimal
};
return { fraction, precision: fractionPrecision };
};

// This function is used to read and interpret non-null values from parser.
Expand Down Expand Up @@ -485,12 +471,12 @@ exports.readMysqlValue = function (
break;
case MysqlTypes.DATE:
raw = parseUInt24(parser);
result = dtDecode.getDate(
zongji.connection.config.dateStrings, // node-mysql dateStrings option
sliceBits(raw, 9, 24), // year
sliceBits(raw, 5, 9), // month
sliceBits(raw, 0, 5) // day
);

result = {
year: sliceBits(raw, 9, 24),
month: sliceBits(raw, 5, 9),
day: sliceBits(raw, 0, 5)
};
break;
case MysqlTypes.TIME:
raw = parseUInt24(parser);
Expand Down Expand Up @@ -523,35 +509,31 @@ exports.readMysqlValue = function (
minute = sliceBits(raw, 6, 12);
second = sliceBits(raw, 0, 6);

if (isNegative && (fraction === false || fraction.value === 0)) {
if (isNegative && (fraction === undefined || fraction.value === 0)) {
second++;
}

result =
(isNegative ? '-' : '') +
zeroPad(hour, hour > 99 ? 3 : 2) +
':' +
zeroPad(minute, 2) +
':' +
zeroPad(second, 2);
result = {
isNegative,
hour,
minute,
second,
fraction
};

if (fraction !== false) {
result += dtDecode.getFractionString(fraction);
}
break;
case MysqlTypes.DATETIME:
raw = parseUInt64(parser);
date = Math.floor(raw / 1000000);
time = raw % 1000000;
result = dtDecode.getDateTime(
zongji.connection.config.dateStrings, // node-mysql dateStrings option
Math.floor(date / 10000), // year
Math.floor((date % 10000) / 100), // month
date % 100, // day
Math.floor(time / 10000), // hour
Math.floor((time % 10000) / 100), // minutes
time % 100 // seconds
);
result = {
year: Math.floor(date / 10000),
month: Math.floor((date % 10000) / 100),
day: date % 100,
hour: Math.floor(time / 10000),
minute: Math.floor((time % 10000) / 100),
second: time % 100
};
break;
case MysqlTypes.DATETIME2: {
// Overlapping high-low to get all data in 32-bit numbers
Expand All @@ -561,31 +543,30 @@ exports.readMysqlValue = function (
fraction = readTemporalFraction(parser, column.metadata.decimals);

yearMonth = sliceBits(rawHigh, 14, 31);
result = dtDecode.getDateTime(
zongji.connection.config.dateStrings, // node-mysql dateStrings option
Math.floor(yearMonth / 13), // year
yearMonth % 13, // month
sliceBits(rawLow, 17, 22), // day
sliceBits(rawLow, 12, 17), // hour
sliceBits(rawLow, 6, 12), // minutes
sliceBits(rawLow, 0, 6), // seconds
fraction // fraction of a second object
);
result = {
year: Math.floor(yearMonth / 13),
month: yearMonth % 13,
day: sliceBits(rawLow, 17, 22),
hour: sliceBits(rawLow, 12, 17),
minute: sliceBits(rawLow, 6, 12),
second: sliceBits(rawLow, 0, 6),
fraction
};
break;
}
case MysqlTypes.TIMESTAMP:
raw = parser.parseUnsignedNumber(4);
result = dtDecode.getTimeStamp(zongji.connection.config.dateStrings, raw);
result = {
secondsFromEpoch: raw
};
break;
case MysqlTypes.TIMESTAMP2:
raw = readIntBE(parser._buffer, parser._offset, 4);
parser._offset += 4;
fraction = readTemporalFraction(parser, column.metadata.decimals);
result = dtDecode.getTimeStamp(
zongji.connection.config.dateStrings,
raw, // seconds from epoch
fraction
); // fraction of a second object
result = {
secondsFromEpoch: raw,
fraction: readTemporalFraction(parser, column.metadata.decimals)
};
break;
case MysqlTypes.YEAR:
raw = parser.parseUnsignedNumber(1);
Expand Down
112 changes: 0 additions & 112 deletions lib/datetime_decode.js

This file was deleted.

Loading