Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for formatters (that could fix few problems at once) #12

Open
d7ark opened this issue Nov 22, 2021 · 3 comments
Open

Support for formatters (that could fix few problems at once) #12

d7ark opened this issue Nov 22, 2021 · 3 comments

Comments

@d7ark
Copy link
Contributor

d7ark commented Nov 22, 2021

Hey,

I'm just migrating from using schemats (https://www.npmjs.com/package/schemats) and would like to work with knex-types, but there's few features missing. I thought rather than forking and just adding it for myself I'll make this project better(?) for everyone who uses it. I hope it's fine.

First thing is an idea that sprouted from this comment. I've looked into suggested approach (asterisk argument for overrides being function taking type and name) and found there are two problems with this:

  1. technical - typescript doesnt allow inconsistent types, so you cannot have object Record<string, string> with special string (*) that takes function. As explained here.
  2. user experience - there's no way to say which types are overwrite with asterisk so we need to turn off any default formatting and ask user to provide formatting for all of the types.

But working on that I came up with (i think) better solution: another option - formatters - it's a set of optional functions that each formats different type (right now I have column, enum, enumEl(ement) and table, but im not 100% sold on these).

It would look like this:

  /**
   * Custom formatters for specific type of data - enum, enumEl, table and column.
   *
   * If any type is null/not specified default formatter for this type will be used.
   *
   * @example
   *   formatters: {
   *      column: (name) => kebabCase(name),
   *      table: (name) => upperFirst(name),
   *   }
   */
  formatters?: {
    column?: (name: string) => string;
    enum?: (name: string) => string;
    enumEl?: (name: string) => string;
    table?: (name: string) => string;
  };

I think it could solve multiple problems: columns with space formatters = { column: name => "${name}"}, obviously camelCasing columns, but also escaping column namesformatters={ column: name => quoteColumnName(name). I think It would add a lot of freedom for users.

I rarely contribute to open source*, so I just wrote code thinking I'll go straight to pushing Pull requests... So I have few things already written. And It seems I cant push to this repo 😅

What should I do next? 🙇

* I'd love to write more for open source projects, but Im not sure where to start and to be honest it's a bit scary.

@koistya
Copy link
Member

koistya commented Nov 23, 2021

Hey @d7ark! Do you think we can extend the existing overrides option to support these scenarios? For example:

CREATE TABLE story (
  id uuid PRIMARY KEY,
  content jsonb NOT NULL DEFAULT '[]'::jsonb,
  created timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
);

type Overrides = Record<string, { name: string } | { type: string } | string> & {
  '$table'?: (name: string, schema: string) => string;
  '$column'?: (name: string, table: string, type: string) => { name?: string, type?: string } | string;
  '$enum'?: (name: string, schema: string) => string;
  '$enumValue'?: (name: string, enumName: string) => { name?: string, type?: string } | string;
};

Also check How to create a Pull Request (PR)

@d7ark
Copy link
Contributor Author

d7ark commented Nov 25, 2021

Hey. Thank you for the pointers. I think your suggestion looks great, but Im not sure what should be the arguments of the overrides functions:
overrides

Could you explain what you had in mind (I think $column would a good example)? What happens when function returns {name, type} object? And as I mentioned before what should be provided as the 2nd and 3rd argument?

Thanks!

@koistya
Copy link
Member

koistya commented Nov 27, 2021

Given the following schema:

CREATE TABLE story (
  id uuid PRIMARY KEY,
  content jsonb NOT NULL DEFAULT '[]'::jsonb,
  created timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
);

And the callback (formatter) function for column names:

updateTypes(db, {
  output: "./types.ts",
  overrides: {
    "$column": (name) => camelCase(name),
  }
});

The $column callback would be called with the following args for the story.content column:

overrides["$column"]("content", "story", "jsonb");

If the function returns a null, false, or undefined the default column name formatter would be used.

updateTypes(db, {
  output: "./types.ts",
  overrides: {
    "$column": (name, table) => table === "story" ? camelCase(name) : undefined,
  }
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants