Repository: denoland/deno
File: ext/node/polyfills/sqlite.ts (TypeScript)

Code before:
 *
 * The backed-up database can be used normally during the backup process. Mutations coming from the same connection - same
 * `DatabaseSync` - object will be reflected in the backup right away. However, mutations from other connections will cause
 * the backup process to restart.
 *
 * ```js
 * import { backup, DatabaseSync } from 'node:sqlite';
 *
 * const sourceDb = new DatabaseSync('source.db');
 * const totalPagesTransferred = await backup(sourceDb, 'backup.db', {
 *   rate: 1, // Copy one page at a time.
 *   progress: ({ totalPages, remainingPages }) => {
 *     console.log('Backup in progress', { totalPages, remainingPages });
 *   },
 * });
 *
 * console.log('Backup completed', totalPagesTransferred);
 * ```
 * @param sourceDb The database to backup. The source database must be open.
 * @param path The path where the backup will be created. If the file already exists,
 * the contents will be overwritten.
 * @param options Optional configuration for the backup. The
 * following properties are supported:
 * @returns A promise that resolves when the backup is completed and rejects if an error occurs.
 */
const backup = op_node_database_backup as (
  sourceDb: DatabaseSync,
  path: string | URL | Buffer,
  options?: BackupOptions,
) => Promise<number>;

export const constants = {
  SQLITE_CHANGESET_OMIT: 0,
  SQLITE_CHANGESET_REPLACE: 1,
  SQLITE_CHANGESET_ABORT: 2,

  SQLITE_CHANGESET_DATA: 1,
  SQLITE_CHANGESET_NOTFOUND: 2,
  SQLITE_CHANGESET_CONFLICT: 3,
  SQLITE_CHANGESET_CONSTRAINT: 4,
  SQLITE_CHANGESET_FOREIGN_KEY: 5,
};

const sqliteTypeSymbol = SymbolFor("sqlite-type");
ObjectDefineProperties(DatabaseSync.prototype, {
  [sqliteTypeSymbol]: {
    __proto__: null,
    value: "node:sqlite",
    enumerable: false,
    configurable: true,
  },

Review comment (suggestion):
I'd suggest to actually have a wrapper function here - do the URL/Buffer handling in this wrapper function and ensure a `string` is passed to the actual `op_node_database_backup`

Code after:
  let parsedPath: string | undefined;
  if (typeof path === "string") {
    parsedPath = path;
  } else if (isUint8Array(path)) {
    const decoder = new TextDecoder("utf8");
    parsedPath = decoder.decode(path);
    // @ts-expect-error safe to check even though `path` is unknown
  } else if (ObjectPrototypeIsPrototypeOf(URLPrototype, path)) {
    if ((path as URL).protocol !== "file:") {
      throw new InvalidURLSchemeError();
    }
    parsedPath = (path as URL).href;
  }

  if (
    typeof parsedPath === "undefined" ||
    StringPrototypeIncludes(parsedPath, "\0")
  ) {
    throw new InvalidPathError();
  }

  return parsedPath;
};

// Using ES5 class allows custom error to be thrown
// when called without `new`.
function DatabaseSync(
  path: string | URL | Buffer,
  options?: unknown,
): DatabaseSyncOp {
  if (new.target === undefined) {
    throw new ConstructCallRequiredError();
  }
  return ReflectConstruct(
    DatabaseSyncOp,
    [parsePath(path), options],
    new.target,
  );
}
ObjectSetPrototypeOf(DatabaseSync.prototype, DatabaseSyncOp.prototype);
ObjectSetPrototypeOf(DatabaseSync, DatabaseSyncOp);

interface BackupOptions {
  /**
   * Name of the source database. This can be `'main'` (the default primary database) or any other
   * database that have been added with [`ATTACH DATABASE`](https://www.sqlite.org/lang_attach.html)
   * @default 'main'
   */
  source?: string | undefined;
  /**
   * Name of the target database. This can be `'main'` (the default primary database) or any other