/**
 *      Interface database class that provides all Acedia's functionality for
 *  querying databases. For most of the cases, this is a class you are expected
 *  to work with and providing appropriate implementation is Acedia's `DBAPI`
 *  responsibility. Choice of the implementation is done based on user's
 *  config files.
 *      All of the methods are asynchronous - they do not return requested
 *  values immediately and instead require user to provide a handler function
 *  that will be called once operation is completed.
 *      Copyright 2021-2023 Anton Tarasenko
 *------------------------------------------------------------------------------
 * This file is part of Acedia.
 *
 * Acedia is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License, or
 * (at your option) any later version.
 *
 * Acedia is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Acedia.  If not, see <https://www.gnu.org/licenses/>.
 */
class Database extends AcediaObject
    abstract;

/**
 *      Describes possible data types that can be stored in Acedia's databases.
 *      Lists consists of all possible JSON values types (with self-explanatory
 *  names) plus technical `JSON_Undefined` type that is used to indicate that
 *  a particular value does not exist.
 */
enum DataType
{
    JSON_Undefined,
    JSON_Null,
    JSON_Boolean,
    JSON_Number,
    JSON_String,
    JSON_Array,
    JSON_Object
};

/**
 *      Possible outcomes of any query: success (only `DBR_Success`) or
 *  some kind of failure (any other value).
 *      This type is common for all queries, however reasons as to why
 *  a particular result value was obtained can differ from one to another.
 */
enum DBQueryResult
{
    //  Means query has succeeded;
    DBR_Success,
    //  Query was provided with an invalid JSON pointer
    //  (`none` or somehow otherwise unfit to be used with a particular query);
    DBR_InvalidPointer,
    //  Operation could not finish because database is damaged and unusable;
    DBR_InvalidDatabase,
    //  Means that data (provided for the query) is somehow invalid.
    DBR_InvalidData
};

/**
 *  Schedules reading data, located at the given `pointer` in
 *  the caller database.
 *
 *  @param  pointerToData   JSON pointer to the value in database to read.
 *      `none` is always treated as an invalid JSON pointer.
 *  @param  makeMutable     Setting this to `false` (default) will force method
 *      to load data as immutable Acedia's types and `true` will make it load
 *      data as mutable types. This setting does not affect `Collection`s into
 *      which JSON arrays and objects are converted - they are always mutable.
 *  @param  requestID       ID of this request. It will be reported when
 *      database's task is completed. Can be used to correspond database's
 *      responses with particular requests.
 *  @return Task object that corresponds to this `ReadData()` call.
 *      *   Guaranteed to be not `none`;
 *      *   Use it to connect a handler for when reading task is complete:
 *          `ReadData(...).connect = handler`,
 *          where `handler` must have the following signature:
 *          ```
 *          connect(
 *              DBQueryResult       result,
 *              take AcediaObject   data,
 *              Database            source,
 *              int                 requestID)`;
 *          ```
 *      *   Ownership of `data` object returned in the `connect()` is considered
 *          to be transferred to whoever handled result of this query.
 *          It must be deallocated once no longer needed.
 *      *   `source` provides reference to the database, whose data was
 *          requested, `requestID` provides the same number as `requestID`
 *          parameter of this method.
 *      *   Possible `DBQueryResult` types are `DBR_Success`,
 *          `DBR_InvalidPointer` and `DBR_InvalidDatabase`;
 *      *   `data` is guaranteed to be `none` if `result != DBR_Success`;
 *      *   `DBR_InvalidPointer` can be produced if either `pointer == none` or
 *          it does not point at any existing value inside the caller database.
 */
public function DBReadTask ReadData(
    BaseJSONPointer pointer,
    optional bool   makeMutable,
    optional int    requestID)
{
    return none;
}

