w3cj / hono-open-api-starter

A starter template for building fully documented type-safe JSON APIs with Hono and Open API
https://www.youtube.com/watch?v=sNh9PoM9sUE
MIT License
243 stars 24 forks source link

Current Database Schema configuration results in `NULL` values for timestamp fields. #6

Open JDGuillaume opened 2 days ago

JDGuillaume commented 2 days ago

Hey CJ! First off - Thank you for the video and thoroughly enjoyed seeing what Hono can do!

Running into an issue with Drizzle where the database schema is resulting in NULL values for the timestamp fields (e.g., createdAt, updatedAt).

// database.schema.ts
export const tasks = sqliteTable("tasks", {
  id: integer("id", { mode: "number" }).primaryKey({ autoIncrement: true }),
  name: text("name").notNull(),
  done: integer("done", { mode: "boolean" }).notNull().default(false),
  createdAt: integer("created_at", { mode: "timestamp" }).$defaultFn(() => new Date()),
  updatedAt: integer("updated_at", { mode: "timestamp" }).$defaultFn(() => new Date()).$onUpdate(() => new Date()),
});
// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

import env from "./src/env.ts";

export default defineConfig({
  out: "./src/db/migrations",
  schema: "./src/db/database.schema.ts",
  dialect: "sqlite",
  dbCredentials: {
    url: env.DATABASE_URL,
    token: env.DATABASE_AUTH_TOKEN,
  },
});
CREATE TABLE `tasks` (
    `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
    `name` text NOT NULL,
    `done` integer DEFAULT false NOT NULL,
    `created_at` integer,
    `updated_at` integer
);

The resulting value in the database is: image

Edit #1 Relevant package.json

"dependencies": {
    "@hono/node-server": "^1.13.2",
    "@hono/zod-openapi": "^0.16.4",
    "@libsql/client": "^0.14.0",
    "@scalar/hono-api-reference": "^0.5.156",
    "dotenv": "^16.4.5",
    "dotenv-expand": "^11.0.6",
    "drizzle-orm": "^0.35.3",
    "hono": "^4.6.7",
    "hono-pino": "^0.4.0",
    "pino": "^9.5.0",
    "pino-pretty": "^11.3.0",
    "stoker": "^1.2.7",
    "zod": "^3.23.8"
  },
  "devDependencies": {
    "@antfu/eslint-config": "^3.8.0",
    "@types/node": "^20.11.17",
    "drizzle-kit": "^0.26.2",
    "eslint": "^9.12.0",
    "eslint-plugin-format": "^0.1.2",
    "tsx": "^4.7.1"
  }
w3cj commented 1 day ago

$defaultFn only works at runtime when queries are run with the drizzle client. Not sure if drizzle studio runs these 🤔

For a "true" default value, you should use default with a tagged sql expression: https://orm.drizzle.team/docs/column-types/sqlite#default-value

w3cj commented 1 day ago

This section has some examples as well: https://orm.drizzle.team/docs/guides/timestamp-default-value#sqlite

I would prefer this example since it stores the value as seconds in the DB but can be used as a Date object in JS:

timestamp1: integer('timestamp1', { mode: 'timestamp' })
    .notNull()
    .default(sql`(unixepoch())`),