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

Import Grants Stack Data Client #2582

Merged
merged 78 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
b71cd82
Initial import
bard Jul 20, 2020
007328b
add jest types
bard Jul 20, 2020
2536fd2
remove lock file, it makes no sense for a template
bard Jul 20, 2020
ef7d1eb
transpile with babel
bard Jul 20, 2020
1743aa0
update package name
bard Jul 22, 2020
3ef54f2
update package name
bard Aug 14, 2020
c53e8ab
add test scripts
bard Aug 21, 2020
c5a195d
limit print width to 76
bard Aug 23, 2020
dca2532
support .env
bard Oct 4, 2020
20cf9a9
clear screen between runs
bard Jan 31, 2021
084a90f
use tsc-watch in place of babel-node
bard Mar 13, 2021
a251439
dev,enh: upgrade husky
bard May 2, 2021
6479608
dev,enh: add lint script and rules
bard May 15, 2021
036aaeb
dev,enh: speed up tests with jest upgrade and esbuild
bard Nov 7, 2021
1e38a2a
dev,enh: clarify script name
bard Nov 7, 2021
c449323
dev,env: add typecheck script
bard May 29, 2022
e05a013
dev,enh: switch to esm, ts-jest, and ts-node
bard May 29, 2022
b5b279a
dev,enh: add debug utility
bard May 29, 2022
157f1d0
dev,enh: switch to tsx for better esm support
bard Oct 14, 2022
ac90c93
dev,enh: switch to @swc/jest for faster tests
bard Oct 14, 2022
9ea6822
dev,enh: switch to pnpm
bard Dec 16, 2022
0d87d26
dev,enh: use nodenext module resolution
bard Dec 16, 2022
bd8e166
dev,fix: add ignore
bard Dec 16, 2022
276fe62
dev,enh: outsource tsconfig
bard Dec 16, 2022
29a2ad5
dev,feat: add build script
bard Dec 16, 2022
282448b
dev,enh: make jest notifier less chatty
bard Dec 16, 2022
48f12d6
dev,enh: use non-esm @tsconfig/node18-strictest variant
bard Jan 3, 2023
a56855d
dev,fix: add start:prod script
bard Jan 3, 2023
e65ca53
dev,enh: use tsx watch mode in place of nodemon
bard Aug 20, 2023
805c336
dev,enh: bump minimum node version
bard Aug 20, 2023
c4a8891
dev,enh: upgrade jest
bard Aug 20, 2023
dca198b
dev,enh: upgrade prettier
bard Aug 20, 2023
ada98c7
dev,enh: use prettier defaults
bard Aug 20, 2023
3354c00
dev,enh: replace jest with vitest
bard Aug 27, 2023
b126d66
dev,enh: update typescript
bard Aug 27, 2023
2f2d787
dev,enh: replace suretype with zod
bard Aug 27, 2023
ec231d7
dev,fix: use pnpm to run hook
bard Aug 27, 2023
6af1eb9
dev,enh: work around husky issue when installing for prod
bard Sep 2, 2023
e81c46e
dev,feat: add typecheck command
bard Sep 2, 2023
d3085c4
dev,feat: add script to review todo's and fixme's
bard Sep 2, 2023
cbe16c0
dev,enh: update typescript-eslint
bard Sep 2, 2023
9d9a1db
dev,feat: add dockerfile and workflow to generate image
bard Sep 2, 2023
7c27f52
dev,enh: generate coverage report
bard Sep 2, 2023
8204451
dev,enh: replace husky with lefthook
bard Sep 10, 2023
4c63492
dev,fix: add missing watch
bard Sep 10, 2023
30781cd
dev,enh: upgrade dependencies
bard Sep 10, 2023
a221382
dev,enh: remove leftover
bard Sep 10, 2023
f52094f
dev,enh: lint unused exports
bard Sep 15, 2023
77b7cf8
dev,enh: silence warning
bard Sep 16, 2023
2a6295a
dev,enh: upgrade dependencies
bard Sep 16, 2023
0fecae2
func,fix: use .env for prod start script
bard Sep 16, 2023
4ef7476
dev,enh: switch to type: "module"
bard Sep 16, 2023
ab2c9ae
dev,fix: fix imports
bard Sep 17, 2023
d244f08
dev,fix: fix script name
bard Sep 17, 2023
cbb37bf
dev,enh: move unused export check to pre-commit hook
bard Sep 18, 2023
7766b9f
dev,fix: don't lint src when linting staged files
bard Sep 18, 2023
3c185be
func,feat: add data client
bard Nov 6, 2023
5f8e767
func,feat: allow shuffling applications before pagination
bard Nov 6, 2023
164a25b
func,fix: use openapi-generator-cli to generate openapi types
bard Nov 6, 2023
8600fcf
func,enh: update types
bard Nov 7, 2023
23587f0
func,feat: add sort by createdAtBlock
bard Nov 7, 2023
d5383e9
func,feat: expose round name
bard Nov 8, 2023
f887367
func,feat: expose model types
bard Nov 8, 2023
e876087
func,feat: add sorting by contribution amount and contributor count
bard Nov 9, 2023
9182ebf
func,feat: support pagination for search results
bard Nov 10, 2023
86a4bf9
func,feat: add filter by chain
bard Nov 13, 2023
2c14a75
chore: move into packages/grants-stack-data-client
boudra Nov 14, 2023
66e6781
chore: move hidden files
boudra Nov 14, 2023
8db012e
chore: import grants-stack-data-client
boudra Nov 14, 2023
7cf0df3
fix: build image workflow
boudra Nov 14, 2023
e3f96d9
chore: link up grants-stack-data-client
boudra Nov 14, 2023
37e5b8a
chore: make updates for new version of gsdata client
boudra Nov 14, 2023
167b926
fix: gsdataclient workflow
boudra Nov 14, 2023
5376d37
fix: workflow push and PR events
boudra Nov 14, 2023
ca07b57
further data client integration
bard Nov 14, 2023
8891777
Merge branch 'main' into feat/grants-stack-data-client
bard Nov 14, 2023
6065659
Merge branch 'main' into feat/grants-stack-data-client
bard Nov 14, 2023
b61b166
cleanup
bard Nov 14, 2023
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
45 changes: 45 additions & 0 deletions .github/workflows/grants-stack-data-client.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Data client - Lint & Test & Typecheck
on:
push:
branches:
- main
- release
pull_request:
branches:
- "**"
jobs:
lint-test-typecheck:
concurrency: ci-data-client-${{ github.head_ref || github.run_id }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 1

- uses: pnpm/action-setup@v2
with:
version: 8

- uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'pnpm'

- name: Install Dependencies
run: |
pnpm install

# TODO
# - name: Lint Data Client
# run: |
# pnpm dc-lint

- name: Test Data Client
run: |
pnpm dc-test

# TODO
# - name: Typecheck Explorer
# run: |
# pnpm ge-typecheck
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ node_modules
.turbo
.husky/
.vercel
/packages/verify-env/dist/
dist/
coverage/
.eslintcache

14 changes: 11 additions & 3 deletions lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,20 @@ pre-commit:
run: pnpm --filter "grant-explorer" lint:local {staged_files}
stage_fixed: true

lint-data-client:
root: "packages/grants-stack-data-client"
glob: "**/*.{js,ts,jsx,tsx}"
# TODO: harmonize command name with others
run: pnpm --filter "grants-stack-data-client" lint {staged_files}
stage_fixed: true


pre-push:
parallel: true
commands:
typecheck:
run: turbo run typecheck
run: pnpm turbo run typecheck
build:
run: turbo run build
run: pnpm turbo run build
test:
run: turbo run test
run: pnpm turbo run test
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
"b-test": "pnpm test --filter=builder",
"b-typecheck": "turbo run typecheck --filter=builder",
"c-test": "turbo run test --filter=common",
"ve-test": "turbo run test --filter=verify-env"
"ve-test": "turbo run test --filter=verify-env",
"// data client script": "====== packages/builder specific ======",
"dc-test": "turbo run test --filter=grants-stack-data-client"
},
"devDependencies": {
"@commitlint/cli": "^17.7.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"dompurify": "^2.4.3",
"ethers": "^5.6.5",
"framer-motion": "^10.12.7",
"grants-stack-data-client": "github:gitcoinco/grants-stack-data-client",
"grants-stack-data-client": "workspace:*",
"markdown-it": "^13.0.1",
"react": "^18.2.0",
"react-hook-form": "^7.42.1",
Expand Down
26 changes: 26 additions & 0 deletions packages/grants-stack-data-client/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [
"prettier",
"@typescript-eslint",
"import"
],
"extends": [
"eslint:recommended",
"prettier",
"plugin:@typescript-eslint/recommended"
],
"env": {
"node": true
},
"rules": {
"@typescript-eslint/no-unused-vars": [
1,
{
"argsIgnorePattern": "^_"
}
],
"import/no-default-export": "error"
}
}
1 change: 1 addition & 0 deletions packages/grants-stack-data-client/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
30 changes: 30 additions & 0 deletions packages/grants-stack-data-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## Development