/**
 *  Schedules writing `data` at the location inside the caller database,
 *  given by the `pointer`.
 *
 *  Only `HashTable` (that represents JSON object) can be recorded as
 *  a database's root value (referred to by an empty JSON pointer "").
 *
 *  @param  pointer JSON pointer to the location in the database, where `data`
 *      should be written (as a JSON value).
 *      This JSON pointer can make use of "-" index for JSON arrays that allows
 *      appending data at their end.
 *      `none` is always treated as an invalid JSON pointer.
 *  @param  data    Data that needs to be written at the specified location
 *      inside the database. For method to succeed this object needs to have
 *      JSON-compatible type (see `_.json.IsCompatible()` for more details).
 *  @param  requestID       ID of this request. It will be reported when
 *      database's task is completed. Can be used to correspond database's
 *      responses with particular requests.
 *  @return Task object that corresponds to this `WriteData()` call.
 *      *   Guaranteed to be not `none`;
 *      *   Use it to connect a handler for when writing task is complete:
 *          `WriteData(...).connect = handler`,
 *          where `handler` must have the following signature:
 *          `connect(DBQueryResult result, Database source, int requestID)`;
 *      *   `source` provides reference to the database, whose data was
 *          requested, `requestID` provides the same number as `requestID`
 *          parameter of this method.
 *      *   Possible `DBQueryResult` types are `DBR_Success`,
 *          `DBR_InvalidPointer`, `DBR_InvalidDatabase` and `DBR_InvalidData`;
 *      *   Data is actually written inside the database iff
 *          `result == DBR_Success`;
 *      *   `result == DBR_InvalidData` iff either given `data`'s type is not
 *          JSON-compatible or a non-`HashTable` was attempted to be
 *          recorded as caller database's root value;
 *      *   `DBR_InvalidPointer` can be produced if either `pointer == none` or
 *          container of the value `pointer` points at does not exist.
 *          Example: writing data at "/sub-object/valueA" will always fail if
 *          "sub-object" does not exist.
 */
public function DBWriteTask WriteData(
    BaseJSONPointer pointer,
    AcediaObject    data,
    optional int    requestID)
{
    return none;
}

/**
 *  Schedules removing data at the location inside the caller database,
 *  given by the `pointer`.
 *
 *  "Removing" root object results in simply erasing all of it's stored data.
 *
 *  @param  pointer JSON pointer to the location of the data to remove from
 *      database. `none` is always treated as an invalid JSON pointer.
 *  @param  requestID       ID of this request. It will be reported when
 *      database's task is completed. Can be used to correspond database's
 *      responses with particular requests.
 *  @return Task object that corresponds to this `RemoveData()` call.
 *      *   Guaranteed to be not `none`;
 *      *   Use it to connect a handler for when writing task is complete:
 *          `RemoveData(...).connect = handler`,
 *          where `handler` must have the following signature:
 *          `connect(DBQueryResult result, Database source, int requestID)`.
 *      *   `source` provides reference to the database, whose data was
 *          requested, `requestID` provides the same number as `requestID`
 *          parameter of this method.
 *      *   Possible `DBQueryResult` types are `DBR_Success`,
 *          `DBR_InvalidPointer` and `DBR_InvalidDatabase`;
 *      *   Data is actually removed from the database iff
 *          `result == DBR_Success`.
 *      *   `DBR_InvalidPointer` can be produced if either `pointer == none` or
 *          it does not point at any existing value inside the caller database.
 */
public function DBRemoveTask RemoveData(
    BaseJSONPointer pointer,
    optional int    requestID)
{
    return none;
}

