Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"@babel/preset-env",
{
"targets": {
"node": "10"
"node": "22"
}
}
],
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ jobs:
python-version: 3.8
- uses: actions/setup-node@v1
with:
node-version: '12.x'
node-version: '22.x'
- run: pip3 install --user virtualenv
- run: make test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ npm-debug.log*
venv
yarn-debug.log*
yarn-error.log*
.yarnrc
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
flow-typed
examples/swapi/swapi-loaders.ts
6 changes: 3 additions & 3 deletions API_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ To use this feature, there are several restrictions. (Please open an issue if yo
```

2. In the response, `properties` are spread at the same level as the `responseKey`. (Check out `getFilmsV2` in [swapi example](./examples/swapi/swapi.js).)
3. All `properties` must be optional in the response object. The flow types currently don't handle the nullability of these properties correctly, so to enforce this, we recommend a build step to ensure that the underlying types are always set as maybe types.
3. All `properties` must be optional in the response object. The TypeScript types currently don't handle the nullability of these properties correctly, so to enforce this, we recommend a build step to ensure that the underlying types are always set as maybe types.
4. The resource must have a one-to-one correspondence between the input "properties" and the output "properties".
- e.g. if we request property "name", the response must have "name" in it, and no extra data associated with it.

Expand All @@ -158,7 +158,7 @@ resources:
responseKey: ?string (non-optional when propertyBatchKey is used)

typings:
language: flow
language: typescript
embedResourcesType:
imports: string
ResourcesType: string
Expand Down Expand Up @@ -199,7 +199,7 @@ Use this to generate type definitions for the generated DataLoaders. At this tim

| Key | Value Description |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `language` | Must be 'flow' until we support other options. |
| `language` | Must be 'typescript' until we support other options. |
| `embedResourcesType.imports` | Lets you inject an arbitrary import statement into the generated file, to help you write the type statement below. |
| `embedResourcesType.ResourcesType` | Inject code to describe the shape of the resources object you're going to pass into `getLoaders`. Should start with `type ResourcesType = ...` |
| |
17 changes: 13 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,30 @@ venv: Makefile requirements-dev.txt
virtualenv venv --python=$(PYTHON3)
venv/bin/pip install -r requirements-dev.txt

node_modules: package.json yarn.lock
node_modules: package.json
yarn

build: node_modules
yarn build
# Generate the .d.ts files
node_modules/.bin/tsc --project tsconfig.json --checkJs false --emitDeclarationOnly || true
# TODO: Loop through everything in the lib folder to create the flow types
yarn flowgen --add-flow-header lib/runtimeHelpers.d.ts --output-file lib/runtimeHelpers.js.flow

link-examples: build
yarn link
cd examples/swapi
yarn link dataloader-codegen

build-examples: link-examples
$(MAKE) -C examples/swapi swapi-loaders.ts
$(MAKE) -C examples/swapi build
node examples/swapi/build/swapi-server.js

.PHONY: test
test: build venv node_modules
test: build venv node_modules build-examples
venv/bin/pre-commit install -f --install-hooks
venv/bin/pre-commit run --all-files
yarn test
yarn test:exampleTypes

.PHONY: clean
clean:
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# 🤖 dataloader-codegen

## Now with TypeScript!

[![npm](https://img.shields.io/npm/v/dataloader-codegen.svg)](https://yarn.pm/dataloader-codegen)
[![Build Status](https://api.travis-ci.com/Yelp/dataloader-codegen.svg?branch=master)](https://travis-ci.com/github/Yelp/dataloader-codegen)

Expand All @@ -14,7 +16,7 @@ Read more about the motivation behind this library in our recent blog post: http
- 🚚 Supports Batched + Non Batched Resources
- ✨ Predictable DataLoader Interfaces
- 🐛 Error Handling
- 🔒 Type Safety (Flow)
- 🔒 Type Safety (TypeScript)
- 🔧 Resource Middleware

## Install
Expand Down
26 changes: 26 additions & 0 deletions __tests__/genType.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { getResourceTypeReference, getNewKeyTypeFromBatchKeySetType, getLoaderTypeKey } from '../src/genType';

it('getResourceTypeReference converts a resource path to a valid reference', () => {
expect(getResourceTypeReference(null, ['foo', 'bar', 'baz'])).toBe("ResourcesType['foo']['bar']['baz']");
});

it('getNewKeyTypeFromBatchKeySetType returns a newKey type with a valid value', () => {
expect(getNewKeyTypeFromBatchKeySetType('bKey', "ResourcesType['foo']['bar']['baz']")).toBe(
`Parameters<ResourcesType['foo']['bar']['baz']['bKey']['has']>[0]`,
);
});

it('getLoaderTypeKey forces a nullable batchKey to be strictly non-nullable', () => {
expect(
getLoaderTypeKey(
{
isBatchResource: true,
newKey: 'test_id',
batchKey: 'test_ids',
},
['a', 'b'],
),
).toBe(
`Omit<Parameters<ResourcesType['a']['b']>[0], 'test_ids'> & { test_id: NonNullable<Parameters<ResourcesType['a']['b']>[0]['test_ids']>[0] }`,
);
});
47 changes: 0 additions & 47 deletions __tests__/genTypeFlow.test.js

This file was deleted.

57 changes: 53 additions & 4 deletions __tests__/implementation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import { getConfig } from '../src/config';

const BABEL_CONFIG = {
presets: [
'@babel/preset-flow',
'@babel/preset-typescript',
[
'@babel/preset-env',
{
modules: 'commonjs',
},
],
],
// Babel needs this dummy file name to determine it's a TypeScript file
filename: 'file.ts',
};

const RUNTIME_HELPERS = path.resolve(__dirname, '..', 'src', 'runtimeHelpers.ts');
Expand Down Expand Up @@ -45,7 +47,7 @@ expect.extend({
async function createDataLoaders(config, cb) {
await tmp.withFile(
async ({ path }) => {
const loadersCode = await babel.transformAsync(codegen(config, RUNTIME_HELPERS), BABEL_CONFIG);
const loadersCode = await babel.transformAsync(await codegen(config, RUNTIME_HELPERS), BABEL_CONFIG);
fs.writeFileSync(path, 'const regeneratorRuntime = require("regenerator-runtime");');
fs.appendFileSync(path, loadersCode.code);
// Import the generated code into memory :scream:
Expand Down Expand Up @@ -886,15 +888,16 @@ test('batch endpoint with isBatchKeyASet handles a response', async () => {

const resources = {
foo: ({ foo_ids, include_extra_info }) => {
if (_.isEqual(foo_ids, [1, 2])) {
expect(foo_ids).toBeInstanceOf(Set);
if (_.isEqual(Array.from(foo_ids), [1, 2])) {
expect(include_extra_info).toBe(false);
return Promise.resolve([
{ foo_id: 1, foo_value: 'hello' },
{ foo_id: 2, foo_value: 'world' },
]);
}

if (_.isEqual(foo_ids, [3])) {
if (_.isEqual(Array.from(foo_ids), [3])) {
expect(include_extra_info).toBe(true);
return Promise.resolve([
{
Expand Down Expand Up @@ -1608,3 +1611,49 @@ test('batch endpoint with propertyBatchKey with reorderResultsByKey handles resp
]);
});
});

test('embeds resource types', async () => {
// For the sake of coverage we pass in these test comments which will get interpolated in the generated code
// but otherwise we don't need to test them.
const config = {
resources: {
foo: {
isBatchResource: false,
docsLink: 'example.com/docs/foo',
},
},
typings: {
embedResourcesType: {
imports: '// test foo',
ResourcesType: '// test bar',
},
},
};

const resources = {
foo: jest
.fn()
.mockReturnValueOnce(
Promise.resolve({
message: 'knock knock',
message_suffix: '!',
}),
)
.mockReturnValueOnce(
Promise.resolve({
message: "who's there",
message_suffix: '?',
}),
),
};

await createDataLoaders(config, async (getLoaders) => {
const loaders = getLoaders(resources);

const results = await loaders.foo.loadMany([{ bar_id: 1 }, { bar_id: 2 }]);
expect(results).toEqual([
{ message: 'knock knock', message_suffix: '!' },
{ message: "who's there", message_suffix: '?' },
]);
});
});
4 changes: 2 additions & 2 deletions examples/swapi/.babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
"@babel/preset-env",
{
"targets": {
"node": "8"
"node": "22"
}
}
],
"@babel/preset-flow"
"@babel/preset-typescript"
]
}
12 changes: 0 additions & 12 deletions examples/swapi/.flowconfig

This file was deleted.

1 change: 1 addition & 0 deletions examples/swapi/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
build
.yarnrc
11 changes: 4 additions & 7 deletions examples/swapi/Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
node_modules: package.json
yarn

.PHONY: swapi-loaders.js
swapi-loaders.js:
node ../../lib/index.js --config swapi.dataloader-config.yaml --output swapi-loaders.js

flow-typed: node_modules
yarn flow-typed install
.PHONY: swapi-loaders.ts
swapi-loaders.ts:
node ../../lib/index.js --config swapi.dataloader-config.yaml --output swapi-loaders.ts

.PHONY: build
build: node_modules
yarn babel *.js -d build
yarn babel *.ts -d build -x .ts
2 changes: 1 addition & 1 deletion examples/swapi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Build the example:
$ cd examples/swapi
$ yarn
$ yarn link dataloader-codegen
$ make swapi-loaders.js
$ make swapi-loaders.ts
$ make build
# Prints out a GraphQL query result:
$ node build/swapi-server.js
Expand Down
46 changes: 0 additions & 46 deletions examples/swapi/flow-typed/npm/@babel/node_vx.x.x.js

This file was deleted.

Loading