chromium/third_party/blink/public/mojom/indexeddb/indexeddb.mojom

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

module blink.mojom;

import "mojo/public/mojom/base/string16.mojom";
import "mojo/public/mojom/base/string16.mojom";
import "mojo/public/mojom/base/time.mojom";
import "third_party/blink/public/mojom/blob/blob.mojom";
import "third_party/blink/public/mojom/file_system_access/file_system_access_transfer_token.mojom";

// kIDBMaxMessageSize is 128MB, originally based on
// IPC::Channel::kMaximumMessageSize.  The "usable" size is this value less
// the overhead size.
const int32 kIDBMaxMessageSize = 134217728;

// kIDBMaxMessageOverhead is the size we expect to be used for the rest of
// the message we will send.  The "usable" size is the max size less this value.
const int32 kIDBMaxMessageOverhead = 1048576;  // 1MB; arbitrarily chosen.

// Default threshold for IDBValueWrapper::WrapIfBiggerThan().
//
// This should be tuned to achieve a compromise between short-term IndexedDB
// throughput and long-term I/O load and memory usage. LevelDB, the underlying
// storage for IndexedDB, was not designed with large values in mind. At the
// very least, large values will slow down compaction, causing occasional I/O
// spikes.
const int32 kIDBWrapThreshold = 65536;

// To avoid GetAll returning too much data in one mojo message, it is returned
// in chunks of keys or values.  This constant is the max number of keys/values
// returned per IDBDatabaseGetAllResultSink::Receive call.
const int32 kIDBGetAllChunkSize = 1000;

enum IDBCursorDirection {
  Next,
  NextNoDuplicate,
  Prev,
  PrevNoDuplicate,
};

enum IDBDataLoss {
  None,
  Total,
};

// In order of the least to the highest precedent in terms of sort order.
enum IDBKeyType {
  // Invalid is used in blink bindings code. When converting a V8 value that
  // is not a valid key, key of this type is returned. Outside of testing
  // it should only be used in blink code.
  Invalid,

  // The following indicate the type of a valid key, per the standard:
  // https://w3c.github.io/IndexedDB/#key-construct
  Array,
  Binary,
  String,
  Date,
  Number,

  // None is used to represent the lack of a key, e.g. when a key range
  // has no upper/lower bound.
  // TODO(jsbell): Consider using Optional<> instead.
  None,

  // Min is used to encode the lower bound of a construct in leveldb, e.g.
  // all entries in a store are in [{id, min}, {id+1, min}). It should
  // only appear in browser code.
  Min,
};

// Durability guarantees during a transaction.  This maps to whether or not
// the writes to disk are explicitly flushed or not.
enum IDBTransactionDurability {
  // Unspecified by caller, and so is implementation defined.
  // May map to either Strict or Relaxed.
  Default,

  // Always flush to disk after a write.
  Strict,

  // Do not flush to disk.  This is much faster.
  Relaxed,
};

union IDBKey {
  array<IDBKey> key_array;
  array<uint8> binary;
  mojo_base.mojom.String16 string;
  double date;
  double number;
  // TODO(jsbell): Consider using Optional<> instead.
  bool other_none;
};

// In order of the least to the highest precedent in terms of sort order.
// These values are written to logs. New enum values can be added, but
// existing enums must never be renumbered or deleted and reused.
enum IDBKeyPathType {
  Null,
  String,
  Array,
};

// Represents WebIDBKeyPathTypeString and WebIDBKeyPathTypeArray in a key path.
union IDBKeyPathData {
  mojo_base.mojom.String16 string;
  array<mojo_base.mojom.String16> string_array;
};

struct IDBKeyPath {
  // A null value here corresponds to WebIDBKeyPathTypeNull.
  IDBKeyPathData? data;
};

struct IDBKeyRange {
  IDBKey lower;
  IDBKey upper;
  bool lower_open;
  bool upper_open;
};

enum IDBOperationType {
  Add,
  Put,
  Delete,
  Clear,
};

enum IDBPutMode {
  AddOrUpdate,
  AddOnly,
  CursorUpdate,
};

enum IDBTaskType {
  Normal,
  Preemptive,
};

enum IDBTransactionMode {
  ReadOnly,
  ReadWrite,
  VersionChange,
};

// These values need to match core/dom/exception_code.h
enum IDBException {
  kNoError = 0,
  kUnknownError = 28,
  kConstraintError = 29,
  kDataError = 30,
  kVersionError = 33,
  kAbortError = 20,
  kIgnorableAbortError = 11,
  kQuotaError = 22,
  kTimeoutError = 23,
};

struct IDBIndexMetadata {
  int64 id;
  mojo_base.mojom.String16 name;
  IDBKeyPath key_path;
  bool unique;
  bool multi_entry;
};