/**
 *  Schedules checking type of data at the location inside the caller database,
 *  given by the `pointer`.
 *
 *  @param  pointer JSON pointer to the location of the data for which type
 *      needs to be checked.
 *      `none` is always treated as an invalid JSON pointer.
 *  @param  requestID       ID of this request. It will be reported when
 *      database's task is completed. Can be used to correspond database's
 *      responses with particular requests.
 *  @return Task object that corresponds to this `CheckDataType()` call.
 *      *   Guaranteed to be not `none`;
 *      *   Use it to connect a handler for when reading task is complete:
 *          `CheckDataType(...).connect = handler`,
 *          where `handler` must have the following signature:
 *          ```
 *          connect(
 *              DBQueryResult       result,
 *              Database.DataType   type,
 *              Database            source,
 *              int                 requestID)
 *          ```
 *      *   `source` provides reference to the database, whose data was
 *          requested, `requestID` provides the same number as `requestID`
 *          parameter of this method.
 *      *   Possible `DBQueryResult` types are `DBR_Success`,
 *          `DBR_InvalidPointer` and `DBR_InvalidDatabase`;
 *      *   This task can only fail if either caller database is broken
 *          (task will produce `DBR_InvalidDatabase` result) or given `pointer` 
 *          is `none` (task will produce `DBR_InvalidPointer` result).
 *          Otherwise the result will be `DBR_Success`.
 *      *   Data is actually removed from the database iff
 *          `result == DBR_Success`.
 */
public function DBCheckTask CheckDataType(
    BaseJSONPointer pointer,
    optional int    requestID)
{
    return none;
}

/**
 *  Schedules obtaining "size": amount of elements stored inside
 *  either JSON object or JSON array, which location inside the caller database
 *  is given by provided `pointer`.
 *
 *  For every JSON value that is neither object or array size is
 *  defined as `-1`.
 *
 *  @param  pointer JSON pointer to the location of the JSON object or array
 *      for which size needs to be obtained.
 *      `none` is always treated as an invalid JSON pointer.
 *  @param  requestID       ID of this request. It will be reported when
 *      database's task is completed. Can be used to correspond database's
 *      responses with particular requests.
 *  @return Task object that corresponds to this `GetDataSize()` call.
 *      *   Guaranteed to be not `none`;
 *      *   Use it to connect a handler for when reading task is complete:
 *          `GetDataSize(...).connect = handler`,
 *          where `handler` must have the following signature:
 *          ```
 *          connect(
 *              DBQueryResult   result,
 *              int             size,
 *              Database        source,
 *              int             requestID)
 *          ```
 *      *   `source` provides reference to the database, whose data was
 *          requested, `requestID` provides the same number as `requestID`
 *          parameter of this method.
 *      *   Possible `DBQueryResult` types are `DBR_Success`,
 *          `DBR_InvalidPointer` and `DBR_InvalidDatabase`;
 *      *   Returned `size` value is actually a size of referred
 *          JSON object/array inside the database iff `result == DBR_Success`;
 *      *   `DBR_InvalidPointer` can be produced if either `pointer == none` or
 *          it does not point at a JSON object or array inside the
 *          caller database.
 */
public function DBSizeTask GetDataSize(
    BaseJSONPointer pointer,
    optional int    requestID)
{
    return none;
}

/**
 *  Schedules obtaining set of keys inside the JSON object, which location in
 *  the caller database is given by provided `pointer`.
 *
 *  Only JSON objects have (and will return) keys (names of their sub-values).
 *
 *  @param  pointer JSON pointer to the location of the JSON object for which
 *      keys need to be obtained.
 *      `none` is always treated as an invalid JSON pointer.
 *  @param  requestID       ID of this request. It will be reported when
 *      database's task is completed. Can be used to correspond database's
 *      responses with particular requests.
 *  @return Task object that corresponds to this `GetDataKeys()` call.
 *      *   Guaranteed to be not `none`;
 *      *   Use it to connect a handler for when reading task is complete:
 *          `GetDataKeys(...).connect = handler`,
 *          where `handler` must have the following signature:
 *          ```
 *          connect(
 *              DBQueryResult   result,
 *              take ArrayList  keys,
 *              Database        source,
 *              int             requestID)
 *          ```
 *      *   Ownership of `keys` array returned in the `connect()` is considered
 *          to be transferred to whoever handled result of this query.
 *          It must be deallocated once no longer needed.
 *      *   `source` provides reference to the database, whose data was
 *          requested, `requestID` provides the same number as `requestID`
 *          parameter of this method.
 *      *   Possible `DBQueryResult` types are `DBR_Success`,
 *          `DBR_InvalidPointer`, `DBR_InvalidData` and `DBR_InvalidDatabase`;
 *      *   Returned `keys` will be non-`none` and contain keys of the referred
 *          JSON object inside the database iff `result == DBR_Success`;
 *      *   `DBR_InvalidPointer` can be produced iff `pointer == none`;
 *      *   `result == DBR_InvalidData` iff `pointer != none`, but does not
 *          point at a JSON object inside caller database
 *          (value can either not exist at all or have some other type).
 */
