Skip to content

dynamicPick ts result type from execute #86

@kir4ik

Description

@kir4ik

Hi,

import {MySqlConnection} from 'ts-sql-query/connections/MySqlConnection';
import {Table} from 'ts-sql-query/Table';
import pick from 'lodash/pick';
import {SelectedValues, UpdatableValues} from 'ts-sql-query/extras/types';
import {extractColumnsFrom} from 'ts-sql-query/extras/utils';
import {dynamicPick} from 'ts-sql-query/dynamicCondition';

class Connection extends MySqlConnection<'Connection'> {
  allowEmptyString = true;
}

class StoreTable extends Table<Connection, 'StoreTable'> {
  id = this.autogeneratedPrimaryKey('id', 'int');
  name = this.column('name', 'string');
  address = this.column('address', 'string');
  foo = this.optionalColumn('foo', 'double');
  bar = this.column('bar', 'boolean');
  someField = this.column('someField', 'string');
  someBool = this.column('someBool', 'boolean');

  constructor() {
    super('store');
  }
}

export const storeTable = new StoreTable();

const EXTRACTED_COLUMNS_FROM_STORE_TABLE = extractColumnsFrom(storeTable);

const AVAILABLE_STORE_FIELD = ['name', 'address', 'foo', 'someBool'] as const;
type AvailableStoreField = typeof AVAILABLE_STORE_FIELD[number];

type SomeStoreClassGetStoreResult<TField extends AvailableStoreField> = Pick<
  SelectedValues<StoreTable>,
  TField
>;

class SomeStoreClass {
  constructor(private getConnection: () => Connection, private storeId: number) {}

  async getStore<TField extends AvailableStoreField>(
    fields: TField[]
  ): Promise<SomeStoreClassGetStoreResult<TField>> {
    const connection = this.getConnection();

    const selectQuery = connection
      .selectFrom(storeTable)
      .select(dynamicPick(EXTRACTED_COLUMNS_FROM_STORE_TABLE, {}, fields))
      // or pick via lodash
      // .select(pick(EXTRACTED_COLUMNS_FROM_STORE_TABLE, fields))
      .where(storeTable.id.equals(this.storeId));

    const store = await selectQuery.executeSelectNoneOrOne();
    if (!store) {
      throw new Error(`store #${this.storeId} not found`);
    }

    // store any field unavailable
    return store; // ts(2322) error
  }
}

const someStoreClass = new SomeStoreClass({} as any, 1);

/**
 * I want to use it like this, so that there are only those fields that I specified
 * and that the type is correct (without undefined for required columns)
 */
someStoreClass.getStore(['address', 'foo']).then((store) => {
  /**
   * store type => SomeStoreClassGetStoreResult<"address" | "foo">
   * store => {address: string; foo?: number | undefined}
   */
})

is it possible to make support for such a sample
Or how can I do the right thing?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions