Migrate from @vercel/postgres to pg
This commit is contained in:
parent
aec3963f17
commit
74ec5fd234
@ -28,7 +28,6 @@
|
||||
"@vercel/analytics": "^1.2.2",
|
||||
"@vercel/blob": "^0.23.2",
|
||||
"@vercel/kv": "^1.0.1",
|
||||
"@vercel/postgres": "^0.8.0",
|
||||
"@vercel/speed-insights": "^1.0.10",
|
||||
"ai": "^3.0.34",
|
||||
"autoprefixer": "10.4.19",
|
||||
|
||||
52
pnpm-lock.yaml
generated
52
pnpm-lock.yaml
generated
@ -65,9 +65,6 @@ importers:
|
||||
'@vercel/kv':
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1
|
||||
'@vercel/postgres':
|
||||
specifier: ^0.8.0
|
||||
version: 0.8.0
|
||||
'@vercel/speed-insights':
|
||||
specifier: ^1.0.10
|
||||
version: 1.0.10(next@14.2.3(@babel/core@7.24.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(svelte@4.2.15)(vue@3.4.25(typescript@5.4.5))
|
||||
@ -690,9 +687,6 @@ packages:
|
||||
'@jridgewell/trace-mapping@0.3.25':
|
||||
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
||||
|
||||
'@neondatabase/serverless@0.7.2':
|
||||
resolution: {integrity: sha512-wU3WA2uTyNO7wjPs3Mg0G01jztAxUxzd9/mskMmtPwPTjf7JKWi9AW5/puOGXLxmZ9PVgRFeBVRVYq5nBPhsCg==}
|
||||
|
||||
'@next/bundle-analyzer@14.2.3':
|
||||
resolution: {integrity: sha512-Z88hbbngMs7njZKI8kTJIlpdLKYfMSLwnsqYe54AP4aLmgL70/Ynx/J201DQ+q2Lr6FxFw1uCeLGImDrHOl2ZA==}
|
||||
|
||||
@ -1363,9 +1357,6 @@ packages:
|
||||
'@types/pg@8.11.5':
|
||||
resolution: {integrity: sha512-2xMjVviMxneZHDHX5p5S6tsRRs7TpDHeeK7kTTMe/kAC/mRRNjWHjZg0rkiY+e17jXSZV3zJYDxXV8Cy72/Vuw==}
|
||||
|
||||
'@types/pg@8.6.6':
|
||||
resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==}
|
||||
|
||||
'@types/prop-types@15.7.12':
|
||||
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
|
||||
|
||||
@ -1514,10 +1505,6 @@ packages:
|
||||
resolution: {integrity: sha512-uTKddsqVYS2GRAM/QMNNXCTuw9N742mLoGRXoNDcyECaxEXvIHG0dEY+ZnYISV4Vz534VwJO+64fd9XeSggSKw==}
|
||||
engines: {node: '>=14.6'}
|
||||
|
||||
'@vercel/postgres@0.8.0':
|
||||
resolution: {integrity: sha512-/QUV9ExwaNdKooRjOQqvrKNVnRvsaXeukPNI5DB1ovUTesglfR/fparw7ngo1KUWWKIVpEj2TRrA+ObRHRdaLg==}
|
||||
engines: {node: '>=14.6'}
|
||||
|
||||
'@vercel/speed-insights@1.0.10':
|
||||
resolution: {integrity: sha512-4uzdKB0RW6Ff2FkzshzjZ+RlJfLPxgm/00i0XXgxfMPhwnnsk92YgtqsxT9OcPLdJUyVU1DqFlSWWjIQMPkh0g==}
|
||||
peerDependencies:
|
||||
@ -4174,18 +4161,6 @@ packages:
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
|
||||
ws@8.14.2:
|
||||
resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
|
||||
ws@8.16.0:
|
||||
resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
@ -5257,10 +5232,6 @@ snapshots:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
|
||||
'@neondatabase/serverless@0.7.2':
|
||||
dependencies:
|
||||
'@types/pg': 8.6.6
|
||||
|
||||
'@next/bundle-analyzer@14.2.3(bufferutil@4.0.8)(utf-8-validate@6.0.3)':
|
||||
dependencies:
|
||||
webpack-bundle-analyzer: 4.10.1(bufferutil@4.0.8)(utf-8-validate@6.0.3)
|
||||
@ -6056,12 +6027,6 @@ snapshots:
|
||||
pg-protocol: 1.6.1
|
||||
pg-types: 4.0.2
|
||||
|
||||
'@types/pg@8.6.6':
|
||||
dependencies:
|
||||
'@types/node': 20.12.7
|
||||
pg-protocol: 1.6.1
|
||||
pg-types: 2.2.0
|
||||
|
||||
'@types/prop-types@15.7.12': {}
|
||||
|
||||
'@types/react-dom@18.3.0':
|
||||
@ -6247,13 +6212,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@upstash/redis': 1.25.1
|
||||
|
||||
'@vercel/postgres@0.8.0':
|
||||
dependencies:
|
||||
'@neondatabase/serverless': 0.7.2
|
||||
bufferutil: 4.0.8
|
||||
utf-8-validate: 6.0.3
|
||||
ws: 8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)
|
||||
|
||||
'@vercel/speed-insights@1.0.10(next@14.2.3(@babel/core@7.24.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(svelte@4.2.15)(vue@3.4.25(typescript@5.4.5))':
|
||||
optionalDependencies:
|
||||
next: 14.2.3(@babel/core@7.24.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@ -6608,6 +6566,7 @@ snapshots:
|
||||
bufferutil@4.0.8:
|
||||
dependencies:
|
||||
node-gyp-build: 4.8.0
|
||||
optional: true
|
||||
|
||||
busboy@1.6.0:
|
||||
dependencies:
|
||||
@ -8266,7 +8225,8 @@ snapshots:
|
||||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
|
||||
node-gyp-build@4.8.0: {}
|
||||
node-gyp-build@4.8.0:
|
||||
optional: true
|
||||
|
||||
node-int64@0.4.0: {}
|
||||
|
||||
@ -9169,6 +9129,7 @@ snapshots:
|
||||
utf-8-validate@6.0.3:
|
||||
dependencies:
|
||||
node-gyp-build: 4.8.0
|
||||
optional: true
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
@ -9309,11 +9270,6 @@ snapshots:
|
||||
bufferutil: 4.0.8
|
||||
utf-8-validate: 6.0.3
|
||||
|
||||
ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3):
|
||||
optionalDependencies:
|
||||
bufferutil: 4.0.8
|
||||
utf-8-validate: 6.0.3
|
||||
|
||||
ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.3):
|
||||
optionalDependencies:
|
||||
bufferutil: 4.0.8
|
||||
|
||||
@ -5,7 +5,7 @@ import { getPhotosCountIncludingHiddenCached } from '@/photo/cache';
|
||||
import StorageUrls from '@/admin/StorageUrls';
|
||||
import { PRO_MODE_ENABLED } from '@/site/config';
|
||||
import { getStoragePhotoUrlsNoStore } from '@/services/storage/cache';
|
||||
import { getPhotos } from '@/services/vercel-postgres';
|
||||
import { getPhotos } from '@/photo/db';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import AdminPhotoTable from '@/admin/AdminPhotoTable';
|
||||
import AdminPhotoTableInfinite from
|
||||
|
||||
@ -4,7 +4,7 @@ import { getPhotosCached } from '@/photo/cache';
|
||||
import TagForm from '@/tag/TagForm';
|
||||
import { PATH_ADMIN, PATH_ADMIN_TAGS, pathForTag } from '@/site/paths';
|
||||
import PhotoLightbox from '@/photo/PhotoLightbox';
|
||||
import { getPhotosTagMeta } from '@/services/vercel-postgres';
|
||||
import { getPhotosTagMeta } from '@/photo/db';
|
||||
import AdminTagBadge from '@/admin/AdminTagBadge';
|
||||
|
||||
const MAX_PHOTO_TO_SHOW = 6;
|
||||
|
||||
@ -10,7 +10,7 @@ import { MAX_PHOTOS_TO_SHOW_OG } from '@/image-response';
|
||||
import { Metadata } from 'next/types';
|
||||
import PhotoGridSidebar from '@/photo/PhotoGridSidebar';
|
||||
import { getPhotoSidebarData } from '@/photo/data';
|
||||
import { getPhotos } from '@/services/vercel-postgres';
|
||||
import { getPhotos } from '@/photo/db';
|
||||
import { cache } from 'react';
|
||||
import PhotoGridInfinite from '@/photo/PhotoGridInfinite';
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import { Metadata } from 'next/types';
|
||||
import { MAX_PHOTOS_TO_SHOW_OG } from '@/image-response';
|
||||
import PhotosLarge from '@/photo/PhotosLarge';
|
||||
import { cache } from 'react';
|
||||
import { getPhotos, getPhotosCount } from '@/services/vercel-postgres';
|
||||
import { getPhotos, getPhotosCount } from '@/photo/db';
|
||||
import PhotosLargeInfinite from '@/photo/PhotosLargeInfinite';
|
||||
|
||||
export const dynamic = 'force-static';
|
||||
|
||||
@ -8,7 +8,7 @@ import {
|
||||
sqlRenamePhotoTagGlobally,
|
||||
getPhoto,
|
||||
getPhotos,
|
||||
} from '@/services/vercel-postgres';
|
||||
} from '@/photo/db';
|
||||
import {
|
||||
PhotoFormData,
|
||||
convertFormDataToPhotoDbInsert,
|
||||
|
||||
@ -20,7 +20,7 @@ import {
|
||||
getPhotosDateRange,
|
||||
getPhotosNearId,
|
||||
getPhotosMostRecentUpdate,
|
||||
} from '@/services/vercel-postgres';
|
||||
} from '@/photo/db';
|
||||
import { parseCachedPhotoDates, parseCachedPhotosDates } from '@/photo';
|
||||
import { createCameraKey } from '@/camera';
|
||||
import {
|
||||
|
||||
@ -9,7 +9,7 @@ import {
|
||||
getUniqueCameras,
|
||||
getUniqueFilmSimulations,
|
||||
getUniqueTags,
|
||||
} from '@/services/vercel-postgres';
|
||||
} from '@/photo/db';
|
||||
import { SHOW_FILM_SIMULATIONS } from '@/site/config';
|
||||
import { sortTagsObject } from '@/tag';
|
||||
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
import { db, sql } from '@vercel/postgres';
|
||||
import {
|
||||
sql,
|
||||
directQuery,
|
||||
convertArrayToPostgresString,
|
||||
} from '@/services/postgres';
|
||||
import {
|
||||
PhotoDb,
|
||||
PhotoDbInsert,
|
||||
@ -16,10 +20,6 @@ import { screenForPPR } from '@/utility/ppr';
|
||||
|
||||
const PHOTO_DEFAULT_LIMIT = 100;
|
||||
|
||||
export const convertArrayToPostgresString = (array?: string[]) => array
|
||||
? `{${array.join(',')}}`
|
||||
: null;
|
||||
|
||||
const sqlCreatePhotosTable = () =>
|
||||
sql`
|
||||
CREATE TABLE IF NOT EXISTS photos (
|
||||
@ -420,7 +420,7 @@ export const getPhotos = async (options: GetPhotosOptions = {}) => {
|
||||
values.push(limit, offset);
|
||||
|
||||
return safelyQueryPhotos(async () => {
|
||||
return db.query(sql.join(' '), values);
|
||||
return directQuery(sql.join(' '), values);
|
||||
}, sql.join(' '))
|
||||
.then(({ rows }) => rows.map(parsePhotoFromDb));
|
||||
};
|
||||
@ -434,7 +434,7 @@ export const getPhotosNearId = async (
|
||||
: 'ORDER BY taken_at DESC';
|
||||
|
||||
return safelyQueryPhotos(async () => {
|
||||
return db.query(
|
||||
return directQuery(
|
||||
`
|
||||
WITH twi AS (
|
||||
SELECT *, row_number()
|
||||
46
src/services/postgres.ts
Normal file
46
src/services/postgres.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { Client, QueryResultRow } from 'pg';
|
||||
|
||||
export type Primitive = string | number | boolean | undefined | null;
|
||||
|
||||
export const directQuery = async <T extends QueryResultRow = any>(
|
||||
queryString: string,
|
||||
values: Primitive[],
|
||||
) => {
|
||||
const client = new Client({
|
||||
connectionString: process.env.POSTGRES_URL,
|
||||
ssl: true,
|
||||
});
|
||||
await client.connect();
|
||||
const response = await client.query<T>(queryString, values);
|
||||
await client.end();
|
||||
return response;
|
||||
};
|
||||
|
||||
export const sql = <T extends QueryResultRow>(
|
||||
strings: TemplateStringsArray,
|
||||
...values: Primitive[]
|
||||
) => {
|
||||
if (!isTemplateStringsArray(strings) || !Array.isArray(values)) {
|
||||
throw new Error('Invalid template literal argument');
|
||||
}
|
||||
|
||||
let result = strings[0] ?? '';
|
||||
|
||||
for (let i = 1; i < strings.length; i++) {
|
||||
result += `$${i}${strings[i] ?? ''}`;
|
||||
}
|
||||
|
||||
return directQuery<T>(result, values);
|
||||
};
|
||||
|
||||
export const convertArrayToPostgresString = (array?: string[]) => array
|
||||
? `{${array.join(',')}}`
|
||||
: null;
|
||||
|
||||
const isTemplateStringsArray = (
|
||||
strings: unknown,
|
||||
): strings is TemplateStringsArray => {
|
||||
return (
|
||||
Array.isArray(strings) && 'raw' in strings && Array.isArray(strings.raw)
|
||||
);
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user