UNPKG

oracle-nosqldb

Version:

Node.js driver for Oracle NoSQL Database

355 lines (344 loc) 15.4 kB
/*- * Copyright (c) 2018, 2024 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/ */ import type { ExtractByType, Expand } from "./type_utils"; /** * For Javascript users: * <p> * 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> * <p> * Typescript-specific: * <p> * This type is used as a default for <em>TRow</em> type parameter for APIs * such as {@link NoSQLClient#get}, {@link NoSQLClient#put} and others as well * as interfaces representing the results of these operations. It represents * object of any type. * <p> * The users are encouraged to define interface or type that describes the * shape of their table rows and use it as <em>TRow</em> type parameter for * these APIs. */ export type AnyRow = { [name: string]: any; }; /** * Typescript-specific. * <p> * Interface that may be used to add custom type definitions to the set of * values allowed by {@link FieldValue} type. For example, when using 3rd * party number library (see {@link DBNumberConfig}) you can use this * interface to include the 3rd party number type as an allowed * {@link FieldValue} in order to avoid compilation errors. For this, define * <em>dbNumber</em> property as shown in the example below. * <p> * Use module agumentation to add custom type definitions via this interface * as shown in the example. Note that it should be sufficient to augment * <em>oracle-nosql</em> module only once for your application project. * * @example * Using CustomFieldTypes interface for 3rd party number support. * ```ts * import type { NoSQLClient } from "oracle-nosqldb"; * import type { Decimal } from "decimal.js"; * * declare module "oracle-nosqldb" { * interface CustomFieldTypes { * dbNumber: Decimal; * } * } * * async function test(client: NoSQLClient): Promise<void> { * ..... * // Ok to use Decimal instance as field value * const res = await client.put("my_table", { * partNo: 1000, * price: new Decimal(123.45) * }); * ..... * } * ``` * @see {@link KeyField} * @see {@link FieldValue} */ export interface CustomFieldTypes {} declare type CustomNumberType = CustomFieldTypes extends { dbNumber: infer T } ? T : never; /** * Represents field types that can be used as a part of primary keys or * secondary index keys in a table. These include numeric types, including * custom number type if provided (see {@link CustomFieldTypes}) as well as * <em>String</em>, <em>Boolean</em> and <em>Timestamp</em>. */ export type KeyField = string | number | bigint | boolean | Date | CustomNumberType; /** * Represents atomic field types. These include {@link KeyField} types as * well as <em>Binary</em>, <em>Null</em> and <em>JSON Null</em>. * @see {@link FieldValue} */ export type AtomicField = KeyField | Buffer | null | undefined; /** * Represents field types that can be used for Identity or UUID fields. */ export type IdentityField = string | number | bigint | CustomNumberType; /** * For Javascript users: * <p> * This is a marker type for primary keys, index keys, full or partial. The * key is represented in the same way as {@link AnyRow}, as plain JavaScript * object, but only key fields are included. * <p> * Typescript-specific: * <p> * This type is used as a default for <em>TKey</em> type parameter for APIs * such as {@link NoSQLClient#get}, {@link NoSQLClient#delete} and others when * using default value for <em>TRow</em> type parameter (see {@link AnyRow}). * It represents object of any type. * <p> * The users are encouraged to define interface or type that describes the * shape of their table rows and use it as <em>TRow</em> type parameter for * these APIs. */ export type AnyKey = { [name: string]: any; } /** * Typescript-specific. * <p> * This type is used to infer the primary key type from the row type as * indicated by the <em>TRow</em> type parameter. As such, it represents all * possible subsets of properties of <em>TRow</em> that include only * properties of types that can be used as primary or secondary index keys * (@see {@link KeyField}). * <p> * This type is used as a default value of <em>TKey</em> type parameter for * APIs that take primary key, such as {@link NoSQLClient#get}, * {@link NoSQLClient#delete} and others. Note that this is only a * best-effort basis to determine the type of the primary key since the driver * is not aware of what fields of the table constitute the primary key. You * can specify the exact shape of the primary key by explicitly providing the * value of <em>TKey</em> type parameter to these APIs. * <p> * If using untyped versions of the above APIs (see {@link AnyRow}), the key * will be of type {@link AnyKey}. * @see {@link AnyKey} * @see {@link AnyRow} */ export type RowKey<TRow> = Expand<Partial<ExtractByType<TRow, KeyField>>>; /** * For Javascript users: * <p> * Marker type that represents types of field values in a table, which are as * used property values for rows and primary keys. * <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 * {@link https://www.json.org | JSON} 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 * {@link https://docs.oracle.com/en/database/other-databases/nosql-database/23.1/sqlreferencefornosql/sql-reference-guide.pdf | SQL Reference Guide} * 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 * {@link !Number.MIN_SAFE_INTEGER | Number.MIN_SAFE_INTEGER} to * {@link !Number.MAX_SAFE_INTEGER | Number.MAX_SAFE_INTEGER}. 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 * {@link !BigInt | 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> * <p> * Typescript-specific: * <p> * Use the above description as a guide to what types are allowed for use as * field values. The users are encouraged to create interfaces or types that * represent the shape of their table rows based on the types described above * and use them as <em>TRow</em> type parameters for APIs such as * {@link NoSQLClient#get}, {@link NoSQLClient#put}, * {@link NoSQLClient#delete}, {@link NoSQLClient#writeMany}, * {@link NoSQLClient#query}, etc. */ export type FieldValue = AtomicField | FieldValue[] | { [name: string]: FieldValue } | Map<string, FieldValue> | CustomFieldTypes[keyof CustomFieldTypes];