To run tests in watch mode:

```sh
pnpm run test:watch
```

To update types from the [search service](https://gitcoin-search-dev.fly.dev/docs), run:

```sh
pnpm run generate:openapi
```

## Example

```ts
import { GrantsStackDataClient } from "grants-stack-data-client";

const gsData = new GrantsStackDataClient({
baseUrl: "https://gitcoin-search-dev.fly.dev",
});

const { applications, pagination } = await gsData.query({
type: "applications-paginated",
page: 0,
});
```

For more examples, see `src/grants-stack-data-client.test.ts`.
7 changes: 7 additions & 0 deletions packages/grants-stack-data-client/openapitools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
"spaces": 2,
"generator-cli": {
"version": "7.0.1"
}
}
57 changes: 57 additions & 0 deletions packages/grants-stack-data-client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "grants-stack-data-client",
bard marked this conversation as resolved.
Show resolved Hide resolved
"version": "1.0.0",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"dev": "tsx watch -r dotenv-flow/config src/index.ts",
"start": "node -r dotenv-flow/config dist/index.js",
"lint": "eslint --cache --max-warnings=0",
"lint:fix": "eslint --cache --max-warnings=0 --fix",
"lint:all": "eslint --cache --max-warnings=0 src",
"generate:openapi": "openapi-generator-cli generate -i https://gitcoin-search-dev.fly.dev/openapi.json -o src/openapi-search-client -g typescript-fetch --additional-properties=importFileExtension=.js",
"generate:openapi:local": "openapi-generator-cli generate -i http://localhost:8000/openapi.json -o src/openapi-search-client -g typescript-fetch --additional-properties=importFileExtension=.js",
"format": "prettier --write",
"lint:unused-exports": "ts-unused-exports ./tsconfig.json --maxIssues=0",
"test": "vitest run --coverage",
"build": "tsc",
"test:watch": "vitest watch",
"typecheck": "tsc --noEmit",
"typecheck:watch": "tsc --noEmit --watch",
"todo": "leasot 'src/**/*.ts'",
"prepare": "tsc"
},
"devDependencies": {
"@openapitools/openapi-generator-cli": "^2.7.0",
"@tsconfig/node18": "^18.2.2",
"@types/debug": "^4.1.8",
"@types/knuth-shuffle-seeded": "^1.0.1",
"@types/node": "^20.6.2",
"@typescript-eslint/eslint-plugin": "^6.7.0",
"@typescript-eslint/parser": "^6.7.0",
"@vitest/coverage-v8": "^0.34.4",
"eslint": "^8.49.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-prettier": "^5.0.0",
"leasot": "^13.3.0",
"lefthook": "^1.4.11",
"prettier": "^3.0.3",
"ts-unused-exports": "^10.0.1",
"tsx": "^3.12.10",
"typescript": "^5.2.2",
"vitest": "^0.34.4"
},
"engines": {
"node": ">=18"
},
"dependencies": {
"cross-fetch": "^4.0.0",
"debug": "^4.3.4",
"dotenv-flow": "^3.3.0",
"knuth-shuffle-seeded": "^1.0.6",
"ts-essentials": "^9.4.1",
"zod": "^3.22.2"
}
}
141 changes: 141 additions & 0 deletions packages/grants-stack-data-client/src/grants-stack-data-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import shuffle from "knuth-shuffle-seeded";
import { UnreachableCaseError } from "ts-essentials";
import _fetch from "cross-fetch";
import {
DataClientInteraction,
ExtractQuery,
ExtractResponse,
} from "./grants-stack-data-client.types.js";
import {
ApplicationSummary,
DefaultApi as SearchApi,
Configuration as SearchApiConfiguration,
} from "./openapi-search-client/index.js";

