Skip to content

Commit 60f6102

Browse files
committed
finish creating datatype timestamp_ns/ms/sec/tz and adding corresponding apis
1 parent 3e5eea2 commit 60f6102

3 files changed

Lines changed: 296 additions & 0 deletions

File tree

src_cpp/node_util.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,30 @@ Napi::Value Util::ConvertToNapiObject(const Value& value, Napi::Env env) {
7272
Interval::MICROS_PER_MSEC;
7373
return Napi::Date::New(env, milliseconds);
7474
}
75+
case LogicalTypeID::TIMESTAMP_TZ: {
76+
auto timestampVal = value.getValue<timestamp_tz_t>();
77+
auto milliseconds = timestampVal.value / Interval::MICROS_PER_MSEC;
78+
return Napi::Date::New(env, milliseconds);
79+
}
7580
case LogicalTypeID::TIMESTAMP: {
7681
auto timestampVal = value.getValue<timestamp_t>();
7782
auto milliseconds = timestampVal.value / Interval::MICROS_PER_MSEC;
7883
return Napi::Date::New(env, milliseconds);
7984
}
85+
case LogicalTypeID::TIMESTAMP_NS: {
86+
auto timestampVal = value.getValue<timestamp_ns_t>();
87+
auto milliseconds = timestampVal.value / Interval::NANOS_PER_MICRO / Interval::MICROS_PER_MSEC;
88+
return Napi::Date::New(env, milliseconds);
89+
}
90+
case LogicalTypeID::TIMESTAMP_MS: {
91+
auto timestampVal = value.getValue<timestamp_ms_t>();
92+
return Napi::Date::New(env, timestampVal.value);
93+
}
94+
case LogicalTypeID::TIMESTAMP_SEC: {
95+
auto timestampVal = value.getValue<timestamp_sec_t>();
96+
auto milliseconds = Timestamp::getEpochMilliSeconds(Timestamp::fromEpochSeconds(timestampVal.value));
97+
return Napi::Date::New(env, milliseconds);
98+
}
8099
case LogicalTypeID::INTERVAL: {
81100
// TODO: By default, Node.js returns the difference in milliseconds between two dates, so we
82101
// follow the convention here, but it might not be the best choice in terms of usability.
@@ -266,6 +285,43 @@ Value Util::TransformNapiValue(
266285
timestamp_t timestamp = Timestamp::fromEpochMilliSeconds(napiDate.ValueOf());
267286
return Value(timestamp);
268287
}
288+
case LogicalTypeID::TIMESTAMP_TZ: {
289+
if (!napiValue.IsDate()) {
290+
throw Exception("Expected a date for parameter " + key + ".");
291+
}
292+
auto napiDate = napiValue.As<Napi::Date>();
293+
timestamp_tz_t timestamp;
294+
timestamp.value = Timestamp::fromEpochMilliSeconds(napiDate.ValueOf()).value;
295+
return Value(timestamp);
296+
}
297+
case LogicalTypeID::TIMESTAMP_NS: {
298+
if (!napiValue.IsDate()) {
299+
throw Exception("Expected a date for parameter " + key + ".");
300+
}
301+
auto napiDate = napiValue.As<Napi::Date>();
302+
timestamp_ns_t timestamp;
303+
timestamp.value =
304+
Timestamp::getEpochNanoSeconds(Timestamp::fromEpochMilliSeconds(napiDate.ValueOf()));
305+
return Value(timestamp);
306+
}
307+
case LogicalTypeID::TIMESTAMP_MS: {
308+
if (!napiValue.IsDate()) {
309+
throw Exception("Expected a date for parameter " + key + ".");
310+
}
311+
auto napiDate = napiValue.As<Napi::Date>();
312+
timestamp_ms_t timestamp{static_cast<int64_t>(napiDate.ValueOf())};
313+
return Value(timestamp);
314+
}
315+
case LogicalTypeID::TIMESTAMP_SEC: {
316+
if (!napiValue.IsDate()) {
317+
throw Exception("Expected a date for parameter " + key + ".");
318+
}
319+
auto napiDate = napiValue.As<Napi::Date>();
320+
timestamp_sec_t timestamp;
321+
timestamp.value =
322+
Timestamp::getEpochSeconds(Timestamp::fromEpochMilliSeconds(napiDate.ValueOf()));
323+
return Value(timestamp);
324+
}
269325
case LogicalTypeID::INTERVAL: {
270326
if (!napiValue.IsNumber()) {
271327
throw Exception("Expected a number for parameter " + key + ".");

test/test_data_type.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,78 @@ describe("TIMESTAMP", function () {
235235
});
236236
});
237237

238+
describe("TIMESTAMP_TZ", function () {
239+
it("should convert TIMESTAMP_TZ type", async function () {
240+
const queryResult = await conn.query(
241+
"MATCH (a:movies) WHERE a.length = 126 RETURN a.description;"
242+
);
243+
const result = await queryResult.getAll();
244+
assert.equal(result.length, 1);
245+
assert.equal(Object.keys(result[0]).length, 1);
246+
assert.isTrue("a.description" in result[0]);
247+
assert.isTrue("release_tz" in result[0]["a.description"]);
248+
assert.equal(typeof result[0]["a.description"]["release_tz"], "object");
249+
assert.equal(
250+
Number(result[0]["a.description"]["release_tz"].getTime()),
251+
Number(new Date("2011-08-20 11:25:30.123Z"))
252+
);
253+
});
254+
});
255+
256+
describe("TIMESTAMP_NS", function () {
257+
it("should convert TIMESTAMP_NS type", async function () {
258+
const queryResult = await conn.query(
259+
"MATCH (a:movies) WHERE a.length = 126 RETURN a.description;"
260+
);
261+
const result = await queryResult.getAll();
262+
assert.equal(result.length, 1);
263+
assert.equal(Object.keys(result[0]).length, 1);
264+
assert.isTrue("a.description" in result[0]);
265+
assert.isTrue("release_ns" in result[0]["a.description"]);
266+
assert.equal(typeof result[0]["a.description"]["release_ns"], "object");
267+
assert.equal(
268+
Number(result[0]["a.description"]["release_ns"].getTime()),
269+
Number(new Date("2011-08-20 11:25:30.123Z"))
270+
);
271+
});
272+
});
273+
274+
describe("TIMESTAMP_MS", function () {
275+
it("should convert TIMESTAMP_MS type", async function () {
276+
const queryResult = await conn.query(
277+
"MATCH (a:movies) WHERE a.length = 126 RETURN a.description;"
278+
);
279+
const result = await queryResult.getAll();
280+
assert.equal(result.length, 1);
281+
assert.equal(Object.keys(result[0]).length, 1);
282+
assert.isTrue("a.description" in result[0]);
283+
assert.isTrue("release_ms" in result[0]["a.description"]);
284+
assert.equal(typeof result[0]["a.description"]["release_ms"], "object");
285+
assert.equal(
286+
Number(result[0]["a.description"]["release_ms"].getTime()),
287+
Number(new Date("2011-08-20 11:25:30.123Z"))
288+
);
289+
});
290+
});
291+
292+
describe("TIMESTAMP_SEC", function () {
293+
it("should convert TIMESTAMP_SEC type", async function () {
294+
const queryResult = await conn.query(
295+
"MATCH (a:movies) WHERE a.length = 126 RETURN a.description;"
296+
);
297+
const result = await queryResult.getAll();
298+
assert.equal(result.length, 1);
299+
assert.equal(Object.keys(result[0]).length, 1);
300+
assert.isTrue("a.description" in result[0]);
301+
assert.isTrue("release_sec" in result[0]["a.description"]);
302+
assert.equal(typeof result[0]["a.description"]["release_sec"], "object");
303+
assert.equal(
304+
Number(result[0]["a.description"]["release_sec"].getTime()),
305+
Number(new Date("2011-08-20 11:25:30Z"))
306+
);
307+
});
308+
});
309+
238310
describe("INTERVAL", function () {
239311
it("should convert INTERVAL type", async function () {
240312
const queryResult = await conn.query(

test/test_parameter.js

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,174 @@ describe("TIMESTAMP", function () {
356356
});
357357
});
358358

359+
describe("TIMESTAMP_TZ", function () {
360+
it("should transform date as TIMESTAMP_TZ parameter", async function () {
361+
const preparedStatement = await conn.prepare(
362+
"MATCH (a:movies) WHERE a.description.release_tz > $1 RETURN COUNT(*)"
363+
);
364+
const queryResult = await conn.execute(preparedStatement, {
365+
1: new Date(0),
366+
});
367+
const result = await queryResult.getAll();
368+
assert.equal(result[0]["COUNT_STAR()"], 3);
369+
});
370+
371+
it("should reject other type as TIMESTAMP_TZ parameter", async function () {
372+
const preparedStatement = await conn.prepare(
373+
"MATCH (a:movies) WHERE a.description.release_tz > $1 RETURN COUNT(*)"
374+
);
375+
try {
376+
await conn.execute(preparedStatement, {
377+
1: "1970-01-01",
378+
});
379+
} catch (e) {
380+
assert.equal(e.message, "Expected a date for parameter 1.");
381+
}
382+
383+
try {
384+
await conn.execute(preparedStatement, {
385+
1: 0,
386+
});
387+
} catch (e) {
388+
assert.equal(e.message, "Expected a date for parameter 1.");
389+
}
390+
391+
try {
392+
await conn.execute(preparedStatement, {
393+
1: true,
394+
});
395+
} catch (e) {
396+
assert.equal(e.message, "Expected a date for parameter 1.");
397+
}
398+
});
399+
});
400+
401+
describe("TIMESTAMP_NS", function () {
402+
it("should transform date as TIMESTAMP_NS parameter", async function () {
403+
const preparedStatement = await conn.prepare(
404+
"MATCH (a:movies) WHERE a.description.release_ns > $1 RETURN COUNT(*)"
405+
);
406+
const queryResult = await conn.execute(preparedStatement, {
407+
1: new Date(0),
408+
});
409+
const result = await queryResult.getAll();
410+
assert.equal(result[0]["COUNT_STAR()"], 3);
411+
});
412+
413+
it("should reject other type as TIMESTAMP_NS parameter", async function () {
414+
const preparedStatement = await conn.prepare(
415+
"MATCH (a:movies) WHERE a.description.release_ns > $1 RETURN COUNT(*)"
416+
);
417+
try {
418+
await conn.execute(preparedStatement, {
419+
1: "1970-01-01",
420+
});
421+
} catch (e) {
422+
assert.equal(e.message, "Expected a date for parameter 1.");
423+
}
424+
425+
try {
426+
await conn.execute(preparedStatement, {
427+
1: 0,
428+
});
429+
} catch (e) {
430+
assert.equal(e.message, "Expected a date for parameter 1.");
431+
}
432+
433+
try {
434+
await conn.execute(preparedStatement, {
435+
1: true,
436+
});
437+
} catch (e) {
438+
assert.equal(e.message, "Expected a date for parameter 1.");
439+
}
440+
});
441+
});
442+
443+
describe("TIMESTAMP_MS", function () {
444+
it("should transform date as TIMESTAMP_MS parameter", async function () {
445+
const preparedStatement = await conn.prepare(
446+
"MATCH (a:movies) WHERE a.description.release_ms > $1 RETURN COUNT(*)"
447+
);
448+
const queryResult = await conn.execute(preparedStatement, {
449+
1: new Date(0),
450+
});
451+
const result = await queryResult.getAll();
452+
assert.equal(result[0]["COUNT_STAR()"], 3);
453+
});
454+
455+
it("should reject other type as TIMESTAMP_MS parameter", async function () {
456+
const preparedStatement = await conn.prepare(
457+
"MATCH (a:movies) WHERE a.description.release_ms > $1 RETURN COUNT(*)"
458+
);
459+
try {
460+
await conn.execute(preparedStatement, {
461+
1: "1970-01-01",
462+
});
463+
} catch (e) {
464+
assert.equal(e.message, "Expected a date for parameter 1.");
465+
}
466+
467+
try {
468+
await conn.execute(preparedStatement, {
469+
1: 0,
470+
});
471+
} catch (e) {
472+
assert.equal(e.message, "Expected a date for parameter 1.");
473+
}
474+
475+
try {
476+
await conn.execute(preparedStatement, {
477+
1: true,
478+
});
479+
} catch (e) {
480+
assert.equal(e.message, "Expected a date for parameter 1.");
481+
}
482+
});
483+
});
484+
485+
describe("TIMESTAMP_SEC", function () {
486+
it("should transform date as TIMESTAMP_SEC parameter", async function () {
487+
const preparedStatement = await conn.prepare(
488+
"MATCH (a:movies) WHERE a.description.release_sec > $1 RETURN COUNT(*)"
489+
);
490+
const queryResult = await conn.execute(preparedStatement, {
491+
1: new Date(0),
492+
});
493+
const result = await queryResult.getAll();
494+
assert.equal(result[0]["COUNT_STAR()"], 3);
495+
});
496+
497+
it("should reject other type as TIMESTAMP_SEC parameter", async function () {
498+
const preparedStatement = await conn.prepare(
499+
"MATCH (a:movies) WHERE a.description.release_sec > $1 RETURN COUNT(*)"
500+
);
501+
try {
502+
await conn.execute(preparedStatement, {
503+
1: "1970-01-01",
504+
});
505+
} catch (e) {
506+
assert.equal(e.message, "Expected a date for parameter 1.");
507+
}
508+
509+
try {
510+
await conn.execute(preparedStatement, {
511+
1: 0,
512+
});
513+
} catch (e) {
514+
assert.equal(e.message, "Expected a date for parameter 1.");
515+
}
516+
517+
try {
518+
await conn.execute(preparedStatement, {
519+
1: true,
520+
});
521+
} catch (e) {
522+
assert.equal(e.message, "Expected a date for parameter 1.");
523+
}
524+
});
525+
});
526+
359527
describe("INTERVAL", function () {
360528
it("should transform number as INTERVAL parameter", async function () {
361529
const preparedStatement = await conn.prepare(

0 commit comments

Comments
 (0)