├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .jshintignore ├── .jshintrc ├── LICENSE ├── Makefile ├── README.md ├── index.d.ts ├── index.js ├── itest ├── asyncreq.js ├── compression.js ├── connect.js ├── deserialization.js ├── emptyChar2null.js ├── flipTables.js ├── issue18.js ├── nanos2date.js ├── readme.js ├── serialization.js ├── subs.js ├── syncreqres.js ├── tls.js └── unicode.js ├── lib ├── assert.js ├── c.js ├── typed.d.ts └── typed.js ├── package-lock.json ├── package.json ├── test ├── c.js ├── compress.js ├── connect.js └── typed.js └── tsconfig.json /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: 'ubuntu-latest' 8 | 9 | steps: 10 | 11 | - uses: 'actions/checkout@v2' 12 | 13 | - uses: 'actions/setup-node@v1' 14 | with: 15 | node-version: '12' 16 | 17 | - name: install dependencies 18 | run: npm ci 19 | 20 | - name: run tests 21 | run: npm test 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | coverage/ 4 | 5 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | test/** 3 | lib/c.js 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "maxerr" : 500, 3 | "bitwise" : true, 4 | "camelcase" : false, 5 | "curly" : true, 6 | "eqeqeq" : true, 7 | "forin" : true, 8 | "immed" : false, 9 | "indent" : 4, 10 | "latedef" : true, 11 | "newcap" : false, 12 | "noarg" : true, 13 | "noempty" : true, 14 | "nonew" : false, 15 | "plusplus" : false, 16 | "quotmark" : false, 17 | "undef" : true, 18 | "unused" : false, 19 | "strict" : true, 20 | "trailing" : true, 21 | "maxparams" : false, 22 | "maxdepth" : false, 23 | "maxstatements" : false, 24 | "maxcomplexity" : false, 25 | "maxlen" : false, 26 | "asi" : false, 27 | "boss" : false, 28 | "debug" : false, 29 | "eqnull" : false, 30 | "es5" : false, 31 | "esnext" : false, 32 | "moz" : false, 33 | "evil" : false, 34 | "expr" : false, 35 | "funcscope" : false, 36 | "globalstrict" : false, 37 | "iterator" : false, 38 | "lastsemic" : false, 39 | "laxbreak" : false, 40 | "laxcomma" : false, 41 | "loopfunc" : false, 42 | "multistr" : false, 43 | "proto" : false, 44 | "scripturl" : false, 45 | "shadow" : false, 46 | "sub" : false, 47 | "supernew" : false, 48 | "validthis" : false, 49 | "browser" : false, 50 | "couch" : false, 51 | "devel" : false, 52 | "dojo" : false, 53 | "jquery" : false, 54 | "mootools" : false, 55 | "node" : true, 56 | "nonstandard" : false, 57 | "prototypejs" : false, 58 | "rhino" : false, 59 | "worker" : false, 60 | "wsh" : false, 61 | "yui" : false, 62 | "globals" : {}, 63 | "predef" : ["describe", "it", "before", "after"] 64 | } 65 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Michael Wittig 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | default: test 2 | 3 | jshint: 4 | @echo "jshint" 5 | @find . -name "*.js" -print0 | xargs -0 ./node_modules/.bin/jshint 6 | 7 | circular: 8 | @echo "circular" 9 | @./node_modules/.bin/madge --circular --format amd --exclude "madge|source-map" . 10 | 11 | mocha: 12 | @echo "mocha (unit test)" 13 | @TZ=UTC ./node_modules/.bin/mocha test/*.js 14 | @echo 15 | 16 | coverage: 17 | @echo "cover" 18 | @./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha test/* 19 | @echo 20 | 21 | mochait: 22 | @echo "mocha (integreation test assumes running kdb+tick process on localhost:5000)" 23 | @TZ=UTC ./node_modules/.bin/mocha -t 5000 itest/*.js 24 | @echo 25 | 26 | test: jshint mocha circular 27 | @echo "test" 28 | @echo 29 | 30 | itest: jshint mocha mochait circular 31 | @echo "test" 32 | @echo 33 | 34 | outdated: 35 | @echo "outdated modules?" 36 | @./node_modules/.bin/npmedge 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-q 2 | 3 | Q interfacing with Node.js. Supports [decompression](http://code.kx.com/wiki/Reference/ipcprotocol#Compression). Can deserialize all q data types (including `guid`) to JavaScript. Can serialize all JavaScript data types to q. 4 | 5 | ## Installation 6 | 7 | ``` 8 | npm install node-q 9 | ``` 10 | 11 | ## Usage 12 | 13 | ### Create Connection 14 | 15 | ```javascript 16 | var nodeq = require("node-q"); 17 | nodeq.connect({host: "localhost", port: 5000}, function(err, con) { 18 | if (err) throw err; 19 | console.log("connected"); 20 | // interact with con like demonstrated below 21 | }); 22 | ``` 23 | 24 | ### Create TLS Connection 25 | 26 | ```javascript 27 | var nodeq = require("node-q"); 28 | nodeq.connect({host: "localhost", port: 6000, useTLS: true}, function(err, con) { 29 | if (err) throw err; 30 | console.log("connected"); 31 | // interact with con like demonstrated below 32 | }); 33 | ``` 34 | 35 | ### Create Connection with user and password auth 36 | 37 | ```javascript 38 | var nodeq = require("node-q"); 39 | nodeq.connect({host: "localhost", port: 5000, user: "user", password: "password"}, function(err, con) { 40 | if (err) throw err; 41 | console.log("connected"); 42 | // interact with con like demonstrated below 43 | }); 44 | ``` 45 | 46 | ### Create Connection with Unix Domain Socket (Doesn't support abstract namespace sockets: KDB 3.5+ on Linux) 47 | 48 | ```javascript 49 | nodeq.connect({ unixSocket: "/path/to/socket" }, function(err, con) { 50 | if (err) throw err; 51 | console.log("connected"); 52 | }); 53 | ``` 54 | 55 | ### Execute Q code and receive result 56 | 57 | ```javascript 58 | con.k("sum 1 2 3", function(err, res) { 59 | if (err) throw err; 60 | console.log("result", res); // 6 61 | }); 62 | ``` 63 | 64 | ### Execute function with one parameter and receive result 65 | 66 | ```javascript 67 | con.k("sum", [1, 2, 3], function(err, res) { 68 | if (err) throw err; 69 | console.log("result", res); // 6 70 | }); 71 | ``` 72 | 73 | ### Execute function with two parameters and receive result 74 | 75 | ```javascript 76 | con.k("cor", [1, 2, 3], [4, 5, 6], function(err, res) { 77 | if (err) throw err; 78 | console.log("result", res); // 1 79 | }); 80 | ``` 81 | 82 | ### Async execute Q code 83 | 84 | ```javascript 85 | con.ks("show 1 2 3", function(err) { 86 | if (err) throw err; 87 | }); 88 | ``` 89 | 90 | ### Async execute function with parameters 91 | 92 | ```javascript 93 | con.ks("show", [1, 2, 3], function(err) { 94 | if (err) throw err; 95 | }); 96 | ``` 97 | 98 | ### Listen to a handle 99 | 100 | ```javascript 101 | con.k(function(err, res) { 102 | if (err) throw err; 103 | console.log("result", res); 104 | }); 105 | ``` 106 | 107 | ### Subscribe to kdb+tick 108 | 109 | ```javascript 110 | con.on("upd", function(table, data) { 111 | console.log(table, data); 112 | }); 113 | 114 | con.ks(".u.sub[`;`]", function(err) { // subscribe to all tables and all symbols 115 | if (err) throw err; 116 | }); 117 | ``` 118 | 119 | ### Close connection 120 | 121 | ```javascript 122 | con.close(function() { 123 | console.log("con closed"); 124 | }); 125 | ``` 126 | 127 | ## Types 128 | 129 | q has more [data types](http://code.kx.com/wiki/Reference/Datatypes) than JavaScript. Therefore you need to know how types are converted. 130 | 131 | ### From q to JavaScript (deserialization) 132 | 133 | | q type | JavaScript type | Null | +Infinity | -Infinity | 134 | | ------ | --------------- | ---- | --------- | --------- | 135 | | boolean | [Boolean](https://developer.mozilla.org/docs/Glossary/Boolean) | | | | 136 | | guid | [String](https://developer.mozilla.org/docs/Glossary/String) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | | | 137 | | byte | [Number](https://developer.mozilla.org/docs/Glossary/Number) | | | | 138 | | short | [Number](https://developer.mozilla.org/docs/Glossary/Number) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | [Infinity](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Infinity) | -[Infinity](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Infinity) | 139 | | int | [Number](https://developer.mozilla.org/docs/Glossary/Number) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | [Infinity](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Infinity) | -[Infinity](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Infinity) | 140 | | long | [Number](https://developer.mozilla.org/docs/Glossary/Number) [5](#types-footnote5) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | [Infinity](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Infinity) | -[Infinity](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Infinity) | 141 | | real | [Number](https://developer.mozilla.org/docs/Glossary/Number) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | [Infinity](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Infinity) | -[Infinity](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Infinity) | 142 | | float | [Number](https://developer.mozilla.org/docs/Glossary/Number) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | [Infinity](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Infinity) | -[Infinity](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Infinity) | 143 | | char | [String](https://developer.mozilla.org/docs/Glossary/String) | [Null](https://developer.mozilla.org/docs/Glossary/Null) [4](#types-footnote4) | | | 144 | | symbol | [String](https://developer.mozilla.org/docs/Glossary/String) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | | | 145 | | timestamp | [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date) [1](#types-footnote1), [2](#types-footnote2) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | | | 146 | | month | [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date) [2](#types-footnote2) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | | | 147 | | date | [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date) [2](#types-footnote2) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | | | 148 | | datetime | [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date) [2](#types-footnote2) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | | | 149 | | timespan | [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date) [1](#types-footnote1), [2](#types-footnote2), [3](#types-footnote3) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | | | 150 | | minute | [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date) [2](#types-footnote2), [3](#types-footnote3) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | | | 151 | | second | [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date) [2](#types-footnote2), [3](#types-footnote3) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | | | 152 | | time | [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date) [2](#types-footnote2), [3](#types-footnote3) | [Null](https://developer.mozilla.org/docs/Glossary/Null) | | | 153 | 154 | * 1: q comes with nanoseconds precision. JavaScript only with milliseconds. You can disable `nanos2date` deserialization during `connect(params, cb)` to get the nanoseconds timestamp as a plain [Number](https://developer.mozilla.org/docs/Glossary/Number). 155 | * 2: think about running your Node.js process with `TZ=UTC node ...` to run in UTC timezone. q doesn't know timezones. 156 | * 3: date is set to `2000-01-01` in the Date object. Only evaluate the time part. 157 | * 4: You can disable `emptyChar2null` deserialization during `connect(params, cb)` to keep the empty char. 158 | * 5: You can disable `long2number` deserialization during `connect(params, cb)` to represent longs as [long.js](https://www.npmjs.com/package/long). 159 | 160 | #### dict 161 | 162 | ``` 163 | q) (`a`b`c)!(1 2 3i) 164 | ``` 165 | 166 | becomes [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) 167 | 168 | 169 | ```javascript 170 | { 171 | a: 1, 172 | b: 2, 173 | c: 3 174 | } 175 | ``` 176 | 177 | #### list 178 | 179 | ``` 180 | q) 1 2 3i 181 | ``` 182 | 183 | becomes [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) 184 | 185 | ```javascript 186 | [1, 2, 3] 187 | ``` 188 | 189 | #### table 190 | 191 | ``` 192 | q) ([] sym:`a`b`c; size:(1 2 3i)) 193 | ``` 194 | 195 | becomes [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) of [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) per row. 196 | 197 | ```javascript 198 | [ 199 | {sym: "a", size: 1}, 200 | {sym: "b", size: 2}, 201 | {sym: "c", size: 3} 202 | ] 203 | ``` 204 | 205 | You can disable `flipTables` during `connect(params, cb)` to get a table as an [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) with an [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) per column. 206 | 207 | ```javascript 208 | { 209 | sym: ["a", "b", "c"], 210 | size: [1, 2, 3] 211 | } 212 | ``` 213 | 214 | ### From JavaScript to q (serialization) 215 | 216 | #### Simple (infer type) 217 | 218 | | JavaScript type | q type | 219 | | --------------- | ------ | 220 | | [Boolean](https://developer.mozilla.org/docs/Glossary/Boolean) | boolean | 221 | | [String](https://developer.mozilla.org/docs/Glossary/String) starting with ` | symbol | 222 | | [String](https://developer.mozilla.org/docs/Glossary/String) | list[char] | 223 | | [Number](https://developer.mozilla.org/docs/Glossary/Number) | float | 224 | | [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date) | datetime | 225 | | [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) | dict | 226 | | [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)[*] | list[*] | 227 | | [Null](https://developer.mozilla.org/docs/Glossary/Null) | unary primitive | 228 | | [Infinity](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Infinity) | float | 229 | | -[Infinity](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Infinity) | float | 230 | 231 | #### Advanced (explicit types) 232 | 233 | If you want to explicitly serialize a JavaScript type as a q type you need to use the typed API. 234 | 235 | Let's start with two examples: 236 | 237 | ```javascript 238 | con.k("type", nodeq.short(1), function(err, res) { 239 | if (err) throw err; 240 | console.log("result", res); // -5 241 | }); 242 | 243 | con.k("type", nodeq.shorts([1, 2, 3]), function(err, res) { 244 | if (err) throw err; 245 | console.log("result", res); // 5 246 | }); 247 | ``` 248 | 249 | For every primitive type in q, this module exports a method to wrap the JavaScript value. You can also wrap a JavaScript array into a q type by appending an s to the primitive wrapper's name. 250 | 251 | | q type | primitive wrapper | array wrapper | 252 | | ------ | ----------------- | ------------- | 253 | | boolean | `boolean(Boolean)` | `booleans(Array[Boolean])` | 254 | | guid | `guid(String)`| `guids(Array[String])` | 255 | | byte | `byte(Number)`| `bytes(Array[Number])` | 256 | | short | `short(Number)` | `shorts(Array[Number])` | 257 | | int | `int(Number)` | `ints(Array[Number])` | 258 | | long | `long(long)` [1](#wrappers-footnote1) | `longs(Array[long])` [1](#wrappers-footnote1) | 259 | | real | `real(Number)` | `reals(Array[Number])` | 260 | | float | `float(Number)` | `floats(Array[Number])` | 261 | | char | `char(String)` | `chars(Array[String])` | 262 | | symbol | `symbol(String)` | `symbols(Array[String])` | 263 | | timestamp | `timestamp(Date)` | `timestamps(Array[Date])` | 264 | | month | `month(Date)` | `months(Array[Date])` | 265 | | date | `date(Date)` | `dates(Array[Date])` | 266 | | datetime | `datetime(Date)` | `datetimes(Array[Date])` | 267 | | timespan | `timespan(Date)` | `timespans(Array[Date])` | 268 | | minute | `minute(Date)` | `minutes(Array[Date])` | 269 | | second | `second(Date)` | `seconds(Array[Date])` | 270 | | time | `time(Date)` | `times(Array[Date])` | 271 | 272 | * 1: JavaScript can not represent 64bit longs. Therefore this module uses the [long.js](https://www.npmjs.com/package/long) module to represent longs. 273 | 274 | ## API 275 | 276 | ### connect(params, cb) 277 | 278 | * `params`: Object 279 | * `host`: String (e. g. "localhost") (optional) 280 | * `port`: Number (e. g. 5000) (optional) 281 | * `unixSocket`: String (e. g. "/path/to/socket") (optional) 282 | * `user`: String (optional) 283 | * `password`: String (optional) 284 | * `useTLS`: Boolean (optional) 285 | * `ca`: Buffer | String (e.g. fs.readFileSync('path\\to\\cert.pem')) (optional) 286 | * `socketNoDelay` : Boolean (optional, see http://nodejs.org/api/net.html#net_socket_setnodelay_nodelay) 287 | * `socketTimeout`: Number (optional, see http://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) 288 | * `nanos2date`: Boolean (optional, default: true) 289 | * `flipTables`: Boolean (optional, default: true) 290 | * `emptyChar2null`: Boolean (optional, default: true) 291 | * `long2number`: Boolean (optional, default: true) 292 | * `cb`: Function(`err`, `con`) 293 | * `err`: `Error` or `undefined` 294 | * `conn`: `Connection` or `undefined` 295 | 296 | ### @deprecated connect(host, port, [user, password,] cb) 297 | 298 | This is deprecated. Please use the new, mor flexible API above! 299 | 300 | * `host`: String (e. g. "localhost") 301 | * `port`: Number (e. g. 5000) 302 | * `user`: String (optional) 303 | * `password`: String (optional) 304 | 305 | ### Connection 306 | 307 | Is an [EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter). 308 | 309 | #### k(s, [x, [y, [z, [...,] ] ] ] cb) 310 | 311 | Sync request/response. 312 | 313 | * `s`: String 314 | * `x`: Object (optional) 315 | * `y`: Object (optional) 316 | * `z`: Object (optional) 317 | * `...`: Object (optional) 318 | * `cb`: Function(`err`, `res`) 319 | * `err`: `Error` or `undefined` 320 | * `res`: `Object` or `undefined` 321 | 322 | #### ks(s, [x, [y, [z, [...,] ] ] ] cb) 323 | 324 | Async request. 325 | 326 | * `s`: String 327 | * `x`: Object (optional) 328 | * `y`: Object (optional) 329 | * `z`: Object (optional) 330 | * `...`: Object (optional) 331 | * `cb`: Function(`err`) 332 | * `err`: `Error` or `undefined` 333 | 334 | #### close(cb) 335 | 336 | * `cb`: Function(`err`) (optional) 337 | * `err`: `Error` or `undefined` 338 | 339 | #### Events 340 | 341 | ##### upd(table, data) 342 | 343 | If you use kdb+tick and subscribe like `con.ks(".u.sub[`;`]", function(err) { throw err; })` you will receive all Updates via `upd` Event. 344 | 345 | * `table`: String (e.g. trades) 346 | * `data`: Object (table represented in JavaScript as [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) of [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)) 347 | 348 | ##### error(err) 349 | 350 | If the socket emit an `error` event. 351 | 352 | * `err`: `Error` 353 | 354 | ##### end() 355 | 356 | If the socket emit an `end` event. 357 | 358 | ##### timeout() 359 | 360 | If the socket emit a `timeout` event. 361 | 362 | ##### close(had_error) 363 | 364 | If the socket emit a `close` event. 365 | 366 | * `had_error`: Boolean (true if the socket had a transmission error) 367 | 368 | ## Contribution 369 | 370 | If you want to create a Pull-Request please make sure that `make test` runs without failures. 371 | 372 | If you have a kdb+tick setup please also run `make mochait`. 373 | 374 | ### Code Style 375 | 376 | make jshint 377 | 378 | ### Unit Tests 379 | 380 | make mocha 381 | 382 | ### Integration Test 383 | 384 | Assumes a running q process on port 5000 with kdb+tick available in QHOME (`QHOME=~/q ~/q/m32/q -p 5000`). For the tls tests you will also need a running q process on port 6000 set up to require tls. Instructions for this can be found [here](https://code.kx.com/q/kb/ssl/). If you are using a self signed certificate you will also need to set the `NODE_TLS_REJECT_UNAUTHORIZED` environment variable to `0`. 385 | 386 | make mochait 387 | 388 | ### Circular depdendencies 389 | 390 | make circular 391 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import * as events from 'events'; 4 | 5 | /** 6 | * A standard node.js callback after an asynchronous call with no return value. 7 | * @param error - This parameter will be undefined if the call was successful, or an error if not. 8 | */ 9 | export declare type AsyncCallback = (error: Error | undefined) => void; 10 | 11 | /** 12 | * A standard node.js callback after an asynchronous call with a return value. 13 | * @param error - This parameter will be undefined if the call was successful, or an error if not. 14 | * @param value - This parameter will be undefined if the call was not successful, or the return value if it was successful. 15 | */ 16 | export declare type AsyncValueCallback = (error: Error | undefined, value: T | undefined) => void; 17 | 18 | /** 19 | * The events that can be raised by the Connection class and the event listener types. 20 | */ 21 | export declare interface ConnectionEvents { 22 | /** 23 | * Raised when the connection is closed. 24 | * @param hadError - Whether or not it was closed due to an error. 25 | */ 26 | close: (hadError: boolean) => void; 27 | /** 28 | * Raised when the connection is ended. 29 | */ 30 | end: () => void; 31 | /** 32 | * Raised when an error is encountered. 33 | * @param error - The error encountered. 34 | */ 35 | error: (error: Error) => void; 36 | /** 37 | * Raised when the connection times out. 38 | */ 39 | timeout: () => void; 40 | /** 41 | * Raised by KDB as an update. Includes the table name and typically one more piece of data indicating the updates (though optionally more than one). 42 | */ 43 | upd: (tableName: string, ...data: any[]) => void; 44 | } 45 | 46 | /** 47 | * Class representing the KDB connection. 48 | */ 49 | export declare class Connection extends events.EventEmitter { 50 | /** 51 | * A private constructor is used to prevent inheritance. 52 | */ 53 | private constructor(); 54 | /** 55 | * Adds an event listener for events of the specified type. 56 | * @param type The event type. 57 | * @param listener The event listener to add. 58 | */ 59 | addListener(type: T, listener: ConnectionEvents[T]): this; 60 | /** 61 | * Closes this connection. 62 | * @param callback Optional callback to be invoked when the close operation has finished. 63 | */ 64 | close(callback?: () => void): void; 65 | /** 66 | * Listen to a handle. 67 | * @param callback The callback to be invoked when the results are available or an error is to be reported. 68 | */ 69 | k(callback: AsyncValueCallback): void; 70 | /** 71 | * Execute a statement synchronously against KDB and return the result when available via the callback. 72 | * @param statement The statement to execute against KDB. 73 | * @param callback The callback to be invoked when the results are available or an error is to be reported. 74 | */ 75 | k(statement: string, callback: AsyncValueCallback): void; 76 | /** 77 | * Execute a statement synchronously against KDB that takes a single parameter and return the result when available via the callback. 78 | * @param statement The statement to execute against KDB. 79 | * @param parameter The parameter to pass to KDB. 80 | * @param callback The callback to be invoked when the results are available or an error is to be reported. 81 | */ 82 | k(statement: string, parameter: any, callback: AsyncValueCallback): void; 83 | /** 84 | * Execute a statement synchronously against KDB that takes an arbitrary number of parameters. The last element in the rest array must be an AsyncValueCallback. 85 | * @param statement The statement to execute against KDB. 86 | * @param parametersEndingInCallback The parameters to pass to KDB, with the last element being the callback to be invoked when the results are available or an error is to be reported. 87 | */ 88 | k(statement: string, ...parametersEndingInCallback: any[]): void; 89 | /** 90 | * Execute a statement asynchronously against KDB with no return value, and return a callback indicating the message was received by KDB successfuly. 91 | * @param statement The statement to execute against KDB. 92 | * @param callback The callback to be invoked when the statement is received by KDB or an error is to be reported. 93 | */ 94 | ks(statement: string, callback: AsyncCallback): void; 95 | /** 96 | * Execute a statement asynchronously against KDB with a single parameter and no return value, and return a callback indicating the message was received by KDB successfuly. 97 | * @param statement The statement to execute against KDB. 98 | * @param callback The callback to be invoked when the statement is received by KDB or an error is to be reported. 99 | */ 100 | ks(statement: string, parameter: any, callback: AsyncCallback): void; 101 | /** 102 | * Execute a statement asynchronously against KDB that takes an arbitrary number of parameters and has no return value. The last element in the rest array must be an AsyncCallback. 103 | * @param statement The statement to execute against KDB. 104 | * @param parametersEndingInCallback The parameters to pass to KDB, with the last element being the callback to be invoked when the statement is received by KDB or an error is to be reported. 105 | */ 106 | ks(statement: string, ...parametersEndingInCallback: any[]): void; 107 | /** 108 | * Gets the number of listeners for the specified event type. 109 | * @param type The event type. 110 | */ 111 | listenerCount(type: keyof ConnectionEvents): number; 112 | /** 113 | * Gets the collection of listeners for the specified event type. 114 | * @param type The event type. 115 | */ 116 | listeners(type: T): ConnectionEvents[T][]; 117 | /** 118 | * Adds an event listener for events of the specified type. 119 | * @param type The event type. 120 | * @param listener The event listener to add. 121 | */ 122 | on(type: T, listener: ConnectionEvents[T]): this; 123 | /** 124 | * Adds an event listener for only the next time an event of the specified type is invoked. 125 | * @param type The event type. 126 | * @param listener The event listener to add. 127 | */ 128 | once(type: T, listener: ConnectionEvents[T]): this; 129 | /** 130 | * Adds an event listener for events of the specified type, but add it at the beginning of the collection of listeners for the event type. 131 | * @param type The event type. 132 | * @param listener The event listener to add. 133 | */ 134 | prependListener(type: T, listener: ConnectionEvents[T]): this; 135 | /** 136 | * Adds an event listener for only the next time events of the specified type are raised, but add it at the beginning of the collection of listeners for the event type. 137 | * @param type The event type. 138 | * @param listener The event listener to add. 139 | */ 140 | prependOnceListener(type: T, listener: ConnectionEvents[T]): this; 141 | /** 142 | * Removes all listeners from all events. 143 | */ 144 | removeAllListeners(): this; 145 | /** 146 | * Removes all listeners from the specified event type. 147 | * @param type The event type. 148 | */ 149 | removeAllListeners(type: keyof ConnectionEvents): this; 150 | /** 151 | * Removes the specified listener from the collection of listeners associated with the type. 152 | * @param type The event type. 153 | * @param listener The listener to remove. 154 | */ 155 | removeListener(type: T, listener: ConnectionEvents[T]): this; 156 | } 157 | 158 | /** 159 | * Connection parameters. 160 | */ 161 | export declare interface ConnectionParameters { 162 | /** 163 | * The KDB host to connect to. 164 | */ 165 | host?: string; 166 | /** 167 | * The port on the KDB host to connect to. 168 | */ 169 | port?: number; 170 | /** 171 | * Optional - The user to authenticate as to KDB. 172 | */ 173 | user?: string; 174 | /** 175 | * Optional - The password to use to authenticate to KDB. 176 | */ 177 | password?: string; 178 | /** 179 | * Set the socket to no-delay. See https://nodejs.org/api/net.html#net_socket_setnodelay_nodelay 180 | */ 181 | socketNoDelay?: boolean; 182 | /** 183 | * Sets the socket to timeout after the number of milliseconds of inactivity. See https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback 184 | */ 185 | socketTimeout?: number; 186 | /** 187 | * Should this connection convert KDB nanoseconds to JavaScript Date objects (defaults to true). 188 | */ 189 | nanos2date?: boolean; 190 | /** 191 | * Should this connection flip tables (defaults to true). 192 | */ 193 | flipTables?: boolean; 194 | /** 195 | * Should this connection convert empty char fields to null (defaults to true). 196 | */ 197 | emptyChar2null?: boolean; 198 | /** 199 | * Should this connection convert KDB longs to JavaScript Number types (defaults to true). 200 | * Specifying false will cause KDB longs to be returned using long.js. 201 | */ 202 | long2number?: boolean; 203 | /** 204 | * Connect with Unix Domain Sockets rather than TCP 205 | */ 206 | unixSocket?: string; 207 | /** 208 | * Should this connection use TLS 209 | */ 210 | useTLS?: boolean; 211 | } 212 | 213 | /** 214 | * Attempt to connect to KDB using the specified connection parameters, and return the connection when it is established. 215 | * @param parameters The connection parameters. 216 | * @param callback Callback to be invoked when the connection is (or fails to be) established. 217 | */ 218 | export declare function connect(parameters: ConnectionParameters, callback: AsyncValueCallback): void; 219 | /** 220 | * Attempt to connect to an unauthenticated KDB instance using the specified host and port, and return the connection when it is established. 221 | * @param host The KDB host to connect to. 222 | * @param port The port on the host to connect to. 223 | * @param callback Callback to be invoked when the connection is (or fails to be) established. 224 | */ 225 | export declare function connect(host: string, port: number, callback: AsyncValueCallback): void; 226 | /** 227 | * Attempt to connect to a KDB instance using the specified host, port, username and password, and return the connection when it is established. 228 | * @param host The KDB host to connect to. 229 | * @param port The port on the host to connect to. 230 | * @param user The user to authenticate to KDB with. 231 | * @param password The password to use to authenticate to KDB. 232 | * @param callback Callback to be invoked when the connection is (or fails to be) established. 233 | */ 234 | export declare function connect(host: string, port: number, user: string, password: string, callback: AsyncValueCallback): void; 235 | /** 236 | * Attempt to connect to KDB using Unix Domain Sockets, and return the connection when it is established. 237 | * @param unixSocket Path to KDB Unix Domain Socket (Doesn't support abstract namespace sockets: KDB3.5+ on Linux) 238 | * @param callback Callback to be invoked when the connection is (or fails to be) established. 239 | */ 240 | export declare function connect(unixSocket: string, callback: AsyncValueCallback): void; 241 | /** 242 | * Brings in the Typed wrapper APIs. 243 | */ 244 | export * from './lib/typed'; 245 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var libc = require("./lib/c.js"); 2 | var net = require("net"); 3 | var tls = require("tls"); 4 | var events = require("events"); 5 | var util = require("util"); 6 | var assert = require("./lib/assert.js"); 7 | var typed = require("./lib/typed.js"); 8 | 9 | function Connection(socket, nanos2date, flipTables, emptyChar2null, long2number) { 10 | "use strict"; 11 | events.EventEmitter.call(this); 12 | this.socket = socket; 13 | this.nanos2date = nanos2date; 14 | this.flipTables = flipTables; 15 | this.emptyChar2null = emptyChar2null; 16 | this.long2number = long2number; 17 | this.nextRequestNo = 1; 18 | this.nextResponseNo = 1; 19 | var self = this; 20 | this.socket.on("end", function() { 21 | self.emit("end"); 22 | }); 23 | this.socket.on("timeout", function() { 24 | self.emit("timeout"); 25 | }); 26 | this.socket.on("error", function(err) { 27 | self.emit("error", err); 28 | }); 29 | this.socket.on("close", function(had_error) { 30 | self.emit("close", had_error); 31 | }); 32 | } 33 | util.inherits(Connection, events.EventEmitter); 34 | Connection.prototype.listen = function() { 35 | "use strict"; 36 | var self = this; 37 | this.chunk = new Buffer(0); 38 | this.socket.on("data", function(inbuffer) { 39 | var buffer, 40 | length, // current msg length 41 | o, // deserialized object 42 | err, // deserialize error 43 | responseNo; 44 | 45 | if (self.chunk.length !== 0) { 46 | buffer = new Buffer(self.chunk.length + inbuffer.length); 47 | self.chunk.copy(buffer); 48 | inbuffer.copy(buffer, self.chunk.length); 49 | } else { 50 | buffer = inbuffer; 51 | } 52 | while (buffer.length >= 8) { 53 | length = buffer.readUInt32LE(4); 54 | if (buffer.length >= length) { 55 | try { 56 | o = libc.deserialize(buffer, self.nanos2date, self.flipTables, self.emptyChar2null, self.long2number); 57 | err = undefined; 58 | } catch (e) { 59 | o = null; 60 | err = e; 61 | } 62 | if (buffer.readUInt8(1) === 2) { // MsgType: 2 := response 63 | responseNo = self.nextResponseNo; 64 | self.nextResponseNo += 1; 65 | self.emit("response:" + responseNo, err, o); 66 | } else { 67 | if (err === undefined && Array.isArray(o) && o[0] === "upd") { 68 | events.EventEmitter.prototype.emit.apply(self, o); 69 | } else { 70 | responseNo = self.nextResponseNo; 71 | self.nextResponseNo += 1; 72 | self.emit("response:" + responseNo, err, o); 73 | } 74 | } 75 | if (buffer.length > length) { 76 | buffer = buffer.slice(length); 77 | } else { 78 | buffer = new Buffer(0); 79 | } 80 | } else { 81 | break; 82 | } 83 | } 84 | 85 | self.chunk = buffer; 86 | }); 87 | }; 88 | Connection.prototype.auth = function(auth, cb) { 89 | "use strict"; 90 | var n = Buffer.byteLength(auth, "ascii"), 91 | b = new Buffer(n + 2), 92 | self = this; 93 | b.write(auth, 0, n, "ascii"); // auth (username:password) 94 | b.writeUInt8(0x3, n); // capability byte (compression, timestamp, timespan) http://code.kx.com/wiki/Reference/ipcprotocol#Handshake 95 | b.writeUInt8(0x0, n+1); // zero terminated 96 | this.socket.write(b); 97 | this.socket.once("data", function(buffer) { 98 | if (buffer.length === 1) { 99 | if (buffer[0] >= 1) { // capability byte must support at least (compression, timestamp, timespan) http://code.kx.com/wiki/Reference/ipcprotocol#Handshake 100 | self.listen(); 101 | cb(); 102 | } else { 103 | cb(new Error("Invalid capability byte from server")); 104 | } 105 | } else { 106 | cb(new Error("Invalid auth response from server")); 107 | } 108 | }); 109 | }; 110 | Connection.prototype.k = function(s, cb) { 111 | "use strict"; 112 | cb = arguments[arguments.length - 1]; 113 | assert.func(cb, "cb"); 114 | var self = this, 115 | payload, 116 | b, 117 | requestNo = this.nextRequestNo; 118 | this.nextRequestNo += 1; 119 | if (arguments.length === 1) { 120 | // Listen for async responses 121 | self.once("response:" + requestNo, function(err, o) { 122 | cb(err, o); 123 | }); 124 | } else { 125 | assert.string(s, "s"); 126 | if (arguments.length === 2) { 127 | payload = s; 128 | } else { 129 | payload = Array.prototype.slice.call(arguments, 0, arguments.length - 1); 130 | } 131 | b = libc.serialize(payload); 132 | b.writeUInt8(0x1, 1); // MsgType: 1 := sync 133 | this.socket.write(b, function() { 134 | self.once("response:" + requestNo, function(err, o) { 135 | cb(err, o); 136 | }); 137 | }); 138 | } 139 | }; 140 | Connection.prototype.ks = function(s, cb) { 141 | "use strict"; 142 | assert.string(s, "s"); 143 | cb = arguments[arguments.length - 1]; 144 | assert.func(cb, "cb"); 145 | var payload, 146 | b; 147 | if (arguments.length === 2) { 148 | payload = s; 149 | } else { 150 | payload = Array.prototype.slice.call(arguments, 0, arguments.length - 1); 151 | } 152 | b = libc.serialize(payload); 153 | this.socket.write(b, function() { 154 | cb(); 155 | }); 156 | }; 157 | Connection.prototype.close = function(cb) { 158 | "use strict"; 159 | assert.optionalFunc(cb, "cb"); 160 | this.socket.once("close", function() { 161 | if (cb) { 162 | cb(); 163 | } 164 | }); 165 | this.socket.end(); 166 | }; 167 | 168 | function connect(params, cb) { 169 | "use strict"; 170 | var auth, 171 | errorcb, 172 | closecb, 173 | socket, 174 | error = false, 175 | close = false; 176 | if (typeof params !== "object") { 177 | params = {}; 178 | if (arguments.length === 2) { 179 | params.unixSocket = arguments[0]; 180 | cb = arguments[1]; 181 | } else if (arguments.length === 3) { 182 | params.host = arguments[0]; 183 | params.port = arguments[1]; 184 | cb = arguments[2]; 185 | } else if (arguments.length === 5) { 186 | params.host = arguments[0]; 187 | params.port = arguments[1]; 188 | params.user = arguments[2]; 189 | params.password = arguments[3]; 190 | cb = arguments[4]; 191 | } else { 192 | throw new Error("only two, three or five arguments allowed"); 193 | } 194 | } 195 | assert.object(params, "params"); 196 | assert.optionalString(params.host, "params.host"); 197 | assert.optionalNumber(params.port, "params.port"); 198 | assert.optionalString(params.user, "params.user"); 199 | assert.optionalString(params.password, "password"); 200 | assert.optionalObject(params.ca, "params.ca"); 201 | assert.optionalBool(params.socketNoDelay, "params.socketNoDelay"); 202 | assert.optionalNumber(params.socketTimeout, "params.socketTimeout"); 203 | assert.optionalBool(params.nanos2date, "params.nanos2date"); 204 | assert.optionalBool(params.flipTables, "params.flipTables"); 205 | assert.optionalBool(params.emptyChar2null, "params.emptyChar2null"); 206 | assert.optionalBool(params.long2number, "params.long2number"); 207 | assert.optionalString(params.unixSocket, "params.unixSocket"); 208 | assert.optionalBool(params.useTLS, "params.useTLS"); 209 | if (params.user !== undefined) { 210 | assert.string(params.password, "password"); 211 | auth = params.user + ":" + params.password; 212 | } else { 213 | auth = "anonymous"; 214 | } 215 | assert.func(cb, "cb"); 216 | errorcb = function(err) { 217 | error = true; 218 | cb(err); 219 | }; 220 | closecb = function() { 221 | close = true; 222 | cb(new Error("Connection closes (wrong auth?)")); 223 | }; 224 | 225 | var socketArgs; 226 | if (params.useTLS) { 227 | socketArgs = {}; 228 | if (params.unixSocket) { 229 | socketArgs.path = params.unixSocket; 230 | } else { 231 | socketArgs.port = params.port; 232 | socketArgs.host = params.host; 233 | socketArgs.ca = params.ca; 234 | } 235 | } else { 236 | socketArgs = []; 237 | if (params.unixSocket) { 238 | socketArgs.push(params.unixSocket); 239 | } 240 | else { 241 | socketArgs.push(params.port, params.host); 242 | } 243 | } 244 | var connectionCBfunc = function() { 245 | socket.removeListener("error", errorcb); 246 | if (error === false) { 247 | socket.once("close", closecb); 248 | var con = new Connection(socket, params.nanos2date, params.flipTables, params.emptyChar2null, params.long2number); 249 | con.once("error", function(err) { 250 | socket.removeListener("close", closecb); 251 | cb(err); 252 | }); 253 | con.auth(auth, function() { 254 | socket.removeListener("close", closecb); 255 | if (close === false) { 256 | cb(undefined, con); 257 | } 258 | }); 259 | } 260 | }; 261 | 262 | if (params.useTLS) { 263 | socket = tls.connect(socketArgs, connectionCBfunc); 264 | } else { 265 | socketArgs.push(connectionCBfunc); 266 | socket = net.connect.apply(null, socketArgs); 267 | } 268 | 269 | if (params.socketTimeout !== undefined) { 270 | socket.setTimeout(params.socketTimeout); 271 | } 272 | if (params.socketNoDelay !== undefined) { 273 | socket.setNoDelay(params.socketNoDelay); 274 | } 275 | socket.once("error", errorcb); 276 | } 277 | exports.connect = connect; 278 | 279 | // export typed API 280 | Object.keys(typed).forEach(function(k) { 281 | "use strict"; 282 | if (/^[a-z]*$/.test(k[0])) { 283 | exports[k] = typed[k]; 284 | } 285 | }); 286 | -------------------------------------------------------------------------------- /itest/asyncreq.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"); 2 | 3 | describe("asyncreq", function() { 4 | "use strict"; 5 | var con; 6 | before(function(done) { 7 | nodeq.connect({host: "localhost", port: 5000}, function(err, c) { 8 | if (err) { throw err; } 9 | con = c; 10 | done(); 11 | }); 12 | }); 13 | after(function(done) { 14 | con.close(function() { 15 | con = undefined; 16 | done(); 17 | }); 18 | }); 19 | it("execute q", function(done) { 20 | con.ks("show 1 2 3", function(err) { 21 | if (err) { throw err; } 22 | done(); 23 | }); 24 | }); 25 | it("execute function with one parameter", function(done) { 26 | con.k("show", [1, 2, 3], function(err) { 27 | if (err) { throw err; } 28 | done(); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /itest/compression.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | assert = require("assert"), 3 | os = require("os"); 4 | 5 | describe("compression", function() { 6 | "use strict"; 7 | var con; 8 | before(function(done) { 9 | nodeq.connect({host: os.hostname(), port: 5000}, function(err, c) { 10 | if (err) { throw err; } 11 | con = c; 12 | done(); 13 | }); 14 | }); 15 | after(function(done) { 16 | con.close(function() { 17 | con = undefined; 18 | done(); 19 | }); 20 | }); 21 | it("uncompress result", function(done) { 22 | con.k("til 1000000", function(err, res) { 23 | if (err) { throw err; } 24 | assert.equal(res.length, 1000000, "res.length"); 25 | done(); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /itest/connect.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"); 2 | 3 | describe("connect", function() { 4 | "use strict"; 5 | describe("old API", function() { 6 | it("should work if enpoint is available", function(done) { 7 | nodeq.connect("localhost", 5000, function(err) { 8 | if (err) { throw err; } 9 | done(); 10 | }); 11 | }); 12 | }); 13 | describe("new API", function() { 14 | it("should work if enpoint is available", function(done) { 15 | nodeq.connect({host: "localhost", port: 5000}, function(err) { 16 | if (err) { throw err; } 17 | done(); 18 | }); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /itest/deserialization.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | assert = require("assert"); 3 | 4 | describe("deserialization", function() { 5 | "use strict"; 6 | var con; 7 | before(function(done) { 8 | nodeq.connect({host: "localhost", port: 5000}, function(err, c) { 9 | if (err) { throw err; } 10 | con = c; 11 | done(); 12 | }); 13 | }); 14 | after(function(done) { 15 | con.close(function() { 16 | con = undefined; 17 | done(); 18 | }); 19 | }); 20 | describe("boolean", function() { 21 | it("true", function(done) { 22 | con.k("1b", function(err, res) { 23 | if (err) { throw err; } 24 | assert.equal(res, true, "res"); 25 | done(); 26 | }); 27 | }); 28 | it("false", function(done) { 29 | con.k("0b", function(err, res) { 30 | if (err) { throw err; } 31 | assert.equal(res, false, "res"); 32 | done(); 33 | }); 34 | }); 35 | }); 36 | describe("guid", function() { 37 | it("null", function(done) { 38 | con.k("0Ng", function(err, res) { 39 | if (err) { throw err; } 40 | assert.equal(res, null, "res"); 41 | done(); 42 | }); 43 | }); 44 | it("random", function(done) { 45 | con.k("rand 0Ng", function(err, res) { 46 | if (err) { throw err; } 47 | assert.equal(typeof res, "string", "res"); 48 | done(); 49 | }); 50 | }); 51 | }); 52 | describe("byte", function() { 53 | it("255", function(done) { 54 | con.k("0xff", function(err, res) { 55 | if (err) { throw err; } 56 | assert.equal(res, 255, "res"); 57 | done(); 58 | }); 59 | }); 60 | it("1", function(done) { 61 | con.k("0x01", function(err, res) { 62 | if (err) { throw err; } 63 | assert.equal(res, 1, "res"); 64 | done(); 65 | }); 66 | }); 67 | it("0", function(done) { 68 | con.k("0x00", function(err, res) { 69 | if (err) { throw err; } 70 | assert.equal(res, 0, "res"); 71 | done(); 72 | }); 73 | }); 74 | }); 75 | describe("short", function() { 76 | it("null", function(done) { 77 | con.k("0Nh", function(err, res) { 78 | if (err) { throw err; } 79 | assert.equal(res, null, "res"); 80 | done(); 81 | }); 82 | }); 83 | it("+infinity", function(done) { 84 | con.k("0Wh", function(err, res) { 85 | if (err) { throw err; } 86 | assert.equal(res, Infinity, "res"); 87 | done(); 88 | }); 89 | }); 90 | it("-infinity", function(done) { 91 | con.k("-0Wh", function(err, res) { 92 | if (err) { throw err; } 93 | assert.equal(res, -Infinity, "res"); 94 | done(); 95 | }); 96 | }); 97 | it("1", function(done) { 98 | con.k("1h", function(err, res) { 99 | if (err) { throw err; } 100 | assert.equal(res, 1, "res"); 101 | done(); 102 | }); 103 | }); 104 | it("0", function(done) { 105 | con.k("0h", function(err, res) { 106 | if (err) { throw err; } 107 | assert.equal(res, 0, "res"); 108 | done(); 109 | }); 110 | }); 111 | it("-1", function(done) { 112 | con.k("-1h", function(err, res) { 113 | if (err) { throw err; } 114 | assert.equal(res, -1, "res"); 115 | done(); 116 | }); 117 | }); 118 | }); 119 | describe("int", function() { 120 | it("null", function(done) { 121 | con.k("0Ni", function(err, res) { 122 | if (err) { throw err; } 123 | assert.equal(res, null, "res"); 124 | done(); 125 | }); 126 | }); 127 | it("+infinity", function(done) { 128 | con.k("0Wi", function(err, res) { 129 | if (err) { throw err; } 130 | assert.equal(res, Infinity, "res"); 131 | done(); 132 | }); 133 | }); 134 | it("-infinity", function(done) { 135 | con.k("-0Wi", function(err, res) { 136 | if (err) { throw err; } 137 | assert.equal(res, -Infinity, "res"); 138 | done(); 139 | }); 140 | }); 141 | it("1", function(done) { 142 | con.k("1i", function(err, res) { 143 | if (err) { throw err; } 144 | assert.equal(res, 1, "res"); 145 | done(); 146 | }); 147 | }); 148 | it("0", function(done) { 149 | con.k("0i", function(err, res) { 150 | if (err) { throw err; } 151 | assert.equal(res, 0, "res"); 152 | done(); 153 | }); 154 | }); 155 | it("-1", function(done) { 156 | con.k("-1i", function(err, res) { 157 | if (err) { throw err; } 158 | assert.equal(res, -1, "res"); 159 | done(); 160 | }); 161 | }); 162 | }); 163 | describe("long", function() { 164 | it("null", function(done) { 165 | con.k("0Nj", function(err, res) { 166 | if (err) { throw err; } 167 | assert.equal(res, null, "res"); 168 | done(); 169 | }); 170 | }); 171 | it("+infinity", function(done) { 172 | con.k("0Wj", function(err, res) { 173 | if (err) { throw err; } 174 | assert.equal(res, Infinity, "res"); 175 | done(); 176 | }); 177 | }); 178 | it("-infinity", function(done) { 179 | con.k("-0Wj", function(err, res) { 180 | if (err) { throw err; } 181 | assert.equal(res, -Infinity, "res"); 182 | done(); 183 | }); 184 | }); 185 | it("1", function(done) { 186 | con.k("1j", function(err, res) { 187 | if (err) { throw err; } 188 | assert.equal(res, 1, "res"); 189 | done(); 190 | }); 191 | }); 192 | it("0", function(done) { 193 | con.k("0j", function(err, res) { 194 | if (err) { throw err; } 195 | assert.equal(res, 0, "res"); 196 | done(); 197 | }); 198 | }); 199 | it("-1", function(done) { 200 | con.k("-1j", function(err, res) { 201 | if (err) { throw err; } 202 | assert.equal(res, -1, "res"); 203 | done(); 204 | }); 205 | }); 206 | }); 207 | describe("real", function() { 208 | it("null", function(done) { 209 | con.k("0Ne", function(err, res) { 210 | if (err) { throw err; } 211 | assert.equal(res, null, "res"); 212 | done(); 213 | }); 214 | }); 215 | it("+infinity", function(done) { 216 | con.k("0We", function(err, res) { 217 | if (err) { throw err; } 218 | assert.equal(res, Infinity, "res"); 219 | done(); 220 | }); 221 | }); 222 | it("-infinity", function(done) { 223 | con.k("-0We", function(err, res) { 224 | if (err) { throw err; } 225 | assert.equal(res, -Infinity, "res"); 226 | done(); 227 | }); 228 | }); 229 | it("1", function(done) { 230 | con.k("1.0e", function(err, res) { 231 | if (err) { throw err; } 232 | assert.equal(res, 1, "res"); 233 | done(); 234 | }); 235 | }); 236 | it("0", function(done) { 237 | con.k("0e", function(err, res) { 238 | if (err) { throw err; } 239 | assert.equal(res, 0, "res"); 240 | done(); 241 | }); 242 | }); 243 | it("-1", function(done) { 244 | con.k("-1e", function(err, res) { 245 | if (err) { throw err; } 246 | assert.equal(res, -1, "res"); 247 | done(); 248 | }); 249 | }); 250 | }); 251 | describe("float", function() { 252 | it("null", function(done) { 253 | con.k("0Nf", function(err, res) { 254 | if (err) { throw err; } 255 | assert.equal(res, null, "res"); 256 | done(); 257 | }); 258 | }); 259 | it("+infinity", function(done) { 260 | con.k("0Wf", function(err, res) { 261 | if (err) { throw err; } 262 | assert.equal(res, Infinity, "res"); 263 | done(); 264 | }); 265 | }); 266 | it("-infinity", function(done) { 267 | con.k("-0Wf", function(err, res) { 268 | if (err) { throw err; } 269 | assert.equal(res, -Infinity, "res"); 270 | done(); 271 | }); 272 | }); 273 | it("1", function(done) { 274 | con.k("1f", function(err, res) { 275 | if (err) { throw err; } 276 | assert.equal(res, 1, "res"); 277 | done(); 278 | }); 279 | }); 280 | it("0", function(done) { 281 | con.k("0f", function(err, res) { 282 | if (err) { throw err; } 283 | assert.equal(res, 0, "res"); 284 | done(); 285 | }); 286 | }); 287 | it("-1", function(done) { 288 | con.k("-1f", function(err, res) { 289 | if (err) { throw err; } 290 | assert.equal(res, -1, "res"); 291 | done(); 292 | }); 293 | }); 294 | }); 295 | describe("char", function() { 296 | it("null", function(done) { 297 | con.k('" "', function(err, res) { 298 | if (err) { throw err; } 299 | assert.equal(res, null, "res"); 300 | done(); 301 | }); 302 | }); 303 | it("a", function(done) { 304 | con.k('"a"', function(err, res) { 305 | if (err) { throw err; } 306 | assert.equal(res, "a", "res"); 307 | done(); 308 | }); 309 | }); 310 | }); 311 | describe("symbol", function() { 312 | it("null", function(done) { 313 | con.k("s: `; s", function(err, res) { 314 | if (err) { throw err; } 315 | assert.equal(res, null, "res"); 316 | done(); 317 | }); 318 | }); 319 | it("`a", function(done) { 320 | con.k("s: `a; s", function(err, res) { 321 | if (err) { throw err; } 322 | assert.equal(res, "a", "res"); 323 | done(); 324 | }); 325 | }); 326 | it("`abc", function(done) { 327 | con.k("s: `abc; s", function(err, res) { 328 | if (err) { throw err; } 329 | assert.equal(res, "abc", "res"); 330 | done(); 331 | }); 332 | }); 333 | }); 334 | describe("timestamp", function() { 335 | it("null", function(done) { 336 | con.k("0Np", function(err, res) { 337 | if (err) { throw err; } 338 | assert.equal(res, null, "res"); 339 | done(); 340 | }); 341 | }); 342 | it("2015.01.01D00:00:00.000000000", function(done) { 343 | con.k("2015.01.01D00:00:00.000000000", function(err, res) { 344 | if (err) { throw err; } 345 | assert.equal(res.getTime(), new Date(2015, 0, 1, 0, 0, 0, 0).getTime(), "res"); 346 | done(); 347 | }); 348 | }); 349 | it("1995.01.01D00:00:00.000000000", function(done) { 350 | con.k("1995.01.01D00:00:00.000000000", function(err, res) { 351 | if (err) { throw err; } 352 | assert.equal(res.getTime(), new Date(1995, 0, 1, 0, 0, 0, 0).getTime(), "res"); 353 | done(); 354 | }); 355 | }); 356 | }); 357 | describe("month", function() { 358 | it("null", function(done) { 359 | con.k("0Nm", function(err, res) { 360 | if (err) { throw err; } 361 | assert.equal(res, null, "res"); 362 | done(); 363 | }); 364 | }); 365 | it("2015.01", function(done) { 366 | con.k("2015.01m", function(err, res) { 367 | if (err) { throw err; } 368 | assert.equal(res.getTime(), new Date(2015, 0, 1, 0, 0, 0, 0).getTime(), "res"); 369 | done(); 370 | }); 371 | }); 372 | it("1995.01", function(done) { 373 | con.k("1995.01m", function(err, res) { 374 | if (err) { throw err; } 375 | assert.equal(res.getTime(), new Date(1995, 0, 1, 0, 0, 0, 0).getTime(), "res"); 376 | done(); 377 | }); 378 | }); 379 | }); 380 | describe("date", function() { 381 | it("null", function(done) { 382 | con.k("0Nd", function(err, res) { 383 | if (err) { throw err; } 384 | assert.equal(res, null, "res"); 385 | done(); 386 | }); 387 | }); 388 | it("2015.01.01", function(done) { 389 | con.k("2015.01.01", function(err, res) { 390 | if (err) { throw err; } 391 | assert.equal(res.getTime(), new Date(2015, 0, 1, 0, 0, 0, 0).getTime(), "res"); 392 | done(); 393 | }); 394 | }); 395 | it("1995.01.01", function(done) { 396 | con.k("1995.01.01", function(err, res) { 397 | if (err) { throw err; } 398 | assert.equal(res.getTime(), new Date(1995, 0, 1, 0, 0, 0, 0).getTime(), "res"); 399 | done(); 400 | }); 401 | }); 402 | }); 403 | describe("datetime", function() { 404 | it("null", function(done) { 405 | con.k("0Nz", function(err, res) { 406 | if (err) { throw err; } 407 | assert.equal(res, null, "res"); 408 | done(); 409 | }); 410 | }); 411 | it("2015.01.01T00:00:00.000", function(done) { 412 | con.k("2015.01.01T00:00:00.000", function(err, res) { 413 | if (err) { throw err; } 414 | assert.equal(res.getTime(), new Date(2015, 0, 1, 0, 0, 0, 0).getTime(), "res"); 415 | done(); 416 | }); 417 | }); 418 | it("1995.01.01T00:00:00.000", function(done) { 419 | con.k("1995.01.01T00:00:00.000", function(err, res) { 420 | if (err) { throw err; } 421 | assert.equal(res.getTime(), new Date(1995, 0, 1, 0, 0, 0, 0).getTime(), "res"); 422 | done(); 423 | }); 424 | }); 425 | }); 426 | describe("timespan", function() { 427 | it("null", function(done) { 428 | con.k("0Nn", function(err, res) { 429 | if (err) { throw err; } 430 | assert.equal(res, null, "res"); 431 | done(); 432 | }); 433 | }); 434 | it("0D00:00:00.000000000", function(done) { 435 | con.k("0D00:00:00.000000000", function(err, res) { 436 | if (err) { throw err; } 437 | assert.equal(res.getTime(), new Date(2000, 0, 1, 0, 0, 0, 0).getTime(), "res"); 438 | done(); 439 | }); 440 | }); 441 | it("0D00:00:00.000000000", function(done) { 442 | con.k("0D00:00:00.000000000", function(err, res) { 443 | if (err) { throw err; } 444 | assert.equal(res.getTime(), new Date(2000, 0, 1, 0, 0, 0, 0).getTime(), "res"); 445 | done(); 446 | }); 447 | }); 448 | }); 449 | describe("minute", function() { 450 | it("null", function(done) { 451 | con.k("0Nu", function(err, res) { 452 | if (err) { throw err; } 453 | assert.equal(res, null, "res"); 454 | done(); 455 | }); 456 | }); 457 | it("00:00", function(done) { 458 | con.k("00:00", function(err, res) { 459 | if (err) { throw err; } 460 | assert.equal(res.getTime(), new Date(2000, 0, 1, 0, 0, 0, 0).getTime(), "res"); 461 | done(); 462 | }); 463 | }); 464 | it("00:01", function(done) { 465 | con.k("00:01", function(err, res) { 466 | if (err) { throw err; } 467 | assert.equal(res.getTime(), new Date(2000, 0, 1, 0, 1, 0, 0).getTime(), "res"); 468 | done(); 469 | }); 470 | }); 471 | }); 472 | describe("second", function() { 473 | it("null", function(done) { 474 | con.k("0Nv", function(err, res) { 475 | if (err) { throw err; } 476 | assert.equal(res, null, "res"); 477 | done(); 478 | }); 479 | }); 480 | it("00:00:00", function(done) { 481 | con.k("00:00:00", function(err, res) { 482 | if (err) { throw err; } 483 | assert.equal(res.getTime(), new Date(2000, 0, 1, 0, 0, 0, 0).getTime(), "res"); 484 | done(); 485 | }); 486 | }); 487 | it("00:00:01", function(done) { 488 | con.k("00:00:01", function(err, res) { 489 | if (err) { throw err; } 490 | assert.equal(res.getTime(), new Date(2000, 0, 1, 0, 0, 1, 0).getTime(), "res"); 491 | done(); 492 | }); 493 | }); 494 | }); 495 | describe("time", function() { 496 | it("null", function(done) { 497 | con.k("0Nt", function(err, res) { 498 | if (err) { throw err; } 499 | assert.equal(res, null, "res"); 500 | done(); 501 | }); 502 | }); 503 | it("00:00:00.000", function(done) { 504 | con.k("00:00:00.000", function(err, res) { 505 | if (err) { throw err; } 506 | assert.equal(res.getTime(), new Date(2000, 0, 1, 0, 0, 0, 0).getTime(), "res"); 507 | done(); 508 | }); 509 | }); 510 | it("00:00:01", function(done) { 511 | con.k("00:00:00.001", function(err, res) { 512 | if (err) { throw err; } 513 | assert.equal(res.getTime(), new Date(2000, 0, 1, 0, 0, 0, 1).getTime(), "res"); 514 | done(); 515 | }); 516 | }); 517 | }); 518 | describe("dict", function() { 519 | it("empty", function(done) { 520 | con.k("()!()", function(err, res) { 521 | if (err) { throw err; } 522 | assert.deepEqual(res, {}, "res"); 523 | done(); 524 | }); 525 | }); 526 | it("single", function(done) { 527 | con.k("(enlist `a)!(enlist 1i)", function(err, res) { 528 | if (err) { throw err; } 529 | assert.deepEqual(res, {a: 1}, "res"); 530 | done(); 531 | }); 532 | }); 533 | it("multi", function(done) { 534 | con.k("(`a`b`c)!(1 2 3i)", function(err, res) { 535 | if (err) { throw err; } 536 | assert.deepEqual(res, {a: 1, b: 2, c: 3}, "res"); 537 | done(); 538 | }); 539 | }); 540 | }); 541 | describe("list", function() { 542 | it("empty", function(done) { 543 | con.k("()", function(err, res) { 544 | if (err) { throw err; } 545 | assert.deepEqual(res, [], "res"); 546 | done(); 547 | }); 548 | }); 549 | it("single", function(done) { 550 | con.k("enlist 1i", function(err, res) { 551 | if (err) { throw err; } 552 | assert.deepEqual(res, [1], "res"); 553 | done(); 554 | }); 555 | }); 556 | it("multi", function(done) { 557 | con.k("1 2 3i", function(err, res) { 558 | if (err) { throw err; } 559 | assert.deepEqual(res, [1, 2, 3], "res"); 560 | done(); 561 | }); 562 | }); 563 | }); 564 | describe("table", function() { 565 | it("empty", function(done) { 566 | con.k("([] sym:`int$(); size:`$())", function(err, res) { 567 | if (err) { throw err; } 568 | assert.deepEqual(res, [], "res"); 569 | done(); 570 | }); 571 | }); 572 | it("single", function(done) { 573 | con.k("([] sym:enlist `a; size:enlist 1i)", function(err, res) { 574 | if (err) { throw err; } 575 | assert.deepEqual(res, [{sym: "a", size: 1}], "res"); 576 | done(); 577 | }); 578 | }); 579 | it("multi", function(done) { 580 | con.k("([] sym:`a`b`c; size:(1 2 3i))", function(err, res) { 581 | if (err) { throw err; } 582 | assert.deepEqual(res, [{sym: "a", size: 1}, {sym: "b", size: 2}, {sym: "c", size: 3}], "res"); 583 | done(); 584 | }); 585 | }); 586 | }); 587 | }); 588 | -------------------------------------------------------------------------------- /itest/emptyChar2null.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | assert = require("assert"); 3 | 4 | describe("emptyChar2null", function() { 5 | "use strict"; 6 | describe("default", function() { 7 | var con; 8 | before(function(done) { 9 | nodeq.connect({host: "localhost", port: 5000}, function(err, c) { 10 | if (err) { throw err; } 11 | con = c; 12 | done(); 13 | }); 14 | }); 15 | after(function(done) { 16 | con.close(function() { 17 | con = undefined; 18 | done(); 19 | }); 20 | }); 21 | it("null", function(done) { 22 | con.k('" "', function(err, res) { 23 | if (err) { throw err; } 24 | assert.equal(res, null, "res"); 25 | done(); 26 | }); 27 | }); 28 | }); 29 | describe("true", function() { 30 | var con; 31 | before(function(done) { 32 | nodeq.connect({host: "localhost", port: 5000, emptyChar2null: true}, function(err, c) { 33 | if (err) { throw err; } 34 | con = c; 35 | done(); 36 | }); 37 | }); 38 | after(function(done) { 39 | con.close(function() { 40 | con = undefined; 41 | done(); 42 | }); 43 | }); 44 | it("null", function(done) { 45 | con.k('" "', function(err, res) { 46 | if (err) { throw err; } 47 | assert.equal(res, null, "res"); 48 | done(); 49 | }); 50 | }); 51 | }); 52 | describe("false", function() { 53 | var con; 54 | before(function(done) { 55 | nodeq.connect({host: "localhost", port: 5000, emptyChar2null: false}, function(err, c) { 56 | if (err) { throw err; } 57 | con = c; 58 | done(); 59 | }); 60 | }); 61 | after(function(done) { 62 | con.close(function() { 63 | con = undefined; 64 | done(); 65 | }); 66 | }); 67 | it("null", function(done) { 68 | con.k('" "', function(err, res) { 69 | if (err) { throw err; } 70 | assert.equal(res, " ", "res"); 71 | done(); 72 | }); 73 | }); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /itest/flipTables.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | assert = require("assert"); 3 | 4 | describe("flipTables", function() { 5 | "use strict"; 6 | describe("default", function() { 7 | var con; 8 | before(function(done) { 9 | nodeq.connect({host: "localhost", port: 5000}, function(err, c) { 10 | if (err) { throw err; } 11 | con = c; 12 | done(); 13 | }); 14 | }); 15 | after(function(done) { 16 | con.close(function() { 17 | con = undefined; 18 | done(); 19 | }); 20 | }); 21 | it("empty", function(done) { 22 | con.k("([] sym:`int$(); size:`$())", function(err, res) { 23 | if (err) { throw err; } 24 | assert.deepEqual(res, [], "res"); 25 | done(); 26 | }); 27 | }); 28 | it("single", function(done) { 29 | con.k("([] sym:enlist `a; size:enlist 1i)", function(err, res) { 30 | if (err) { throw err; } 31 | assert.deepEqual(res, [{sym: "a", size: 1}], "res"); 32 | done(); 33 | }); 34 | }); 35 | it("multi", function(done) { 36 | con.k("([] sym:`a`b`c; size:(1 2 3i))", function(err, res) { 37 | if (err) { throw err; } 38 | assert.deepEqual(res, [{sym: "a", size: 1}, {sym: "b", size: 2}, {sym: "c", size: 3}], "res"); 39 | done(); 40 | }); 41 | }); 42 | }); 43 | describe("true", function() { 44 | var con; 45 | before(function(done) { 46 | nodeq.connect({host: "localhost", port: 5000, flipTables: true}, function(err, c) { 47 | if (err) { throw err; } 48 | con = c; 49 | done(); 50 | }); 51 | }); 52 | after(function(done) { 53 | con.close(function() { 54 | con = undefined; 55 | done(); 56 | }); 57 | }); 58 | it("empty", function(done) { 59 | con.k("([] sym:`int$(); size:`$())", function(err, res) { 60 | if (err) { throw err; } 61 | assert.deepEqual(res, [], "res"); 62 | done(); 63 | }); 64 | }); 65 | it("single", function(done) { 66 | con.k("([] sym:enlist `a; size:enlist 1i)", function(err, res) { 67 | if (err) { throw err; } 68 | assert.deepEqual(res, [{sym: "a", size: 1}], "res"); 69 | done(); 70 | }); 71 | }); 72 | it("multi", function(done) { 73 | con.k("([] sym:`a`b`c; size:(1 2 3i))", function(err, res) { 74 | if (err) { throw err; } 75 | assert.deepEqual(res, [{sym: "a", size: 1}, {sym: "b", size: 2}, {sym: "c", size: 3}], "res"); 76 | done(); 77 | }); 78 | }); 79 | }); 80 | describe("false", function() { 81 | var con; 82 | before(function(done) { 83 | nodeq.connect({host: "localhost", port: 5000, flipTables: false}, function(err, c) { 84 | if (err) { throw err; } 85 | con = c; 86 | done(); 87 | }); 88 | }); 89 | after(function(done) { 90 | con.close(function() { 91 | con = undefined; 92 | done(); 93 | }); 94 | }); 95 | it("empty", function(done) { 96 | con.k("([] sym:`int$(); size:`$())", function(err, res) { 97 | if (err) { throw err; } 98 | assert.deepEqual(res, {sym: [], size: []}, "res"); 99 | done(); 100 | }); 101 | }); 102 | it("single", function(done) { 103 | con.k("([] sym:enlist `a; size:enlist 1i)", function(err, res) { 104 | if (err) { throw err; } 105 | assert.deepEqual(res, {sym: ["a"], size: [1]}, "res"); 106 | done(); 107 | }); 108 | }); 109 | it("multi", function(done) { 110 | con.k("([] sym:`a`b`c; size:(1 2 3i))", function(err, res) { 111 | if (err) { throw err; } 112 | assert.deepEqual(res, {sym: ["a", "b", "c"], size: [1, 2, 3]}, "res"); 113 | done(); 114 | }); 115 | }); 116 | }); 117 | }); 118 | -------------------------------------------------------------------------------- /itest/issue18.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | async = require("async"), 3 | assert = require("assert"); 4 | 5 | describe("issue 18", function() { 6 | "use strict"; 7 | var con; 8 | before(function(done) { 9 | nodeq.connect({host: "localhost", port: 5000}, function(err, c) { 10 | if (err) { throw err; } 11 | async.each([ 12 | "numtests:100; timerange:10D; freq:0D00:05", 13 | "testid:(til numtests)!000000999999+numtests?20", 14 | "fcn:numtests*fc:`long$timerange%freq", 15 | "tests:([]time:(-0D00:00:10 + fcn?0D00:00:20)+fcn#(.z.p - timerange)+freq*til fc; test:raze fc#'key testid; testin:fcn?16741128383987; testout:fcn?16741128383987)" 16 | ], function(q, cb) { 17 | c.k(q, cb); 18 | }, function(err) { 19 | if (err) { throw err; } 20 | con = c; 21 | done(); 22 | }); 23 | }); 24 | }); 25 | after(function(done) { 26 | con.close(function() { 27 | con = undefined; 28 | done(); 29 | }); 30 | }); 31 | it("keyed table", function(done) { 32 | con.k("select min testin by test from tests", function(err, res) { 33 | if (err) { throw err; } 34 | assert.equal(res[0].length, 100, "res[0].length"); 35 | assert.equal(res[1].length, 100, "res[1].length"); 36 | done(); 37 | }); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /itest/nanos2date.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | assert = require("assert"); 3 | 4 | describe("nanos2date", function() { 5 | "use strict"; 6 | describe("default", function() { 7 | var con; 8 | before(function(done) { 9 | nodeq.connect({host: "localhost", port: 5000}, function(err, c) { 10 | if (err) { throw err; } 11 | con = c; 12 | done(); 13 | }); 14 | }); 15 | after(function(done) { 16 | con.close(function() { 17 | con = undefined; 18 | done(); 19 | }); 20 | }); 21 | it("timestamp", function(done) { 22 | con.k("2011.10.10D14:48:00.000000000", function(err, res) { 23 | if (err) { throw err; } 24 | assert.equal(res.getTime(), 1318258080000, "res"); 25 | done(); 26 | }); 27 | }); 28 | }); 29 | describe("true", function() { 30 | var con; 31 | before(function(done) { 32 | nodeq.connect({host: "localhost", port: 5000, nanos2date: true}, function(err, c) { 33 | if (err) { throw err; } 34 | con = c; 35 | done(); 36 | }); 37 | }); 38 | after(function(done) { 39 | con.close(function() { 40 | con = undefined; 41 | done(); 42 | }); 43 | }); 44 | it("timestamp", function(done) { 45 | con.k("2011.10.10D14:48:00.000000000", function(err, res) { 46 | if (err) { throw err; } 47 | assert.equal(res.getTime(), 1318258080000, "res"); 48 | done(); 49 | }); 50 | }); 51 | }); 52 | describe("false", function() { 53 | var con; 54 | before(function(done) { 55 | nodeq.connect({host: "localhost", port: 5000, nanos2date: false}, function(err, c) { 56 | if (err) { throw err; } 57 | con = c; 58 | done(); 59 | }); 60 | }); 61 | after(function(done) { 62 | con.close(function() { 63 | con = undefined; 64 | done(); 65 | }); 66 | }); 67 | it("timestamp", function(done) { 68 | con.k("2011.10.10D14:48:00.000000000", function(err, res) { 69 | if (err) { throw err; } 70 | assert.equal(res, 1318258080000000000, "res"); 71 | done(); 72 | }); 73 | }); 74 | it("timespan 1 nano", function(done) { 75 | con.k("0D00:00:00.000000001", function(err, res) { 76 | if (err) { throw err; } 77 | assert.equal(res, 1, "res"); 78 | done(); 79 | }); 80 | }); 81 | it("timespan 1 day", function(done) { 82 | con.k("1D00:00:00.000000000", function(err, res) { 83 | if (err) { throw err; } 84 | assert.equal(res, 24 * 60 * 60 * 1000 * 1000 * 1000, "res"); 85 | done(); 86 | }); 87 | }); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /itest/readme.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | async = require("async"), 3 | assert = require("assert"); 4 | 5 | describe("readme", function() { 6 | "use strict"; 7 | var con; 8 | before(function(done) { 9 | nodeq.connect({host: "localhost", port: 5000}, function(err, c) { 10 | if (err) { 11 | done(err); 12 | } else { 13 | async.each([ 14 | 'system "l tick/u.q"', 15 | "trade: ([] sym:`$(); time:`timestamp$())", 16 | ".u.init[]", 17 | ".z.ts: {[] trade::0#trade; trade,::(`a;.z.p); .u.pub[`trade;trade]}", 18 | 'system "t 500"' 19 | ], function(q, cb) { 20 | c.k(q, cb); 21 | }, function(err) { 22 | if (err) { throw err; } 23 | con = c; 24 | done(); 25 | }); 26 | } 27 | }); 28 | }); 29 | after(function(done) { 30 | con.close(done); 31 | }); 32 | it("Execute Q code and receive result", function(done) { 33 | con.k("sum 1 2 3", function(err, res) { 34 | if (err) { 35 | done(err); 36 | } else { 37 | assert.equal(res, 6); 38 | done(); 39 | } 40 | }); 41 | }); 42 | it("Execute function with one parameter and receive result", function(done) { 43 | con.k("sum", [1, 2, 3], function(err, res) { 44 | if (err) { 45 | done(err); 46 | } else { 47 | assert.equal(res, 6); 48 | done(); 49 | } 50 | }); 51 | }); 52 | it("Execute function with two parameters and receive result", function(done) { 53 | con.k("cor", [1, 2, 3], [4, 5, 6], function(err, res) { 54 | if (err) { 55 | done(err); 56 | } else { 57 | assert.equal(res, 1); 58 | done(); 59 | } 60 | }); 61 | }); 62 | it("Async execute Q code", function(done) { 63 | con.ks("show 1 2 3", done); 64 | }); 65 | it("Async execute function with parameters", function(done) { 66 | con.ks("show", [1, 2, 3], done); 67 | }); 68 | it("Async execute and get async response", function(done) { 69 | con.ks("show 1;neg[.z.w][33]", function(err) { 70 | if (err) { 71 | throw err; 72 | } 73 | }); 74 | con.k(function(err, res) { 75 | if (err) { 76 | done(err); 77 | } else { 78 | assert.equal(res, 33); 79 | done(); 80 | } 81 | }); 82 | }); 83 | it("Subscribe to kdb+tick", function(done) { 84 | con.once("upd", function(table, data) { 85 | assert.equal(table, "trade"); 86 | assert.equal(data[0].sym, "a"); 87 | done(); 88 | }); 89 | con.ks(".u.sub[`;`]", function(err) { 90 | if (err) { 91 | done(err); 92 | } 93 | }); 94 | }); 95 | describe("typed", function() { 96 | it("short", function(done) { 97 | con.k("type", nodeq.short(1), function(err, res) { 98 | if (err) { 99 | done(err); 100 | } else { 101 | assert.equal(res, -5); 102 | done(); 103 | } 104 | }); 105 | }); 106 | it("shorts", function(done) { 107 | con.k("type", nodeq.shorts([1, 2, 3]), function(err, res) { 108 | if (err) { 109 | done(err); 110 | } else { 111 | assert.equal(res, 5); 112 | done(); 113 | } 114 | }); 115 | }); 116 | }); 117 | }); 118 | -------------------------------------------------------------------------------- /itest/serialization.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | assert = require("assert"); 3 | 4 | describe("deserialization", function() { 5 | "use strict"; 6 | var con; 7 | before(function(done) { 8 | nodeq.connect({host: "localhost", port: 5000}, function(err, c) { 9 | if (err) { throw err; } 10 | con = c; 11 | c.k("testType: {type x};", function(err, res) { 12 | if (err) { throw err; } 13 | c.k("testValue: {x};", function(err, res) { 14 | if (err) { throw err; } 15 | done(); 16 | }); 17 | }); 18 | }); 19 | }); 20 | after(function(done) { 21 | con.close(function() { 22 | con = undefined; 23 | done(); 24 | }); 25 | }); 26 | describe("Null", function() { 27 | it("type", function(done) { 28 | con.k("testType", null, function(err, res) { 29 | if (err) { throw err; } 30 | assert.equal(res, 101, "res"); 31 | done(); 32 | }); 33 | }); 34 | it("value", function(done) { 35 | con.k("testValue", null, function(err, res) { 36 | if (err) { throw err; } 37 | assert.equal(res, null, "res"); 38 | done(); 39 | }); 40 | }); 41 | }); 42 | describe("Infinity", function() { 43 | describe("+", function() { 44 | it("type", function(done) { 45 | con.k("testType", Infinity, function(err, res) { 46 | if (err) { throw err; } 47 | assert.equal(res, -9, "res"); 48 | done(); 49 | }); 50 | }); 51 | it("value", function(done) { 52 | con.k("testValue", Infinity, function(err, res) { 53 | if (err) { throw err; } 54 | assert.equal(res, Infinity, "res"); 55 | done(); 56 | }); 57 | }); 58 | }); 59 | describe("-", function() { 60 | it("type", function(done) { 61 | con.k("testType", -Infinity, function(err, res) { 62 | if (err) { throw err; } 63 | assert.equal(res, -9, "res"); 64 | done(); 65 | }); 66 | }); 67 | it("value", function(done) { 68 | con.k("testValue", -Infinity, function(err, res) { 69 | if (err) { throw err; } 70 | assert.equal(res, -Infinity, "res"); 71 | done(); 72 | }); 73 | }); 74 | }); 75 | }); 76 | describe("Boolean", function() { 77 | it("type", function(done) { 78 | con.k("testType", true, function(err, res) { 79 | if (err) { throw err; } 80 | assert.equal(res, -1, "res"); 81 | done(); 82 | }); 83 | }); 84 | it("value", function(done) { 85 | con.k("testValue", true, function(err, res) { 86 | if (err) { throw err; } 87 | assert.equal(res, true, "res"); 88 | done(); 89 | }); 90 | }); 91 | }); 92 | describe("String", function() { 93 | describe("starting with `", function() { 94 | it("type", function(done) { 95 | con.k("testType", "`a", function(err, res) { 96 | if (err) { throw err; } 97 | assert.equal(res, -11, "res"); 98 | done(); 99 | }); 100 | }); 101 | it("value", function(done) { 102 | con.k("testValue", "`a", function(err, res) { 103 | if (err) { throw err; } 104 | assert.equal(res, "a", "res"); 105 | done(); 106 | }); 107 | }); 108 | }); 109 | describe("single char", function() { 110 | it("type", function(done) { 111 | con.k("testType", "a", function(err, res) { 112 | if (err) { throw err; } 113 | assert.equal(res, 10, "res"); 114 | done(); 115 | }); 116 | }); 117 | it("value", function(done) { 118 | con.k("testValue", "a", function(err, res) { 119 | if (err) { throw err; } 120 | assert.equal(res, "a", "res"); 121 | done(); 122 | }); 123 | }); 124 | }); 125 | describe("string", function() { 126 | it("type", function(done) { 127 | con.k("testType", "abc", function(err, res) { 128 | if (err) { throw err; } 129 | assert.equal(res, 10, "res"); 130 | done(); 131 | }); 132 | }); 133 | it("value", function(done) { 134 | con.k("testValue", "abc", function(err, res) { 135 | if (err) { throw err; } 136 | assert.equal(res, "abc", "res"); 137 | done(); 138 | }); 139 | }); 140 | }); 141 | }); 142 | describe("Number", function() { 143 | it("type", function(done) { 144 | con.k("testType", 1, function(err, res) { 145 | if (err) { throw err; } 146 | assert.equal(res, -9, "res"); 147 | done(); 148 | }); 149 | }); 150 | it("value", function(done) { 151 | con.k("testValue", 1, function(err, res) { 152 | if (err) { throw err; } 153 | assert.equal(res, 1, "res"); 154 | done(); 155 | }); 156 | }); 157 | }); 158 | describe("Date", function() { 159 | describe("year 2015", function() { 160 | it("type", function(done) { 161 | con.k("testType", new Date(2015, 0, 1, 0, 0, 0, 0), function(err, res) { 162 | if (err) { throw err; } 163 | assert.equal(res, -15, "res"); 164 | done(); 165 | }); 166 | }); 167 | it("value", function(done) { 168 | con.k("testValue", new Date(2015, 0, 1, 0, 0, 0, 0), function(err, res) { 169 | if (err) { throw err; } 170 | assert.equal(res.getTime(), new Date(2015, 0, 1, 0, 0, 0, 0).getTime(), "res"); 171 | done(); 172 | }); 173 | }); 174 | }); 175 | describe("year 2000", function() { 176 | it("type", function(done) { 177 | con.k("testType", new Date(2000, 0, 1, 0, 0, 0, 0), function(err, res) { 178 | if (err) { throw err; } 179 | assert.equal(res, -15, "res"); 180 | done(); 181 | }); 182 | }); 183 | it("value", function(done) { 184 | con.k("testValue", new Date(2000, 0, 1, 0, 0, 0, 0), function(err, res) { 185 | if (err) { throw err; } 186 | assert.equal(res.getTime(), new Date(2000, 0, 1, 0, 0, 0, 0).getTime(), "res"); 187 | done(); 188 | }); 189 | }); 190 | }); 191 | describe("year 1995", function() { 192 | it("type", function(done) { 193 | con.k("testType", new Date(1995, 0, 1, 0, 0, 0, 0), function(err, res) { 194 | if (err) { throw err; } 195 | assert.equal(res, -15, "res"); 196 | done(); 197 | }); 198 | }); 199 | it("value", function(done) { 200 | con.k("testValue", new Date(1995, 0, 1, 0, 0, 0, 0), function(err, res) { 201 | if (err) { throw err; } 202 | assert.equal(res.getTime(), new Date(1995, 0, 1, 0, 0, 0, 0).getTime(), "res"); 203 | done(); 204 | }); 205 | }); 206 | }); 207 | }); 208 | describe("Object", function() { 209 | it("type", function(done) { 210 | con.k("testType", {a: 1, b: 2, c: 3}, function(err, res) { 211 | if (err) { throw err; } 212 | assert.equal(res, 99, "res"); 213 | done(); 214 | }); 215 | }); 216 | it("value", function(done) { 217 | con.k("testValue", {a: 1, b: 2, c: 3}, function(err, res) { 218 | if (err) { throw err; } 219 | assert.deepEqual(res, {a: 1, b: 2, c: 3}, "res"); 220 | done(); 221 | }); 222 | }); 223 | }); 224 | describe("Array", function() { 225 | describe("Boolean", function() { 226 | it("type", function(done) { 227 | con.k("testType", [true, false, true], function(err, res) { 228 | if (err) { throw err; } 229 | assert.equal(res, 1, "res"); 230 | done(); 231 | }); 232 | }); 233 | it("value", function(done) { 234 | con.k("testValue", [true, false, true], function(err, res) { 235 | if (err) { throw err; } 236 | assert.deepEqual(res, [true, false, true], "res"); 237 | done(); 238 | }); 239 | }); 240 | }); 241 | describe("String", function() { 242 | describe("starting with `", function() { 243 | it("type", function(done) { 244 | con.k("testType", ["`a", "`b", "`c"], function(err, res) { 245 | if (err) { throw err; } 246 | assert.equal(res, 11, "res"); 247 | done(); 248 | }); 249 | }); 250 | it("value", function(done) { 251 | con.k("testValue", ["`a", "`b", "`c"], function(err, res) { 252 | if (err) { throw err; } 253 | assert.deepEqual(res, ["a", "b", "c"], "res"); 254 | done(); 255 | }); 256 | }); 257 | }); 258 | describe("single char", function() { 259 | it("type", function(done) { 260 | con.k("testType", ["a", "b", "c"], function(err, res) { 261 | if (err) { throw err; } 262 | assert.equal(res, 0, "res"); 263 | done(); 264 | }); 265 | }); 266 | it("value", function(done) { 267 | con.k("testValue", ["a", "b", "c"], function(err, res) { 268 | if (err) { throw err; } 269 | assert.deepEqual(res, ["a", "b", "c"], "res"); 270 | done(); 271 | }); 272 | }); 273 | }); 274 | describe("string", function() { 275 | it("type", function(done) { 276 | con.k("testType", ["abc", "bcd", "cde"], function(err, res) { 277 | if (err) { throw err; } 278 | assert.equal(res, 0, "res"); 279 | done(); 280 | }); 281 | }); 282 | it("value", function(done) { 283 | con.k("testValue", ["abc", "bcd", "cde"], function(err, res) { 284 | if (err) { throw err; } 285 | assert.deepEqual(res, ["abc", "bcd", "cde"], "res"); 286 | done(); 287 | }); 288 | }); 289 | }); 290 | }); 291 | describe("Number", function() { 292 | it("type", function(done) { 293 | con.k("testType", [1, 2, 3], function(err, res) { 294 | if (err) { throw err; } 295 | assert.equal(res, 9, "res"); 296 | done(); 297 | }); 298 | }); 299 | it("value", function(done) { 300 | con.k("testValue", [1, 2, 3], function(err, res) { 301 | if (err) { throw err; } 302 | assert.deepEqual(res, [1, 2, 3], "res"); 303 | done(); 304 | }); 305 | }); 306 | }); 307 | describe("Date", function() { 308 | it("type", function(done) { 309 | con.k("testType", [new Date(2015, 0, 1, 0, 0, 0, 0), new Date(2000, 0, 1, 0, 0, 0, 0), new Date(1995, 0, 1, 0, 0, 0, 0)], function(err, res) { 310 | if (err) { throw err; } 311 | assert.equal(res, 15, "res"); 312 | done(); 313 | }); 314 | }); 315 | it("value", function(done) { 316 | con.k("testValue", [new Date(2015, 0, 1, 0, 0, 0, 0), new Date(2000, 0, 1, 0, 0, 0, 0), new Date(1995, 0, 1, 0, 0, 0, 0)], function(err, res) { 317 | if (err) { throw err; } 318 | assert.deepEqual(res[0].getTime(), new Date(2015, 0, 1, 0, 0, 0, 0).getTime(), "res[0]"); 319 | assert.deepEqual(res[1].getTime(), new Date(2000, 0, 1, 0, 0, 0, 0).getTime(), "res[1]"); 320 | assert.deepEqual(res[2].getTime(), new Date(1995, 0, 1, 0, 0, 0, 0).getTime(), "res[2]"); 321 | done(); 322 | }); 323 | }); 324 | }); 325 | }); 326 | }); 327 | -------------------------------------------------------------------------------- /itest/subs.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | async = require("async"), 3 | assert = require("assert"); 4 | 5 | describe("subs", function() { 6 | "use strict"; 7 | var con; 8 | before(function(done) { 9 | nodeq.connect({host: "localhost", port: 5000}, function(err, c) { 10 | if (err) { throw err; } 11 | async.each([ 12 | 'system "l tick/u.q"', 13 | "trade: ([] sym:`$(); time:`timestamp$())", 14 | ".u.init[]", 15 | ".z.ts: {[] trade::0#trade; trade,::(`a;.z.p); .u.pub[`trade;trade]}", 16 | 'system "t 500"' 17 | ], function(q, cb) { 18 | c.k(q, cb); 19 | }, function(err) { 20 | if (err) { throw err; } 21 | con = c; 22 | done(); 23 | }); 24 | }); 25 | }); 26 | after(function(done) { 27 | con.close(function() { 28 | con = undefined; 29 | done(); 30 | }); 31 | }); 32 | it("subscribe all", function(done) { 33 | con.once("upd", function(table, data) { 34 | assert.equal(typeof table, "string", "table"); 35 | assert.equal(Array.isArray(data), true, "data"); 36 | done(); 37 | }); 38 | con.ks(".u.sub[`;`]", function(err) { 39 | if (err) { throw err; } 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /itest/syncreqres.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | assert = require("assert"), 3 | async = require("async"); 4 | 5 | describe("syncreqres", function() { 6 | "use strict"; 7 | var con; 8 | before(function(done) { 9 | nodeq.connect({host: "localhost", port: 5000}, function(err, c) { 10 | if (err) { throw err; } 11 | con = c; 12 | done(); 13 | }); 14 | }); 15 | after(function(done) { 16 | con.close(function() { 17 | con = undefined; 18 | done(); 19 | }); 20 | }); 21 | it("evaluate q", function(done) { 22 | con.k("sum 1 2 3", function(err, res) { 23 | if (err) { throw err; } 24 | assert.equal(res, 6, "res"); 25 | done(); 26 | }); 27 | }); 28 | it("evaluate malformed q", function(done) { 29 | con.k("sxm 1 2 3", function(err) { 30 | if (err) { 31 | assert.equal(err.message, "sxm", "err"); 32 | done(); 33 | } else { 34 | assert.fail("no err"); 35 | } 36 | }); 37 | }); 38 | it("evaluate function with one parameter", function(done) { 39 | con.k("sum", [1, 2, 3], function(err, res) { 40 | if (err) { throw err; } 41 | assert.equal(res, 6, "res"); 42 | done(); 43 | }); 44 | }); 45 | it("evaluate function with two parameters", function(done) { 46 | con.k("cor", [1, 2, 3], [4, 5, 6], function(err, res) { 47 | if (err) { throw err; } 48 | assert.equal(res, 1, "res"); 49 | done(); 50 | }); 51 | }); 52 | it("mass requests", function(done) { 53 | async.map([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], function(i, cb) { 54 | con.k("sum", [i, i], cb); 55 | }, function(err, res) { 56 | if (err) { throw err; } 57 | assert.deepEqual(res, [0, 2, 4, 6, 8, 10, 12, 14, 16, 18], "res"); 58 | done(); 59 | }); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /itest/tls.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | assert = require("assert"); 3 | 4 | describe("tls", function() { 5 | "use strict"; 6 | it("should fail if endpoint expects tls and we don't set useTLS to true", function(done) { 7 | nodeq.connect({host: "localhost", port: 6000}, function(err) { 8 | assert.ok(err); 9 | done(); 10 | }); 11 | }); 12 | 13 | it("should connect successfully if useTLS is true", function(done) { 14 | nodeq.connect({host: "localhost", port: 6000, useTLS: true}, function(err) { 15 | if (err) { 16 | throw err; 17 | } 18 | done(); 19 | }); 20 | }); 21 | 22 | it("should fail if useTLS is true and endpoint doesn't expect it", function(done) { 23 | nodeq.connect({host: "localhost", port: 5000, useTLS: true}, function(err) { 24 | assert.ok(err); 25 | done(); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /itest/unicode.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | assert = require("assert"); 3 | 4 | describe("unicode", function() { 5 | "use strict"; 6 | 7 | var con; 8 | before(function(done) { 9 | nodeq.connect({host: "localhost", port: 5000}, function(err, c) { 10 | if (err) { throw err; } 11 | con = c; 12 | done(); 13 | }); 14 | }); 15 | after(function(done) { 16 | con.close(function() { 17 | con = undefined; 18 | done(); 19 | }); 20 | }); 21 | describe("string", function() { 22 | it("count", function(done) { 23 | con.k("count", "你好", function(err, res) { 24 | if (err) { throw err; } 25 | assert.equal(res, 6, "res"); 26 | done(); 27 | }); 28 | }); 29 | it("value", function(done) { 30 | con.k('s: "你好"; s', function(err, res) { 31 | if (err) { throw err; } 32 | assert.equal(res, "你好", "res"); 33 | done(); 34 | }); 35 | }); 36 | }); 37 | describe("symbol", function() { 38 | it("count", function(done) { 39 | con.k("count", "`你好", function(err, res) { 40 | if (err) { throw err; } 41 | assert.equal(res, 1, "res"); 42 | done(); 43 | }); 44 | }); 45 | it("value", function(done) { 46 | con.k('s: `$"你好"; s', function(err, res) { 47 | if (err) { throw err; } 48 | assert.equal(res, "你好", "res"); 49 | done(); 50 | }); 51 | }); 52 | }); 53 | describe("symbols", function() { 54 | it("count", function(done) { 55 | con.k("count", ["`你好", "`你好", "`你好"], function(err, res) { 56 | if (err) { throw err; } 57 | assert.equal(res, 3, "res"); 58 | done(); 59 | }); 60 | }); 61 | it("values", function(done) { 62 | con.k('s: (`$"你好";`$"你好";`$"你好"); s', function(err, res) { 63 | if (err) { throw err; } 64 | assert.deepEqual(res, ["你好", "你好", "你好"], "res"); 65 | done(); 66 | }); 67 | }); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /lib/assert.js: -------------------------------------------------------------------------------- 1 | var Long = require("long"); 2 | 3 | function optional(fun) { 4 | "use strict"; 5 | return function(val, message) { 6 | if (val === null || val === undefined) { 7 | return; 8 | } 9 | return fun(val, message); 10 | }; 11 | } 12 | 13 | function string(val, message) { 14 | "use strict"; 15 | if (typeof val !== "string") { 16 | throw new Error(message); 17 | } 18 | } 19 | exports.string = string; 20 | exports.optionalString = optional(string); 21 | 22 | function func(val, message) { 23 | "use strict"; 24 | if (typeof val !== "function") { 25 | throw new Error(message); 26 | } 27 | } 28 | exports.func = func; 29 | exports.optionalFunc = optional(func); 30 | 31 | function bool(val, message) { 32 | "use strict"; 33 | if (typeof val !== "boolean") { 34 | throw new Error(message); 35 | } 36 | } 37 | exports.bool = bool; 38 | exports.optionalBool = optional(bool); 39 | 40 | function object(val, message) { 41 | "use strict"; 42 | if (typeof val !== "object") { 43 | throw new Error(message); 44 | } 45 | } 46 | exports.object = object; 47 | exports.optionalObject = optional(object); 48 | 49 | function number(val, message) { 50 | "use strict"; 51 | if (typeof val !== "number") { 52 | throw new Error(message); 53 | } 54 | } 55 | exports.number = number; 56 | exports.optionalNumber = optional(number); 57 | 58 | function date(val, message) { 59 | "use strict"; 60 | if (!(val instanceof Date)) { 61 | throw new Error(message); 62 | } 63 | } 64 | exports.date = date; 65 | exports.optionalDate = optional(date); 66 | 67 | function array(val, message) { 68 | "use strict"; 69 | if (!Array.isArray(val)) { 70 | throw new Error(message); 71 | } 72 | } 73 | exports.array = array; 74 | exports.optionalArray = optional(array); 75 | 76 | function long(val, message) { 77 | "use strict"; 78 | if (!Long.isLong(val)) { 79 | throw new Error(message); 80 | } 81 | } 82 | exports.long = long; 83 | exports.optionalLong = optional(long); 84 | -------------------------------------------------------------------------------- /lib/c.js: -------------------------------------------------------------------------------- 1 | var Long = require("long"); 2 | var uuid = require("node-uuid"); 3 | require("buffer-indexof-polyfill"); 4 | 5 | var typed = require("./typed.js"); 6 | 7 | var J2P32 = Math.pow(2, 32); 8 | 9 | var UUID_NULL = "00000000-0000-0000-0000-000000000000"; 10 | var SHORT_NULL = -32768; 11 | var SHORT_INFINITY = 32767; 12 | var SHORT_NEG_INFINITY = 0 - SHORT_INFINITY; 13 | var INT_NULL = -2147483648; 14 | var INT_INFINITY = 2147483647; 15 | var INT_NEG_INFINITY = 0 - INT_INFINITY; 16 | var LONG_NULL = Long.fromString("9223372036854775808", false, 10); 17 | var LONG_INFINITY = Long.fromString("9223372036854775807", false, 10); 18 | var LONG_NEG_INFINITY = Long.fromString("9223372036854775809", false, 10); 19 | var ZERO_BYTE = new Buffer(1); 20 | ZERO_BYTE.writeUInt8(0, 0); 21 | 22 | var QTYPES2NUM = { 23 | "null": 101, 24 | "boolean": 1, 25 | "guid": 2, 26 | "byte": 4, 27 | "short": 5, 28 | "int": 6, 29 | "long": 7, 30 | "real": 8, 31 | "float": 9, 32 | "char": 10, 33 | "symbol": 11, 34 | "timestamp": 12, 35 | "month": 13, 36 | "date": 14, 37 | "datetime": 15, 38 | "timespan": 16, 39 | "minute": 17, 40 | "second": 18, 41 | "time": 19 42 | }; 43 | var QTYPES2SIZE = { 44 | "null": 1, 45 | "boolean": 1, 46 | "guid": 16, 47 | "byte": 1, 48 | "short": 2, 49 | "int": 4, 50 | "long": 8, 51 | "real": 4, 52 | "float": 8, 53 | "char": 1, 54 | // "symbol": , // variable length 55 | "timestamp": 8, 56 | "month": 4, 57 | "date": 4, 58 | "datetime": 8, 59 | "timespan": 8, 60 | "minute": 4, 61 | "second": 4, 62 | "time": 4 63 | }; 64 | var symbolStringRegex = /^`\S+$/; 65 | 66 | function type2num(t) { 67 | var num = QTYPES2NUM[t]; 68 | if (num === undefined) { 69 | throw new Error("bad type " + t); 70 | } 71 | return num; 72 | } 73 | 74 | function type2size(t) { 75 | var size = QTYPES2SIZE[t]; 76 | if (size === undefined) { 77 | throw new Error("bad type " + t); 78 | } 79 | return size; 80 | } 81 | 82 | // added support for decompression [GMelika] 83 | function decompress(compressedSize, b) { 84 | "use strict"; 85 | var n = 0, 86 | r = 0, 87 | f = 0, 88 | s = 8, 89 | p = s, 90 | i = 0; 91 | var dst = new Buffer(compressedSize); 92 | var d = 12; 93 | var aa = new Int32Array(256); 94 | while (s < dst.length) { 95 | if (!i) { 96 | f = b[d++]; 97 | i = 1; 98 | } 99 | if (f & i) { 100 | r = aa[b[d++]]; 101 | dst[s++] = dst[r++]; 102 | dst[s++] = dst[r++]; 103 | n = 0xff & b[d++]; 104 | for (var m = 0; m < n; m++) { 105 | dst[s + m] = dst[r + m]; 106 | } 107 | } else { 108 | dst[s++] = b[d++]; 109 | } 110 | while (p < (s - 1)) { 111 | aa[dst[p] ^ dst[p + 1]] = p++; 112 | } 113 | if (f & i) { 114 | p = (s += n); 115 | } 116 | i *= 2; 117 | if (i === 256) { 118 | i = 0; 119 | } 120 | } 121 | return dst; 122 | } 123 | 124 | function deserialize(b, nanos2date, flipTables, emptyChar2null, long2number) { 125 | "use strict"; 126 | var pos = 8, isCompressed = (b[2] === 1); 127 | function rBool() { 128 | return rInt8() === 1; 129 | } 130 | function rChar() { 131 | var val = rUInt8(); 132 | if (val === 32 && emptyChar2null !== false) { 133 | return null; 134 | } else { 135 | return String.fromCharCode(val); 136 | } 137 | } 138 | function rString(n) { 139 | var val = b.slice(pos, pos+n).toString('utf8'); 140 | pos += n; 141 | return val; 142 | } 143 | function rInt8() { 144 | var val = b.readInt8(pos); 145 | pos += 1; 146 | return val; 147 | } 148 | function rInt(n) { 149 | var val; 150 | if (n === 1) { 151 | val = b.readInt8(pos); 152 | } else if (n === 2) { 153 | val = b.readInt16LE(pos); 154 | } else if (n === 4) { 155 | val = b.readInt32LE(pos); 156 | } else { 157 | throw new Error("only n = 1, 2 or 4 is supported"); 158 | } 159 | pos += n; 160 | return val; 161 | } 162 | function rUInt8() { 163 | var val = b.readUInt8(pos); 164 | pos += 1; 165 | return val; 166 | } 167 | function rGuid() { 168 | var x = "0123456789abcdef", s = ""; 169 | for (var i = 0; i < 16; i++) { 170 | var c = rUInt8(); 171 | s += i === 4 || i === 6 || i === 8 || i === 10 ? "-" : ""; 172 | s += x[c >> 4]; 173 | s += x[c & 15]; 174 | } 175 | if (s === UUID_NULL) { 176 | return null; 177 | } else { 178 | return s; 179 | } 180 | } 181 | function rInt16() { 182 | var h = rInt(2); 183 | if (h === SHORT_NULL) { 184 | return null; 185 | } else if (h === SHORT_INFINITY) { 186 | return Infinity; 187 | } else if (h === SHORT_NEG_INFINITY) { 188 | return -Infinity; 189 | } else { 190 | return h; 191 | } 192 | } 193 | function rInt32() { 194 | var i = rInt(4); 195 | if (i === INT_NULL) { 196 | return null; 197 | } else if (i === INT_INFINITY) { 198 | return Infinity; 199 | } else if (i === INT_NEG_INFINITY) { 200 | return -Infinity; 201 | } else { 202 | return i; 203 | } 204 | } 205 | function rInt64() { // long or closest number 206 | if (long2number === false) { 207 | var low = rInt(4); 208 | var high = rInt(4); 209 | var val = new Long(low, high, false); 210 | if (low === 0 && high === INT_NULL) { 211 | return null; 212 | } 213 | if (low === -1 && high === INT_INFINITY) { 214 | return Infinity; 215 | } 216 | if (low === 1 && high === INT_NULL) { 217 | return -Infinity; 218 | } 219 | return val; 220 | } else { 221 | var y = rInt(4); 222 | var x = rInt(4); 223 | if (x === INT_NULL && y === 0) { 224 | return null; 225 | } else if (x === 2147483647 && y === -1) { 226 | return Infinity; 227 | } else if (x === -2147483648 && y === 1) { 228 | return -Infinity; 229 | } else { 230 | return x * J2P32 + (y >= 0 ? y : J2P32 + y); 231 | } 232 | } 233 | } 234 | function rFloat32() { 235 | var val = b.readFloatLE(pos); 236 | pos += 4; 237 | if (Number.isNaN(val)) { 238 | return null; 239 | } else { 240 | return val; 241 | } 242 | } 243 | function rFloat64() { 244 | var val = b.readDoubleLE(pos); 245 | pos += 8; 246 | if (Number.isNaN(val)) { 247 | return null; 248 | } else { 249 | return val; 250 | } 251 | } 252 | function rSymbol() { 253 | var e = b.indexOf(ZERO_BYTE, pos); 254 | var s = rString(e-pos); 255 | pos += 1; // zero byte 256 | if (s === "") { 257 | return null; 258 | } else { 259 | return s; 260 | } 261 | } 262 | function rTimestamp() { 263 | var val = rInt64(); 264 | if (val === null) { 265 | return null; 266 | } 267 | if (nanos2date === false) { 268 | return 86400000000000 * (10957 + (val / 86400000000000)); 269 | } else { 270 | return date(val / 86400000000000); 271 | } 272 | } 273 | function rMonth() { 274 | var y = rInt32(); 275 | if (y === null) { 276 | return null; 277 | } 278 | var m = y % 12; 279 | y = 2000 + y / 12; 280 | return new Date(Date.UTC(y, m, 1)); 281 | } 282 | function date(n) { 283 | return new Date(86400000 * (10957 + n)); 284 | } 285 | function rDate() { 286 | var val = rInt32(); 287 | return (val === null) ? null : date(val); 288 | } 289 | function rDateTime() { 290 | var val = rFloat64(); 291 | return (val === null) ? null : date(val); 292 | } 293 | function rTimespan() { 294 | var val = rInt64(); 295 | if (val === null) { 296 | return null; 297 | } 298 | if (nanos2date === false) { 299 | return val; 300 | } 301 | return date(val / 86400000000000); 302 | } 303 | function rSecond() { 304 | var val = rInt32(); 305 | if (val === null) { 306 | return null; 307 | } 308 | return date(val / 86400); 309 | } 310 | function rMinute() { 311 | var val = rInt32(); 312 | if (val === null) { 313 | return null; 314 | } 315 | return date(val / 1440); 316 | } 317 | function rTime() { 318 | var val = rInt32(); 319 | if (val === null) { 320 | return null; 321 | } 322 | return date(val / 86400000); 323 | } 324 | function r() { 325 | var fns = [r, rBool, rGuid, null, rUInt8, rInt16, rInt32, rInt64, rFloat32, rFloat64, rChar, rSymbol, rTimestamp, rMonth, rDate, rDateTime, rTimespan, rMinute, rSecond, rTime]; 326 | var i = 0, n, t = rInt8(); 327 | if (t === -128) { 328 | throw new Error(rSymbol()); 329 | } 330 | if (t < 0 && t > -20) { 331 | return fns[-t](); 332 | } 333 | if (t > 99) { 334 | if (t === 100) { 335 | rSymbol(); 336 | return r(); 337 | } 338 | if (t < 104) { 339 | return rInt8() === 0 && t === 101 ? null : "func"; 340 | } 341 | if (t > 105) { 342 | r(); 343 | } else { 344 | for (n = rInt32(); i < n; i++) { 345 | r(); 346 | } 347 | } 348 | return "func"; 349 | } 350 | if (99 === t) { 351 | var flip = 98 === rUInt8(); 352 | pos -= 1; 353 | var x = r(), 354 | y = r(), 355 | o; 356 | if (!flip) { 357 | o = {}; 358 | for (i = 0; i < x.length; i++) { 359 | o[x[i]] = y[i]; 360 | } 361 | } else { 362 | o = new Array(2); 363 | o[0]=x; 364 | o[1]=y; 365 | } 366 | return o; 367 | } 368 | pos++; 369 | if (98 === t) { 370 | if (flipTables === false) { 371 | return r(); 372 | } else { 373 | rInt8(); 374 | var x = r(); 375 | var y = r(); 376 | var A = new Array(y[0].length); 377 | for (var j = 0; j < y[0].length; j++) { 378 | var o = {}; 379 | for (var i = 0; i < x.length; i++) { 380 | o[x[i]] = y[i][j]; 381 | } 382 | A[j] = o; 383 | } 384 | return A; 385 | } 386 | } 387 | n = rInt32(); 388 | if (10 === t) { 389 | return rString(n); 390 | } 391 | var A = new Array(n); 392 | var f = fns[t]; 393 | for (i = 0; i < n; i++) { 394 | A[i] = f(); 395 | } 396 | return A; 397 | } 398 | if (isCompressed) { 399 | var compressedSize = rInt32(); 400 | b = decompress(compressedSize, b); 401 | pos = 8; 402 | } 403 | return r(); 404 | } 405 | 406 | function inferType(x) { 407 | if (typed.isTyped(x)) { 408 | return x.type(); 409 | } 410 | if (x === null) { 411 | return "null"; 412 | } 413 | if (typeof x === "number") { 414 | return "float"; 415 | } 416 | if (x instanceof Date) { 417 | return "datetime"; 418 | } 419 | if (typeof x === "boolean") { 420 | return "boolean"; 421 | } 422 | if (Array.isArray(x)) { 423 | return "list"; 424 | } 425 | if (typeof x === "string") { 426 | return "string"; 427 | } 428 | if (typeof x === "object") { 429 | return "dict"; 430 | } 431 | } 432 | 433 | function isListOfSamePrimitiveType(elements, valuetype) { 434 | if (valuetype === "list" || valuetype === "typedlist" || valuetype === "mixedlist" || valuetype === "string" || valuetype === "dict" || valuetype === "null") { 435 | return false; 436 | } 437 | return elements.every(function(x) { 438 | return inferType(x) === valuetype; 439 | }); 440 | } 441 | 442 | function calcN(x, dt) { 443 | var t, vt; 444 | if (dt) { 445 | t = dt; 446 | } else { 447 | if (typed.isTyped(x)) { 448 | t = x.type(); 449 | if (t === "typedlist") { 450 | vt = x.valuetype(); 451 | } 452 | x = x.value(); 453 | } else { 454 | t = inferType(x); 455 | } 456 | } 457 | switch (t) { 458 | case "null": // JavaScript only type 459 | return 2; 460 | case "symbol": 461 | { 462 | if (x === null) { 463 | return 2; 464 | } 465 | return 2 + Buffer.byteLength(x, 'utf8'); 466 | } 467 | case "dict": 468 | { 469 | var n = 1 + 6; 470 | var k = Object.keys(x); 471 | for (var i = 0; i < k.length; i++) { 472 | n += 1 + k[i].length; 473 | } 474 | return n + calcN(getVals(x)); 475 | } 476 | case "list": 477 | { 478 | if (x.length > 0 && (dt === null || dt === undefined)) { 479 | var valuetype = inferType(x[0]); 480 | if (isListOfSamePrimitiveType(x, valuetype)) { 481 | return calcN(new typed.Typed("typedlist", x.map(function(x1) { 482 | if (typed.isTyped(x1)) { 483 | return x1.value(); 484 | } else { 485 | return x1; 486 | } 487 | }), valuetype)); 488 | } 489 | } 490 | return calcN(x, "mixedlist"); 491 | } 492 | case "mixedlist": 493 | { 494 | var n = 6; 495 | for (var i = 0; i < x.length; i++) { 496 | n += calcN(x[i], null); 497 | } 498 | return n; 499 | } 500 | case "typedlist": 501 | { 502 | var n = 6; 503 | if (vt === "symbol") { 504 | for (var i = 0; i < x.length; i++) { 505 | n += 1 + Buffer.byteLength(x[i], 'utf8'); 506 | } 507 | } else { 508 | n += type2size(vt) * x.length; 509 | } 510 | return n; 511 | } 512 | case "string": // JavaScript only type => list of char 513 | { 514 | var n=Buffer.byteLength(x, 'utf8') + (symbolStringRegex.test(x) ? 1 : 6); 515 | return n; 516 | } 517 | // TODO implement calcN for table type 518 | } 519 | return 1 + type2size(t); 520 | } 521 | 522 | function getVals(x) { // can be replaces with Object.values someday 523 | var v = [], o; 524 | for (o in x) { 525 | if (x.hasOwnProperty(o)) { 526 | v.push(x[o]); 527 | } 528 | } 529 | return v; 530 | } 531 | 532 | function serialize(x) { 533 | "use strict"; 534 | var pos = 0, b; 535 | function wb(i) { 536 | b.writeInt8(i, pos); 537 | pos += 1; 538 | } 539 | function wub(i) { 540 | b.writeUInt8(i, pos); 541 | pos += 1; 542 | } 543 | function wr(i) { 544 | b.writeFloatLE(i, pos); 545 | pos += 4; 546 | } 547 | function wf(i) { 548 | b.writeDoubleLE(i, pos); 549 | pos += 8; 550 | } 551 | function wn(n, i) { 552 | if (n === 1) { 553 | b.writeInt8(i, pos); 554 | } else if (n === 2) { 555 | b.writeInt16LE(i, pos); 556 | } else if (n === 4) { 557 | b.writeInt32LE(i, pos); 558 | } else { 559 | throw new Error("only n = 1, 2 or 4 is supported"); 560 | } 561 | pos += n; 562 | } 563 | function wlongjs(x) { 564 | wn(4, x.low); 565 | wn(4, x.high); 566 | } 567 | function wboolean(x) { 568 | wb(x ? 1 : 0); 569 | } 570 | function wguid(x) { 571 | if (x === null) { 572 | uuid.parse(UUID_NULL, b, pos); 573 | } else { 574 | uuid.parse(x, b, pos); 575 | } 576 | pos+=16; 577 | } 578 | function wbyte(x) { 579 | wb(x); 580 | } 581 | function wshort(x) { 582 | if (x === null) { 583 | wn(2, SHORT_NULL); 584 | } else if (x === Infinity) { 585 | wn(2, SHORT_INFINITY); 586 | } else if (x === -Infinity) { 587 | wn(2, SHORT_NEG_INFINITY); 588 | } else { 589 | wn(2, x); 590 | } 591 | } 592 | function wint(x) { 593 | if (x === null) { 594 | wn(4, INT_NULL); 595 | } else if (x === Infinity) { 596 | wn(4, INT_INFINITY); 597 | } else if (x === -Infinity) { 598 | wn(4, INT_NEG_INFINITY); 599 | } else { 600 | wn(4, x); 601 | } 602 | } 603 | function wlong(x) { 604 | if (x === null) { 605 | wub(0); 606 | wub(0); 607 | wub(0); 608 | wub(0); 609 | wub(0); 610 | wub(0); 611 | wub(0); 612 | wub(128); 613 | } else if (x === Infinity) { 614 | wub(255); 615 | wub(255); 616 | wub(255); 617 | wub(255); 618 | wub(255); 619 | wub(255); 620 | wub(255); 621 | wub(127); 622 | } else if (x === -Infinity) { 623 | wub(1); 624 | wub(0); 625 | wub(0); 626 | wub(0); 627 | wub(0); 628 | wub(0); 629 | wub(0); 630 | wub(128); 631 | } else { 632 | wlongjs(x); 633 | } 634 | } 635 | function wreal(x) { 636 | if (x === null) { 637 | wub(0); 638 | wub(0); 639 | wub(192); 640 | wub(255); 641 | } else if (x === Infinity) { 642 | wub(0); 643 | wub(0); 644 | wub(128); 645 | wub(127); 646 | } else if (x === -Infinity) { 647 | wub(0); 648 | wub(0); 649 | wub(128); 650 | wub(255); 651 | } else { 652 | wr(x); 653 | } 654 | } 655 | function wfloat(x) { 656 | if (x === null) { 657 | wub(0); 658 | wub(0); 659 | wub(0); 660 | wub(0); 661 | wub(0); 662 | wub(0); 663 | wub(248); 664 | wub(255); 665 | } else if (x === Infinity) { 666 | wub(0); 667 | wub(0); 668 | wub(0); 669 | wub(0); 670 | wub(0); 671 | wub(0); 672 | wub(240); 673 | wub(127); 674 | } else if (x === -Infinity) { 675 | wub(0); 676 | wub(0); 677 | wub(0); 678 | wub(0); 679 | wub(0); 680 | wub(0); 681 | wub(240); 682 | wub(255); 683 | } else { 684 | wf(x); 685 | } 686 | } 687 | function wchar(x) { 688 | if (x === null) { 689 | wub(32); 690 | } else { 691 | wub(x.charCodeAt()); 692 | } 693 | } 694 | function wstring(x) { 695 | pos += b.write(x, pos, 'utf8'); 696 | } 697 | function wsymbol(x) { 698 | if (x !== null) { 699 | wstring(x); 700 | } 701 | wb(0); 702 | } 703 | function wtimestamp(x) { 704 | if (x === null) { 705 | wlong(null); 706 | } else { 707 | // 86400000000000 * (x.getTime() / 86400000 - 10957) 708 | wlong(Long.fromNumber(Long.fromString("1000000", false, 10).multiply(Long.fromNumber(x.getTime())).subtract(Long.fromString("946684800000000000", false, 10)))); 709 | } 710 | } 711 | function wmonth(x) { 712 | if (x == null) { 713 | wn(4, INT_NULL); 714 | } else { 715 | wn(4, (x.getUTCFullYear() - 2000) * 12 + x.getUTCMonth()); 716 | } 717 | } 718 | function wdate(x) { 719 | if (x == null) { 720 | wn(4, INT_NULL); 721 | } else { 722 | wn(4, x.getTime() / 86400000 - 10957); 723 | } 724 | } 725 | function wdatetime(x) { 726 | if (x === null) { 727 | wub(0); 728 | wub(0); 729 | wub(0); 730 | wub(0); 731 | wub(0); 732 | wub(0); 733 | wub(248); 734 | wub(255); 735 | } else { 736 | wf(x.getTime() / 86400000 - 10957); 737 | } 738 | } 739 | function wtimespan(x) { 740 | if (x === null) { 741 | wlong(null); 742 | } else { 743 | var nanos = (((x.getUTCHours() * 60 + x.getUTCMinutes()) * 60 + x.getUTCSeconds()) * 1000 + x.getUTCMilliseconds()) * 1000 * 1000; 744 | wlong(Long.fromNumber(nanos)); 745 | } 746 | } 747 | function wminute(x) { 748 | if (x == null) { 749 | wn(4, INT_NULL); 750 | } else { 751 | wn(4, x.getUTCHours() * 60 + x.getUTCMinutes()); 752 | } 753 | } 754 | function wsecond(x) { 755 | if (x == null) { 756 | wn(4, INT_NULL); 757 | } else { 758 | wn(4, (x.getUTCHours() * 60 + x.getUTCMinutes()) * 60 + x.getUTCSeconds()); 759 | } 760 | } 761 | function wtime(x) { 762 | if (x == null) { 763 | wn(4, INT_NULL); 764 | } else { 765 | wn(4, ((x.getUTCHours() * 60 + x.getUTCMinutes()) * 60 + x.getUTCSeconds()) * 1000 + x.getUTCMilliseconds()); 766 | } 767 | } 768 | function wnull() { 769 | wb(0); 770 | } 771 | 772 | var qtype2wfn = { 773 | "null": wnull, 774 | "boolean": wboolean, 775 | "guid": wguid, 776 | "byte": wbyte, 777 | "short": wshort, 778 | "int": wint, 779 | "long": wlong, 780 | "real": wreal, 781 | "float": wfloat, 782 | "char": wchar, 783 | "symbol": wsymbol, 784 | "timestamp": wtimestamp, 785 | "month": wmonth, 786 | "date": wdate, 787 | "datetime": wdatetime, 788 | "timespan": wtimespan, 789 | "minute": wminute, 790 | "second": wsecond, 791 | "time": wtime 792 | }; 793 | 794 | function type2wfn(t) { 795 | var wfn = qtype2wfn[t]; 796 | if (wfn === undefined) { 797 | throw new Error("bad type " + t); 798 | } 799 | return wfn; 800 | } 801 | 802 | function w(x, dt) { 803 | var t, vt; 804 | if (dt) { 805 | t = dt; 806 | } else { 807 | if (typed.isTyped(x)) { 808 | t = x.type(); 809 | if (t === "typedlist") { 810 | vt = x.valuetype(); 811 | } 812 | x = x.value(); 813 | } else { 814 | t = inferType(x); 815 | } 816 | } 817 | switch (t) { 818 | case "null": // JavaScript only type 819 | { 820 | wb(101); 821 | wb(0); 822 | } 823 | return; 824 | case "dict": 825 | { 826 | var k = Object.keys(x); 827 | wb(99); 828 | wb(11); 829 | wb(0); 830 | wn(4, k.length); 831 | for (var i = 0; i < k.length; i++) { 832 | wsymbol(k[i]); 833 | } 834 | w(getVals(x)); 835 | } 836 | return; 837 | case "list": 838 | { 839 | if (x.length > 0 && (dt === null || dt === undefined)) { 840 | var valuetype = inferType(x[0]); 841 | if (isListOfSamePrimitiveType(x, valuetype)) { 842 | return w(new typed.Typed("typedlist", x.map(function(x1) { 843 | if (typed.isTyped(x1)) { 844 | return x1.value(); 845 | } else { 846 | return x1; 847 | } 848 | }), valuetype)); 849 | } 850 | } 851 | return w(x, "mixedlist"); 852 | } 853 | case "mixedlist": 854 | { 855 | wb(0); 856 | wb(0); 857 | wn(4, x.length); 858 | for (var i = 0; i < x.length; i++) { 859 | w(x[i], null); 860 | } 861 | return; 862 | } 863 | case "typedlist": 864 | { 865 | wb(type2num(vt)); 866 | wb(0); 867 | wn(4, x.length); 868 | var wfn = type2wfn(vt); 869 | x.forEach(wfn); 870 | } 871 | return; 872 | case "string": // JavaScript only type => list of char 873 | { 874 | if (symbolStringRegex.test(x)) { 875 | w(x.substr(1), "symbol"); 876 | } else { 877 | wb(10); 878 | wb(0); 879 | wn(4, Buffer.byteLength(x, 'utf8')); 880 | wstring(x); 881 | } 882 | return; 883 | } 884 | // TODO implement write to buffer for table type 885 | } 886 | var num = type2num(t); 887 | var wfn = type2wfn(t); 888 | wb(0-num); 889 | wfn(x); 890 | 891 | } 892 | var n = calcN(x, null); 893 | b = new Buffer(8 + n); 894 | wb(1); 895 | wb(0); 896 | wb(0); 897 | wb(0); 898 | wn(4, b.length); 899 | w(x, null); 900 | return b; 901 | } 902 | 903 | exports.deserialize = deserialize; 904 | exports.serialize = serialize; 905 | -------------------------------------------------------------------------------- /lib/typed.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /** 4 | * Explicit serialization to KDB is possible using the Typed API. 5 | */ 6 | export declare class Typed { 7 | /** 8 | * A private constructor is used to prevent inheritance. 9 | */ 10 | private constructor(); 11 | /** 12 | * Name of the type to serialize as. 13 | */ 14 | readonly type: string; 15 | /** 16 | * The JavaScript value of the Typed object. 17 | */ 18 | readonly value: any; 19 | /** 20 | * When the type is a list, this property returns the type of values within the list. 21 | */ 22 | readonly valueType: string | undefined; 23 | } 24 | 25 | /* Primitive wrapper methods */ 26 | 27 | /** 28 | * Explicitly wrap the specified value as a boolean. 29 | * @param value The value to wrap. 30 | */ 31 | export declare function boolean(value: boolean): Typed; 32 | /** 33 | * Explicitly wrap the specified value as a guid. 34 | * @param value The value to wrap. 35 | */ 36 | export declare function guid(value: string): Typed; 37 | /** 38 | * Explicitly wrap the specified value as a byte. 39 | * @param value The value to wrap. 40 | */ 41 | export declare function byte(value: number): Typed; 42 | /** 43 | * Explicitly wrap the specified value as a short. 44 | * @param value The value to wrap. 45 | */ 46 | export declare function short(value: number): Typed; 47 | /** 48 | * Explicitly wrap the specified value as a int. 49 | * @param value The value to wrap. 50 | */ 51 | export declare function int(value: number): Typed; 52 | /** 53 | * Explicitly wrap the specified value as a long. 54 | * @param value The value to wrap. 55 | */ 56 | export declare function long(value: Long): Typed; 57 | /** 58 | * Explicitly wrap the specified value as a real. 59 | * @param value The value to wrap. 60 | */ 61 | export declare function real(value: number): Typed; 62 | /** 63 | * Explicitly wrap the specified value as a float. 64 | * @param value The value to wrap. 65 | */ 66 | export declare function float(value: number): Typed; 67 | /** 68 | * Explicitly wrap the specified value as a char. 69 | * @param value The value to wrap. 70 | */ 71 | export declare function char(value: string): Typed; 72 | /** 73 | * Explicitly wrap the specified value as a symbol. 74 | * @param value The value to wrap. 75 | */ 76 | export declare function symbol(value: string): Typed; 77 | /** 78 | * Explicitly wrap the specified value as a timestamp. 79 | * @param value The value to wrap. 80 | */ 81 | export declare function timestamp(value: Date): Typed; 82 | /** 83 | * Explicitly wrap the specified value as a month. 84 | * @param value The value to wrap. 85 | */ 86 | export declare function month(value: Date): Typed; 87 | /** 88 | * Explicitly wrap the specified value as a date. 89 | * @param value The value to wrap. 90 | */ 91 | export declare function date(value: Date): Typed; 92 | /** 93 | * Explicitly wrap the specified value as a datetime. 94 | * @param value The value to wrap. 95 | */ 96 | export declare function datetime(value: Date): Typed; 97 | /** 98 | * Explicitly wrap the specified value as a timespan. 99 | * @param value The value to wrap. 100 | */ 101 | export declare function timespan(value: Date): Typed; 102 | /** 103 | * Explicitly wrap the specified value as a minute. 104 | * @param value The value to wrap. 105 | */ 106 | export declare function minute(value: Date): Typed; 107 | /** 108 | * Explicitly wrap the specified value as a second. 109 | * @param value The value to wrap. 110 | */ 111 | export declare function second(value: Date): Typed; 112 | /** 113 | * Explicitly wrap the specified value as a time. 114 | * @param value The value to wrap. 115 | */ 116 | export declare function time(value: Date): Typed; 117 | 118 | /* Array wrapper methods */ 119 | 120 | /** 121 | * Explicitly wrap the specified array as a typed list of booleans. 122 | * @param value The array to wrap. 123 | */ 124 | export declare function booleans(value: boolean[] | ReadonlyArray): Typed; 125 | /** 126 | * Explicitly wrap the specified array as a typed list of guids. 127 | * @param value The array to wrap. 128 | */ 129 | export declare function guids(value: string[] | ReadonlyArray): Typed; 130 | /** 131 | * Explicitly wrap the specified array as a typed list of bytes. 132 | * @param value The array to wrap. 133 | */ 134 | export declare function bytes(value: number[] | ReadonlyArray): Typed; 135 | /** 136 | * Explicitly wrap the specified array as a typed list of shorts. 137 | * @param value The array to wrap. 138 | */ 139 | export declare function shorts(value: number[] | ReadonlyArray): Typed; 140 | /** 141 | * Explicitly wrap the specified array as a typed list of ints. 142 | * @param value The array to wrap. 143 | */ 144 | export declare function ints(value: number[] | ReadonlyArray): Typed; 145 | /** 146 | * Explicitly wrap the specified array as a typed list of longs. 147 | * @param value The array to wrap. 148 | */ 149 | export declare function longs(value: Long[] | ReadonlyArray): Typed; 150 | /** 151 | * Explicitly wrap the specified array as a typed list of reals. 152 | * @param value The array to wrap. 153 | */ 154 | export declare function reals(value: number[] | ReadonlyArray): Typed; 155 | /** 156 | * Explicitly wrap the specified array as a typed list of floats. 157 | * @param value The array to wrap. 158 | */ 159 | export declare function floats(value: number[] | ReadonlyArray): Typed; 160 | /** 161 | * Explicitly wrap the specified array as a typed list of chars. 162 | * @param value The array to wrap. 163 | */ 164 | export declare function chars(value: string[] | ReadonlyArray): Typed; 165 | /** 166 | * Explicitly wrap the specified array as a typed list of symbols. 167 | * @param value The array to wrap. 168 | */ 169 | export declare function symbols(value: string[] | ReadonlyArray): Typed; 170 | /** 171 | * Explicitly wrap the specified array as a typed list of timestamps. 172 | * @param value The array to wrap. 173 | */ 174 | export declare function timestamps(value: Date[] | ReadonlyArray): Typed; 175 | /** 176 | * Explicitly wrap the specified array as a typed list of months. 177 | * @param value The array to wrap. 178 | */ 179 | export declare function months(value: Date[] | ReadonlyArray): Typed; 180 | /** 181 | * Explicitly wrap the specified array as a typed list of dates. 182 | * @param value The array to wrap. 183 | */ 184 | export declare function dates(value: Date[] | ReadonlyArray): Typed; 185 | /** 186 | * Explicitly wrap the specified array as a typed list of datetimes. 187 | * @param value The array to wrap. 188 | */ 189 | export declare function datetimes(value: Date[] | ReadonlyArray): Typed; 190 | /** 191 | * Explicitly wrap the specified array as a typed list of timespans. 192 | * @param value The array to wrap. 193 | */ 194 | export declare function timespans(value: Date[] | ReadonlyArray): Typed; 195 | /** 196 | * Explicitly wrap the specified array as a typed list of mibutes. 197 | * @param value The array to wrap. 198 | */ 199 | export declare function minutes(value: Date[] | ReadonlyArray): Typed; 200 | /** 201 | * Explicitly wrap the specified array as a typed list of seconds. 202 | * @param value The array to wrap. 203 | */ 204 | export declare function seconds(value: Date[] | ReadonlyArray): Typed; 205 | /** 206 | * Explicitly wrap the specified array as a typed list of times. 207 | * @param value The array to wrap. 208 | */ 209 | export declare function times(value: Date[] | ReadonlyArray): Typed; 210 | /** 211 | * Gets a value indicating if the specified value is a Typed wrapper. 212 | * @param value The value to test for being a Typed wrapper. 213 | */ 214 | export declare function isTyped(value: any): value is Typed; 215 | -------------------------------------------------------------------------------- /lib/typed.js: -------------------------------------------------------------------------------- 1 | var assert = require("./assert.js"); 2 | 3 | function Typed(type, value, valuetype) { 4 | "use strict"; 5 | this._type = type; 6 | this._value = value; 7 | this._valuetype = valuetype; 8 | } 9 | Typed.prototype.type = function() { 10 | "use strict"; 11 | return this._type; 12 | }; 13 | Typed.prototype.value = function() { 14 | "use strict"; 15 | return this._value; 16 | }; 17 | Typed.prototype.valuetype = function() { 18 | "use strict"; 19 | if (this._type !== "typedlist") { 20 | throw new Error("only available for type typedlist"); 21 | } 22 | return this._valuetype; 23 | }; 24 | Typed.prototype.toString = function() { 25 | "use strict"; 26 | if (this._type === "typedlist") { 27 | return "list[" + this._valuetype + "](" + this._value + ")"; 28 | } 29 | return this._type + "(" + this._value + ")"; 30 | }; 31 | 32 | function listOf(assertfn, values, valuetype) { 33 | "use strict"; 34 | assert.array(values, "array"); 35 | values.forEach(function(v) { 36 | assertfn(v, assertfn.name); 37 | }); 38 | return new Typed("typedlist", values, valuetype); 39 | } 40 | 41 | exports.boolean = function(boolean) { 42 | "use strict"; 43 | assert.bool(boolean, "boolean"); 44 | return new Typed("boolean", boolean); 45 | }; 46 | exports.booleans = function(booleans) { 47 | "use strict"; 48 | return listOf(assert.bool, booleans, "boolean"); 49 | }; 50 | 51 | exports.guid = function(string) { 52 | "use strict"; 53 | if (string !== null) { 54 | assert.string(string, "string"); 55 | } 56 | return new Typed("guid", string); 57 | }; 58 | exports.guids = function(strings) { 59 | "use strict"; 60 | return listOf(assert.string, strings, "guid"); 61 | }; 62 | 63 | exports.byte = function(number) { 64 | "use strict"; 65 | assert.number(number, "number"); 66 | return new Typed("byte", number); 67 | }; 68 | exports.bytes = function(numbers) { 69 | "use strict"; 70 | return listOf(assert.number, numbers, "byte"); 71 | }; 72 | 73 | exports.short = function(number) { 74 | "use strict"; 75 | if (number !== null) { 76 | assert.number(number, "number"); 77 | } 78 | return new Typed("short", number); 79 | }; 80 | exports.shorts = function(numbers) { 81 | "use strict"; 82 | return listOf(assert.number, numbers, "short"); 83 | }; 84 | 85 | exports.int = function(number) { 86 | "use strict"; 87 | if (number !== null) { 88 | assert.number(number, "number"); 89 | } 90 | return new Typed("int", number); 91 | }; 92 | exports.ints = function(numbers) { 93 | "use strict"; 94 | return listOf(assert.number, numbers, "int"); 95 | }; 96 | 97 | exports.long = function(long) { 98 | "use strict"; 99 | if (long !== null && long !== Infinity && long !== -Infinity) { 100 | assert.long(long, "long"); 101 | } 102 | return new Typed("long", long); 103 | }; 104 | exports.longs = function(longs) { 105 | "use strict"; 106 | return listOf(assert.long, longs, "long"); 107 | }; 108 | 109 | exports.real = function(number) { 110 | "use strict"; 111 | if (number !== null) { 112 | assert.number(number, "number"); 113 | } 114 | return new Typed("real", number); 115 | }; 116 | exports.reals = function(numbers) { 117 | "use strict"; 118 | return listOf(assert.number, numbers, "real"); 119 | }; 120 | 121 | exports.float = function(number) { 122 | "use strict"; 123 | if (number !== null) { 124 | assert.number(number, "number"); 125 | } 126 | return new Typed("float", number); 127 | }; 128 | exports.floats = function(numbers) { 129 | "use strict"; 130 | return listOf(assert.number, numbers, "float"); 131 | }; 132 | 133 | exports.char = function(string) { 134 | "use strict"; 135 | if (string !== null) { 136 | assert.string(string, "string"); 137 | } 138 | return new Typed("char", string); 139 | }; 140 | exports.chars = function(strings) { 141 | "use strict"; 142 | return listOf(assert.string, strings, "char"); 143 | }; 144 | 145 | exports.symbol = function(string) { 146 | "use strict"; 147 | if (string !== null) { 148 | assert.string(string, "string"); 149 | string = string.replace(/\u0000/g, ""); 150 | } 151 | return new Typed("symbol", string); 152 | }; 153 | exports.symbols = function(strings) { 154 | "use strict"; 155 | return listOf(assert.string, strings, "symbol"); 156 | }; 157 | 158 | exports.timestamp = function(date) { 159 | "use strict"; 160 | if (date !== null) { 161 | assert.date(date, "date"); 162 | } 163 | return new Typed("timestamp", date); 164 | }; 165 | exports.timestamps = function(dates) { 166 | "use strict"; 167 | return listOf(assert.date, dates, "timestamp"); 168 | }; 169 | 170 | exports.month = function(date) { 171 | "use strict"; 172 | if (date !== null) { 173 | assert.date(date, "date"); 174 | } 175 | return new Typed("month", date); 176 | }; 177 | exports.months = function(dates) { 178 | "use strict"; 179 | return listOf(assert.date, dates, "month"); 180 | }; 181 | 182 | exports.date = function(date) { 183 | "use strict"; 184 | if (date !== null) { 185 | assert.date(date, "date"); 186 | } 187 | return new Typed("date", date); 188 | }; 189 | exports.dates = function(dates) { 190 | "use strict"; 191 | return listOf(assert.date, dates, "date"); 192 | }; 193 | 194 | exports.datetime = function(date) { 195 | "use strict"; 196 | if (date !== null) { 197 | assert.date(date, "date"); 198 | } 199 | return new Typed("datetime", date); 200 | }; 201 | exports.datetimes = function(dates) { 202 | "use strict"; 203 | return listOf(assert.date, dates, "datetime"); 204 | }; 205 | 206 | exports.timespan = function(date) { 207 | "use strict"; 208 | if (date !== null) { 209 | assert.date(date, "date"); 210 | } 211 | return new Typed("timespan", date); 212 | }; 213 | exports.timespans = function(dates) { 214 | "use strict"; 215 | return listOf(assert.date, dates, "timespan"); 216 | }; 217 | 218 | exports.minute = function(date) { 219 | "use strict"; 220 | if (date !== null) { 221 | assert.date(date, "date"); 222 | } 223 | return new Typed("minute", date); 224 | }; 225 | exports.minutes = function(dates) { 226 | "use strict"; 227 | return listOf(assert.date, dates, "minute"); 228 | }; 229 | 230 | exports.second = function(date) { 231 | "use strict"; 232 | if (date !== null) { 233 | assert.date(date, "date"); 234 | } 235 | return new Typed("second", date); 236 | }; 237 | exports.seconds = function(dates) { 238 | "use strict"; 239 | return listOf(assert.date, dates, "second"); 240 | }; 241 | 242 | exports.time = function(date) { 243 | "use strict"; 244 | if (date !== null) { 245 | assert.date(date, "date"); 246 | } 247 | return new Typed("time", date); 248 | }; 249 | exports.times = function(dates) { 250 | "use strict"; 251 | return listOf(assert.date, dates, "time"); 252 | }; 253 | 254 | exports.mixedlist = function(values) { 255 | "use strict"; 256 | assert.array(values, "array"); 257 | return new Typed("mixedlist", values); 258 | }; 259 | 260 | exports.dict = function(object) { 261 | "use strict"; 262 | assert.object(object, "object"); 263 | return new Typed("dict", object); 264 | }; 265 | 266 | // TODO expose typed table as soon as implemented 267 | /*exports.table = function(array) { 268 | "use strict"; 269 | assert.array(array, "array"); 270 | return new Typed("table", array); 271 | };*/ 272 | 273 | exports.Typed = Typed; 274 | exports.isTyped = function(val) { 275 | "use strict"; 276 | return (val instanceof Typed); 277 | }; 278 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-q", 3 | "version": "2.7.0", 4 | "description": "Q interfacing with Node.js", 5 | "keywords": [ 6 | "q", 7 | "kx", 8 | "kdb+", 9 | "kdb+tick", 10 | "interfacing" 11 | ], 12 | "main": "index.js", 13 | "types": "index.d.ts", 14 | "scripts": { 15 | "test": "make test", 16 | "itest": "make itest", 17 | "prepublish": "tsc" 18 | }, 19 | "author": "Michael Wittig ", 20 | "license": "MIT", 21 | "dependencies": { 22 | "buffer-indexof-polyfill": "1.0.1", 23 | "long": "3.0.3", 24 | "node-uuid": "1.4.7" 25 | }, 26 | "devDependencies": { 27 | "@types/long": "^3.0.31", 28 | "@types/node": "^8.0.8", 29 | "async": "1.5.2", 30 | "istanbul": "0.4.2", 31 | "jshint": "2.9.1", 32 | "madge": "0.5.3", 33 | "mocha": "2.4.5", 34 | "moment": "2.22.2", 35 | "npmedge": "0.2.2", 36 | "typescript": "^2.4.1" 37 | }, 38 | "repository": { 39 | "type": "git", 40 | "url": "https://github.com/michaelwittig/node-q.git" 41 | }, 42 | "engines": { 43 | "node": ">=0.10" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/c.js: -------------------------------------------------------------------------------- 1 | var c = require("../lib/c.js"), 2 | typed = require("../lib/typed.js"), 3 | moment = require("moment"), 4 | assert = require("assert"), 5 | Long = require("long"); 6 | 7 | function hexstr_to_bin(str) { 8 | "use strict"; 9 | return new Buffer(str, "hex"); 10 | } 11 | 12 | function bin_to_hexstr(b) { 13 | "use strict"; 14 | return b.toString("hex"); 15 | } 16 | 17 | // use -8! in q to get the byte representation 18 | 19 | describe("c", function() { 20 | "use strict"; 21 | describe("deserialize", function() { 22 | describe("little", function() { 23 | describe("primitives", function() { 24 | it("boolean", function() { // 1b 25 | assert.equal(c.deserialize(hexstr_to_bin("010000000a000000ff01")), true); 26 | }); 27 | describe("guid", function() { 28 | it("guid", function() { // 0a369037-75d3-b24d-6721-5a1d44d4bed5 29 | assert.equal(c.deserialize(hexstr_to_bin("0100000019000000fe0a36903775d3b24d67215a1d44d4bed5")), "0a369037-75d3-b24d-6721-5a1d44d4bed5"); 30 | }); 31 | it("null", function() { // 0Ng 32 | assert.equal(c.deserialize(hexstr_to_bin("0100000019000000fe00000000000000000000000000000000")), null); 33 | }); 34 | }); 35 | it("byte", function() { // 0x01 36 | assert.equal(c.deserialize(hexstr_to_bin("010000000a000000fc01")), "1"); 37 | }); 38 | describe("short", function() { 39 | it("1", function() { // 1h 40 | assert.equal(c.deserialize(hexstr_to_bin("010000000b000000fb0100")), 1); 41 | }); 42 | it("-1", function() { // -1h 43 | assert.equal(c.deserialize(hexstr_to_bin("010000000b000000fbffff")), -1); 44 | }); 45 | it("null", function() { // 0Nh 46 | assert.equal(c.deserialize(hexstr_to_bin("010000000b000000fb0080")), null); 47 | }); 48 | it("Infinity", function() { // 0wh 49 | assert.equal(c.deserialize(hexstr_to_bin("010000000b000000fbff7f")), Infinity); 50 | }); 51 | it("-Infinity", function() { // -0wh 52 | assert.equal(c.deserialize(hexstr_to_bin("010000000b000000fb0180")), -Infinity); 53 | }); 54 | }); 55 | describe("integer", function() { 56 | it("1", function() { // 1i 57 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000fa01000000")), 1); 58 | }); 59 | it("-1", function() { // -1i 60 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000faffffffff")), -1); 61 | }); 62 | it("null", function() { // 0Ni 63 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000fa00000080")), null); 64 | }); 65 | it("Infinity", function() { // 0wi 66 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000faffffff7f")), Infinity); 67 | }); 68 | it("-Infinity", function() { // -0wi 69 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000fa01000080")), -Infinity); 70 | }); 71 | }); 72 | describe("long", function() { 73 | describe("long2number", function() { 74 | describe("default", function() { 75 | it("1", function() { // 1j 76 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90100000000000000")), 1); 77 | }); 78 | it("-1", function() { // -1j 79 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f9ffffffffffffffff")), -1); 80 | }); 81 | it("2147483647", function() { // 2147483647j 82 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f9ffffff7f00000000")), 2147483647); 83 | }); 84 | it("2147483648", function() { // 2147483648j 85 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90000008000000000")), 2147483648); 86 | }); 87 | it("2147483649", function() { // 2147483649j 88 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90100008000000000")), 2147483649); 89 | }); 90 | it("4294967295", function() { // 4294967295j 91 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f9ffffffff00000000")), 4294967295); 92 | }); 93 | it("4294967296", function() { // 4294967296j 94 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90000000001000000")), 4294967296); 95 | }); 96 | it("4294967297", function() { // 4294967297j 97 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90100000001000000")), 4294967297); 98 | }); 99 | it("null", function() { // 0Nj 100 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90000000000000080")), null); 101 | }); 102 | it("Infinity", function() { // 0wj 103 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f9ffffffffffffff7f")), Infinity); 104 | }); 105 | it("-Infinity", function() { // -0wj 106 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90100000000000080")), -Infinity); 107 | }); 108 | }); 109 | describe("false", function() { 110 | it("1", function() { // 1j 111 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90100000000000000"), undefined, undefined, undefined, false).toNumber(), 1); 112 | }); 113 | it("-1", function() { // -1j 114 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f9ffffffffffffffff"), undefined, undefined, undefined, false).toNumber(), -1); 115 | }); 116 | it("2147483647", function() { // 2147483647j 117 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f9ffffff7f00000000"), undefined, undefined, undefined, false).toNumber(), 2147483647); 118 | }); 119 | it("2147483648", function() { // 2147483648j 120 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90000008000000000"), undefined, undefined, undefined, false).toNumber(), 2147483648); 121 | }); 122 | it("2147483649", function() { // 2147483649j 123 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90100008000000000"), undefined, undefined, undefined, false).toNumber(), 2147483649); 124 | }); 125 | it("4294967295", function() { // 4294967295j 126 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f9ffffffff00000000"), undefined, undefined, undefined, false).toNumber(), 4294967295); 127 | }); 128 | it("4294967296", function() { // 4294967296j 129 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90000000001000000"), undefined, undefined, undefined, false).toNumber(), 4294967296); 130 | }); 131 | it("4294967297", function() { // 4294967297j 132 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90100000001000000"), undefined, undefined, undefined, false).toNumber(), 4294967297); 133 | }); 134 | it("null", function() { // 0Nj 135 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90000000000000080"), undefined, undefined, undefined, false), null); 136 | }); 137 | it("Infinity", function() { // 0wj 138 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f9ffffffffffffff7f"), undefined, undefined, undefined, false), Infinity); 139 | }); 140 | it("-Infinity", function() { // -0wj 141 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90100000000000080"), undefined, undefined, undefined, false), -Infinity); 142 | }); 143 | }); 144 | describe("true", function() { 145 | it("1", function() { // 1j 146 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90100000000000000"), undefined, undefined, undefined, true), 1); 147 | }); 148 | it("-1", function() { // -1j 149 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f9ffffffffffffffff"), undefined, undefined, undefined, true), -1); 150 | }); 151 | it("2147483647", function() { // 2147483647j 152 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f9ffffff7f00000000"), undefined, undefined, undefined, true), 2147483647); 153 | }); 154 | it("2147483648", function() { // 2147483648j 155 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90000008000000000"), undefined, undefined, undefined, true), 2147483648); 156 | }); 157 | it("2147483649", function() { // 2147483649j 158 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90100008000000000"), undefined, undefined, undefined, true), 2147483649); 159 | }); 160 | it("4294967295", function() { // 4294967295j 161 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f9ffffffff00000000"), undefined, undefined, undefined, true), 4294967295); 162 | }); 163 | it("4294967296", function() { // 4294967296j 164 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90000000001000000"), undefined, undefined, undefined, true), 4294967296); 165 | }); 166 | it("4294967297", function() { // 4294967297j 167 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90100000001000000"), undefined, undefined, undefined, true), 4294967297); 168 | }); 169 | it("null", function() { // 0Nj 170 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90000000000000080"), undefined, undefined, undefined, true), null); 171 | }); 172 | it("Infinity", function() { // 0wj 173 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f9ffffffffffffff7f"), undefined, undefined, undefined, true), Infinity); 174 | }); 175 | it("-Infinity", function() { // -0wj 176 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f90100000000000080"), undefined, undefined, undefined, true), -Infinity); 177 | }); 178 | }); 179 | }); 180 | }); 181 | describe("real", function() { 182 | it("1", function() { // 1e 183 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f80000803f")), 1.0); 184 | }); 185 | it("-1", function() { // -1e 186 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f8000080bf")), -1.0); 187 | }); 188 | it("null", function() { // 0Ne 189 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f80000c0ff")), null); 190 | }); 191 | it("Infinity", function() { // 0we 192 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f80000807f")), Infinity); 193 | }); 194 | it("-Infinity", function() { // -0we 195 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f8000080ff")), -Infinity); 196 | }); 197 | }); 198 | describe("float", function() { 199 | it("1", function() { // 1f 200 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f7000000000000f03f")), 1.0); 201 | }); 202 | it("-1", function() { // -1f 203 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f7000000000000f0bf")), -1.0); 204 | }); 205 | it("null", function() { // 0Nf 206 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f7000000000000f8ff")), null); 207 | }); 208 | it("Infinity", function() { // 0wf 209 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f7000000000000f07f")), Infinity); 210 | }); 211 | it("-Infinity", function() { // -0wf 212 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f7000000000000f0ff")), -Infinity); 213 | }); 214 | }); 215 | describe("char", function() { 216 | describe("emptyChar2null", function() { 217 | describe("default", function() { 218 | it("a", function() { // "a" 219 | assert.equal(c.deserialize(hexstr_to_bin("010000000a000000f661")), "a"); 220 | }); 221 | it("null", function() { // " " 222 | assert.equal(c.deserialize(hexstr_to_bin("010000000a000000f620")), null); 223 | }); 224 | }); 225 | describe("true", function() { 226 | it("a", function() { // "a" 227 | assert.equal(c.deserialize(hexstr_to_bin("010000000a000000f661"), undefined, undefined, true), "a"); 228 | }); 229 | it("null", function() { // " " 230 | assert.equal(c.deserialize(hexstr_to_bin("010000000a000000f620"), undefined, undefined, true), null); 231 | }); 232 | }); 233 | describe("false", function() { 234 | it("a", function() { // "a" 235 | assert.equal(c.deserialize(hexstr_to_bin("010000000a000000f661"), undefined, undefined, false), "a"); 236 | }); 237 | it("null", function() { // " " 238 | assert.equal(c.deserialize(hexstr_to_bin("010000000a000000f620"), undefined, undefined, false), " "); 239 | }); 240 | }); 241 | }); 242 | }); 243 | describe("symbol", function() { 244 | it("length 1", function() { // `a 245 | assert.equal(c.deserialize(hexstr_to_bin("010000000b000000f56100")), "a"); 246 | }); 247 | it("null", function() { // ` 248 | assert.equal(c.deserialize(hexstr_to_bin("010000000a000000f500")), null); 249 | }); 250 | it("length 2", function() { // `ab 251 | assert.equal(c.deserialize(hexstr_to_bin("010000000c000000f5616200")), "ab"); 252 | }); 253 | it("length 3", function() { // `abc 254 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f561626300")), "abc"); 255 | }); 256 | it("length 4", function() { // `abcd 257 | assert.equal(c.deserialize(hexstr_to_bin("010000000e000000f56162636400")), "abcd"); 258 | }); 259 | it("lenth 5", function() { // `abcde 260 | assert.equal(c.deserialize(hexstr_to_bin("010000000f000000f5616263646500")), "abcde"); 261 | }); 262 | it("unicode length 1", function() { // `$"你" 263 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f5e4bda000")), "你"); 264 | }); 265 | it("unicode length 2", function() { // `$"你好" 266 | assert.equal(c.deserialize(hexstr_to_bin("0100000010000000f5e4bda0e5a5bd00")), "你好"); 267 | }); 268 | }); 269 | describe("nanos2date", function() { 270 | describe("default", function() { 271 | it("deserialize_timestamp_little_test", function() { // 2014.06.23D11:34:39.412547000 272 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f4b84d1d352d045706")).getTime(), moment.utc("2014.06.23 11:34:39.412547000", "YYYY.MM.DD HH:mm:ss.SSS").toDate().getTime()); 273 | }); 274 | it("deserialize_timestamp_null_little_test", function() { // 0Np 275 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f40000000000000080")), null); 276 | }); 277 | it("deserialize_timespan_little_test", function() { // 00:01:00.000000000 278 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f0005847f80d000000")).getTime(), moment.utc("2000.01.01 00:01:00.000", "YYYY.MM.DD HH:mm:ss.SSS").toDate().getTime()); 279 | }); 280 | it("deserialize_timespan_null_little_test", function() { // 0Nn 281 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f00000000000000080")), null); 282 | }); 283 | }); 284 | describe("true", function() { 285 | it("deserialize_timestamp_little_test", function() { // 2014.06.23D11:34:39.412547000 286 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f4b84d1d352d045706"), true).getTime(), moment.utc("2014.06.23 11:34:39.412547000", "YYYY.MM.DD HH:mm:ss.SSS").toDate().getTime()); 287 | }); 288 | it("deserialize_timestamp_null_little_test", function() { // 0Np 289 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f40000000000000080"), true), null); 290 | }); 291 | it("deserialize_timespan_little_test", function() { // 00:01:00.000000000 292 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f0005847f80d000000"), true).getTime(), moment.utc("2000.01.01 00:01:00.000", "YYYY.MM.DD HH:mm:ss.SSS").toDate().getTime()); 293 | }); 294 | it("deserialize_timespan_null_little_test", function() { // 0Nn 295 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f00000000000000080"), true), null); 296 | }); 297 | }); 298 | describe("false", function() { 299 | it("deserialize_timestamp_little_test", function() { // 2014.06.23D11:34:39.412547000 300 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f4b84d1d352d045706"), false), 1403523279412547000); 301 | }); 302 | it("deserialize_timestamp_null_little_test", function() { // 0Np 303 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f40000000000000080"), false), null); 304 | }); 305 | it("deserialize_timespan_little_test", function() { // 00:01:00.000000000 306 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f0005847f80d000000"), false), 60000000000); 307 | }); 308 | it("deserialize_timespan_null_little_test", function() { // 0Nn 309 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f00000000000000080"), false), null); 310 | }); 311 | }); 312 | }); 313 | describe("month", function() { 314 | it("201401", function() { // 2014.01m 315 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f3a8000000")).getTime(), moment.utc("2014.01", "YYYY.MM").toDate().getTime()); 316 | }); 317 | it("null", function() { // 0Nm 318 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f300000080")), null); 319 | }); 320 | it("199501", function() { // 1995.01m 321 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f3c4ffffff")).getTime(), moment.utc("1995.01", "YYYY.MM").toDate().getTime()); 322 | }); 323 | }); 324 | describe("date", function() { 325 | it("20140101", function() { // 2014.01.01 326 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f2fa130000")).getTime(), moment.utc("2014.01.91", "YYYY.MM").toDate().getTime()); 327 | }); 328 | it("null", function() { // 0Nd 329 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f200000080")), null); 330 | }); 331 | it("19950101", function() { // 1995.01.01 332 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000f2def8ffff")).getTime(), moment.utc("1995.01.01", "YYYY.MM").toDate().getTime()); 333 | }); 334 | }); 335 | describe("datetime", function() { 336 | it("datetime", function() { // 2014.06.23T11:49:31.533 337 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f1facf4b237ea7b440")).getTime(), moment.utc("2014.06.23 11:49:31.533", "YYYY.MM.DD HH:mm:ss.SSS").toDate().getTime()); 338 | }); 339 | it("null", function() { // 0Nz 340 | assert.equal(c.deserialize(hexstr_to_bin("0100000011000000f1000000000000f8ff")), null); 341 | }); 342 | }); 343 | describe("minute", function() { 344 | it("00:01", function() { // 00:01 345 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000ef01000000")).getTime(), moment.utc("2000.01.01 00:01:00.000", "YYYY.MM.DD HH:mm:ss.SSS").toDate().getTime()); 346 | }); 347 | it("null", function() { // 0Nu 348 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000ef00000080")), null); 349 | }); 350 | }); 351 | describe("second", function() { 352 | it("00:00:01", function() { // 00:00:01 353 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000ee01000000")).getTime(), moment.utc("2000.01.01 00:00:01.000", "YYYY.MM.DD HH:mm:ss.SSS").toDate().getTime()); 354 | }); 355 | it("null", function() { // 0Nv 356 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000ee00000080")), null); 357 | }); 358 | }); 359 | describe("time", function() { 360 | it("00:00:00.001", function() { // 00:00:00.001 361 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000ed01000000")).getTime(), moment.utc("2000.01.01 00:00:00.001", "YYYY.MM.DD HH:mm:ss.SSS").toDate().getTime()); 362 | }); 363 | it("null", function() { // 0Nt 364 | assert.equal(c.deserialize(hexstr_to_bin("010000000d000000ed00000080")), null); 365 | }); 366 | }); 367 | }); 368 | describe("list", function() { 369 | it("empty", function() { 370 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000000e000000000000000000")), []); 371 | }); 372 | it("generic", function() { // (1j;1b;3h) 373 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001c000000000003000000f90100000000000000ff01fb0300")), [1, true, 3]); 374 | }); 375 | it("null", function() { // (::;::;::) 376 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000014000000000003000000650065006500")), [null, null, null]); 377 | }); 378 | describe("list of list", function() { 379 | it("same types", function() { // enlist (1f;2f;3f) 380 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000002c000000000001000000090003000000000000000000f03f00000000000000400000000000000840")), [[1, 2, 3]]); 381 | }); 382 | it("different types", function() { // enlist (1f;1b;3h) 383 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000022000000000001000000000003000000f7000000000000f03fff01fb0300")), [[1, true, 3]]); 384 | }); 385 | }); 386 | describe("boolean", function() { 387 | it("single", function() { 388 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000000f00000001000100000001")), [true]); 389 | }); 390 | it("multi", function() { 391 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000011000000010003000000010001")), [true, false, true]); 392 | }); 393 | }); 394 | describe("guid", function() { 395 | it("single", function() { 396 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001e000000020001000000daedb4cc85f44ba0e3083c62191c0865")), ["daedb4cc-85f4-4ba0-e308-3c62191c0865"]); 397 | }); 398 | it("multi", function() { 399 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000003e000000020003000000ca3b0039fc23f2892c3769d4a24fe17cc73d1b400fce85c1a78fb653c8c6d022f4f58976d8cad4c10db7d102c6f91025")), ["ca3b0039-fc23-f289-2c37-69d4a24fe17c", "c73d1b40-0fce-85c1-a78f-b653c8c6d022", "f4f58976-d8ca-d4c1-0db7-d102c6f91025"]); 400 | }); 401 | }); 402 | describe("byte", function() { 403 | it("single", function() { 404 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000000f00000004000100000001")), [1]); 405 | }); 406 | it("multi", function() { 407 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000011000000040003000000010203")), [1, 2, 3]); 408 | }); 409 | }); 410 | describe("short", function() { 411 | it("single", function() { 412 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000100000000500010000000100")), [1]); 413 | }); 414 | it("multi", function() { 415 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000014000000050003000000010002000300")), [1, 2, 3]); 416 | }); 417 | }); 418 | describe("int", function() { 419 | it("single", function() { 420 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001200000006000100000001000000")), [1]); 421 | }); 422 | it("multi", function() { 423 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001a000000060003000000010000000200000003000000")), [1, 2, 3]); 424 | }); 425 | }); 426 | describe("long", function() { 427 | it("single", function() { 428 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000160000000700010000000100000000000000")), [1]); 429 | }); 430 | it("multi", function() { 431 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000026000000070003000000010000000000000002000000000000000300000000000000")), [1, 2, 3]); 432 | }); 433 | }); 434 | describe("real", function() { 435 | it("single", function() { 436 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000120000000800010000000000803f")), [1]); 437 | }); 438 | it("multi", function() { 439 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001a0000000800030000000000803f0000004000004040")), [1, 2, 3]); 440 | }); 441 | }); 442 | describe("float", function() { 443 | it("single", function() { 444 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000016000000090001000000000000000000f03f")), [1]); 445 | }); 446 | it("multi", function() { 447 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000026000000090003000000000000000000f03f00000000000000400000000000000840")), [1, 2, 3]); 448 | }); 449 | }); 450 | describe("char", function() { 451 | it("single", function() { 452 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000000f0000000a000100000061")), "a"); 453 | }); 454 | it("multi", function() { 455 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000100000000a00020000006162")), "ab"); 456 | }); 457 | it("unicode", function() { // "你好" 458 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000140000000a0006000000e4bda0e5a5bd")), "你好"); 459 | }); 460 | }); 461 | describe("symbol", function() { 462 | it("single", function() { 463 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000100000000b00010000006100")), ["a"]); 464 | }); 465 | it("multi", function() { 466 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000170000000b0003000000610061620061626300")), ["a", "ab", "abc"]); 467 | }); 468 | }); 469 | describe("timestamp", function() { 470 | describe("nanos2date", function() { 471 | describe("default", function() { 472 | it("single", function() { // 2014.06.23D11:34:39.412547000 473 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000160000000c0001000000b84d1d352d045706")), [new Date("2014-06-23T11:34:39.412")]); 474 | }); 475 | it("multi", function() { // 2014.06.23D11:34:39.412547000 476 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000260000000c0003000000b84d1d352d045706b84d5f3c96396006b84df0d493bd6906")), [new Date("2014-06-23T11:34:39.412"), new Date("2014-07-23T11:34:39.412"), new Date("2014-08-23T11:34:39.412")]); 477 | }); 478 | }); 479 | describe("true", function() { 480 | it("single", function() { // 2014.06.23D11:34:39.412547000 481 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000160000000c0001000000b84d1d352d045706"), true), [new Date("2014-06-23T11:34:39.412")]); 482 | }); 483 | it("multi", function() { // 2014.06.23D11:34:39.412547000 484 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000260000000c0003000000b84d1d352d045706b84d5f3c96396006b84df0d493bd6906"), true), [new Date("2014-06-23T11:34:39.412"), new Date("2014-07-23T11:34:39.412"), new Date("2014-08-23T11:34:39.412")]); 485 | }); 486 | }); 487 | describe("false", function() { 488 | it("single", function() { // 2014.06.23D11:34:39.412547000 489 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000160000000c0001000000b84d1d352d045706"), false), [1403523279412547000]); 490 | }); 491 | it("multi", function() { // 2014.06.23D11:34:39.412547000 492 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000260000000c0003000000b84d1d352d045706b84d5f3c96396006b84df0d493bd6906"), false), [1403523279412547000, 1406115279412547000, 1408793679412547000]); 493 | }); 494 | }); 495 | }); 496 | }); 497 | describe("month", function() { 498 | it("single", function() { // 1997.01m 499 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000120000000d0001000000dcffffff")), [new Date("1997-01-01T00:00:00.000")]); 500 | }); 501 | it("multi", function() { 502 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001a0000000d0003000000dcffffffe8fffffff4ffffff")), [new Date("1997-01-01T00:00:00.000"), new Date("1998-01-01T00:00:00.000"), new Date("1999-01-01T00:00:00.000")]); 503 | }); 504 | }); 505 | describe("date", function() { 506 | it("single", function() { // 1997.01.01 507 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000120000000e0001000000b9fbffff")), [new Date("1997-01-01T00:00:00.000")]); 508 | }); 509 | it("multi", function() { 510 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001a0000000e0003000000b9fbffff26fdffff93feffff")), [new Date("1997-01-01T00:00:00.000"), new Date("1998-01-01T00:00:00.000"), new Date("1999-01-01T00:00:00.000")]); 511 | }); 512 | }); 513 | describe("datetime", function() { 514 | it("single", function() { // 2001.01.01T00:00:00.000 515 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000160000000f00010000000000000000e07640")), [new Date("2001-01-01T00:00:00.000")]); 516 | }); 517 | it("multi", function() { 518 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000260000000f00030000000000000000e076400000000000d078400000000000907a40")), [new Date("2001-01-01T00:00:00.000"), new Date("2001-02-01T00:00:00.000"), new Date("2001-03-01T00:00:00.000")]); 519 | }); 520 | }); 521 | describe("timespan", function() { 522 | describe("nanos2date", function() { 523 | describe("default", function() { 524 | it("single", function() { // 00:01:00.000000000 525 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000016000000100001000000005847f80d000000")), [new Date("2000-01-01T00:01:00.000")]); 526 | }); 527 | it("multi", function() { // 00:01:00.000000000 528 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000026000000100003000000005847f80d00000000b08ef01b0000000008d6e829000000")), [new Date("2000-01-01T00:01:00.000"), new Date("2000-01-01T00:02:00.000"), new Date("2000-01-01T00:03:00.000")]); 529 | }); 530 | }); 531 | describe("true", function() { 532 | it("single", function() { // 00:01:00.000000000 533 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000016000000100001000000005847f80d000000"), true), [new Date("2000-01-01T00:01:00.000")]); 534 | }); 535 | it("multi", function() { // 00:01:00.000000000 536 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000026000000100003000000005847f80d00000000b08ef01b0000000008d6e829000000"), true), [new Date("2000-01-01T00:01:00.000"), new Date("2000-01-01T00:02:00.000"), new Date("2000-01-01T00:03:00.000")]); 537 | }); 538 | }); 539 | describe("false", function() { 540 | it("single", function() { // 00:01:00.000000000 541 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000016000000100001000000005847f80d000000"), false), [60000000000]); 542 | }); 543 | it("multi", function() { // 00:01:00.000000000 544 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000026000000100003000000005847f80d00000000b08ef01b0000000008d6e829000000"), false), [60000000000, 120000000000, 180000000000]); 545 | }); 546 | }); 547 | }); 548 | }); 549 | describe("minute", function() { 550 | it("single", function() { // 00:01 551 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001200000011000100000001000000")), [new Date("2000-01-01T00:01:00.000")]); 552 | }); 553 | it("multi", function() { 554 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001a000000110003000000010000000200000003000000")), [new Date("2000-01-01T00:01:00.000"), new Date("2000-01-01T00:02:00.000"), new Date("2000-01-01T00:03:00.000")]); 555 | }); 556 | }); 557 | describe("second", function() { 558 | it("single", function() { // 00:00:01 559 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001200000012000100000001000000")), [new Date("2000-01-01T00:00:01.000")]); 560 | }); 561 | it("multi", function() { 562 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001a000000120003000000010000000200000003000000")), [new Date("2000-01-01T00:00:01.000"), new Date("2000-01-01T00:00:02.000"), new Date("2000-01-01T00:00:03.000")]); 563 | }); 564 | }); 565 | describe("time", function() { 566 | it("single", function() { // 00:00:00.001 567 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001200000013000100000001000000")), [new Date("2000-01-01T00:00:00.001")]); 568 | }); 569 | it("multi", function() { 570 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001a000000130003000000010000000200000003000000")), [new Date("2000-01-01T00:00:00.001"), new Date("2000-01-01T00:00:00.002"), new Date("2000-01-01T00:00:00.003")]); 571 | }); 572 | }); 573 | }); 574 | describe("dict", function() { 575 | it("empty", function() { 576 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001500000063000000000000000000000000")), {}); 577 | }); 578 | it("single entry", function() { 579 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000001f000000630b000100000061000700010000000100000000000000")), {a: 1}); 580 | }); 581 | it("multiple entries same type", function() { 582 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000033000000630b0003000000610062006300070003000000010000000000000002000000000000000300000000000000")), {a: 1, b: 2, c: 3}); 583 | }); 584 | it("multiple entries different types", function() { 585 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000002f000000630b0003000000610062006300000003000000f90100000000000000ff01f70000000000000840")), {a: 1, b: true, c: 3}); 586 | }); 587 | it("multiple entries, null values", function() { 588 | assert.deepEqual(c.deserialize(hexstr_to_bin("0100000021000000630b0003000000610062006300000003000000650065006500")), {a: null, b: null, c: null}); 589 | }); 590 | }); 591 | describe("table", function() { 592 | describe("flipTables", function() { 593 | describe("default", function() { 594 | it("multiple rows", function() { 595 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000620000006200630b0003000000610062006300000003000000070003000000010000000000000002000000000000000300000000000000010003000000010001090003000000000000000000f03f00000000000000400000000000000840")), [{a: 1, b: true, c: 1}, {a: 2, b: false, c: 2}, {a: 3, b: true, c: 3}]); 596 | }); 597 | it("no rows", function() { 598 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000002f0000006200630b0003000000610062006300000003000000070000000000010000000000090000000000")), []); 599 | }); 600 | }); 601 | describe("true", function() { 602 | it("multiple rows", function() { 603 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000620000006200630b0003000000610062006300000003000000070003000000010000000000000002000000000000000300000000000000010003000000010001090003000000000000000000f03f00000000000000400000000000000840"), undefined, true), [{a: 1, b: true, c: 1}, {a: 2, b: false, c: 2}, {a: 3, b: true, c: 3}]); 604 | }); 605 | it("no rows", function() { 606 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000002f0000006200630b0003000000610062006300000003000000070000000000010000000000090000000000"), undefined, true), []); 607 | }); 608 | }); 609 | describe("false", function() { 610 | it("multiple rows", function() { 611 | assert.deepEqual(c.deserialize(hexstr_to_bin("01000000620000006200630b0003000000610062006300000003000000070003000000010000000000000002000000000000000300000000000000010003000000010001090003000000000000000000f03f00000000000000400000000000000840"), undefined, false), {a: [1, 2, 3], b: [true, false, true], c: [1, 2, 3]}); 612 | }); 613 | it("no rows", function() { 614 | assert.deepEqual(c.deserialize(hexstr_to_bin("010000002f0000006200630b0003000000610062006300000003000000070000000000010000000000090000000000"), undefined, false), {a: [], b: [], c: []}); 615 | }); 616 | }); 617 | }); 618 | }); 619 | }); 620 | }); 621 | describe("serialize", function() { 622 | describe("infer type", function() { 623 | describe("little", function() { 624 | it("Boolean", function() { 625 | assert.equal(bin_to_hexstr(c.serialize(true)), "010000000a000000ff01"); 626 | }); 627 | it("symbol length 1", function() { 628 | assert.equal(bin_to_hexstr(c.serialize("`a")), "010000000b000000f56100"); 629 | }); 630 | it("symbol unicode length 1", function() { 631 | assert.equal(bin_to_hexstr(c.serialize("`你")), "010000000d000000f5e4bda000"); 632 | }); 633 | it("symbol unicode length 2", function() { 634 | assert.equal(bin_to_hexstr(c.serialize("`你好")), "0100000010000000f5e4bda0e5a5bd00"); 635 | }); 636 | it("symbol length 2", function() { // `ab 637 | assert.equal(bin_to_hexstr(c.serialize("`ab")), "010000000c000000f5616200"); 638 | }); 639 | it("symbol length 3", function() { // `abc 640 | assert.equal(bin_to_hexstr(c.serialize("`abc")), "010000000d000000f561626300"); 641 | }); 642 | it("symbol length 4", function() { // `abcd 643 | assert.equal(bin_to_hexstr(c.serialize("`abcd")), "010000000e000000f56162636400"); 644 | }); 645 | it("symbol length 5", function() { // `abcde 646 | assert.equal(bin_to_hexstr(c.serialize("`abcde")), "010000000f000000f5616263646500"); 647 | }); 648 | it("String", function() { 649 | assert.equal(bin_to_hexstr(c.serialize("abc")), "01000000110000000a0003000000616263"); 650 | }); 651 | it("Number", function() { 652 | assert.equal(bin_to_hexstr(c.serialize(1.0)), "0100000011000000f7000000000000f03f"); 653 | }); 654 | it("Date", function() { 655 | assert.equal(bin_to_hexstr(c.serialize(new Date("2014-06-23T11:49:31.533"))), "0100000011000000f1facf4b237ea7b440"); 656 | }); 657 | describe("Object", function() { 658 | it("one key", function() { 659 | assert.equal(bin_to_hexstr(c.serialize({a: 1})), "010000001f000000630b00010000006100090001000000000000000000f03f"); 660 | }); 661 | it("one key, null value", function() { 662 | assert.equal(bin_to_hexstr(c.serialize({a: null})), "0100000019000000630b000100000061000000010000006500"); 663 | }); 664 | it("multiple keys, same value type", function() { 665 | assert.equal(bin_to_hexstr(c.serialize({a: 1, b: 2, c: 3})), "0100000033000000630b0003000000610062006300090003000000000000000000f03f00000000000000400000000000000840"); 666 | }); 667 | it("multiple keys, different value types", function() { 668 | assert.equal(bin_to_hexstr(c.serialize({a: 1, b: true, c: 3})), "010000002f000000630b0003000000610062006300000003000000f7000000000000f03fff01f70000000000000840"); 669 | }); 670 | it("multiple keys, null value", function() { 671 | assert.equal(bin_to_hexstr(c.serialize({a: null, b: null, c: null})), "0100000021000000630b0003000000610062006300000003000000650065006500"); 672 | }); 673 | }); 674 | describe("Array", function() { 675 | it("empty", function() { 676 | assert.equal(bin_to_hexstr(c.serialize([])), "010000000e000000000000000000"); 677 | }); 678 | it("one element", function() { 679 | assert.equal(bin_to_hexstr(c.serialize([1])), "0100000016000000090001000000000000000000f03f"); 680 | }); 681 | it("multiple elements, same types", function() { 682 | assert.equal(bin_to_hexstr(c.serialize([1, 2, 3])), "0100000026000000090003000000000000000000f03f00000000000000400000000000000840"); 683 | }); 684 | it("multiple elements, different types", function() { 685 | assert.equal(bin_to_hexstr(c.serialize([1, true, 3])), "0100000022000000000003000000f7000000000000f03fff01f70000000000000840"); 686 | }); 687 | it("Array of Array same type", function() { 688 | assert.equal(bin_to_hexstr(c.serialize([[1, 2, 3]])), "010000002c000000000001000000090003000000000000000000f03f00000000000000400000000000000840"); 689 | }); 690 | it("Array of Array different types", function() { 691 | assert.equal(bin_to_hexstr(c.serialize([[1, true, 3]])), "0100000028000000000001000000000003000000f7000000000000f03fff01f70000000000000840"); 692 | }); 693 | it("one null", function() { 694 | assert.equal(bin_to_hexstr(c.serialize([null])), "01000000100000000000010000006500"); 695 | }); 696 | it("three nulls", function() { 697 | assert.equal(bin_to_hexstr(c.serialize([null, null, null])), "0100000014000000000003000000650065006500"); 698 | }); 699 | }); 700 | it("Null", function() { 701 | assert.equal(bin_to_hexstr(c.serialize(null)), "010000000a0000006500"); 702 | }); 703 | it("Infinity", function() { 704 | assert.equal(bin_to_hexstr(c.serialize(Infinity)), "0100000011000000f7000000000000f07f"); 705 | }); 706 | it("-Infinity", function() { 707 | assert.equal(bin_to_hexstr(c.serialize(-Infinity)), "0100000011000000f7000000000000f0ff"); 708 | }); 709 | }); 710 | }); 711 | describe("typed", function() { 712 | describe("little", function() { 713 | describe("primitives", function() { 714 | it("boolean", function() { // 1b 715 | assert.equal(bin_to_hexstr(c.serialize(typed.boolean(true))), "010000000a000000ff01"); 716 | }); 717 | describe("guid", function() { 718 | it("guid", function() { // 0a369037-75d3-b24d-6721-5a1d44d4bed5 719 | assert.equal(bin_to_hexstr(c.serialize(typed.guid("0a369037-75d3-b24d-6721-5a1d44d4bed5"))), "0100000019000000fe0a36903775d3b24d67215a1d44d4bed5"); 720 | }); 721 | it("null", function() { // 0Ng 722 | assert.equal(bin_to_hexstr(c.serialize(typed.guid(null))), "0100000019000000fe00000000000000000000000000000000"); 723 | }); 724 | }); 725 | it("byte", function() { // 0x01 726 | assert.equal(bin_to_hexstr(c.serialize(typed.byte(1))), "010000000a000000fc01"); 727 | }); 728 | describe("short", function() { 729 | it("1", function() { // 1h 730 | assert.equal(bin_to_hexstr(c.serialize(typed.short(1))), "010000000b000000fb0100"); 731 | }); 732 | it("-1", function() { // -1h 733 | assert.equal(bin_to_hexstr(c.serialize(typed.short(-1))), "010000000b000000fbffff"); 734 | }); 735 | it("null", function() { // 0Nh 736 | assert.equal(bin_to_hexstr(c.serialize(typed.short(null))), "010000000b000000fb0080"); 737 | }); 738 | it("Infinity", function() { // 0wh 739 | assert.equal(bin_to_hexstr(c.serialize(typed.short(Infinity))), "010000000b000000fbff7f"); 740 | }); 741 | it("-Infinity", function() { // -0wh 742 | assert.equal(bin_to_hexstr(c.serialize(typed.short(-Infinity))), "010000000b000000fb0180"); 743 | }); 744 | }); 745 | describe("integer", function() { 746 | it("1", function() { // 1i 747 | assert.equal(bin_to_hexstr(c.serialize(typed.int(1))), "010000000d000000fa01000000"); 748 | }); 749 | it("-1", function() { // -1i 750 | assert.equal(bin_to_hexstr(c.serialize(typed.int(-1))), "010000000d000000faffffffff"); 751 | }); 752 | it("null", function() { // 0Ni 753 | assert.equal(bin_to_hexstr(c.serialize(typed.int(null))), "010000000d000000fa00000080"); 754 | }); 755 | it("Infinity", function() { // 0wi 756 | assert.equal(bin_to_hexstr(c.serialize(typed.int(Infinity))), "010000000d000000faffffff7f"); 757 | }); 758 | it("-Infinity", function() { // -0wi 759 | assert.equal(bin_to_hexstr(c.serialize(typed.int(-Infinity))), "010000000d000000fa01000080"); 760 | }); 761 | }); 762 | describe("long", function() { 763 | it("1", function() { // 1j 764 | assert.equal(bin_to_hexstr(c.serialize(typed.long(Long.fromString("1", false, 10)))), "0100000011000000f90100000000000000"); 765 | }); 766 | it("-1", function() { // -1j 767 | assert.equal(bin_to_hexstr(c.serialize(typed.long(Long.fromString("-1", false, 10)))), "0100000011000000f9ffffffffffffffff"); 768 | }); 769 | it("2147483647", function() { // 2147483647j 770 | assert.equal(bin_to_hexstr(c.serialize(typed.long(Long.fromString("2147483647", false, 10)))), "0100000011000000f9ffffff7f00000000"); 771 | }); 772 | it("2147483648", function() { // 2147483648j 773 | assert.equal(bin_to_hexstr(c.serialize(typed.long(Long.fromString("2147483648", false, 10)))), "0100000011000000f90000008000000000"); 774 | }); 775 | it("2147483649", function() { // 2147483649j 776 | assert.equal(bin_to_hexstr(c.serialize(typed.long(Long.fromString("2147483649", false, 10)))), "0100000011000000f90100008000000000"); 777 | }); 778 | it("4294967295", function() { // 4294967295j 779 | assert.equal(bin_to_hexstr(c.serialize(typed.long(Long.fromString("4294967295", false, 10)))), "0100000011000000f9ffffffff00000000"); 780 | }); 781 | it("4294967296", function() { // 4294967296j 782 | assert.equal(bin_to_hexstr(c.serialize(typed.long(Long.fromString("4294967296", false, 10)))), "0100000011000000f90000000001000000"); 783 | }); 784 | it("4294967297", function() { // 4294967297j 785 | assert.equal(bin_to_hexstr(c.serialize(typed.long(Long.fromString("4294967297", false, 10)))), "0100000011000000f90100000001000000"); 786 | }); 787 | it("null", function() { // 0Nj 788 | assert.equal(bin_to_hexstr(c.serialize(typed.long(null))), "0100000011000000f90000000000000080"); 789 | }); 790 | it("Infinity", function() { // 0wj 791 | assert.equal(bin_to_hexstr(c.serialize(typed.long(Infinity))), "0100000011000000f9ffffffffffffff7f"); 792 | }); 793 | it("-Infinity", function() { // -0wj 794 | assert.equal(bin_to_hexstr(c.serialize(typed.long(-Infinity))), "0100000011000000f90100000000000080"); 795 | }); 796 | }); 797 | describe("real", function() { 798 | it("1", function() { // 1e 799 | assert.equal(bin_to_hexstr(c.serialize(typed.real(1.0))), "010000000d000000f80000803f"); 800 | }); 801 | it("-1", function() { // -1e 802 | assert.equal(bin_to_hexstr(c.serialize(typed.real(-1.0))), "010000000d000000f8000080bf"); 803 | }); 804 | it("null", function() { // 0Ne 805 | assert.equal(bin_to_hexstr(c.serialize(typed.real(null))), "010000000d000000f80000c0ff"); 806 | }); 807 | it("Infinity", function() { // 0we 808 | assert.equal(bin_to_hexstr(c.serialize(typed.real(Infinity))), "010000000d000000f80000807f"); 809 | }); 810 | it("-Infinity", function() { // -0we 811 | assert.equal(bin_to_hexstr(c.serialize(typed.real(-Infinity))), "010000000d000000f8000080ff"); 812 | }); 813 | }); 814 | describe("float", function() { 815 | it("1", function() { // 1f 816 | assert.equal(bin_to_hexstr(c.serialize(typed.float(1.0))), "0100000011000000f7000000000000f03f"); 817 | }); 818 | it("-1", function() { // -1f 819 | assert.equal(bin_to_hexstr(c.serialize(typed.float(-1.0))), "0100000011000000f7000000000000f0bf"); 820 | }); 821 | it("null", function() { // 0Nf 822 | assert.equal(bin_to_hexstr(c.serialize(typed.float(null))), "0100000011000000f7000000000000f8ff"); 823 | }); 824 | it("Infinity", function() { // 0wf 825 | assert.equal(bin_to_hexstr(c.serialize(typed.float(Infinity))), "0100000011000000f7000000000000f07f"); 826 | }); 827 | it("-Infinity", function() { // -0wf 828 | assert.equal(bin_to_hexstr(c.serialize(typed.float(-Infinity))), "0100000011000000f7000000000000f0ff"); 829 | }); 830 | }); 831 | describe("char", function() { 832 | it("a", function() { // "a" 833 | assert.equal(bin_to_hexstr(c.serialize(typed.char("a"))), "010000000a000000f661"); 834 | }); 835 | it("null", function() { // " " 836 | assert.equal(bin_to_hexstr(c.serialize(typed.char(null))), "010000000a000000f620"); 837 | }); 838 | }); 839 | describe("symbol", function() { 840 | it("length 1", function() { // `a 841 | assert.equal(bin_to_hexstr(c.serialize(typed.symbol("a"))), "010000000b000000f56100"); 842 | }); 843 | it("unicode", function() { // `你 844 | assert.equal(bin_to_hexstr(c.serialize(typed.symbol("你"))), "010000000d000000f5e4bda000"); 845 | }); 846 | it("null", function() { // ` 847 | assert.equal(bin_to_hexstr(c.serialize(typed.symbol(null))), "010000000a000000f500"); 848 | }); 849 | it("length 2", function() { // `ab 850 | assert.equal(bin_to_hexstr(c.serialize(typed.symbol("ab"))), "010000000c000000f5616200"); 851 | }); 852 | it("length 3", function() { // `abc 853 | assert.equal(bin_to_hexstr(c.serialize(typed.symbol("abc"))), "010000000d000000f561626300"); 854 | }); 855 | it("length 4", function() { // `abcd 856 | assert.equal(bin_to_hexstr(c.serialize(typed.symbol("abcd"))), "010000000e000000f56162636400"); 857 | }); 858 | it("length 5", function() { // `abcde 859 | assert.equal(bin_to_hexstr(c.serialize(typed.symbol("abcde"))), "010000000f000000f5616263646500"); 860 | }); 861 | }); 862 | describe("timestamp", function() { 863 | it("timestamp", function() { // 2014.06.23D11:34:39.412000000 864 | assert.equal(bin_to_hexstr(c.serialize(typed.timestamp(new Date("2014-06-23T11:34:39.412000000")))), "0100000011000000f400f514352d045706"); 865 | }); 866 | it("null", function() { // 0Np 867 | assert.equal(bin_to_hexstr(c.serialize(typed.timestamp(null))), "0100000011000000f40000000000000080"); 868 | }); 869 | }); 870 | describe("month", function() { 871 | it("201401", function() { // 2014.01m 872 | assert.equal(bin_to_hexstr(c.serialize(typed.month(new Date("2014-01-01")))), "010000000d000000f3a8000000"); 873 | }); 874 | it("null", function() { // 0Nm 875 | assert.equal(bin_to_hexstr(c.serialize(typed.month(null))), "010000000d000000f300000080"); 876 | }); 877 | it("199501", function() { // 1995.01m 878 | assert.equal(bin_to_hexstr(c.serialize(typed.month(new Date("1995-01-01")))), "010000000d000000f3c4ffffff"); 879 | }); 880 | }); 881 | describe("date", function() { 882 | it("20140101", function() { // 2014.01.01 883 | assert.equal(bin_to_hexstr(c.serialize(typed.date(new Date("2014-01-01")))), "010000000d000000f2fa130000"); 884 | }); 885 | it("null", function() { // 0Nd 886 | assert.equal(bin_to_hexstr(c.serialize(typed.date(null))), "010000000d000000f200000080"); 887 | }); 888 | it("19950101", function() { // 1995.01.01 889 | assert.equal(bin_to_hexstr(c.serialize(typed.date(new Date("1995-01-01")))), "010000000d000000f2def8ffff"); 890 | }); 891 | }); 892 | describe("datetime", function() { 893 | it("datetime", function() { // 2014.06.23T11:49:31.533 894 | assert.equal(bin_to_hexstr(c.serialize(typed.datetime(new Date("2014-06-23T11:49:31.533")))), "0100000011000000f1facf4b237ea7b440"); 895 | }); 896 | it("null", function() { // 0Nz 897 | assert.equal(bin_to_hexstr(c.serialize(typed.datetime(null))), "0100000011000000f1000000000000f8ff"); 898 | }); 899 | }); 900 | describe("timespan", function() { 901 | it("timespan", function() { // 00:01:00.000000000 902 | assert.equal(bin_to_hexstr(c.serialize(typed.timespan(new Date("2000-01-01T00:01:00.000")))), "0100000011000000f0005847f80d000000"); 903 | }); 904 | it("null", function() { // 0Nn 905 | assert.equal(bin_to_hexstr(c.serialize(typed.timespan(null))), "0100000011000000f00000000000000080"); 906 | }); 907 | }); 908 | describe("minute", function() { 909 | it("minute", function() { // 00:01 910 | assert.equal(bin_to_hexstr(c.serialize(typed.minute(new Date("2000-01-01T00:01:00.000")))), "010000000d000000ef01000000"); 911 | }); 912 | it("null", function() { // 0Nu 913 | assert.equal(bin_to_hexstr(c.serialize(typed.minute(null))), "010000000d000000ef00000080"); 914 | }); 915 | }); 916 | describe("second", function() { 917 | it("second", function() { // 00:00:01 918 | assert.equal(bin_to_hexstr(c.serialize(typed.second(new Date("2000-01-01T00:00:01.000")))), "010000000d000000ee01000000"); 919 | }); 920 | it("null", function() { // 0Nv 921 | assert.equal(bin_to_hexstr(c.serialize(typed.second(null))), "010000000d000000ee00000080"); 922 | }); 923 | }); 924 | describe("time", function() { 925 | it("time", function() { // 00:00:00.001 926 | assert.equal(bin_to_hexstr(c.serialize(typed.time(new Date("2000-01-01T00:00:00.001")))), "010000000d000000ed01000000"); 927 | }); 928 | it("null", function() { // 0Nt 929 | assert.equal(bin_to_hexstr(c.serialize(typed.time(null))), "010000000d000000ed00000080"); 930 | }); 931 | }); 932 | }); 933 | describe("list", function() { 934 | describe("generic", function() { 935 | it("two values", function() { 936 | assert.equal(bin_to_hexstr(c.serialize([typed.boolean(true), typed.float(1)])), "0100000019000000000002000000ff01f7000000000000f03f"); 937 | }); 938 | it("three values", function() { // (1l;1b;`a) 939 | assert.equal(bin_to_hexstr(c.serialize([typed.long(Long.fromString("1", false, 10)), typed.boolean(true), typed.symbol("a")])), "010000001c000000000003000000f90100000000000000ff01f56100"); 940 | }); 941 | it("list of list", function() { 942 | assert.equal(bin_to_hexstr(c.serialize([typed.bytes([0, 1, 2, 3, 4])])), "01000000190000000000010000000400050000000001020304"); 943 | }); 944 | }); 945 | describe("typed", function() { 946 | it("boolean", function() { 947 | assert.equal(bin_to_hexstr(c.serialize(typed.booleans([true, false]))), "01000000100000000100020000000100"); 948 | }); 949 | it("guid", function() { 950 | assert.equal(bin_to_hexstr(c.serialize(typed.guids(["0a369037-75d3-b24d-6721-5a1d44d4bed5", "0a369037-75d3-b24d-6721-5a1d44d4bed5"]))), "010000002e0000000200020000000a36903775d3b24d67215a1d44d4bed50a36903775d3b24d67215a1d44d4bed5"); 951 | }); 952 | it("byte", function() { 953 | assert.equal(bin_to_hexstr(c.serialize(typed.bytes([0, 1, 2, 3, 4]))), "01000000130000000400050000000001020304"); 954 | }); 955 | it("short", function() { 956 | assert.equal(bin_to_hexstr(c.serialize(typed.shorts([1, 2, 3]))), "0100000014000000050003000000010002000300"); 957 | }); 958 | it("1 integer", function() { 959 | assert.equal(bin_to_hexstr(c.serialize(typed.ints([1]))), "010000001200000006000100000001000000"); 960 | }); 961 | it("3 integers", function() { 962 | assert.equal(bin_to_hexstr(c.serialize(typed.ints([1, 2, 3]))), "010000001a000000060003000000010000000200000003000000"); 963 | }); 964 | it("long", function() { // 965 | assert.equal(bin_to_hexstr(c.serialize(typed.longs([Long.fromString("1", false, 10), Long.fromString("2", false, 10), Long.fromString("3", false, 10)]))), "0100000026000000070003000000010000000000000002000000000000000300000000000000"); 966 | }); 967 | it("real", function() { // 968 | assert.equal(bin_to_hexstr(c.serialize(typed.reals([1.0, 2.0, 3.0]))), "010000001a0000000800030000000000803f0000004000004040"); 969 | }); 970 | it("float", function() { // 971 | assert.equal(bin_to_hexstr(c.serialize(typed.floats([1.0, 2.0, 3.0]))), "0100000026000000090003000000000000000000f03f00000000000000400000000000000840"); 972 | }); 973 | it("char", function() { // 974 | assert.equal(bin_to_hexstr(c.serialize(typed.chars(["a", "b", "c"]))), "01000000110000000a0003000000616263"); 975 | }); 976 | it("symbol", function() { // 977 | assert.equal(bin_to_hexstr(c.serialize(typed.symbols(["a", "ab", "abc"]))), "01000000170000000b0003000000610061620061626300"); 978 | }); 979 | it("timestamp", function() { // (2014.01.01D12:00:00.000000000;2014.01.02D12:00:00.000000000;2014.01.03D12:00:00.000000000) 980 | assert.equal(bin_to_hexstr(c.serialize(typed.timestamps([new Date("2014-01-01T12:00:00.000000000"), new Date("2014-01-02T12:00:00.00000000"), new Date("2014-01-03T12:00:00.000000000")]))), "01000000260000000c00030000000080cd0c29eb210600801c9ebd39220600806b2f52882206"); 981 | }); 982 | it("month", function() { // (1995.01m;1995.02m;1995.03m) 983 | assert.equal(bin_to_hexstr(c.serialize(typed.months([new Date("1995-01-01"), new Date("1995-02-01"), new Date("1995-03-01")]))), "010000001a0000000d0003000000c4ffffffc5ffffffc6ffffff"); 984 | }); 985 | it("date", function() { // (2014.01.01;2014.01.02;2014.01.03) 986 | assert.equal(bin_to_hexstr(c.serialize(typed.dates([new Date("2014-01-01"), new Date("2014-01-02"), new Date("2014-01-03")]))), "010000001a0000000e0003000000fa130000fb130000fc130000"); 987 | }); 988 | it("datetime", function() { // (2014.06.23T11:49:31.533;2014.06.23T11:49:31.534;2014.06.23T11:49:31.535) 989 | assert.equal(bin_to_hexstr(c.serialize(typed.datetimes([new Date("2014-06-23T11:49:31.533"), new Date("2014-06-23T11:49:31.534"), new Date("2014-06-23T11:49:31.535")]))), "01000000260000000f0003000000facf4b237ea7b440b0014c237ea7b44066334c237ea7b440"); 990 | }); 991 | it("timespan", function() { // (00:01:00.000000000;00:02:00.000000000;00:03:00.000000000) 992 | assert.equal(bin_to_hexstr(c.serialize(typed.timespans([new Date("2000-01-01T00:01:00.000"), new Date("2000-01-01T00:02:00.000"), new Date("2000-01-01T00:03:00.000")]))), "0100000026000000100003000000005847f80d00000000b08ef01b0000000008d6e829000000"); 993 | }); 994 | it("minute", function() { // (00:01;00:02;00:03) 995 | assert.equal(bin_to_hexstr(c.serialize(typed.minutes([new Date("2000-01-01T00:01:00.000"), new Date("2000-01-01T00:02:00.000"), new Date("2000-01-01T00:03:00.000")]))), "010000001a000000110003000000010000000200000003000000"); 996 | }); 997 | it("second", function() { // (00:00:01;00:00:02;00:00:03) 998 | assert.equal(bin_to_hexstr(c.serialize(typed.seconds([new Date("2000-01-01T00:00:01.000"), new Date("2000-01-01T00:00:02.000"), new Date("2000-01-01T00:00:03.000")]))), "010000001a000000120003000000010000000200000003000000"); 999 | }); 1000 | it("time", function() { // (00:00:00.001;00:00:00.002;00:00:00.003) 1001 | assert.equal(bin_to_hexstr(c.serialize(typed.times([new Date("2000-01-01T00:00:00.001"), new Date("2000-01-01T00:00:00.002"), new Date("2000-01-01T00:00:00.003")]))), "010000001a000000130003000000010000000200000003000000"); 1002 | }); 1003 | }); 1004 | }); 1005 | it("mixedlist", function() { // (1j;1b;3h) 1006 | assert.equal(bin_to_hexstr(c.serialize(typed.mixedlist([typed.long(Long.fromString("1", false, 10)), typed.boolean(true), typed.short(3)]))), "010000001c000000000003000000f90100000000000000ff01fb0300"); 1007 | }); 1008 | describe("dict", function() { 1009 | it("one key", function() { 1010 | assert.equal(bin_to_hexstr(c.serialize(typed.dict({a: typed.byte(1)}))), "0100000018000000630b0001000000610004000100000001"); 1011 | }); 1012 | it("multiple keys, same value type", function() { 1013 | assert.equal(bin_to_hexstr(c.serialize(typed.dict({a: typed.long(Long.fromString("1", false, 10)), b: typed.long(Long.fromString("2", false, 10)), c: typed.long(Long.fromString("3", false, 10))}))), "0100000033000000630b0003000000610062006300070003000000010000000000000002000000000000000300000000000000"); 1014 | }); 1015 | it("multiple keys, different value types", function() { 1016 | assert.equal(bin_to_hexstr(c.serialize(typed.dict({a: typed.long(Long.fromString("1", false, 10)), b: typed.boolean(true), c: typed.float(3)}))), "010000002f000000630b0003000000610062006300000003000000f90100000000000000ff01f70000000000000840"); 1017 | }); 1018 | }); 1019 | // TODO test serialize table 1020 | }); 1021 | }); 1022 | }); 1023 | }); 1024 | -------------------------------------------------------------------------------- /test/compress.js: -------------------------------------------------------------------------------- 1 | var c = require("../lib/c.js"), 2 | typed = require("../lib/typed.js"), 3 | moment = require("moment"), 4 | assert = require("assert"), 5 | Long = require("long"); 6 | 7 | function hexstr_to_bin(str) { 8 | "use strict"; 9 | return new Buffer(str, "hex"); 10 | } 11 | 12 | function bin_to_hexstr(b) { 13 | "use strict"; 14 | return b.toString("hex"); 15 | } 16 | 17 | // use -18! in q to get the compressed byte representation 18 | 19 | describe("compress", function() { 20 | "use strict"; 21 | describe("deserialize", function() { 22 | describe("little", function() { 23 | describe("list", function() { 24 | it("booleans", function() { 25 | assert.equal(c.deserialize(hexstr_to_bin("01000100680000001e270000000100102700000101ff00ff00ff00ff00ff00ff00ff00ff00ffff00ff00ff00ff00ff00ff00ff00ff00ffff00ff00ff00ff00ff00ff00ff00ff00ffff00ff00ff00ff00ff00ff00ff00ff00ff7f00ff00ff00ff00ff00ff00ff00e6")).length, 10000); 26 | }); 27 | it("guid", function() { 28 | assert.equal(c.deserialize(hexstr_to_bin("01000100b60000008e3e0000000200e803000042d8008ac824e2f268a5be80629cacef657f4252ffef42ffecffc6ff10fff2cdff1bffdcffbffeff30ff43ff8aff1aff3dff4252ffef42ffecffc6ff10fff2cdff1bffdcffbffeff30ff43ff8aff1aff3dff4252ffef42ffecffc6ff10fff2cdff1bffdcffbffeff30ff43ff8aff1aff3dff4252ffef42ffecffc6ff10fff2cdff1bffdcffbffeff30ff43ff8aff1aff3dff4252ff6f42ffecffc6ff10fff2cdff1b26")).length, 1000); 29 | }); 30 | it("byte", function() { 31 | assert.equal(c.deserialize(hexstr_to_bin("01000100680000001e270000000400102700000101ff00ff00ff00ff00ff00ff00ff00ff00ffff00ff00ff00ff00ff00ff00ff00ff00ffff00ff00ff00ff00ff00ff00ff00ff00ffff00ff00ff00ff00ff00ff00ff00ff00ff7f00ff00ff00ff00ff00ff00ff00e6")).length, 10000); 32 | }); 33 | it("short", function() { 34 | assert.equal(c.deserialize(hexstr_to_bin("01000100110100002e4e0000800500102700000101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ffaa0101ff0101ff0101ff0101ff02010183")).length, 10000); 35 | }); 36 | it("integer", function() { 37 | assert.equal(c.deserialize(hexstr_to_bin("0100010054000000ae0f0000800600e8030000010000be0001ff00ff000001ff00000001ffef00ff000001ff00000001ff00ff0000fb01ff00000001ff00ff000001ff0000be0001ff00ff000001ff0000000172")).length, 1000); 38 | }); 39 | it("long", function() { 40 | assert.equal(c.deserialize(hexstr_to_bin("01000100da0000004e1f0000800700e8030000010000ff000301ff0003000001ff0000000301ffff0003000001ff0000000301ff00030000ff01ff0000000301ff0003000001ff0000ff000301ff0003000001ff0000000301ffff0003000001ff0000000301ff00030000ff01ff0000000301ff0003000001ff0000ff000301ff0003000001ff0000000301ffff0003000001ff0000000301ff00030000ff01ff0000000301ff0003000001ff0000ff000301ff0003000001ff0000000301ffff0003000001ff0000000301ff000300000f01ff000000030146")).length, 1000); 41 | }); 42 | it("real", function() { 43 | assert.equal(c.deserialize(hexstr_to_bin("010001003b000000ae0f0000400800e8030000000080fa3f00ff00bfff3fff00ff80ffbfffff3fff00ff80ffbfff3fff00ff80ffbfff033fff008a")).length, 1000); 44 | }); 45 | it("float", function() { 46 | assert.equal(c.deserialize(hexstr_to_bin("01000100720000004e1f0000400900e80300000004f0be3f00ff0003cfff3fff000300cfffff3fff00ff0003cfff3fff0003f0ffcfffff3fff00ff0003cfff3fff0003f0ffcfffff3fff00ff0003cfff3fff0003f0ffcfffff3fff00ff0003cfff3fff0003f0ffcfff0f3fff00ff0003cfe0")).length, 1000); 47 | }); 48 | //it("char", function() { no compression? 49 | //}); 50 | it("symbol", function() { 51 | assert.equal(c.deserialize(hexstr_to_bin("010001002d000000de070000800b00e80300006161ffaa6161ff6161ff6161ff6161ff2a6161ff6161ff6161bf")).length, 1000); 52 | }); 53 | it("timestamp", function() { 54 | assert.equal(c.deserialize(hexstr_to_bin("01000100600000004e1f0000000c00e8030000c087c0ff599c3c1a0747ff78ffffa6ffc5ffa0ff26ff1dffc7ff47ff78ffffa6ffc5ffa0ff26ff1dffc7ff47ff78ffffa6ffc5ffa0ff26ff1dffc7ff47ff78ff3fa6ffc5ffa0ff26ff1dffc717")).length, 1000); 55 | }); 56 | it("month", function() { 57 | assert.equal(c.deserialize(hexstr_to_bin("010001008c0000004e1f0000000900e80300006666f10001789f4000010000e7ffdfffff26ff00000001e7ffdfff26ff00010000ffe7ffdfff26ff00000001e7ffdfff26ffff00010000e7ffdfff26ff00000001e7ffffdfff26ff00010000e7ffdfff26ff0000ff0001e7ffdfff26ff00010000e7ffdfffff26ff00000001e7ffdfff26ff0001000001e7e1")).length, 1000); 58 | }); 59 | it("date", function() { 60 | assert.equal(c.deserialize(hexstr_to_bin("0100010037000000ae0f0000000e00e80300000b15ff00ff0bff1eff15ff00ff0bff1eff15ffff00ff0bff1eff15ff00ff0bff1eff158d")).length, 1000); 61 | }); 62 | it("datetime", function() { 63 | assert.equal(c.deserialize(hexstr_to_bin("01000100600000004e1f0000000f00e8030000facfc04b237ea7b44035ff84ffff68ff5dffd9ff13fff4ffbaff35ff84ffff68ff5dffd9ff13fff4ffbaff35ff84ffff68ff5dffd9ff13fff4ffbaff35ff84ff3f68ff5dffd9ff13fff4ffba17")).length, 1000); 64 | }); 65 | it("minute", function() { 66 | assert.equal(c.deserialize(hexstr_to_bin("0100010054000000ae0f0000801100e8030000010000be0001ff00ff000001ff00000001ffef00ff000001ff00000001ff00ff0000fb01ff00000001ff00ff000001ff0000be0001ff00ff000001ff0000000172")).length, 1000); 67 | }); 68 | it("second", function() { 69 | assert.equal(c.deserialize(hexstr_to_bin("0100010054000000ae0f0000801200e8030000010000be0001ff00ff000001ff00000001ffef00ff000001ff00000001ff00ff0000fb01ff00000001ff00ff000001ff0000be0001ff00ff000001ff0000000172")).length, 1000); 70 | }); 71 | it("time", function() { 72 | assert.equal(c.deserialize(hexstr_to_bin("0100010054000000ae0f0000801300e8030000010000be0001ff00ff000001ff00000001ffef00ff000001ff00000001ff00ff0000fb01ff00000001ff00ff000001ff0000be0001ff00ff000001ff0000000172")).length, 1000); 73 | }); 74 | }); 75 | it("dict", function() { 76 | assert.equal(Object.keys(c.deserialize(hexstr_to_bin("0100010099010000055e000000630b00060000006100006200630064006514006600000006020900f4a60100010003f03f000300cfffff3fff00ff0003cfff3fff0003f0ffcfffff3fff00ff0003cfff3fff0003f0ffcfffff3fff00ff0003cf6809ff0001cf680001ff0001cfff3fff00010001cfff3fff0001ff0001cfff3fff00010001cfff3fff0001ff0001cfff3fff00010001cfff3fff0001ff0001cfff3fff09ff00ff0000cfff3fffff00000002cfff3fff00020000cfff3fffff00000002cfff3fff00020000cfff3fffff00000002cfff3fff00020000cfff3f6fff09ff0000f0ffcfff3f6f00010001cfffff3fff00010001cfff3fff00010001cfffff3fff00010001cfff3fff00010001cfffff3fff00010001cfff3fff09ff00ff0000ffcfff3fff00000002cfff3fff00020000ffcfff3fff00000002cfff3fff00020000ffcfff3fff00000002cfff3fff00020000ffcfff3f6f09ff0000f0ffcfff3f6f0001ff0001cfff3fff00010001cfff3fff0001ff0001cfff3fff00010001cfff3fff00017f0001cfff3fff00010001cfff3fff"))).length, 6); 77 | }); 78 | it("table", function() { 79 | assert.equal(c.deserialize(hexstr_to_bin("0100010008010000a73e0000006200630b00020000380061006200000002020900cce80300000004f03f00ff0003f7cfff3fff000300cfff3fff00ff0003ffcfff3fff0003f0ffcfff3fff00ff0003ffcfff3fff0003f0ffcfff3fff00ff0003ffcfff3fff0003f0ffcfff3fff00ff0003ffcfff3fff0003f0ffcfff3fff00ff0003ffcfe009ff0001cfe000010001cfff3fffff00010001cfff3fff00010001cfff3fffff00010001cfff3fff00010001cfff3fffff00010001cfff3fff00010001cfff3fffff00010001cfff3fff00010001cfff3fffff00010001cfff3fff00010001cfff3fffff00010001cfff3fff00010001cfff3fff7f00010001cfff3fff00010001cfe8")).length, 1000); 80 | }); 81 | }); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /test/connect.js: -------------------------------------------------------------------------------- 1 | var nodeq = require("../index.js"), 2 | assert = require("assert"); 3 | 4 | describe("connect", function() { 5 | "use strict"; 6 | describe("old API", function() { 7 | it("should fail if enpoint is unavailable", function(done){ 8 | nodeq.connect("localhost", 9999, function(err) { 9 | if (err) { 10 | done(); 11 | } else { 12 | assert.fail("no err"); 13 | } 14 | }); 15 | }); 16 | }); 17 | describe("new API", function() { 18 | it("should fail if enpoint is unavailable", function(done){ 19 | nodeq.connect({host: "localhost", port: 9999}, function(err) { 20 | if (err) { 21 | done(); 22 | } else { 23 | assert.fail("no err"); 24 | } 25 | }); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/typed.js: -------------------------------------------------------------------------------- 1 | var typed = require("../lib/typed.js"), 2 | assert = require("assert"); 3 | 4 | describe("typed", function() { 5 | describe("toString", function() { 6 | it("int", function() { 7 | assert.equal(typed.int(1) + "", "int(1)"); 8 | }); 9 | it("ints", function() { 10 | assert.equal(typed.ints([1, 2, 3]) + "", "list[int](1,2,3)"); 11 | }); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "target": "es2015", 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "declaration": true, 8 | "noEmit": true, 9 | "strictNullChecks": true 10 | } 11 | } 12 | --------------------------------------------------------------------------------