oracle-nosqldb
Version:
Node.js driver for Oracle NoSQL Database
355 lines (344 loc) • 15.4 kB
TypeScript
/*-
* 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/
*/
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];