Skip to content

Commit

Permalink
feat(nodejs): support BigInt type for timestamp values
Browse files Browse the repository at this point in the history
  • Loading branch information
puzpuzpuz committed Sep 18, 2023
1 parent 82ced72 commit 9935f99
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 106 deletions.
14 changes: 10 additions & 4 deletions docs/Sender.html
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,9 @@ <h5>Parameters:</h5>


<span class="param-type">string</span>
|

<span class="param-type">bigint</span>



Expand All @@ -290,7 +293,7 @@ <h5>Parameters:</h5>



<td class="description last">A string represents the designated timestamp in nanoseconds.</td>
<td class="description last">A string or BigInt that represents the designated timestamp in epoch nanoseconds.</td>
</tr>


Expand Down Expand Up @@ -420,7 +423,7 @@ <h4 class="name" id="atNow"><span class="type-signature"></span>atNow<span class

<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="src_sender.js.html">src/sender.js</a>, <a href="src_sender.js.html#line380">line 380</a>
<a href="src_sender.js.html">src/sender.js</a>, <a href="src_sender.js.html#line381">line 381</a>
</li></ul></dd>


Expand Down Expand Up @@ -2266,6 +2269,9 @@ <h5>Parameters:</h5>


<span class="param-type">number</span>
|

<span class="param-type">bigint</span>



Expand All @@ -2275,7 +2281,7 @@ <h5>Parameters:</h5>



<td class="description last">Column value, accepts only number objects.</td>
<td class="description last">Epoch timestamp in microseconds, accepts only numbers or BigInts.</td>
</tr>


Expand Down Expand Up @@ -2390,7 +2396,7 @@ <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-@q
<br class="clear">

<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.11</a> on Fri May 26 2023 10:30:37 GMT+0100 (British Summer Time)
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> on Mon Sep 18 2023 14:26:27 GMT+0300 (Eastern European Summer Time)
</footer>

<script> prettyPrint(); </script>
Expand Down
2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-@q
<br class="clear">

<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.11</a> on Fri May 26 2023 10:30:37 GMT+0100 (British Summer Time)
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> on Mon Sep 18 2023 14:26:27 GMT+0300 (Eastern European Summer Time)
</footer>

<script> prettyPrint(); </script>
Expand Down
2 changes: 1 addition & 1 deletion docs/index.js.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-@q
<br class="clear">

<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.11</a> on Fri May 26 2023 10:30:37 GMT+0100 (British Summer Time)
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> on Mon Sep 18 2023 14:26:27 GMT+0300 (Eastern European Summer Time)
</footer>

<script> prettyPrint(); </script>
Expand Down
38 changes: 1 addition & 37 deletions docs/module-@questdb_nodejs-client.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ <h1 class="page-title">Module: @questdb/nodejs-client</h1>

<header>





</header>

<article>
Expand All @@ -42,20 +38,6 @@ <h1 class="page-title">Module: @questdb/nodejs-client</h1>



















<dl class="details">
Expand Down Expand Up @@ -98,24 +80,6 @@ <h1 class="page-title">Module: @questdb/nodejs-client</h1>

</dl>






















Expand Down Expand Up @@ -156,7 +120,7 @@ <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-@q
<br class="clear">

<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.11</a> on Fri May 26 2023 10:30:37 GMT+0100 (British Summer Time)
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> on Mon Sep 18 2023 14:26:27 GMT+0300 (Eastern European Summer Time)
</footer>

