Skip to content

Commit f785907

Browse files
committed
seed local d1
1 parent 63dc297 commit f785907

File tree

12 files changed

+223
-211
lines changed

12 files changed

+223
-211
lines changed

app/lib/auth.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import { anonymous } from "better-auth/plugins";
44
import * as schema from "../lib/db/schema";
55
import { getDB } from "./db";
66

7-
export function getAuth(env?: Env) {
7+
export function getAuth(env: Env) {
88
const auth = betterAuth({
99
database: drizzleAdapter(getDB(env), {
10-
provider: "pg",
10+
provider: "sqlite",
1111
schema: schema,
1212
}),
1313
emailAndPassword: {
@@ -28,5 +28,3 @@ export function getAuth(env?: Env) {
2828
});
2929
return auth;
3030
}
31-
// This is for @better-auth/cli
32-
// export const auth = getAuth();

app/lib/db/index.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
1-
import { drizzle as drizzleNeon } from "drizzle-orm/neon-http";
2-
import { drizzle as drizzlePg } from "drizzle-orm/node-postgres";
1+
import { drizzle } from "drizzle-orm/d1";
32

4-
export function getDB(env?: Env) {
5-
// better-auth/cli を実行するとき
6-
if (!env) {
7-
const db = drizzlePg(process.env.DATABASE_URL);
8-
return db;
9-
}
10-
const db =
11-
env.NODE_ENV === "development"
12-
? drizzlePg(env.DATABASE_URL)
13-
: drizzleNeon(env.DATABASE_URL);
3+
export function getDB(env: Env) {
4+
const db = drizzle(env.DB);
145
return db;
156
}

app/lib/db/schema.ts

Lines changed: 67 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,38 @@
1+
import type { string } from "better-auth";
12
import { sql } from "drizzle-orm";
23
import {
3-
boolean,
44
check,
5+
customType,
56
index,
67
integer,
7-
pgEnum,
8-
pgTable,
98
primaryKey,
10-
serial,
9+
sqliteTable,
1110
text,
12-
timestamp,
13-
} from "drizzle-orm/pg-core";
11+
} from "drizzle-orm/sqlite-core";
12+
import type { Hai } from "../hai/utils";
1413

15-
export const haiyama = pgTable("haiyama", {
16-
id: text("id").primaryKey(),
14+
const haiArray = customType<{ data: Hai[]; driverData: string }>({
15+
dataType() {
16+
return "text";
17+
},
18+
toDriver(value: Hai[]) {
19+
return JSON.stringify(value);
20+
},
21+
fromDriver(value: string) {
22+
return JSON.parse(value) as Hai[];
23+
},
1724
});
1825

19-
export const haiKindEnum = pgEnum("hai_kind", [
20-
"manzu",
21-
"pinzu",
22-
"souzu",
23-
"jihai",
24-
]);
25-
26-
export const hai = pgTable("hai", {
27-
id: serial("id").primaryKey(),
28-
haiyamaId: text("haiyama_id")
29-
.notNull()
30-
.references(() => haiyama.id, { onDelete: "cascade" }),
31-
kind: haiKindEnum("kind").notNull(), // "manzu" | "pinzu" | "souzu" | "jihai"
32-
value: text("value").notNull(), // 1~9 or "ton" ~ "tyun"
33-
order: integer("order").notNull(), // 0~17
34-
index: integer("index").notNull(), // haiToIndex
26+
export const haiyama = sqliteTable("haiyama", {
27+
id: text("id")
28+
.primaryKey()
29+
.$defaultFn(() => crypto.randomUUID()),
30+
// D1だと1クエリあたり100パラメータまでなので、あえて正規化していない
31+
tiles: haiArray("tiles").notNull(),
3532
});
3633

3734
// relation between user and haiyama
38-
export const kyoku = pgTable(
35+
export const kyoku = sqliteTable(
3936
"kyoku",
4037
{
4138
userId: text("user_id")
@@ -44,7 +41,7 @@ export const kyoku = pgTable(
4441
haiyamaId: text("haiyama_id")
4542
.notNull()
4643
.references(() => haiyama.id, { onDelete: "cascade" }),
47-
didAgari: boolean("did_agari").notNull(),
44+
didAgari: integer("did_agari", { mode: "boolean" }).notNull(),
4845
agariJunme: integer("agari_junme"),
4946
},
5047
(table) => [
@@ -59,36 +56,43 @@ export const kyoku = pgTable(
5956
);
6057

6158
// better-auth
62-
export const user = pgTable("user", {
59+
export const user = sqliteTable("user", {
6360
id: text("id").primaryKey(),
6461
name: text("name").notNull(),
6562
email: text("email").notNull().unique(),
66-
emailVerified: boolean("email_verified").default(false).notNull(),
67-
image: text("image"),
68-
createdAt: timestamp("created_at").defaultNow().notNull(),
69-
updatedAt: timestamp("updated_at")
70-
.defaultNow()
71-
.$onUpdate(() => /* @__PURE__ */ new Date())
63+
emailVerified: integer("email_verified", { mode: "boolean" })
64+
.default(false)
7265
.notNull(),
73-
isAnonymous: boolean("is_anonymous"),
66+
image: text("image"),
67+
createdAt: integer("created_at", { mode: "timestamp" })
68+
.notNull()
69+
.$defaultFn(() => new Date()),
70+
updatedAt: integer("updated_at", { mode: "timestamp" })
71+
.notNull()
72+
.$defaultFn(() => new Date())
73+
.$onUpdate(() => new Date()),
74+
isAnonymous: integer("is_anonymous", { mode: "boolean" }),
7475
});
7576

76-
export const session = pgTable("session", {
77+
export const session = sqliteTable("session", {
7778
id: text("id").primaryKey(),
78-
expiresAt: timestamp("expires_at").notNull(),
79+
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
7980
token: text("token").notNull().unique(),
80-
createdAt: timestamp("created_at").defaultNow().notNull(),
81-
updatedAt: timestamp("updated_at")
82-
.$onUpdate(() => /* @__PURE__ */ new Date())
83-
.notNull(),
81+
createdAt: integer("created_at", { mode: "timestamp" })
82+
.notNull()
83+
.$defaultFn(() => new Date()),
84+
updatedAt: integer("updated_at", { mode: "timestamp" })
85+
.notNull()
86+
.$defaultFn(() => new Date())
87+
.$onUpdate(() => new Date()),
8488
ipAddress: text("ip_address"),
8589
userAgent: text("user_agent"),
8690
userId: text("user_id")
8791
.notNull()
8892
.references(() => user.id, { onDelete: "cascade" }),
8993
});
9094

91-
export const account = pgTable("account", {
95+
export const account = sqliteTable("account", {
9296
id: text("id").primaryKey(),
9397
accountId: text("account_id").notNull(),
9498
providerId: text("provider_id").notNull(),
@@ -98,24 +102,33 @@ export const account = pgTable("account", {
98102
accessToken: text("access_token"),
99103
refreshToken: text("refresh_token"),
100104
idToken: text("id_token"),
101-
accessTokenExpiresAt: timestamp("access_token_expires_at"),
102-
refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
105+
accessTokenExpiresAt: integer("access_token_expires_at", {
106+
mode: "timestamp",
107+
}),
108+
refreshTokenExpiresAt: integer("refresh_token_expires_at", {
109+
mode: "timestamp",
110+
}),
103111
scope: text("scope"),
104112
password: text("password"),
105-
createdAt: timestamp("created_at").defaultNow().notNull(),
106-
updatedAt: timestamp("updated_at")
107-
.$onUpdate(() => /* @__PURE__ */ new Date())
108-
.notNull(),
113+
createdAt: integer("created_at", { mode: "timestamp" })
114+
.notNull()
115+
.$defaultFn(() => new Date()),
116+
updatedAt: integer("updated_at", { mode: "timestamp" })
117+
.notNull()
118+
.$defaultFn(() => new Date())
119+
.$onUpdate(() => new Date()),
109120
});
110121

111-
export const verification = pgTable("verification", {
122+
export const verification = sqliteTable("verification", {
112123
id: text("id").primaryKey(),
113124
identifier: text("identifier").notNull(),
114125
value: text("value").notNull(),
115-
expiresAt: timestamp("expires_at").notNull(),
116-
createdAt: timestamp("created_at").defaultNow().notNull(),
117-
updatedAt: timestamp("updated_at")
118-
.defaultNow()
119-
.$onUpdate(() => /* @__PURE__ */ new Date())
120-
.notNull(),
126+
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
127+
createdAt: integer("created_at", { mode: "timestamp" })
128+
.notNull()
129+
.$defaultFn(() => new Date()),
130+
updatedAt: integer("updated_at", { mode: "timestamp" })
131+
.notNull()
132+
.$defaultFn(() => new Date())
133+
.$onUpdate(() => new Date()),
121134
});

app/lib/db/seed.ts

Lines changed: 0 additions & 57 deletions
This file was deleted.

app/lib/hai/utils.ts

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -78,36 +78,3 @@ export function constructHai(kind: HaiKind, value: number | JihaiValue): Hai {
7878
export function sortTehai(haiArray: Hai[]): Hai[] {
7979
return haiArray.sort((a, b) => haiToIndex(a) - haiToIndex(b));
8080
}
81-
82-
// To store hai in DB
83-
export type DBHai = {
84-
haiyamaId: string;
85-
kind: HaiKind;
86-
value: string;
87-
order: number;
88-
index: number;
89-
};
90-
91-
export function haiToDBHai(hai: Hai, haiyamaId: string, order: number): DBHai {
92-
return {
93-
haiyamaId,
94-
kind: hai.kind,
95-
value: String(hai.value),
96-
order,
97-
index: haiToIndex(hai),
98-
};
99-
}
100-
101-
export function dbHaiToHai(dbHai: DBHai): Hai {
102-
if (dbHai.kind === "jihai") {
103-
return {
104-
kind: dbHai.kind,
105-
value: dbHai.value as JihaiValue,
106-
};
107-
} else {
108-
return {
109-
kind: dbHai.kind as SuhaiKind,
110-
value: Number(dbHai.value),
111-
};
112-
}
113-
}

app/routes/api.seed.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { getDB } from "../lib/db";
2+
import { haiyama } from "../lib/db/schema";
3+
import type { Hai, SuhaiKind } from "../lib/hai/utils";
4+
import { constructHai } from "../lib/hai/utils";
5+
import type { Route } from "./+types/api.seed";
6+
7+
function shuffleArray<T>(array: T[]): T[] {
8+
for (let i = array.length - 1; i > 0; i--) {
9+
const j = Math.floor(Math.random() * (i + 1));
10+
const temp = array[i];
11+
if (temp !== undefined && array[j] !== undefined) {
12+
array[i] = array[j];
13+
array[j] = temp;
14+
}
15+
}
16+
return array;
17+
}
18+
19+
function createHaiyama(): Hai[] {
20+
const kinds: SuhaiKind[] = ["manzu", "pinzu", "souzu"];
21+
let sortedHaiyama: Hai[] = [];
22+
23+
for (const kind of kinds) {
24+
for (let value = 1; value < 10; value++) {
25+
sortedHaiyama = sortedHaiyama.concat(
26+
new Array<Hai>(4).fill(constructHai(kind, value)),
27+
);
28+
}
29+
}
30+
const minLengthOfHaiyama = 31;
31+
const shuffledHaiyama = shuffleArray(sortedHaiyama);
32+
const trimedHaiyama = shuffledHaiyama.slice(0, minLengthOfHaiyama);
33+
return trimedHaiyama;
34+
}
35+
36+
async function seed(env: Env) {
37+
const db = getDB(env);
38+
39+
const haiyamaData = createHaiyama();
40+
41+
await db.insert(haiyama).values({ tiles: haiyamaData });
42+
43+
console.log("Seeding complete");
44+
}
45+
46+
export async function loader({ context }: Route.LoaderArgs) {
47+
const { env } = context.cloudflare;
48+
await seed(env);
49+
}

app/routes/play.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { sql } from "drizzle-orm";
22
import { Form } from "react-router";
33
import { getAuth } from "~/lib/auth";
44
import { getDB } from "~/lib/db";
5-
import { hai, haiyama } from "~/lib/db/schema";
5+
import { haiyama } from "~/lib/db/schema";
66
import judgeAgari from "~/lib/hai/judgeAgari";
7-
import { dbHaiToHai, sortTehai } from "~/lib/hai/utils";
7+
import { sortTehai } from "~/lib/hai/utils";
88
import { type GameState, getRedisClient, init } from "~/lib/redis";
99
import type { Route } from "./+types/play";
1010

@@ -47,15 +47,7 @@ export async function loader({
4747
throw new Response("No haiyama found", { status: 404 });
4848
}
4949

50-
const selectedHaiyama = randomHaiyama[0];
51-
const rawHaiData = await db
52-
.select()
53-
.from(hai)
54-
.where(sql`${hai.haiyamaId} = ${selectedHaiyama.id}`)
55-
.orderBy(hai.order);
56-
57-
const haiData = rawHaiData.map((hai) => dbHaiToHai(hai));
58-
50+
const haiData = randomHaiyama[0].tiles;
5951
// Initialize game state in Redis
6052
await init(redisClient, userId, haiData);
6153

0 commit comments

Comments
 (0)