Skip to content

Commit

Permalink
Update generic cruds to use generic d1 binding methods (#212)
Browse files Browse the repository at this point in the history
  • Loading branch information
G4brym authored Dec 12, 2024
1 parent 75ae459 commit 5ba6d95
Show file tree
Hide file tree
Showing 22 changed files with 478 additions and 440 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/create-pullrequest-prerelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ jobs:
You can install this latest build in your project with:
```sh
npm install --save https://prerelease-registry.devprod.cloudflare.dev/chanfana/runs/${{ github.workflow_run.id }}/npm-package-chanfana-${{ github.event.number }}
npm install --save https://prerelease-registry.devprod.cloudflare.dev/chanfana/runs/${{ github.run_id }}/npm-package-chanfana-${{ github.event.number }}
```
Or you can immediately run this with `npx`:
```sh
npx https://prerelease-registry.devprod.cloudflare.dev/chanfana/runs/${{ github.workflow_run.id }}/npm-package-chanfana-${{ github.event.number }}
npx https://prerelease-registry.devprod.cloudflare.dev/chanfana/runs/${{ github.run_id }}/npm-package-chanfana-${{ github.event.number }}
```
62 changes: 31 additions & 31 deletions biome.json
Original file line number Diff line number Diff line change
@@ -1,46 +1,46 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": false,
"ignore": ["dist", "docs", "example"]
},
"formatter": {
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": false,
"ignore": ["dist", "docs", "example"]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 120
},
"organizeImports": {
"enabled": true
},
"javascript": {
"formatter": {
"quoteStyle": "double"
}
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
},
"organizeImports": {
"enabled": true
},
"javascript": {
"formatter": {
"quoteStyle": "double"
}
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": {
"noBannedTypes": "off",
"noThisInStatic": "off"
},
"suspicious": {
"noExplicitAny": "off",
"noImplicitAnyLet": "off"
},
"performance": {
"noAccumulatingSpread": "off"
},
"noExplicitAny": "off",
"noImplicitAnyLet": "off"
},
"performance": {
"noAccumulatingSpread": "off"
},
"style": {
"noParameterAssign": "off"
}
}
}
}
}
140 changes: 68 additions & 72 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,74 +1,70 @@
{
"name": "chanfana",
"version": "2.4.2",
"description": "OpenAPI 3 and 3.1 schema generator and validator for Hono, itty-router and more!",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"files": [
"dist",
"LICENSE",
"README.md"
],
"scripts": {
"prepare": "husky",
"build": "rm -rf dist/ && tsup src/index.ts --format cjs,esm --dts --config tsconfig.json",
"lint": "npx @biomejs/biome check src/ tests/ || (npx @biomejs/biome check --write src/ tests/; exit 1)",
"test": "vitest run --root tests",
"deploy-docs": "cd docs && mkdocs build && wrangler pages deploy site --project-name chanfana --branch main"
},
"keywords": [
"cloudflare",
"worker",
"workers",
"serverless",
"cloudflare workers",
"router",
"openapi",
"swagger",
"openapi generator",
"cf",
"optional",
"middleware",
"parameters",
"typescript",
"npm",
"package",
"cjs",
"esm",
"umd",
"typed"
],
"author": "Gabriel Massadas <[email protected]> (https://github.com/g4brym)",
"license": "MIT",
"homepage": "https://chanfana.pages.dev",
"repository": {
"type": "git",
"url": "https://github.com/cloudflare/chanfana.git"
},
"bugs": {
"url": "https://github.com/cloudflare/chanfana/issues"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@cloudflare/vitest-pool-workers": "^0.5.26",
"@cloudflare/workers-types": "4.20241127.0",
"@types/js-yaml": "^4.0.9",
"@types/node": "22.10.1",
"@types/service-worker-mock": "^2.0.1",
"hono": "4.6.12",
"husky": "9.1.7",
"itty-router": "5.0.18",
"tsup": "8.3.5",
"typescript": "5.7.2",
"vitest": "2.1.6",
"vitest-openapi": "^1.0.3",
"wrangler": "3.91.0"
},
"dependencies": {
"@asteasolutions/zod-to-openapi": "^7.2.0",
"js-yaml": "^4.1.0",
"openapi3-ts": "^4.4.0",
"zod": "^3.23.8"
}
"name": "chanfana",
"version": "2.4.2",
"description": "OpenAPI 3 and 3.1 schema generator and validator for Hono, itty-router and more!",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"files": ["dist", "LICENSE", "README.md"],
"scripts": {
"prepare": "husky",
"build": "rm -rf dist/ && tsup src/index.ts --format cjs,esm --dts --config tsconfig.json",
"lint": "npx @biomejs/biome check src/ tests/ || (npx @biomejs/biome check --write src/ tests/; exit 1)",
"test": "vitest run --root tests",
"deploy-docs": "cd docs && mkdocs build && wrangler pages deploy site --project-name chanfana --branch main"
},
"keywords": [
"cloudflare",
"worker",
"workers",
"serverless",
"cloudflare workers",
"router",
"openapi",
"swagger",
"openapi generator",
"cf",
"optional",
"middleware",
"parameters",
"typescript",
"npm",
"package",
"cjs",
"esm",
"umd",
"typed"
],
"author": "Gabriel Massadas <[email protected]> (https://github.com/g4brym)",
"license": "MIT",
"homepage": "https://chanfana.pages.dev",
"repository": {
"type": "git",
"url": "https://github.com/cloudflare/chanfana.git"
},
"bugs": {
"url": "https://github.com/cloudflare/chanfana/issues"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@cloudflare/vitest-pool-workers": "^0.5.26",
"@cloudflare/workers-types": "4.20241127.0",
"@types/js-yaml": "^4.0.9",
"@types/node": "22.10.1",
"@types/service-worker-mock": "^2.0.1",
"hono": "4.6.12",
"husky": "9.1.7",
"itty-router": "5.0.18",
"tsup": "8.3.5",
"typescript": "5.7.2",
"vitest": "2.1.6",
"vitest-openapi": "^1.0.3",
"wrangler": "3.91.0"
},
"dependencies": {
"@asteasolutions/zod-to-openapi": "^7.2.0",
"js-yaml": "^4.1.0",
"openapi3-ts": "^4.4.0",
"zod": "^3.23.8"
}
}
4 changes: 4 additions & 0 deletions src/adapters/hono.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export class HonoOpenAPIHandler extends OpenAPIHandler {
getUrlParams(args: any[]): Record<string, any> {
return args[0].req.param();
}

getBindings(args: any[]): Record<string, any> {
return args[0].env;
}
}