<script> prettyPrint(); </script>
Expand Down
21 changes: 11 additions & 10 deletions docs/src_sender.js.html
Original file line number Diff line number Diff line change
Expand Up @@ -365,12 +365,12 @@ <h1 class="page-title">Source: src/sender.js</h1>
* Write a timestamp column with its value into the buffer of the sender.
*
* @param {string} name - Column name.
* @param {number} value - Column value, accepts only number objects.
* @param {number | bigint} value - Epoch timestamp in microseconds, accepts only numbers or BigInts.
* @return {Sender} Returns with a reference to this sender.
*/
timestampColumn(name, value) {
if (!Number.isInteger(value)) {
throw new Error(`Value must be an integer, received ${value}`);
if (typeof value !== "bigint" || !Number.isInteger(value)) {
throw new Error(`Value must be an integer or BigInt, received ${value}`);
}
writeColumn(this, name, value, () => {
const valueStr = value.toString();
Expand All @@ -384,19 +384,20 @@ <h1 class="page-title">Source: src/sender.js</h1>
/**
* Closing the row after writing the designated timestamp into the buffer of the sender.
*
* @param {string} timestamp - A string represents the designated timestamp in nanoseconds.
* @param {string | bigint} timestamp - A string or BigInt that represents the designated timestamp in epoch nanoseconds.
*/
at(timestamp) {
if (!this.hasSymbols &amp;&amp; !this.hasColumns) {
throw new Error("The row must have a symbol or column set before it is closed");
}
if (typeof timestamp !== "string") {
throw new Error(`The designated timestamp must be of type string, received ${typeof timestamp}`);
if (typeof timestamp !== "string" || typeof timestamp !== "bigint") {
throw new Error(`The designated timestamp must be of type string or BigInt, received ${typeof timestamp}`);
}
validateDesignatedTimestamp(timestamp);
checkCapacity(this, [], 2 + timestamp.length);
const timestampStr = timestamp.toString();
checkCapacity(this, [], 2 + timestampStr.length);
write(this, ' ');
write(this, timestamp);
write(this, timestampStr);
write(this, '\n');
startNewRow(this);
}
Expand Down Expand Up @@ -529,7 +530,7 @@ <h1 class="page-title">Source: src/sender.js</h1>
}

exports.Sender = Sender;
exports.DEFAULT_BUFFER_SIZE = DEFAULT_BUFFER_SIZE
exports.DEFAULT_BUFFER_SIZE = DEFAULT_BUFFER_SIZE;
</code></pre>
</article>
</section>
Expand All @@ -546,7 +547,7 @@ <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-@q
<br class="clear">

<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.11</a> on Fri May 26 2023 10:30:37 GMT+0100 (British Summer Time)
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> on Mon Sep 18 2023 14:26:26 GMT+0300 (Eastern European Summer Time)
</footer>

<script> prettyPrint(); </script>
Expand Down
41 changes: 17 additions & 24 deletions examples/basic.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,40 @@
const { Sender } = require("@questdb/nodejs-client");

async function run() {
// create a sender with a 4k buffer
// create a sender with a 4KB buffer
const sender = new Sender({ bufferSize: 4096 });

// connect to QuestDB
// host and port are required in connect options
await sender.connect({ port: 9009, host: "localhost" });

// add rows to the buffer of the sender
let bday = Date.parse("1856-07-10");
sender
.table("prices")
.symbol("instrument", "EURUSD")
.floatColumn("bid", 1.0195)
.floatColumn("ask", 1.0221)
.atNow();

.table("inventors")
.symbol("born", "Austrian Empire")
.timestampColumn("birthday", BigInt(bday) * 1000n) // epoch in micros (BigInt)
.intColumn("id", 0)
.stringColumn("name", "Nicola Tesla")
.at(BigInt(Date.now()) * 1000_000n); // epoch in nanos (BigInt)
bday = Date.parse("1847-02-11");
sender
.table("prices")
.symbol("instrument", "GBPUSD")
.floatColumn("bid", 1.2076)
.floatColumn("ask", 1.2082)
.table("inventors")
.symbol("born", "USA")
.timestampColumn("birthday", BigInt(bday) * 1000n)
.intColumn("id", 1)
.stringColumn("name", "Thomas Alva Edison")
.atNow();

// flush the buffer of the sender, sending the data to QuestDB
// the buffer is cleared after the data is sent and the sender is ready to accept new data
await sender.flush();

// add rows to the buffer again and send it to the server
sender
.table("prices")
.symbol("instrument", "EURUSD")
.floatColumn("bid", 1.0197)
.floatColumn("ask", 1.0224)
.atNow();

await sender.flush();

// close the connection after all rows ingested
// close the connection after all rows were sent
await sender.close();
return 0;
}

run()
.then((value) => console.log(value))
.catch((err) => console.log(err));
.then(console.log)
.catch(console.error);
4 changes: 0 additions & 4 deletions notes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
### Certs used in tests generated by running:
> ./scripts/generateCerts.sh . questdbPwd123
### TODO:
- Would be nice to accept alternative logger implementations to be used instead of console
- If the buffer had to be extended, shrink it back to original size on a subsequent flush() call?
23 changes: 12 additions & 11 deletions src/sender.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,46 +329,47 @@ class Sender {
checkCapacity(this, [valueStr], 1 + valueStr.length);
write(this, valueStr);
write(this, 'i');
}, "number");
});
return this;
}

