-
Notifications
You must be signed in to change notification settings - Fork 100
fix(cloudflare): handle large d1 migrations in local dev #1246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
fd8f946
fix(cloudflare): handle large d1 migrations in local dev
john-royal ef2f96a
feat: local access to d1
john-royal 20c2975
fix return type
john-royal e9e9c50
ditto
john-royal 87402fc
one more time
john-royal 07c5f97
async binding proxy refinement
john-royal File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| import * as mf from "miniflare"; | ||
| import { Scope } from "../../scope.ts"; | ||
| import { | ||
| createCloudflareApi, | ||
| type CloudflareApi, | ||
| type CloudflareApiOptions, | ||
| } from "../api.ts"; | ||
| import type { Binding, Bindings } from "../bindings.ts"; | ||
| import type { Bound } from "../bound.ts"; | ||
| import { buildBindings } from "./build-worker-options.ts"; | ||
| import { getDefaultPersistPath } from "./paths.ts"; | ||
|
|
||
| async function makeMiniflare( | ||
| api: CloudflareApi, | ||
| name: string, | ||
| bindings: Bindings, | ||
| ) { | ||
| const { options, remoteProxy } = await buildBindings({ | ||
| api, | ||
| name, | ||
| bindings, | ||
| eventSources: undefined, | ||
| assets: undefined, | ||
| port: 0, | ||
| cwd: Scope.current.rootDir, | ||
| }); | ||
| const miniflare = new mf.Miniflare({ | ||
| script: "", | ||
| modules: true, | ||
| defaultPersistRoot: getDefaultPersistPath(Scope.current.rootDir), | ||
| log: process.env.DEBUG ? new mf.Log(mf.LogLevel.DEBUG) : undefined, | ||
| ...options, | ||
| analyticsEngineDatasetsPersist: !!options.analyticsEngineDatasets, | ||
| d1Persist: !!options.d1Databases, | ||
| durableObjectsPersist: !!options.durableObjects, | ||
| kvPersist: !!options.kvNamespaces, | ||
| r2Persist: !!options.r2Buckets, | ||
| secretsStorePersist: !!options.secretsStoreSecrets, | ||
| workflowsPersist: !!options.workflows, | ||
| } as mf.MiniflareOptions); | ||
| await miniflare.ready; | ||
| return { | ||
| miniflare, | ||
| dispose: async () => { | ||
| await Promise.all([miniflare.dispose(), remoteProxy?.close()]); | ||
| }, | ||
| }; | ||
| } | ||
|
|
||
| export type Lazy<T> = T[keyof T] extends (...args: any[]) => Promise<any> | ||
| ? T | ||
| : { | ||
| [k in keyof T]: EnsurePromiseReturnType<T[k]>; | ||
| }; | ||
|
|
||
| type EnsurePromiseReturnType<T> = T extends ( | ||
| ...args: infer Args | ||
| ) => infer Return | ||
| ? (...args: Args) => Return extends Promise<any> ? Return : Promise<Return> | ||
| : never; | ||
|
|
||
| function makeAsyncProxy<Target extends object, Functions>( | ||
| target: Target, | ||
| make: () => Promise<Functions>, | ||
| properties: (keyof Functions)[], | ||
| ): Target & Lazy<Functions> { | ||
| let promise: Promise<Functions> | undefined; | ||
| return new Proxy(target, { | ||
| get(target, prop) { | ||
| if (!properties.includes(prop as keyof Functions)) { | ||
| return Reflect.get(target, prop); | ||
| } | ||
| return async (...args: any[]) => { | ||
| promise ??= make(); | ||
| const obj = await promise; | ||
| // @ts-expect-error - prop is a valid key of T | ||
| return obj[prop as keyof T].apply(obj, args); | ||
| }; | ||
| }, | ||
| has(target, prop) { | ||
| return ( | ||
| properties.includes(prop as keyof Functions) || | ||
| Reflect.has(target, prop) | ||
| ); | ||
| }, | ||
| }) as Target & Lazy<Functions>; | ||
| } | ||
|
|
||
| export function makeAsyncProxyForBinding< | ||
| B extends Extract<Binding, object>, | ||
| >(options: { | ||
| apiOptions: CloudflareApiOptions; | ||
| name: string; | ||
| binding: Omit<B, keyof Lazy<Bound<B>>>; | ||
| properties: (keyof NoInfer<Bound<B>>)[]; | ||
| }): B { | ||
| const api = makeAsyncProxy( | ||
| {}, | ||
| async () => await createCloudflareApi(options.apiOptions), | ||
| ["get", "post", "put", "delete", "patch", "head"], | ||
| ) as CloudflareApi; | ||
| return makeAsyncProxy( | ||
| options.binding, | ||
| async () => { | ||
| const { miniflare, dispose } = await makeMiniflare(api, options.name, { | ||
| binding: options.binding as B, | ||
| }); | ||
| Scope.current.onCleanup(async () => { | ||
| await dispose(); | ||
| }); | ||
| return (await miniflare.getBindings())["binding"] as Bound<B>; | ||
| }, | ||
| options.properties, | ||
| ) as B; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,3 @@ | ||
| .alchemy/ | ||
| .alchemy | ||
|
|
||
| migrations/02-seed.sql | ||
sam-goodwin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if splitting by semicolon is a good idea. Drizzle splits by statement breakpoint (https://github.com/drizzle-team/drizzle-orm/blob/c445637df39366bcf47b12601896ce851771c1c2/drizzle-orm/src/migrator.ts#L44)