public function DBKeysTask GetDataKeys(
    BaseJSONPointer pointer,
    optional int    requestID)
{
    return none;
}

/**
 *  Schedules "incrementing" data, located at the given `pointer` in
 *  the caller database.
 *
 *  "Incrementing" is an operation that is safe from the point of view of
 *  simultaneous access. What "incrementing" actually does depends on
 *  the passed JSON value (`increment` parameter):
 *
 *      (0. ...unless `pointer` points at the JSON null or missing value (within
 *          existing container - then "increment" acts as a `WriteData()` method
 *          regardless of `increment`'s value;)
 *      1.  JSON null: it never modifies existing value and reports an error if
 *          existing value was not itself JSON null;
 *      2.  JSON bool: if combined with stored JSON bool value -
 *          performs logical "or" operation. Otherwise fails;
 *      3.  JSON number: if combined with stored JSON numeric value -
 *          adds values together. Otherwise fails.
 *      4.  JSON string: if combined with stored JSON string value -
 *          concatenates itself at the end. Otherwise fails.
 *      5.  JSON array: if combined with stored JSON array value -
 *          concatenates itself at the end. Otherwise fails.
 *      6.  JSON object: if combined with stored JSON object value -
 *          `increment` adds it's own values with new keys into the stored
 *          JSON object. Does not override old values.
 *          Fails when combined with any other type.
 *
 *  @param  pointer     JSON pointer to the location in the database, where
 *      data should be incremented (by `increment`).
 *      `none` is always treated as an invalid JSON pointer.
 *      This JSON pointer can make use of "-" index for JSON arrays that allows
 *      to add `none` value at the end of that array and then "increment" it
 *      with `increment` parameter.
 *  @param  increment   JSON-compatible value to be used as an increment for
 *      the data at the specified location inside the database.
 *  @param  requestID       ID of this request. It will be reported when
 *      database's task is completed. Can be used to correspond database's
 *      responses with particular requests.
 *  @return Task object that corresponds to this `IncrementData()` call.
 *      *   Guaranteed to be not `none`;
 *      *   Use it to connect a handler for when reading task is complete:
 *          `IncrementData(...).connect = handler`,
 *          where `handler` must have the following signature:
 *          `connect(DBQueryResult result, Database source, int requestID)`.
 *      *   `source` provides reference to the database, whose data was
 *          requested, `requestID` provides the same number as `requestID`
 *          parameter of this method.
 *      *   Possible `DBQueryResult` types are `DBR_Success`,
 *          `DBR_InvalidPointer`, `DBR_InvalidData` and `DBR_InvalidDatabase`;
 *      *   Data is actually incremented iff `result == DBR_Success`;
 *      *   `DBR_InvalidPointer` can be produced if either `pointer == none` or
 *          container of the value `pointer` points at does not exist.
 *          Example: incrementing data at "/sub-object/valueA" will always fail
 *          if "sub-object" does not exist.
 *      *   `result == DBR_InvalidData` iff `pointer != none`, but does not
 *          point at a JSON value compatible (in the sense of "increment"
 *          operation) with `increment` parameter.
 */
public function DBIncrementTask IncrementData(
    BaseJSONPointer pointer,
    AcediaObject    increment,
    optional int    requestID)
{
    return none;
}

defaultproperties
{
}