Skip to content

DBNova registers some type information with the TypeScript language service of the Monaco editor to provide better code completion and type checking.

The Monaco editor supports only a single global TypeScript language service instance. Since DBNova needs to support SQL, MongoDB, and Redis, interaction logic is implemented in separate entry functions.

typescript
mongoshell<IMongoDBTypes>((db) => {
  db.status();
  db.collection("users").find();
});

redisshell((cli) => {
  cli.scan(0).stream();
});

sqlshell<ISQLTypes>((ctx, db) => {
  sql`select ${params.int("a")} + ${params.int("b")}`.export(ctx);
  // mysql
  db.manycols.select({}).export(ctx);
  // postgresql
  db.public.datatypetest.select({}).export(ctx);
});

TIP

Entry functions are automatically populated when opening the editor and do not need to be manually entered.

You can also customize the initial code in the database settings.

TIP

Functions may also be asynchronous.

Defining Parameters

In TypeScript, you can define parameters through methods of the params object.

WARNING

Corresponding type values are not actually returned, so parameters cannot be used for calculations.

typescript
// This is incorrect; parameters cannot be directly used in calculations
const pa = params.int("a") * 2;

// Use `valmap` to implement calculations
const pa = params.int("a", { valmap: (v) => v * 2 });

For more parameter options, refer to Feats-Params.

MongoDB

typescript
declare class MongoDB<T extends Record<string, any>> {
  mkcmd(cmd: Record<string, any>, opts?: IMakeCmdOpts): ICommand;

  aggregate(pipeline: IDoc[], opts?: IAggregateOptions): ICommand;
  collection<K extends keyof T & string>(name: K): MongoCollection<T[K]>;
  ...
  stats(opts?: IDBStatusOptions): ICommand;
}
declare class MongoCollection<T> {
  insertOne(doc: T): ICommand;
  insertMany(docs: T[], opts?: ICommonOptions): ICommand;
  ...
  dropIndex(name: string): ICommand;
  stats(): ICommand;
}

Users can also call the db.mkcmd method to register arbitrary commands.

Redis

typescript
declare class RedisClient {
  mkcmd(cmd: string, ...args: (string | number)[]): ICommand;

  bitcount(key: string, opts?: BitCountOptions): ICommand;
  ...
  ping(message?: string): ICommand;
}

Users can also call the cli.mkcmd method to register arbitrary commands.

SQL

DBNova has open-sourced its built-in SQL Generator aghsorm,which you can use to generate SQL statements.

Support for user-defined SQL Generators will be added in the future.

typescript
sqlshell<IDBTypes>((ctx, db) => {
  // raw sql
  sql`select ${params.int("a")} + ${params.int("b")}`.export(ctx);

  // select
  db.article
    .select({ id: params.int("id") }, { exclude: ["content"] })
    .export(ctx);

  // delete
  db.article.delete({ id: params.int("id") }).export(ctx);

  // insert
  db.article
    .insert({
      id: params.int("id"),
      title: params.string("title"),
      content: params.string("content"),
    })
    .export(ctx);

  // update
  db.article
    .update(
      { read_count: db.article.field("read_count").plus(1) },
      { id: params.int("id") },
    )
    .export(ctx);
});

SQL Export

Each SQL statement must explicitly call export(ctx).

For column rendering options, refer to Feats-ColRender.

Database Type Inference

To prevent database lag during index data processing from affecting normal business operations, DBNova's indexing is manual. Currently, this feature supports SQL and MongoDB.

All field names that do not comply with JavaScript variable name rules will be converted to valid names.

MongoDB

Use collection.aggregate([{$sample: {size: 50}}]) to obtain sample documents; you can change the sample size in the settings.

For heterogeneous fields, a union based on first-level fields is generated. For example:

typescript
[
  { a: 1, b: { c: 122 } },
  { a: 2, b: { d: false } },
];

// The following types will be generated:

// The names of these sub-types are currently meaningless hashes
interface Ixxxxxxxxxxxxxxxx {
  c: number;
}

interface Iyyyyyyyyyyyyyyyy {
  d: boolean;
}

interface ICollection {
  a: number;
  b: Ixxxxxxxxxxxxxxxx | Iyyyyyyyyyyyyyyyy;
}

For method calls such as find and updateOne, corresponding field prompts and checks are provided. (However, this is far less robust than VSCode; improvements may be made through a separately implemented LSP in the future.)

SQL

Special type conversions:

  • 64-bit and larger integer types are inferred as bigint.
  • decimal types are inferred as Decimal.
  • Time-related types are inferred as Date.
  • Binary types are inferred as Binary.

Schema concepts in databases such as PostgreSQL are also supported, with each schema being a separate namespace.

Additional TypeScript Types and APIs

typescript
declare class Base64 {
  static encode(input: Uint8Array): string;
  static decode(input: string): Uint8Array;
}

declare interface IHTTPOptions {
  query?: { [k: string]: string[] | string };
  headers?: { [k: string]: string[] | string };
  body?: ["file", string] | Uint8Array | string | any;
  timeouts?: number;
  proxy?: "app" | string;
}

declare interface IHttpResponse {
  code: number;
  message: string;
  headers: { [k: string]: string[] };
  body: Uint8Array;

  json<T>(): T;
  text(): string;
}

declare function http(
  method: "get" | "post" | "put" | "head" | "delete" | "options" | "patch",
  url: string,
  opts?: IHTTPOptions,
): Promise<IHttpResponse>;

declare namespace bson {
  class ObjectID {}
  class Long {}
  class Timestamp {}
  class UUID {}
  class Decimal128 {}
  class Binary {}
  class MinKey {}
  class MaxKey {}
}

declare const Binary: typeof bson.Binary;
declare const Decimal: typeof bson.Decimal128;