export function fromHono<M>(router: M, options?: RouterOptions): M & HonoOpenAPIRouterType<M> {
Expand Down
4 changes: 4 additions & 0 deletions src/adapters/ittyRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ export class IttyRouterOpenAPIHandler extends OpenAPIHandler {
getUrlParams(args: any[]): Record<string, any> {
return args[0].params;
}

getBindings(args: any[]): Record<string, any> {
return args[1];
}
}

export function fromIttyRouter<M>(router: M, options?: RouterOptions): M & OpenAPIRouterType<M> {
Expand Down
10 changes: 0 additions & 10 deletions src/endpoints/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ export class CreateEndpoint<HandleArgs extends Array<object> = Array<object>> ex
return MetaGenerator(this._meta);
}

defaultValues?: Record<string, () => any>; // TODO: move this into model

getSchema() {
const bodyParameters = this.meta.fields.omit(
(this.params.urlParams || []).reduce((a, v) => ({ ...a, [v]: true }), {}),
Expand Down Expand Up @@ -55,14 +53,6 @@ export class CreateEndpoint<HandleArgs extends Array<object> = Array<object>> ex
newData[param] = (data.params as any)[param];
}

if (this.defaultValues) {
for (const [key, value] of Object.entries(this.defaultValues)) {
if (newData[key] === undefined) {
newData[key] = value();
}
}
}

return newData;
}

Expand Down
54 changes: 54 additions & 0 deletions src/endpoints/d1/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ApiException, InputValidationException } from "../../exceptions";
import { CreateEndpoint } from "../create";
import type { Logger, O } from "../types";

export class D1CreateEndpoint<HandleArgs extends Array<object> = Array<object>> extends CreateEndpoint<HandleArgs> {
dbName = "DB";
logger?: Logger;

getDBBinding(): D1Database {
const env = this.params.router.getBindings(this.args);
if (env[this.dbName] === undefined) {
throw new ApiException(`Binding "${this.dbName}" is not defined in worker`);
}

if (env[this.dbName].prepare === undefined) {
throw new ApiException(`Binding "${this.dbName}" is not a D1 binding`);
}

return env[this.dbName];
}

async create(data: O<typeof this.meta>): Promise<O<typeof this.meta>> {
let inserted;
try {
const result = await this.getDBBinding()
.prepare(
`INSERT INTO ${this.meta.model.tableName} (${Object.keys(data).join(", ")}) VALUES (${Object.values(data)
.map(() => "?")
.join(", ")}) RETURNING *`,
)
.bind(...Object.values(data))
.all();

inserted = result.results[0] as O<typeof this.meta>;
} catch (e: any) {
if (this.logger)
this.logger.error(`Caught exception while trying to create ${this.meta.model.tableName}: ${e.message}`);
if (e.message.includes("UNIQUE constraint failed")) {
if (e.message.includes(this.meta.model.tableName) && e.message.includes(this.meta.model.primaryKeys[0])) {
throw new InputValidationException(`An object with this ${this.meta.model.primaryKeys[0]} already exists`, [
"body",
this.meta.model.primaryKeys[0],
]);
}
}

throw new ApiException(e.message);
}

if (this.logger) this.logger.log(`Successfully created ${this.meta.model.tableName}`);

return inserted;
}
}
Loading

0 comments on commit 5ba6d95

Please sign in to comment.