Skip to content

Commit

Permalink
feat: add transform method
Browse files Browse the repository at this point in the history
  • Loading branch information
fredericoo committed Jun 30, 2024
1 parent 8c8c1f8 commit 3605cc5
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# drizzle-toolbelt

## 1.2.0

### Minor Changes

- Add `transform` method with data-first and data-last overloads

## 1.1.1

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "drizzle-toolbelt",
"version": "1.1.1",
"version": "1.2.0",
"description": "Set of tools for drizzle-orm.",
"scripts": {
"build": "tsup --dts --dts-resolve",
Expand Down
3 changes: 1 addition & 2 deletions src/aggregate.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import get from 'lodash/get';
import type { Prettify } from './utils';

/** More performant version of Object.values */
function extractValues<T extends object>(obj: T) {
Expand All @@ -9,8 +10,6 @@ function extractValues<T extends object>(obj: T) {
return values;
}

// eslint-disable-next-line @typescript-eslint/ban-types
export type Prettify<T> = { [K in keyof T]: T[K] } & {};
export type FlatKey<T extends Record<string, any>> = {
[K in keyof T]: NonNullable<T[K]> extends PropertyKey
? K
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { aggregate } from './aggregate';
export { takeFirst, takeFirstOrThrow } from './take';
export { transform } from './transform';
91 changes: 91 additions & 0 deletions src/transform.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { describe, test, expect } from 'bun:test';
import { transform } from './transform';
import { aggregate } from './aggregate';

describe('transform', () => {
test('data-first', async () => {
const rows = [
{ id: 1, name: 'salem', age: 8, post: { id: 1, title: '1' } },
{ id: 1, name: 'salem', age: 8, post: { id: 4, title: '4' } },
{ id: 2, name: 'mimo', age: 7, post: { id: 2, title: '2' } },
{ id: 3, name: 'tapi', age: 6, post: { id: 3, title: '3' } },
];

const transformed = transform({
rows,
fields: {
name: (row) => row.name.toUpperCase(),
post: (row) => ({ id: row.post.id, title: +row.post.title }),
},
});

expect(transformed).toEqual([
{ id: 1, name: 'SALEM', age: 8, post: { id: 1, title: 1 } },
{ id: 1, name: 'SALEM', age: 8, post: { id: 4, title: 4 } },
{ id: 2, name: 'MIMO', age: 7, post: { id: 2, title: 2 } },
{ id: 3, name: 'TAPI', age: 6, post: { id: 3, title: 3 } },
]);
});

test('data-last', async () => {
const getRows = async () => [
{ id: 1, name: 'salem', age: 8, post: { id: 1, title: '1' } },
{ id: 1, name: 'salem', age: 8, post: { id: 4, title: '4' } },
{ id: 2, name: 'mimo', age: 7, post: { id: 2, title: '2' } },
{ id: 3, name: 'tapi', age: 6, post: { id: 3, title: '3' } },
];

const transformed = await getRows().then(
transform({
fields: {
age: (row) => row.age + 1,
},
}),
);

expect(transformed).toEqual([
{ id: 1, name: 'salem', age: 9, post: { id: 1, title: '1' } },
{ id: 1, name: 'salem', age: 9, post: { id: 4, title: '4' } },
{ id: 2, name: 'mimo', age: 8, post: { id: 2, title: '2' } },
{ id: 3, name: 'tapi', age: 7, post: { id: 3, title: '3' } },
]);
});

test('with aggregate', async () => {
const getRows = async () => [
{ id: 1, name: 'salem', age: 8, post: { id: 1, title: '1' } },
{ id: 1, name: 'salem', age: 8, post: { id: 4, title: '4' } },
{ id: 2, name: 'mimo', age: 7, post: { id: 2, title: '2' } },
{ id: 3, name: 'tapi', age: 6, post: { id: 3, title: '3' } },
];

const transformed = await getRows()
.then(
aggregate({
pkey: 'id',
fields: { posts: 'post.id' },
}),
)
.then(
transform({
fields: {
age: (row) => row.age + 1,
},
}),
);

expect(transformed).toEqual([
{
id: 1,
name: 'salem',
age: 9,
posts: [
{ id: 1, title: '1' },
{ id: 4, title: '4' },
],
},
{ id: 2, name: 'mimo', age: 8, posts: [{ id: 2, title: '2' }] },
{ id: 3, name: 'tapi', age: 7, posts: [{ id: 3, title: '3' }] },
]);
});
});
44 changes: 44 additions & 0 deletions src/transform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { Prettify } from './utils';

export function transform<
TRow extends Record<PropertyKey, any>,
TTransform extends Partial<{ [K in keyof TRow]: (row: TRow) => any }>,
>(params: {
rows: TRow[];
fields: TTransform;
}): Prettify<
Omit<TRow, keyof TTransform> & {
[K in keyof TTransform]: TTransform[K] extends (params: any) => infer Ret ? Ret : never;
}
>[];

export function transform<
TRow extends Record<PropertyKey, any>,
TTransform extends Partial<{ [K in keyof TRow]: (row: TRow) => any }>,
>(params: {
fields: TTransform;
}): (rows: TRow[]) => Prettify<
Omit<TRow, keyof TTransform> & {
[K in keyof TTransform]: TTransform[K] extends (params: any) => infer Ret ? Ret : never;
}
>[];

export function transform<
TRow extends Record<PropertyKey, any>,
TTransform extends Partial<{ [K in keyof TRow]: (row: TRow) => any }>,
>(params: {
rows?: TRow[];
fields: TTransform;
}) {
// if rows is missing, build a data-last function
if (params.rows === undefined) return (rows: TRow[]) => transform({ rows, ...params });

for (const row of params.rows) {
for (const key in params.fields) {
const transform = params.fields[key];
row[key] = transform?.(row);
}
}

return params.rows;
}
3 changes: 3 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type Prettify<T> = {
[K in keyof T]: T[K];
} & {};

0 comments on commit 3605cc5

Please sign in to comment.