struct IDBObjectStoreMetadata {
  int64 id;
  mojo_base.mojom.String16 name;
  IDBKeyPath key_path;
  bool auto_increment;
  int64 max_index_id;
  map<int64, IDBIndexMetadata> indexes;
};

struct IDBDatabaseMetadata {
  int64 id;
  mojo_base.mojom.String16 name;
  int64 version;
  int64 max_object_store_id;
  map<int64, IDBObjectStoreMetadata> object_stores;
  bool was_cold_open;
};

struct IDBNameAndVersion {
  mojo_base.mojom.String16 name;
  int64 version;
};

struct IDBIndexKeys {
  int64 index_id;
  array<IDBKey> index_keys;
};

struct IDBFileInfo {
  mojo_base.mojom.String16 name;
  mojo_base.mojom.Time last_modified;
};

struct IDBBlobInfo {
  pending_remote<blink.mojom.Blob> blob;
  string uuid;
  mojo_base.mojom.String16 mime_type;
  int64 size;
  IDBFileInfo? file;
};

union IDBExternalObject {
  IDBBlobInfo blob_or_file;
  pending_remote<FileSystemAccessTransferToken> file_system_access_token;
};

struct IDBValue {
  array<uint8> bits;
  array<IDBExternalObject> external_objects;
};

struct IDBReturnValue {
  IDBValue value;
  IDBKey primary_key;
  IDBKeyPath key_path;
};

// The IDBFactoryClient interface is used to return results for requests to open or
// delete databases.
interface IDBFactoryClient {
  // These may be called during either Open or DeleteDatabase operations.
  Error(IDBException code, mojo_base.mojom.String16 message);
  Blocked(int64 existing_version);

  // Called during Open operations.
  UpgradeNeeded(pending_associated_remote<IDBDatabase> pending_database,
                int64 old_version, IDBDataLoss data_loss,
                string data_loss_message, IDBDatabaseMetadata db_metadata);
  OpenSuccess(pending_associated_remote<IDBDatabase>? pending_database,
              IDBDatabaseMetadata metadata);

  // Called after a successful DeleteDatabase operation.
  DeleteSuccess(int64 old_version);
};

// The IDBDatabaseCallbacks interface is used to notification of events out of
// band to individual requests. A single instance is used for the lifetime of
// a database connection.
interface IDBDatabaseCallbacks {
  ForcedClose();
  VersionChange(int64 old_version, int64 new_version);
  Abort(int64 transaction_id, IDBException code,
        mojo_base.mojom.String16 message);
  Complete(int64 transaction_id);
};

struct IDBError {
  IDBException error_code;
  mojo_base.mojom.String16 error_message;
};

struct IDBCursorValue {
  array<IDBKey> keys;
  array<IDBKey> primary_keys;
  array<IDBValue> values;
};

union IDBCursorResult {
  IDBError error_result;  // |error| is reserved, so call this |error_result|.
  bool empty;  // False values are not allowed.
  IDBCursorValue values;
};

// Advance(), Continue(), and Prefetch() can call its return callback in
// one of 3 ways:
// * with |error| set and |value| unset, if an error occurs
// * with |error| unset and |value| set, under normal operation
// * with |error| unset and |value| unset, under normal operation when the end
//   of the source being iterated is reached
interface IDBCursor {
  Advance(uint32 count) => (IDBCursorResult result);
  Continue(IDBKey key, IDBKey primary_key) => (IDBCursorResult result);
  Prefetch(int32 count) => (IDBCursorResult result);
  PrefetchReset(int32 used_prefetches);
};

union IDBTransactionPutResult {
  IDBError error_result;  // |error| is reserved, so call this |error_result|.
  IDBKey key;
};

interface IDBTransaction {
  CreateObjectStore(int64 object_store_id,
                    mojo_base.mojom.String16 name,
                    IDBKeyPath key_path,
                    bool auto_increment);
  DeleteObjectStore(int64 object_store_id);
  Put(int64 object_store_id,
      IDBValue value,
      IDBKey key,
      IDBPutMode mode,
      array<IDBIndexKeys> index_keys)
    => (IDBTransactionPutResult result);
  Commit(int64 num_errors_handled);
};

union IDBDatabaseGetResult {
  IDBError error_result;  // |error| is reserved, so call this |error_result|.
  bool empty;  // False values are not allowed.
  IDBKey key;
  IDBReturnValue value;
};

// Result receiver type for GetAll to incrementally receive chunks of results.
interface IDBDatabaseGetAllResultSink {
  // Incrementally receive some values. If `done` is true, then all keys have
  // been sent. Otherwise, `ReceiveValues` or `OnError` will be called again
  // later.
  ReceiveValues(array<IDBReturnValue> values, bool done);

  // Incrementally receive some keys. If `done` is true, then all keys have been
  // sent. Otherwise, `ReceiveValues` or `OnError` will be called again later.
  ReceiveKeys(array<IDBKey> keys, bool done);

