2022-05-17 11:09:34 +08:00
|
|
|
// Copyright (c) 2019, 2022, Oracle and/or its affiliates.
|
2019-06-23 06:36:03 +08:00
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
2023-02-21 09:43:43 +08:00
|
|
|
// This software is dual-licensed to you under the Universal Permissive License
|
|
|
|
// (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
|
|
|
|
// 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
|
|
|
|
// either license.
|
2019-06-23 06:36:03 +08:00
|
|
|
//
|
2023-02-21 09:43:43 +08:00
|
|
|
// If you elect to accept the software under the Apache License, Version 2.0,
|
|
|
|
// the following applies:
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
2019-06-23 06:36:03 +08:00
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
2023-02-21 09:43:43 +08:00
|
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
2019-06-23 06:36:03 +08:00
|
|
|
//
|
2023-02-21 09:43:43 +08:00
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
2019-06-23 06:36:03 +08:00
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
2023-02-21 07:44:26 +08:00
|
|
|
const constants = require('./constants.js');
|
2023-02-21 09:33:06 +08:00
|
|
|
const Lob = require('./lob.js');
|
|
|
|
const impl = require('./impl');
|
2023-02-21 09:47:14 +08:00
|
|
|
const errors = require('./errors.js');
|
2019-06-23 06:36:03 +08:00
|
|
|
const util = require('util');
|
|
|
|
|
|
|
|
// define base database object class; instances of this class are never
|
|
|
|
// instantiated; instead, classes subclassed from this one will be
|
|
|
|
// instantiated; a cache of these classes are maintained on each connection
|
|
|
|
class BaseDbObject {
|
|
|
|
|
2023-02-21 09:33:06 +08:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// _getAttrValue()
|
|
|
|
//
|
|
|
|
// Returns the value of the given attribute on the object.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
_getAttrValue(attr) {
|
|
|
|
const value = this._impl.getAttrValue(attr);
|
|
|
|
return this._transformValueOut(value, attr.typeClass);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// _setAttrValue()
|
|
|
|
//
|
|
|
|
// Sets the value of the attribute on the object to the given value.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
_setAttrValue(attr, value) {
|
|
|
|
value = this._transformValueIn(value, attr.typeClass);
|
|
|
|
this._impl.setAttrValue(attr, value);
|
2019-06-23 06:36:03 +08:00
|
|
|
}
|
|
|
|
|
2023-02-21 09:33:06 +08:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// _toPojo()
|
|
|
|
//
|
|
|
|
// Returns the database object as a plain Javascript object.
|
|
|
|
//---------------------------------------------------------------------------
|
2019-06-23 06:36:03 +08:00
|
|
|
_toPojo() {
|
|
|
|
if (this.isCollection) {
|
2020-11-19 10:06:47 +08:00
|
|
|
const result = this.getValues();
|
2023-02-21 07:44:26 +08:00
|
|
|
if (this.elementType == constants.DB_TYPE_OBJECT) {
|
2020-11-19 10:06:47 +08:00
|
|
|
for (let i = 0; i < result.length; i++) {
|
|
|
|
result[i] = result[i]._toPojo();
|
|
|
|
}
|
|
|
|
}
|
2021-04-01 12:48:37 +08:00
|
|
|
return (result);
|
2019-06-23 06:36:03 +08:00
|
|
|
}
|
|
|
|
const result = {};
|
2023-02-21 09:33:06 +08:00
|
|
|
for (const name in this.attributes) {
|
2019-06-23 06:36:03 +08:00
|
|
|
let value = this[name];
|
|
|
|
if (value instanceof BaseDbObject) {
|
|
|
|
value = value._toPojo();
|
|
|
|
}
|
|
|
|
result[name] = value;
|
|
|
|
}
|
2021-04-01 12:48:37 +08:00
|
|
|
return (result);
|
2019-06-23 06:36:03 +08:00
|
|
|
}
|
|
|
|
|
2023-02-21 09:33:06 +08:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// _transformValueIn()
|
|
|
|
//
|
|
|
|
// Transforms a value coming from the caller to the implementation.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
_transformValueIn(value, cls) {
|
|
|
|
let outValue = value;
|
|
|
|
if (cls && value !== null && value !== undefined) {
|
|
|
|
if (value instanceof cls) {
|
|
|
|
outValue = value._impl;
|
|
|
|
} else {
|
|
|
|
outValue = new cls(value)._impl;
|
|
|
|
}
|
|
|
|
} else if (value instanceof Lob) {
|
|
|
|
outValue = value._impl;
|
|
|
|
}
|
|
|
|
return outValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// _transformValueOut()
|
|
|
|
//
|
|
|
|
// Transforms a value going out to the caller from the implementation.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
_transformValueOut(value, cls) {
|
|
|
|
let outValue = value;
|
|
|
|
if (value instanceof impl.LobImpl) {
|
|
|
|
outValue = new Lob();
|
|
|
|
outValue._setup(value, true);
|
|
|
|
} else if (value instanceof impl.DbObjectImpl) {
|
|
|
|
outValue = Object.create(cls.prototype);
|
|
|
|
outValue._impl = value;
|
|
|
|
if (outValue.isCollection) {
|
|
|
|
outValue = new Proxy(outValue, BaseDbObject._collectionProxyHandler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return outValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// append()
|
|
|
|
//
|
|
|
|
// Appends an element to the collection.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
append(value) {
|
|
|
|
errors.assertArgCount(arguments, 1, 1);
|
|
|
|
value = this._transformValueIn(value, this.elementTypeClass);
|
|
|
|
this._impl.append(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// attributes
|
|
|
|
//
|
|
|
|
// Property for the attributes stored on the object type.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get attributes() {
|
|
|
|
if (!this._attributes) {
|
|
|
|
const implAttrs = this._objType.attributes;
|
|
|
|
const attrs = {};
|
|
|
|
for (let i = 0; i < implAttrs.length; i++) {
|
|
|
|
const implAttr = implAttrs[i];
|
|
|
|
const attr = {
|
|
|
|
type: implAttr.type,
|
|
|
|
typeName: implAttr.typeName
|
|
|
|
};
|
|
|
|
if (implAttr.typeClass) {
|
|
|
|
attr.typeClass = implAttr.typeClass;
|
|
|
|
}
|
|
|
|
attrs[implAttr.name] = attr;
|
|
|
|
}
|
|
|
|
this._attributes = attrs;
|
|
|
|
}
|
|
|
|
return this._attributes;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// deleteElement()
|
|
|
|
//
|
|
|
|
// Deletes the element in a collection at the specified index.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
deleteElement(index) {
|
|
|
|
errors.assertArgCount(arguments, 1, 1);
|
|
|
|
errors.assertParamValue(Number.isInteger(index), 1);
|
|
|
|
return this._impl.deleteElement(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// elementType
|
|
|
|
//
|
|
|
|
// Property for the element type, if the database object type is a
|
|
|
|
// collection. It will be one of the DB_TYPE_ constants.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get elementType() {
|
|
|
|
return this._objType.elementType;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// elementTypeClass
|
|
|
|
//
|
|
|
|
// Property for the element type class, if the database object type is a
|
|
|
|
// collection and the elements in the collection refer to database objects.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get elementTypeClass() {
|
|
|
|
return this._objType.elementTypeClass;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// elementTypeName
|
|
|
|
//
|
|
|
|
// Property for the element type name, if the database object type is a
|
|
|
|
// collection.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get elementTypeName() {
|
|
|
|
return this._objType.elementTypeName;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// fqn
|
|
|
|
//
|
|
|
|
// Property for the fully qualified name of the database object type in the
|
|
|
|
// form: <schema>.<name>.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get fqn() {
|
|
|
|
return this._objType.fqn;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// getElement()
|
|
|
|
//
|
|
|
|
// Returns the element in a collection at the specified index.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
getElement(index) {
|
|
|
|
errors.assertArgCount(arguments, 1, 1);
|
|
|
|
errors.assertParamValue(Number.isInteger(index), 1);
|
|
|
|
const value = this._impl.getElement(index);
|
|
|
|
return this._transformValueOut(value, this.elementTypeClass);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// getKeys()
|
|
|
|
//
|
|
|
|
// Returns an array of the keys of the collection.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
getKeys() {
|
|
|
|
errors.assertArgCount(arguments, 0, 0);
|
|
|
|
return this._impl.getKeys();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// getFirstIndex()
|
|
|
|
//
|
|
|
|
// Returns the first index in the collection.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
getFirstIndex() {
|
|
|
|
errors.assertArgCount(arguments, 0, 0);
|
|
|
|
return this._impl.getFirstIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// getLastIndex()
|
|
|
|
//
|
|
|
|
// Returns the last index in the collection.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
getLastIndex() {
|
|
|
|
errors.assertArgCount(arguments, 0, 0);
|
|
|
|
return this._impl.getLastIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// getNextIndex()
|
|
|
|
//
|
|
|
|
// Returns the next index in the collection.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
getNextIndex(index) {
|
|
|
|
errors.assertArgCount(arguments, 1, 1);
|
|
|
|
errors.assertParamValue(Number.isInteger(index), 1);
|
|
|
|
return this._impl.getNextIndex(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// getPrevIndex()
|
|
|
|
//
|
|
|
|
// Returns the previous index in the collection.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
getPrevIndex(index) {
|
|
|
|
errors.assertArgCount(arguments, 1, 1);
|
|
|
|
errors.assertParamValue(Number.isInteger(index), 1);
|
|
|
|
return this._impl.getPrevIndex(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// getValues()
|
|
|
|
//
|
|
|
|
// Returns the elements in a collection.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
getValues() {
|
|
|
|
errors.assertArgCount(arguments, 0, 0);
|
|
|
|
const values = this._impl.getValues();
|
|
|
|
for (let i = 0; i < values.length; i++) {
|
|
|
|
values[i] = this._transformValueOut(values[i], this.elementTypeClass);
|
|
|
|
}
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// hasElement()
|
|
|
|
//
|
|
|
|
// Returns a boolean indicating if an element exists at the specified index.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
hasElement(index) {
|
|
|
|
errors.assertArgCount(arguments, 1, 1);
|
|
|
|
errors.assertParamValue(Number.isInteger(index), 1);
|
|
|
|
return this._impl.hasElement(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// isCollection
|
|
|
|
//
|
|
|
|
// Property indicating if the object is a collection or not.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get isCollection() {
|
|
|
|
return this._objType.isCollection;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// name
|
|
|
|
//
|
|
|
|
// Property for the name of the database object type.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get name() {
|
|
|
|
return this._objType.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// schema
|
|
|
|
//
|
|
|
|
// Property for the schema of the database object type.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get schema() {
|
|
|
|
return this._objType.schema;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// setElement()
|
|
|
|
//
|
|
|
|
// Sets the element in the collection at the specified index to the given
|
|
|
|
// value.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
setElement(index, value) {
|
|
|
|
errors.assertArgCount(arguments, 2, 2);
|
|
|
|
errors.assertParamValue(Number.isInteger(index), 1);
|
|
|
|
value = this._transformValueIn(value, this.elementTypeClass);
|
|
|
|
this._impl.setElement(index, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// trim()
|
|
|
|
//
|
|
|
|
// Trims the specified number of elements from the end of the collection.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
trim(numToTrim) {
|
|
|
|
errors.assertArgCount(arguments, 1, 1);
|
2023-02-21 10:48:15 +08:00
|
|
|
errors.assertParamValue(Number.isInteger(numToTrim) && numToTrim >= 0, 1);
|
2023-02-21 09:33:06 +08:00
|
|
|
this._impl.trim(numToTrim);
|
|
|
|
}
|
|
|
|
|
2019-06-23 06:36:03 +08:00
|
|
|
// custom inspection routine
|
|
|
|
[util.inspect.custom](depth, options) {
|
2021-04-01 12:48:37 +08:00
|
|
|
return ('[' + this.fqn + '] ' + util.inspect(this._toPojo(), options));
|
2019-06-23 06:36:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
[Symbol.iterator]() {
|
|
|
|
if (this.isCollection) {
|
|
|
|
const values = this.getValues();
|
2021-04-01 12:48:37 +08:00
|
|
|
return (values[Symbol.iterator]());
|
2019-06-23 06:36:03 +08:00
|
|
|
}
|
|
|
|
throw TypeError("obj is not iterable");
|
|
|
|
}
|
|
|
|
|
2019-06-28 08:29:16 +08:00
|
|
|
[Symbol.toPrimitive](hint) {
|
|
|
|
switch (hint) {
|
|
|
|
case 'number':
|
2021-04-01 12:48:37 +08:00
|
|
|
return (NaN);
|
2019-06-28 08:29:16 +08:00
|
|
|
default:
|
2021-04-01 12:48:37 +08:00
|
|
|
return ('[' + this.fqn + '] ' + util.inspect(this._toPojo(), {}));
|
2019-06-28 08:29:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-05 07:54:10 +08:00
|
|
|
get [Symbol.toStringTag]() {
|
2021-04-01 12:48:37 +08:00
|
|
|
return (this.fqn);
|
2019-11-05 07:54:10 +08:00
|
|
|
}
|
|
|
|
|
2019-06-23 06:36:03 +08:00
|
|
|
toJSON() {
|
2021-04-01 12:48:37 +08:00
|
|
|
return (this._toPojo());
|
2019-06-23 06:36:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-05 07:54:10 +08:00
|
|
|
// define proxy handler used for collections
|
|
|
|
BaseDbObject._collectionProxyHandler = {
|
|
|
|
|
|
|
|
deleteProperty(target, prop) {
|
|
|
|
if (typeof prop === 'string') {
|
|
|
|
const index = +prop;
|
|
|
|
if (!isNaN(index)) {
|
2021-04-01 12:48:37 +08:00
|
|
|
return (target.deleteElement(index));
|
2019-11-05 07:54:10 +08:00
|
|
|
}
|
|
|
|
}
|
2021-04-01 12:48:37 +08:00
|
|
|
return (delete target[prop]);
|
2019-11-05 07:54:10 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
get(target, prop) {
|
|
|
|
if (typeof prop === 'string') {
|
|
|
|
const index = +prop;
|
|
|
|
if (!isNaN(index)) {
|
2021-04-01 12:48:37 +08:00
|
|
|
return (target.getElement(index));
|
2019-11-05 07:54:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
const value = target[prop];
|
|
|
|
if (typeof value === 'function') {
|
2021-04-01 12:48:37 +08:00
|
|
|
return (value.bind(target));
|
2019-11-05 07:54:10 +08:00
|
|
|
}
|
2021-04-01 12:48:37 +08:00
|
|
|
return (value);
|
2019-11-05 07:54:10 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
set(target, prop, value) {
|
|
|
|
if (typeof prop === 'string') {
|
|
|
|
const index = +prop;
|
|
|
|
if (!isNaN(index)) {
|
|
|
|
target.setElement(index, value);
|
2021-04-01 12:48:37 +08:00
|
|
|
return (true);
|
2019-11-05 07:54:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
target[prop] = value;
|
2021-04-01 12:48:37 +08:00
|
|
|
return (true);
|
2019-11-05 07:54:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-06-23 06:36:03 +08:00
|
|
|
module.exports = BaseDbObject;
|