kysely icon indicating copy to clipboard operation
kysely copied to clipboard

add more control through configuration @ `ParseJSONResultsPlugin`.

Open igalklebanov opened this issue 1 year ago • 1 comments

Hey :wave:

This PR revisits ParseJSONResultsPlugin and attempts to provide more fine-grained control to consumers.

  • skipKeys allows you to specify columns to not parse in a result object.
  • reviver allows passing a custom reviver function to the JSON.parse invocations. This can allow you to instantiate native Dates, or omit keys.
  • __proto__ keys are always deleted to deny prototype pollution.
  • isJSON allows overriding what is or what isn't considered a JSON string before attempting to JSON.parse it.

igalklebanov avatar Oct 06 '24 05:10 igalklebanov

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
kysely ✅ Ready (Inspect) Visit Preview 💬 Add feedback Mar 16, 2025 9:05pm

vercel[bot] avatar Oct 06 '24 05:10 vercel[bot]

Coming from https://github.com/kysely-org/kysely/issues/1275 for context

I know you are doing some absolute black magic with the types, so I'm not sure how cleanly this can be done with respect to revivers (though possibly it'd be cleaner?)

I'd much prefer explicit opt-in than an opt-out list by column names. skipKeys seems to exist at the wrong level of abstraction here; it doesn't entirely solve the problem because it's not defined at the table/column level. What are the chances of implementing a syntax more like this?

const rows = db.selectFrom('table').select(eb => eb.json('column_name')).execute();

Since the expression builder has the capability to pass forward its column's expected type, this should allow for syntax like:

const rows = db.selectFrom('table').select(eb => eb.json('column_name', reviver)).execute();

Obviously this is less convenient, but it is more safe and flexible since you can define a type-safe reviver (or validation) function, type guard, etc. at the point of use. This means that you can see clearly what the query is doing and what you expect to receive.

For convenience's sake, if you wanted to globally define JSON parsing behavior at the plugin level, you could potentially do something like this:

interface ParseJSONResultsPluginOptions<Database> {
  revivers: Partial<{
    [Table in keyof Database]:
      Partial<{
        [Column in keyof Table]:
          Table[Column] extends Reviver<infer P> ? P : never
      }>
  }>
}

(not fully sure if that syntax would work, and of course it could be extracted into further generics)

The idea being that, if you supply the plugin with your database interface (which is expected to match the same interface that you provide to the Kysely instance, and this should be enforceable?) - then you can define revivers for specific columns on specific tables, both of which are fully type-safe, and ensure that the reviver supplied returns the type defined on the table's interface.

myndzi avatar Nov 22 '24 22:11 myndzi

Open in Stackblitzkysely_koa_example

npm i https://pkg.pr.new/kysely-org/kysely@1170

commit: 60f32e2

pkg-pr-new[bot] avatar Nov 24 '24 00:11 pkg-pr-new[bot]