diff --git a/packages/cli/package.json b/packages/cli/package.json index bb33dbf5c..1625a3049 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -16,7 +16,7 @@ "lint": "eslint --ext .ts src", "lint:report": "pnpm lint -- --format json --output-file report.json", "prepack": "pnpm build", - "dev": "ts-node src/index.ts" + "dev": "ts-node --files src/index.ts" }, "engines": { "node": ">=16.0.0" @@ -38,6 +38,7 @@ "dependencies": { "@logto/schemas": "^0.1.0", "decamelize": "^5.0.0", + "dotenv": "^10.0.0", "roarr": "^7.11.0", "slonik": "^28.1.0", "slonik-interceptor-preset": "^1.2.10", diff --git a/packages/cli/src/database.ts b/packages/cli/src/database.ts index 0880f1c76..0f323f53c 100644 --- a/packages/cli/src/database.ts +++ b/packages/cli/src/database.ts @@ -2,7 +2,7 @@ import { readdir, readFile } from 'fs/promises'; import path from 'path'; import { seeds } from '@logto/schemas'; -import { createPool, sql } from 'slonik'; +import { createPool, parseDsn, sql, stringifyDsn } from 'slonik'; import { createInterceptors } from 'slonik-interceptor-preset'; import { raw } from 'slonik-sql-tag-raw'; @@ -11,9 +11,33 @@ import { insertInto } from './utilities'; const { managementResource, defaultSignInExperience, createDefaultSetting } = seeds; const tableDirectory = 'node_modules/@logto/schemas/tables'; const domain = 'http://localhost:3001'; +const defaultDatabase = 'logto_test'; -export const createDatabaseCli = (uri: string) => { - const pool = createPool(uri, { interceptors: createInterceptors() }); +/** + * Create a database. + * @returns DSN with the created database name. + */ +export const createDatabase = async ( + dsn: string, + databaseName = defaultDatabase +): Promise => { + const { databaseName: _, ...restDsn } = parseDsn(dsn); + const pool = createPool(dsn); + + await pool.query(sql` + create database ${sql.identifier([databaseName])} + with + encoding = 'UTF8' + lc_collate = 'C' + lc_ctype = 'en_US.utf8' + connection_limit = -1; + `); + + return stringifyDsn({ ...restDsn, databaseName }); +}; + +export const createDatabaseCli = (dsn: string) => { + const pool = createPool(dsn, { interceptors: createInterceptors() }); const createTables = async () => { const directory = await readdir(tableDirectory); @@ -46,5 +70,4 @@ export const createDatabaseCli = (uri: string) => { }; // For testing purpose, will remove later -const cli = createDatabaseCli(process.env.DSN ?? ''); -void cli.seedTables(); +void createDatabase(process.env.DSN ?? ''); diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 9cd8c5a53..83e6e368c 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1 +1,5 @@ +import dotenv from 'dotenv'; + +dotenv.config(); + export * from './database'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc0087c52..afbf0fa80 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,6 +25,7 @@ importers: '@silverhand/ts-config': ^0.10.2 '@types/node': '14' decamelize: ^5.0.0 + dotenv: ^10.0.0 eslint: ^8.10.0 lint-staged: ^11.1.1 prettier: ^2.3.2 @@ -37,6 +38,7 @@ importers: dependencies: '@logto/schemas': link:../schemas decamelize: 5.0.1 + dotenv: 10.0.0 roarr: 7.11.0 slonik: 28.1.0 slonik-interceptor-preset: 1.2.10