/**
* Write a timestamp column with its value into the buffer of the sender.
*
* @param {string} name - Column name.
* @param {number} value - Column value, accepts only number objects.
* @param {number | bigint} value - Epoch timestamp in microseconds, accepts only numbers or BigInts.
* @return {Sender} Returns with a reference to this sender.
*/
timestampColumn(name, value) {
if (!Number.isInteger(value)) {
throw new Error(`Value must be an integer, received ${value}`);
if (typeof value !== "bigint" && !Number.isInteger(value)) {
throw new Error(`Value must be an integer or BigInt, received ${value}`);
}
writeColumn(this, name, value, () => {
const valueStr = value.toString();
checkCapacity(this, [valueStr], 1 + valueStr.length);
write(this, valueStr);
write(this, 't');
}, "number");
});
return this;
}

/**
* Closing the row after writing the designated timestamp into the buffer of the sender.
*
* @param {string} timestamp - A string represents the designated timestamp in nanoseconds.
* @param {string | bigint} timestamp - A string or BigInt that represents the designated timestamp in epoch nanoseconds.
*/
at(timestamp) {
if (!this.hasSymbols && !this.hasColumns) {
throw new Error("The row must have a symbol or column set before it is closed");
}
if (typeof timestamp !== "string") {
throw new Error(`The designated timestamp must be of type string, received ${typeof timestamp}`);
if (typeof timestamp !== "string" && typeof timestamp !== "bigint") {
throw new Error(`The designated timestamp must be of type string or BigInt, received ${typeof timestamp}`);
}
validateDesignatedTimestamp(timestamp);
checkCapacity(this, [], 2 + timestamp.length);
const timestampStr = timestamp.toString();
checkCapacity(this, [], 2 + timestampStr.length);
write(this, ' ');
write(this, timestamp);
write(this, timestampStr);
write(this, '\n');
startNewRow(this);
}
Expand Down Expand Up @@ -441,7 +442,7 @@ function writeColumn(sender, name, value, writeValue, valueType) {
if (typeof name !== "string") {
throw new Error(`Column name must be a string, received ${typeof name}`);
}
if (typeof value !== valueType) {
if (valueType != null && typeof value !== valueType) {
throw new Error(`Column value must be of type ${valueType}, received ${typeof value}`);
}
if (!sender.hasTable) {
Expand Down
20 changes: 11 additions & 9 deletions src/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,17 +123,19 @@ function validateColumnName(name) {
* Validates a designated timestamp. The value must contain only digits.<br>
* Throws an error if the value is invalid.
*
* @param {string} timestamp - The table name to validate.
* @param {string | bigint} timestamp - The table name to validate.
*/
function validateDesignatedTimestamp(timestamp) {
const len = timestamp.length;
if (len === 0) {
throw new Error("Empty string is not allowed as designated timestamp");
}
for (let i = 0; i < len; i++) {
let ch = timestamp[i];
if (ch < '0' || ch > '9') {
throw new Error(`Invalid character in designated timestamp: ${ch}`);
if (typeof timestamp === "string") {
const len = timestamp.length;
if (len === 0) {
throw new Error("Empty string is not allowed as designated timestamp");
}
for (let i = 0; i < len; i++) {
let ch = timestamp[i];
if (ch < '0' || ch > '9') {
throw new Error(`Invalid character in designated timestamp: ${ch}`);
}
}
}
}
Expand Down
Loading

0 comments on commit 9935f99

Please sign in to comment.