Skip to content
Open
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
19 changes: 14 additions & 5 deletions typescript/rest-hono-cf-d1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,25 @@ npm install

### 2. Create and seed the database

Run the command to create your D1 database
> [!IMPORTANT]
> Update [wrangler.toml](./wrangler.toml) database_id

```
Run the command to create your production D1 database

```bash
npx wrangler d1 create test-sutando
```
Update [wrangler.toml](./wrangler.toml) database_id

Run the command to create your local D1 database

```bash
npx knex-cloudflare-d1 setup
```

Import test data to local database

```
npx wrangler d1 execute test-sutando --local --file=./migrations/0000_lucky_gideon.sql
npx sutando migrate:run
```

### 3. Start the REST API server
Expand Down Expand Up @@ -67,7 +75,8 @@ You can access the REST API of the server using the following endpoints:
- `/users`: Create a new user
- Body:
- `email: String` (required): The email address of the user
- `name: String` (optional): The name of the user
- `first_name: String` (optional): The first name of the user
- `last_name: String` (optional): The last name of the user

### `PUT`

Expand Down
11 changes: 0 additions & 11 deletions typescript/rest-hono-cf-d1/migrations/0000_lucky_gideon.sql

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const { Migration } = require("sutando");

module.exports = class extends Migration {
/**
* Run the migrations.
*/
async up(schema) {
await schema.createTable("users", (table) => {
table.increments("id");
table.string("first_name");
table.string("last_name");
table.string("email");
table.timestamps();
});
}

/**
* Reverse the migrations.
*/
async down(schema) {
await schema.dropTableIfExists("users");
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const { Migration, sutando } = require("sutando");

module.exports = class extends Migration {
/**
* Run the migrations.
*/
async up(schema) {
await schema.createTable("posts", (table) => {
table.uuid('id');
table.integer("author_id").unsigned().notNullable();
table.string("title", 30);
table.string("content");
table.timestamps();
table.timestamp("published_at");
table.integer("views_count").defaultTo(0);
});
}

/**
* Reverse the migrations.
*/
async down(schema) {
await schema.dropTableIfExists("posts");
}
};
4 changes: 2 additions & 2 deletions typescript/rest-hono-cf-d1/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
},
"dependencies": {
"hono": "^4.2.3",
"knex-cloudflare-d1": "^0.1.1",
"sutando": "1.5.4",
"knex-cloudflare-d1": "github:jjjrmy/knex-cloudflare-d1#master",
"sutando": "^1.7.1-dev.7",
"uuid": "^9.0.1"
},
"devDependencies": {
Expand Down
21 changes: 13 additions & 8 deletions typescript/rest-hono-cf-d1/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,26 @@ import { Hono } from 'hono';
import { ModelNotFoundError, sutando } from 'sutando';
import { Post, User } from './models';
import type { OrderByDirection } from 'sutando';
import ClientD1 from 'knex-cloudflare-d1';
// @ts-ignore
import config from "../sutando.config.cjs";

type Bindings = {
DB: D1Database
}

const app = new Hono();

app.get('/', (c) => {
return c.text("Hello World");
});

app.post(`/users`, async (c) => {
const body = await c.req.json();
const { name, email } = body;
const { first_name, last_name, email } = body;

const user = new User({
name,
first_name,
last_name,
email,
});
await user.save();
Expand Down Expand Up @@ -48,7 +54,7 @@ app.put('/posts/:id/views', async (c) => {

app.get('/users', async (c) => {
const users = await User.query().withCount({
posts: q => q.where('published', true)
posts: q => q.whereNotNull('published_at')
}).get();
return c.json(users);
});
Expand All @@ -58,7 +64,7 @@ app.get('/users/:id/drafts', async (c) => {

const drafts = await User.query()
.with({
posts: q => q.where('published', false),
posts: q => q.whereNull('published_at'),
})
.findOrFail(id);

Expand Down Expand Up @@ -106,7 +112,7 @@ app.put('/publish/:id', async (c) => {
const { id } = c.req.param();

const post = await Post.query().findOrFail(id);
post.published = !post.published;
post.published_at = new Date();
await post.save();

return c.json(post);
Expand All @@ -127,11 +133,10 @@ app.onError((err, c) => {
export default {
fetch: (req: Request, env: Bindings) => {
sutando.addConnection({
client: ClientD1,
... config,
connection: {
database: env.DB
},
useNullAsDefault: true,
});

return app.fetch(req, env)
Expand Down
19 changes: 8 additions & 11 deletions typescript/rest-hono-cf-d1/src/models.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
import { Model, HasUniqueIds } from 'sutando';
import { v4 as uuid } from 'uuid';

const BaseModel = HasUniqueIds(Model) as typeof Model;
const UuidModel = HasUniqueIds(Model) as typeof Model;

export class User extends BaseModel {
export class User extends Model {
table = 'users';

id!: string;
name!: string;
id!: number;
first_name!: string;
last_name!: string;
email!: string;
created_at!: Date;
updated_at!: Date;

newUniqueId(): string {
return uuid();
}

relationPosts() {
return this.hasMany(Post, 'author_id');
}
}

export class Post extends BaseModel {
export class Post extends UuidModel {
table = 'posts';

id!: string;
Expand All @@ -30,11 +27,11 @@ export class Post extends BaseModel {
content!: string;
created_at!: Date;
updated_at!: Date;
published!: boolean;
published_at!: Date;
views_count!: number;

casts = {
published: 'boolean'
published_at: 'datetime'
}

newUniqueId(): string {
Expand Down
15 changes: 15 additions & 0 deletions typescript/rest-hono-cf-d1/sutando.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = {
client: require('knex-cloudflare-d1'),
connection: {
database: "test-sutando", // From Wrangler Binding
local: true, // Toggles `--local` flag on `wrangler d1 exec` command (Default as false)
},
useNullAsDefault: true,
migrations: {
table: 'migrations',
path: './migrations',
},
models: {
path: './models'
}
};
17 changes: 17 additions & 0 deletions typescript/rest-hono-cf-d1/sutando.config.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
declare const config: {
client: any;
connection: {
database: string;
wranglerPath: string;
};
useNullAsDefault: boolean;
migrations: {
table: string;
path: string;
};
models: {
path: string;
};
};

export default config;
5 changes: 3 additions & 2 deletions typescript/rest-hono-cf-d1/wrangler.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name = "rest-hono-cf-d1"
compatibility_date = "2023-12-01"
node_compat = true
compatibility_date = "2024-12-05"
compatibility_flags = ["nodejs_compat"]
main = "src/index.ts"

# [vars]
# MY_VAR = "my-variable"
Expand Down