UNPKG

oracle-nosqldb

Version:

Node.js driver for Oracle NoSQL Database

273 lines (267 loc) 11.7 kB
/*- * Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved. * * Licensed under the Universal Permissive License v 1.0 as shown at * https://oss.oracle.com/licenses/upl/ */ 'use strict'; /** * Desribes row and key format and datatypes used by the driver. */ /** * This is a marker type for records such as table rows or query results. * <p> * The driver uses plain JavaScript objects to represent table rows for * put operations and as results of get operations and query results. A row * object consists of properties each designating a table field (on input) or * field generated by a query (on output). The property keys must * match their corresponding field names and property values are used as * corresponding field values. The match between the keys and field names * is case-insensitive. For put operations such as {@link NoSQLClient#put}, * the property values must be of a type that maps to the corresponding data * type of the table field as described in {@link FieldValue}. When a row * object is received on output, such as from {@link NoSQLClient#get}, its * value will always conform to the schema of the table from which the it was * received or the implied schema of a query projection. * <p> * Note the following: * <ul> * <li>To represent rows as objects, you may only use plain JavaScript * objects, that is object literals. The driver will reject any class * instances</li> * <li>You may also specify a valid JSON string as a row value, in which case * it will be parsed via <em>JSON.parse</em> and the result subjected to the * same validation as above</li> * </ul> * * @example //Put * //Let's assume the following table schema: * //Emp(id INTEGER, lastName STRING, firstName STRING, address RECORD( * //city STRING, streetName STRING, streetNo INTEGER)) PRIMARY KEY(id) * * const client = new NoSQLClient(...); * ..... * let res = await client.put('Emp', { * id: 1000, * lastName: 'Doe', * firstName: 'Jonh', * address: { * city: 'Redwood City', * streetName: 'Broadway', * streetNo: 1000 * } * }); * * @example //Query, continued from previous example * const opt = {}; * do { * res = await client.query('SELECT id, address.city from Emp', opt); * if (res.rows.length) { * console.log(res.rows[0]); * //{ id: 1000, city: 'Redwood City' } * } * opt.continuationKey = res.continuationKey; * } while(res.continuationKey); * * @example //Delete, continued from previous example * //Primary key is represented same as row, but only with primary key fields * //included. * res = await client.delete('Emp', { id: 1000 }); * * @see {@link NoSQLClient#put} * @see {@link NoSQLClient#get} * @see {@link NoSQLClient#query} * * @global * @typedef {object} Row */ /** * This is a marker type for primary keys, index keys, full or partial. The * key is represented in the same way as {@link Row}, as plain JavaScript * object, but only key fields are included. * @see {@link Row} * * @global * @typedef {object} Key */ /** * This is a marker type for field values which are property values of the * {@link Row} and {@link Key} objects. * <p> * FieldValue represents a data item in Oracle NoSQL Database. * FieldValue objects can be one of several JavaScript and Node.js types, * the type being dependent on how this value maps onto a given database * type. For put and other operations where field values are used as input * their type must be one of the allowable types that maps onto given * database type (usually being the type of a table field). * <p> * FieldValue objects used for put operations are not validated against the * target table schema in the driver. Validation happens where the table * schema is available. If an instance does not match the target table an * error results. * <p> * You may specify field value as a (synchronous) function. In this case the * function will be called with no arguments and its return value will be used * as the field value. This could be useful if this function is returned from * a closure context or bound to a class that automatically generates field * values in some manner. * <p> * FieldValue objects returned by the driver (such as from get or query * operations) always conform to a table schema, or to the shape implied * by a query projection. * <p> * Here we will discuss how JavaScript types map onto the database types and * vice versa. When field values are used as an input (such as by * {@link NoSQLClient#put}), some conversions are allowed so there could be * more than one JavaScript type used for given database type. In this * instance, we will list preferred JavaScript type first followed by others * if any. For output field values returned by the driver (such as by * {@link NoSQLClient#get} and {@link NoSQLClient#query}) * there is a definite JavaScript type used for a given database type. For * completeness, we will list mappings on input and on output separately. * Note that for composite database types such as Array, Map, Record and * JSON, their constituent elements also follow these mappings. * <p> * For datatype <em>Number</em>, the driver supports integration with 3rd * party number libraries such as decimal.js, bignumber.js and others. See * {@link DBNumberConfig} for details. If this feature is enabled, the * field value will be an object representing number in the 3rd party * library, indicated in the table below as "3rd party number". Thus 3rd * party number will be the output type and preferred input type. If this * feature is not enabled, the output type and preferred input type will be * Javascript number. In both cases, you may also use string (representing * number) as an input type. * <p> * Oracle NoSQL Database has a special type JSON NULL, which represents a * [JSON]{@link https://www.json.org} type NULL. JSON NULL may occur as a * value of a field of Oracle NoSQL Database type JSON or one of its * subfields that has a value 'null'. JSON NULL value is different and * separate from SQL NULL. For example, if table <em>MyTable</em> has a field * <em>info</em> of type JSON, a query such as * <em>SELECT info.name from MyTable</em> will yield different results for * records where the value of <em>info.name</em> is null (e.g. if the value of * <em>info</em> is { "name": null }) with result being JSON NULL and for * records where the value of the <em>info</em> field itself is NULL * (SQL NULL), with result being a SQL NULL. In addition, the <em>info</em> * field itself may take values of SQL NULL or JSON NULL which are distinct * values, the latter being a value of a JSON type NULL (i.e. the value of * <em>info</em> is JSON value <em>null</em>). For more details, please see * [SQL Reference Guide]{@link https://docs.oracle.com/en/database/other-databases/nosql-database/20.2/sqlreferencefornosql/} * and SQL for Oracle NoSQL Database Specification. * <p> * The driver represents JSON NULL as JavaScript type <b>null</b> and SQL NULL * as JavaScript type <b>undefined</b>. When such distinction is not * important, you may use non-strict comparison (e.g. <em>value == null</em>) * to determine if the field value is NULL (either SQL or JSON). To * distinquish between JSON and SQL NULL, use strict comparison (e.g. * <em>value === undefined</em>). Note that for non-JSON fields, on input you * may pass either undefined or null, or omit a field alltogether for * {@link NoSQLClient#put} operations, all of the above being interpreted as * SQL NULL. For JSON fields, on input you may use either null or undefined * as a value of the subfield (e.g. <em>info.name</em>) which will be * interpreted as JSON NULL, but for the field itself (e.g. <em>info</em>) * null and undefined will be treated as distinct values (JSON NULL and SQL * NULL correspondingly) as mentioned above. * * <table> * <tr><th>Database Type</th><th>JavaScript Input Type(s)</th><th>JavaScript * Output Type</th></tr> * <tr> * <td>Array</td><td>Array</td> * <td>Array</td> * </tr> * <tr> * <td>Binary</td><td>Buffer</td> * <td>Buffer</td> * </tr> * <tr> * <td>Boolean</td><td>boolean</td><td>boolean</td> * </tr> * <tr> * <td>Double</td><td>number</td><td>number</td> * </tr> * <tr> * <td>Enum</td><td>string</td><td>string</td> * </tr> * <tr> * <td>Fixed Binary</td><td>Buffer</td> * <td>Buffer</td> * </tr> * <tr> * <td>Float</td><td>number</td><td>number</td> * </tr> * <tr> * <td>Integer</td><td>number</td><td>number</td> * </tr> * <tr> * <td>Json</td><td>object, string, Map</td> * <td>object</td> * </tr> * <tr> * <td>Json Null</td><td>null, undefined (only as sub-field of JSON field)</td> * <td>null</td> * </tr> * <tr> * <td>Long</td><td>number, bigint</td> * <td>number, bigint</td> * </tr> * <tr> * <td>Map</td><td>object, Map</td><td>object</td> * </tr> * <tr> * <td>SQL Null</td><td>undefined (or omit field), null (only for non-JSON fields)</td> * <td>undefined</td> * </tr> * <tr> * <td>Number</td><td>3rd party number, Javascript number (with limitation), string</td><td>3rd party number or Javascript number (with limitation)</td> * </tr> * <tr> * <td>Record</td><td>object, Map</td><td>object</td> * </tr> * <tr> * <td>String</td><td>string</td><td>string</td> * </tr> * <tr> * <td>Timestamp</td><td>Date, string</td> * <td>Date</td> * </tr> * </table> * <p> * Note the following: * <ul> * <li>For database types Binary and FixedBinary the driver uses Node.js * <em>Buffer</em> class</li> * <li> For database type <em>Long</em>, you have an option to use either * JavaScript type <em>number</em> or <em>bigint</em>. By default, * <em>number</em> is used. Note that JavaScript type <em>number</em> cannot * have precise representation of integers outside of safe integer range, * that is outside of range from <em>Number.MIN_SAFE_INTEGER</em> to * <em>Number.MAX_SAFE_INTEGER</em>. For values outside that range (that is * when their magnitude exceeds 53 bits in size), loss of precision may * occur. Alternatively, you can use JavaScript type * [bigint]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt} * by setting option {@link Config}#longAsBigInt. In this case, values of * datatype <em>Long</em> returned by get and query operations will be * represented as <em>bigint</em>, which avoids the loss of precision for the * entire range of datatype <em>Long</em>. For values passed to operations * such as put and delete, you may use either <em>bigint</em> or * <em>number</em>. Note that in either case <em>Long</em> values passed to * the driver may not be outside the range of datatype <em>Long</em> (from * -2^63 to 2^63-1)</li> * <li>For datatype <em>Number</em>, unless you are using 3rd party number * library feature (see {@link DBNumberConfig}), the driver will return * Javascript number values in the results, which means loss of precision and * rounding errors may occur in some cases. On input (for put operations), * you may pass NoSQL Number values either as 3rd party numbers (if enabled), * Javascript numbers or strings</li> * <li>To represent database type Timestamp, you may use either * JavaScript <em>Date</em> class or a string. The string * should represent a date in valid ISO 8601 format. Timestamps are always * stored and managed in UTC</li> * </ul> * * @tutorial tables * * @global * @typedef {(string|number|boolean|object|Array|Map|Buffer|Date)} FieldValue */