kopia lustrzana https://github.com/cloudflare/wildebeest
add neon client
rodzic
1b830d8df2
commit
c3fb612d21
|
@ -273,6 +273,7 @@ jobs:
|
|||
echo -e "DOMAIN=\"${{ vars.CF_DEPLOY_DOMAIN }}\"\n" >> consumer/wrangler.toml
|
||||
echo -e "ADMIN_EMAIL=\"${{ vars.ADMIN_EMAIL }}\"\n" >> consumer/wrangler.toml
|
||||
|
||||
yarn
|
||||
yarn --cwd consumer/
|
||||
echo "******"
|
||||
command: publish --config consumer/wrangler.toml
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import type { Env } from 'wildebeest/backend/src/types/env'
|
||||
import d1 from './d1'
|
||||
import neon from './neon'
|
||||
|
||||
export interface Result<T = unknown> {
|
||||
results?: T[]
|
||||
|
@ -32,6 +33,10 @@ export interface QueryBuilder {
|
|||
insertOrIgnore(q: string): string
|
||||
}
|
||||
|
||||
export async function getDatabase(env: Pick<Env, 'DATABASE'>): Promise<Database> {
|
||||
export async function getDatabase(env: Pick<Env, 'DATABASE' | 'NEON_DATABASE_URL'>): Promise<Database> {
|
||||
if (env.NEON_DATABASE_URL !== undefined) {
|
||||
return neon(env)
|
||||
}
|
||||
|
||||
return d1(env)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
import * as neon from '@neondatabase/serverless'
|
||||
import type { Database, Result, QueryBuilder } from 'wildebeest/backend/src/database'
|
||||
import type { Env } from 'wildebeest/backend/src/types/env'
|
||||
|
||||
function sqliteToPsql(query: string): string {
|
||||
let c = 0
|
||||
return query.replaceAll(/\?([0-9])?/g, (match: string, p1: string) => {
|
||||
c += 1
|
||||
return `$${p1 || c}`
|
||||
})
|
||||
}
|
||||
|
||||
const qb: QueryBuilder = {
|
||||
jsonExtract(obj: string, prop: string): string {
|
||||
return `json_extract_path(${obj}::json, '${prop}')::text`
|
||||
},
|
||||
|
||||
jsonExtractIsNull(obj: string, prop: string): string {
|
||||
return `${qb.jsonExtract(obj, prop)} = 'null'`
|
||||
},
|
||||
|
||||
set(array: string): string {
|
||||
return `(SELECT value::text FROM json_array_elements_text(${array}))`
|
||||
},
|
||||
|
||||
epoch(): string {
|
||||
return 'epoch'
|
||||
},
|
||||
|
||||
insertOrIgnore(q: string): string {
|
||||
return `INSERT ${q} ON CONFLICT DO NOTHING`
|
||||
},
|
||||
}
|
||||
|
||||
export default async function make(env: Pick<Env, 'NEON_DATABASE_URL'>): Promise<Database> {
|
||||
const client = new neon.Client(env.NEON_DATABASE_URL)
|
||||
await client.connect()
|
||||
|
||||
return {
|
||||
qb,
|
||||
|
||||
prepare(query: string) {
|
||||
return new PreparedStatement(env, query, [], client)
|
||||
},
|
||||
|
||||
dump() {
|
||||
throw new Error('not implemented')
|
||||
},
|
||||
|
||||
async batch<T = unknown>(statements: PreparedStatement[]): Promise<Result<T>[]> {
|
||||
throw new Error('not implemented')
|
||||
console.log(statements)
|
||||
},
|
||||
|
||||
async exec<T = unknown>(query: string): Promise<Result<T>> {
|
||||
throw new Error('not implemented')
|
||||
console.log(query)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export class PreparedStatement {
|
||||
private env: Pick<Env, 'NEON_DATABASE_URL'>
|
||||
private client: neon.Client
|
||||
private query: string
|
||||
private values: any[]
|
||||
|
||||
constructor(env: Pick<Env, 'NEON_DATABASE_URL'>, query: string, values: any[], client: neon.Client) {
|
||||
this.env = env
|
||||
this.query = query
|
||||
this.values = values
|
||||
this.client = client
|
||||
}
|
||||
|
||||
bind(...values: any[]): PreparedStatement {
|
||||
return new PreparedStatement(this.env, this.query, [...this.values, ...values], this.client)
|
||||
}
|
||||
|
||||
async first<T = unknown>(colName?: string): Promise<T> {
|
||||
if (colName) {
|
||||
throw new Error('not implemented')
|
||||
}
|
||||
const query = sqliteToPsql(this.query)
|
||||
|
||||
const results = await this.client.query(query, this.values)
|
||||
if (results.rows.length !== 1) {
|
||||
throw new Error(`expected a single row, returned ${results.rows.length} row(s)`)
|
||||
}
|
||||
|
||||
return results.rows[0] as T
|
||||
}
|
||||
|
||||
async run<T = unknown>(): Promise<Result<T>> {
|
||||
return this.all()
|
||||
}
|
||||
|
||||
async all<T = unknown>(): Promise<Result<T>> {
|
||||
const query = sqliteToPsql(this.query)
|
||||
const results = await this.client.query(query, this.values)
|
||||
|
||||
return {
|
||||
results: results.rows as T[],
|
||||
success: true,
|
||||
meta: {},
|
||||
}
|
||||
}
|
||||
|
||||
async raw<T = unknown>(): Promise<T[]> {
|
||||
throw new Error('not implemented')
|
||||
}
|
||||
}
|
|
@ -25,4 +25,6 @@ export interface Env {
|
|||
SENTRY_DSN: string
|
||||
SENTRY_ACCESS_CLIENT_ID: string
|
||||
SENTRY_ACCESS_CLIENT_SECRET: string
|
||||
|
||||
NEON_DATABASE_URL?: string
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
"deploy": "yarn build && yarn database:migrate && yarn pages publish frontend/dist --project-name=wildebeest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@neondatabase/serverless": "^0.2.5",
|
||||
"@types/cookie": "^0.5.1",
|
||||
"cookie": "^0.5.0",
|
||||
"http-message-signatures": "^0.1.2",
|
||||
|
|
|
@ -807,6 +807,11 @@
|
|||
undici "5.9.1"
|
||||
ws "^8.2.2"
|
||||
|
||||
"@neondatabase/serverless@^0.2.5":
|
||||
version "0.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@neondatabase/serverless/-/serverless-0.2.5.tgz#78bd4a905f50d087d06f16c02711fdd05b2a851d"
|
||||
integrity sha512-Qu/nNZftfoqw4ojVCXU/EgYlfII3mzLm82iXNOUljFumPhoZ/Wp8NJG5DgSAKCWC0zwTyJsojdPLQDj/UPs2vg==
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
|
||||
|
|
Ładowanie…
Reference in New Issue