surrealdb / surrealdb.js

SurrealDB SDK for JavaScript
https://surrealdb.com
Apache License 2.0
294 stars 48 forks source link

Bug: Problems with not flexible type Record<...> #206

Open Black1358 opened 9 months ago

Black1358 commented 9 months ago

Describe the bug

The issue revolves around the use of Record<string, unknown> in the generic signatures:

type RawQueryResult = string | ... | Record<string, unknown>;

async query<T extends RawQueryResult[]>(...): Promise<T>;
async live<T extends Record<string, unknown>>(...): Promise<T>;

Steps to reproduce

I don't have enough SDK capabilities and I wrote a universal repository that I use for the entire project. Here is its MAXimally simplified version with one method with vanilla SDK:

export interface BaseRecord {
    id: string;
    created: number;
}
export type Omitter<T> = Omit<T, keyof BaseRecord>;

export class Repository<T extends BaseRecord, P extends T> {
    constructor(readonly name: string) {}

    async create(data: Omitter<P>, safe?: boolean): Promise<P> {
        const now = Date.now();
        const copy = (safe ? { ...data } : data) as Omit<P, "id"> & { id: undefined };
        copy.id = undefined;
        copy.created = now;
        const query = `CREATE ${this.name} CONTENT ${JSON.stringify(copy)}`;
        const sql = await surreal.query<P[][]>(query);
        return sql[0][0];
    }
}

image

image

But you can add extends to BaseRecord:

export interface BaseRecord extends Record<string, unknown>

The typing error will be resolved (I'm not sure, because this is a stripped-down version of the code, but it should). But the price of this is the loss of Code Intelligence:

image image

You can read more here TypeScript/issue

This code:

export interface TestRecord extends BaseRecord {
    str?: string;
    nub: number;
    cleaned: boolean;
    opts?: {
        test?: string;
    };
}

const testRepository = new Repository<TestRecord, TestRecord>("test");

await testRepository.create({
    cleaned: true,
    nub: 4254,

}),

Expected behaviour

To solve this problem for myself, I use this crutch solution:

import type { PreparedQuery } from "surrealdb";
import { Surreal } from "surrealdb";

export class FixedSurreal extends Surreal {
    async query<T>(query: string | PreparedQuery, bindings?: Record<string, unknown>) {
        const result = await super.query(query, bindings) as unknown as T[];
        return result[0];
    }
    //...
}

I use result[0] because all my queries are always a single transaction. But it would be better if I didn't have to use this solution at all and everything worked correctly.

SurrealDB version

Surreal 1.0.0

SurrealDB.js version

0.11.0

Contact Details

vlad.logvin84@gmail.com

Is there an existing issue for this?

Code of Conduct