export class GrantsStackDataClient {
private pageSize: number;
private searchApi: SearchApi;

constructor({
fetch,
baseUrl,
pagination,
}: {
fetch?: typeof _fetch;
pagination?: { pageSize: number };
baseUrl: string;
}) {
this.searchApi = new SearchApi(
new SearchApiConfiguration({
fetchApi: fetch,
basePath: baseUrl,
}),
);
this.pageSize = pagination?.pageSize ?? 10;
}

async query(
q: ExtractQuery<DataClientInteraction, "applications-by-refs">,
): Promise<ExtractResponse<DataClientInteraction, "applications-by-refs">>;
async query(
q: ExtractQuery<DataClientInteraction, "applications-paginated">,
): Promise<ExtractResponse<DataClientInteraction, "applications-paginated">>;
async query(
q: ExtractQuery<DataClientInteraction, "applications-search">,
): Promise<ExtractResponse<DataClientInteraction, "applications-search">>;
async query(
q: DataClientInteraction["query"],
): Promise<DataClientInteraction["response"]> {
switch (q.type) {
case "applications-search": {
const { results } = await this.searchApi.searchSearchGet({
q: q.queryString,
});

// TODO consider unifying with /applications endpoint
const pageStart = q.page * this.pageSize;
const pageEnd = pageStart + this.pageSize;
const page = results.slice(pageStart, pageEnd);

return {
results: page,
pagination: {
currentPage: q.page,
totalPages: Math.ceil(results.length / this.pageSize),
totalItems: results.length,
},
};
}

case "applications-by-refs": {
const { applicationSummaries } =
await this.searchApi.getApplicationsApplicationsGet();

return {
applications: applicationSummaries.filter((a) =>
q.refs.includes(a.applicationRef),
),
};
}

case "applications-paginated": {
const { applicationSummaries } =
await this.searchApi.getApplicationsApplicationsGet();

const pageStart = q.page * this.pageSize;
const pageEnd = pageStart + this.pageSize;

let filteredApplicationSummaries: ApplicationSummary[];
if (q.filter === undefined) {
filteredApplicationSummaries = applicationSummaries;
} else if (q.filter.type === "chain") {
const { chainId } = q.filter;
filteredApplicationSummaries = applicationSummaries.filter(
(a) => a.chainId === chainId,
);
} else if (q.filter.type === "refs") {
const { refs } = q.filter;
filteredApplicationSummaries = applicationSummaries.filter((a) =>
refs.includes(a.applicationRef),
);
} else {
throw new Error(`Unreachable brank invoked`);
}

let orderedApplicationSummaries: ApplicationSummary[];
if (q.order === undefined) {
orderedApplicationSummaries = filteredApplicationSummaries;
} else if (q.order.type === "random") {
orderedApplicationSummaries = shuffle(
filteredApplicationSummaries,
q.order.seed,
);
} else {
const { direction, type: property } = q.order;
orderedApplicationSummaries = [...filteredApplicationSummaries].sort(
(a, b) =>
direction === "asc"
? a[property] - b[property]
: b[property] - a[property],
);
}

const page = orderedApplicationSummaries.slice(pageStart, pageEnd);

return {
applications: page,
pagination: {
currentPage: q.page,
totalPages: Math.ceil(
filteredApplicationSummaries.length / this.pageSize,
),
totalItems: filteredApplicationSummaries.length,
},
};
}

default:
throw new UnreachableCaseError(q);
}
}
}
Loading