  // If any error occurs, call this function.  Once this function has been
  // called, ReceiveValues/ReceiveKeys should not be called again and
  // the entire result should be considered an error.
  OnError(IDBError error);
};

struct IDBDatabaseOpenCursorValue {
  pending_associated_remote<IDBCursor> cursor;
  IDBKey key;
  IDBKey primary_key;
  IDBValue? value;
};

union IDBDatabaseOpenCursorResult {
  IDBError error_result;  // |error| is reserved, so call this |error_result|.
  bool empty;  // Only true values are allowed.
  IDBDatabaseOpenCursorValue value;
};

// The interface used by the IndexedDB client (which lives in the renderer process)
// to trigger some actions from the IndexedDB service (which currently lives in the
// browser process, but will be potentially moved to a separate one in the future).
interface IDBDatabase {
  RenameObjectStore(int64 transaction_id,
                    int64 object_store_id,
                    mojo_base.mojom.String16 new_name);
  CreateTransaction(pending_associated_receiver<IDBTransaction> transaction_receiver,
                    int64 transaction_id,
                    array<int64> object_store_ids,
                    IDBTransactionMode mode,
                    IDBTransactionDurability durability);
  VersionChangeIgnored();
  Get(int64 transaction_id,
      int64 object_store_id,
      int64 index_id,
      IDBKeyRange key_range,
      bool key_only)
    => (IDBDatabaseGetResult result);
  GetAll(int64 transaction_id,
         int64 object_store_id,
         int64 index_id,
         IDBKeyRange key_range,
         bool key_only,
         int64 max_count)
    => (pending_associated_receiver<IDBDatabaseGetAllResultSink> receiver);
  SetIndexKeys(int64 transaction_id,
               int64 object_store_id,
               IDBKey primary_key,
               array<IDBIndexKeys> index_keys);
  SetIndexesReady(int64 transaction_id,
                  int64 object_store_id,
                  array<int64> index_ids);
  OpenCursor(int64 transaction_id,
             int64 object_store_id,
             int64 index_id,
             IDBKeyRange key_range,
             IDBCursorDirection direction,
             bool key_only,
             IDBTaskType task_type)
    => (IDBDatabaseOpenCursorResult result);
  // Correlates to IDBObjectStore::count(). On success, the return value will be
  // the number of records that match the given query.
  Count(int64 transaction_id,
        int64 object_store_id,
        int64 index_id,
        IDBKeyRange key_range) => (bool success, uint32 count);
  // Correlates to IDBObjectStore::delete() and also used by devtools.
  DeleteRange(int64 transaction_id,
              int64 object_store_id,
              IDBKeyRange key_range) => (bool success);
  // Gets the current number of an IndexedDB ObjectStore's key generator.
  GetKeyGeneratorCurrentNumber(int64 transaction_id, int64 object_store_id)
      => (int64 result, IDBError? error);
  // Correlates to IDBObjectStore::clear()
  Clear(int64 transaction_id,
        int64 object_store_id) => (bool success);
  // Correlates to IDBObjectStore::createIndex()
  CreateIndex(int64 transaction_id,
              int64 object_store_id,
              int64 index_id,
              mojo_base.mojom.String16 name,
              IDBKeyPath key_path,
              bool unique,
              bool multi_entry);
  DeleteIndex(int64 transaction_id,
              int64 object_store_id,
              int64 index_id);
  RenameIndex(int64 transaction_id,
              int64 object_store_id,
              int64 index_id,
              mojo_base.mojom.String16 new_name);
  Abort(int64 transaction_id);
  // Called when the document is moved into BFCache, the IndexedDB service
  // receiving this should check if the client is blocking other clients
  // or being blocked by other clients, and disallow the re-activation of
  // the document if so.
  DidBecomeInactive();
};

interface IDBFactory {
  // Gets high level info about databases that exist in the frame's origin.
  // When successful, `error->error_code` will be `kNoError`.
  GetDatabaseInfo() => (array<IDBNameAndVersion> names_and_versions, IDBError error);

  // Opens a database |name| in the frame's origin at version |version|.
  // |version_change_transaction_receiver| will have version change
  // transaction operations posted to it. |transaction_id| corresponds
  // to the transaction number for this connection's context.
  // Posts request events and results to |client| and database-level
  // events and results to |database_callbacks|.
  Open(pending_associated_remote<IDBFactoryClient> client,
       pending_associated_remote<IDBDatabaseCallbacks> database_callbacks,
       mojo_base.mojom.String16 name,
       int64 version,
       pending_associated_receiver<IDBTransaction> version_change_transaction_receiver,
       int64 transaction_id);

  // Deletes a database |name| in the frame's origin. If |force_close|
  // is true, any existing connections to that database will be closed
  // immediately.
  DeleteDatabase(pending_associated_remote<IDBFactoryClient> client,
                 mojo_base.mojom.String16 name, bool force_close);
};