Skip to content

Commit

Permalink
fix: use module-specific env vars for migrations
Browse files Browse the repository at this point in the history
  • Loading branch information
MasterPtato committed Apr 19, 2024
1 parent 78861aa commit af18a0b
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 47 deletions.
1 change: 1 addition & 0 deletions src/artifacts/build_runtime_archive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const rootSrc = resolve(dirname, "..", "..");
const files = await glob.glob([
"src/{runtime,types}/*.ts",
"src/deps.ts",
"src/utils/db.ts",
], { cwd: rootSrc });

const archiveFiles: Record<string, string> = {};
Expand Down
61 changes: 49 additions & 12 deletions src/build/entrypoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { genRegistryMapPath, genRuntimeModPath, genRuntimePath } from "../projec
import { CommandError } from "../error/mod.ts";
import { autoGenHeader } from "./misc.ts";
import { BuildOpts, DbDriver, Runtime } from "./mod.ts";
import { dedent } from "./deps.ts";

export async function generateEntrypoint(project: Project, opts: BuildOpts) {
const runtimeModPath = genRuntimeModPath(project);
Expand Down Expand Up @@ -73,10 +74,13 @@ export async function generateEntrypoint(project: Project, opts: BuildOpts) {
} else if (opts.runtime == Runtime.Cloudflare) {
const runtimePath = genRuntimePath(project);
const serverTsPath = resolve(runtimePath, "src", "runtime", "server.ts");
const errorTsPath = resolve(runtimePath, "src", "runtime", "error.ts");

entrypointSource = `
${autoGenHeader()}
import type { IncomingRequestCf } from 'https://raw.githubusercontent.com/skymethod/denoflare/v0.6.0/common/cloudflare_workers_types.d.ts';
import { Runtime } from "${runtimeModPath}";
import { RuntimeError } from "${errorTsPath}";
import { camelToSnake } from "${registryMapPath}";
import type { Registry, RegistryCamel } from "./registry.d.ts";
import config from "./runtime_config.ts";
Expand All @@ -86,21 +90,22 @@ export async function generateEntrypoint(project: Project, opts: BuildOpts) {
const SERVER_HANDLER = serverHandler(RUNTIME);
export default {
async fetch(req, env) {
// Deno env polyfill
globalThis.Deno = {
env: {
get(name) {
return env.hasOwnProperty(name) ? env[name] : undefined;
}
}
};
async fetch(req: IncomingRequestCf, env: { [k: string]: unknown; }) {
${denoEnvPolyfill()}
const ip = req.headers.get("CF-Connecting-IP") ?? req.headers.get("X-Real-Ip");
if(!ip) {
throw new RuntimeError(
"CANNOT_READ_IP",
{ cause: "Could not get IP of incoming request" },
);
}
return await SERVER_HANDLER(req, {
remoteAddr: {
transport: "", // TODO:
hostname: req.headers.get("CF-Connecting-IP"),
port: 0, // TODO:
transport: "" as any,
hostname: ip,
port: 0,
}
});
}
Expand Down Expand Up @@ -213,3 +218,35 @@ function generateDbDriver(opts: BuildOpts, prismaImportName: string) {

return dbDriver;
}

function denoEnvPolyfill() {
// Deno env polyfill
return dedent`
globalThis.Deno = {
env: {
get(name: string): unknown | undefined {
return env.hasOwnProperty(name) ? env[name] : undefined;
},
set() {
throw new RuntimeError("UNIMPLEMENTED", {
cause: "Deno.env.set is unimplemented in Cloudflare Workers"
});
},
delete() {
throw new RuntimeError("UNIMPLEMENTED", {
cause: "Deno.env.delete is unimplemented in Cloudflare Workers"
});
},
has(name: string): boolean {
return env.hasOwnProperty(name);
},
toObject(): { [k:string]: string; } {
return Object.fromEntries(
Object.entries(env as { [k: string]: string; })
.filter(([k, v]) => typeof v === 'string')
);
}
}
} as any;
`;
}
9 changes: 6 additions & 3 deletions src/build/plan/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { BuildState, buildStep } from "../../build_state/mod.ts";
import { assertExists, resolve } from "../../deps.ts";
import { Module, Project, Script } from "../../project/mod.ts";
import { compileScriptHelper } from "../gen.ts";
import { BuildOpts } from "../mod.ts";
import { compileScriptSchema } from "../script_schema.ts";
import { BuildOpts } from "../mod.ts";

export async function planScriptBuild(
buildState: BuildState,
Expand All @@ -19,8 +19,11 @@ export async function planScriptBuild(
module,
script,
condition: {
// TODO: use tjs.getProgramFiles() to get the dependent files?
files: opts.strictSchemas ? [script.path] : [],
// TODO: This module and all of its dependent scripts. Use tjs.getProgramFiles() to get the dependent files?
files: [
// If the script is modified
script.path,
],
expressions: {
strictSchemas: opts.strictSchemas,
},
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Project } from "../../project/mod.ts";

export const buildCommand = new Command<GlobalOpts>()
.description("Build the project")
.option("--watch", "Automatically rebuid on changes", { default: false })
.option("--watch", "Automatically rebuild on changes", { default: false })
.option(
"-r, --runtime <runtime:string>",
"Set target runtime (deno, cloudflare)",
Expand Down
19 changes: 4 additions & 15 deletions src/migrate/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { verbose } from "../term/status.ts";
import { ensurePostgresRunning } from "../utils/postgres_daemon.ts";
import { createOnce, Once } from "../utils/once.ts";
import { getOrInitOnce } from "../utils/once.ts";
import { getDatabaseUrl, getDefaultDatabaseUrl } from "../utils/db.ts";

export type ForEachDatabaseCallback = (
opts: { databaseUrl: string; module: Module; db: ModuleDatabase },
Expand All @@ -25,14 +26,9 @@ interface DbState {
createdDatabases: Set<string>;
}

function getDefaultDatabaseUrl(_project: Project) {
return Deno.env.get("DATABASE_URL") ??
"postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable";
}

async function getDefaultClient(project: Project) {
async function getDefaultClient(_project: Project) {
return await getOrInitOnce(DB_STATE.defaultClientOnce, async () => {
const client = new PostgresClient(getDefaultDatabaseUrl(project));
const client = new PostgresClient(getDefaultDatabaseUrl());
await client.connect();

addShutdownHandler(async () => {
Expand Down Expand Up @@ -63,10 +59,6 @@ export async function forEachDatabase(

await ensurePostgresRunning(project);

// Setup database
const defaultDatabaseUrl = Deno.env.get("DATABASE_URL") ??
"postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable";

const defaultClient = await getDefaultClient(project);

for (const mod of modules) {
Expand All @@ -77,10 +69,7 @@ export async function forEachDatabase(
// Create database
await createDatabase(defaultClient, mod.db);

// Build URL
const urlParsed = new URL(defaultDatabaseUrl);
urlParsed.pathname = `/${mod.db.name}`;
const databaseUrl = urlParsed.toString();
const databaseUrl = getDatabaseUrl(mod.db.name).toString();

// Callback
await callback({ databaseUrl, module: mod, db: mod.db });
Expand Down
2 changes: 1 addition & 1 deletion src/project/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export async function loadModule(
let db: ModuleDatabase | undefined = undefined;
if (await exists(resolve(modulePath, "db"), { isDirectory: true })) {
db = {
name: name.replace("-", "_"),
name: `module_${name.replace("-", "_")}`,
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class Context<RegistryT, RegistryCamelT> {
script: { module: moduleName, script: scriptName },
}),
moduleName,
this.runtime.postgres.getOrCreatePool(moduleName, module)?.prisma,
this.runtime.postgres.getOrCreatePool(module)?.prisma,
scriptName,
this.camelMap,
);
Expand Down
16 changes: 3 additions & 13 deletions src/runtime/postgres.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { QueryClient, Transaction } from "./deps.ts";
import { Module } from "./runtime.ts";

const DEFAULT_DATABASE_URL = "postgres://postgres:postgres@localhost:5432/postgres";
import { getDatabaseUrl } from "../utils/db.ts";

type PostgresRunScope<T> = (conn: QueryClient) => Promise<T>;
type PostgresTransactionScope<T> = (conn: Transaction) => Promise<T>;
Expand Down Expand Up @@ -29,23 +28,14 @@ export class Postgres {
}
}

public getOrCreatePool(moduleName: string, module: Module): Pool | undefined {
public getOrCreatePool(module: Module): Pool | undefined {
if (!module.db) return undefined;
if (this.isShutDown) throw new Error("Postgres is shutting down");

if (this.pools.has(module.db.name)) {
return this.pools.get(module.db.name)!;
} else {
const moduleDbUrl = Deno.env.get(`DATABASE_URL_${moduleName}__${module.db.name}`);
let url;

if (moduleDbUrl) {
url = new URL(moduleDbUrl);
} else {
// Build URL for this database
url = new URL(Deno.env.get("DATABASE_URL") ?? DEFAULT_DATABASE_URL);
url.pathname = "/" + module.db.name;
}
const url = getDatabaseUrl(module.db.name);

// Create & insert pool
const output = module.db.createPrisma(url.toString());
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export class Runtime<RegistryT, RegistryCamelT> {
test: { module: moduleName, name: testName },
}),
moduleName,
runtime.postgres.getOrCreatePool(moduleName, module)?.prisma,
runtime.postgres.getOrCreatePool(module)?.prisma,
map,
);

Expand Down
20 changes: 20 additions & 0 deletions src/utils/db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const DEFAULT_DATABASE_URL = "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable";

export function getDatabaseUrl(dbName: string): URL {
const moduleDbUrl = Deno.env.get(`DATABASE_URL_${dbName}`);

let url;
if (moduleDbUrl) {
url = new URL(moduleDbUrl);
} else {
// Build URL for this database
url = new URL(getDefaultDatabaseUrl());
url.pathname = "/" + dbName;
}

return url;
}

export function getDefaultDatabaseUrl() {
return Deno.env.get("DATABASE_URL") ?? DEFAULT_DATABASE_URL;
}

0 comments on commit af18a0b

Please sign in to comment.