From dff105c74797c86ef21d33292cf6aa6d2b2f7740 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Mon, 26 Dec 2022 21:51:16 -0800 Subject: [PATCH] Updated prisma and redis clients. --- lib/cache.ts | 14 ++++++--- lib/db.js | 1 - lib/middleware.js | 6 ++-- lib/prisma.ts | 59 +++++--------------------------------- lib/redis.js | 62 ---------------------------------------- package.json | 2 ++ pages/api/auth/login.ts | 2 +- pages/api/auth/logout.ts | 2 +- yarn.lock | 17 ++++++++++- 9 files changed, 40 insertions(+), 125 deletions(-) delete mode 100644 lib/redis.js diff --git a/lib/cache.ts b/lib/cache.ts index 5c79def0..2aad7ed8 100644 --- a/lib/cache.ts +++ b/lib/cache.ts @@ -1,10 +1,16 @@ import { User, Website } from '@prisma/client'; -import redis from 'lib/redis'; +import redis from '@umami/redis-client'; import { getSession, getUser, getWebsite } from '../queries'; +const DELETED = 'DELETED'; + async function fetchObject(key, query) { const obj = await redis.get(key); + if (obj === DELETED) { + return null; + } + if (!obj) { return query().then(async data => { if (data) { @@ -22,8 +28,8 @@ async function storeObject(key, data) { return redis.set(key, data); } -async function deleteObject(key) { - return redis.set(key, redis.DELETED); +async function deleteObject(key, soft = false) { + return soft ? redis.set(key, DELETED) : redis.del(key); } async function fetchWebsite(id): Promise { @@ -42,7 +48,7 @@ async function deleteWebsite(id) { } async function fetchUser(id): Promise { - return fetchObject(`user:${id}`, () => getUser({ id }, true)); + return fetchObject(`user:${id}`, () => getUser({ id }, { includePassword: true })); } async function storeUser(data) { diff --git a/lib/db.js b/lib/db.js index e58a18c8..19e46a3d 100644 --- a/lib/db.js +++ b/lib/db.js @@ -4,7 +4,6 @@ export const MYSQL = 'mysql'; export const CLICKHOUSE = 'clickhouse'; export const KAFKA = 'kafka'; export const KAFKA_PRODUCER = 'kafka-producer'; -export const REDIS = 'redis'; // Fixes issue with converting bigint values BigInt.prototype.toJSON = function () { diff --git a/lib/middleware.js b/lib/middleware.js index 9d1498c7..1d8ff807 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -2,10 +2,10 @@ import { createMiddleware, unauthorized, badRequest, parseSecureToken } from 'ne import debug from 'debug'; import cors from 'cors'; import { validate } from 'uuid'; +import redis from '@umami/redis-client'; import { findSession } from 'lib/session'; import { getAuthToken, parseShareToken } from 'lib/auth'; import { secret } from 'lib/crypto'; -import redis from 'lib/redis'; import { ROLES } from 'lib/constants'; import { getUser } from '../queries'; @@ -17,7 +17,7 @@ export const useSession = createMiddleware(async (req, res, next) => { const session = await findSession(req); if (!session) { - log('useSession:session-not-found'); + log('useSession: Session not found'); return badRequest(res); } @@ -42,7 +42,7 @@ export const useAuth = createMiddleware(async (req, res, next) => { log({ token, payload, user, shareToken }); if (!user && !shareToken) { - log('useAuth:user-not-authorized'); + log('useAuth: User not authorized'); return unauthorized(res); } diff --git a/lib/prisma.ts b/lib/prisma.ts index e7c16a5c..55e5644a 100644 --- a/lib/prisma.ts +++ b/lib/prisma.ts @@ -1,10 +1,7 @@ -import { PrismaClient } from '@prisma/client'; -import chalk from 'chalk'; +import prisma from '@umami/prisma-client'; import moment from 'moment-timezone'; -import debug from 'debug'; -import { PRISMA, MYSQL, POSTGRESQL, getDatabaseType } from 'lib/db'; +import { MYSQL, POSTGRESQL, getDatabaseType } from 'lib/db'; import { FILTER_IGNORED } from 'lib/constants'; -import { PrismaClientOptions } from '@prisma/client/runtime'; const MYSQL_DATE_FORMATS = { minute: '%Y-%m-%d %H:%i:00', @@ -22,39 +19,7 @@ const POSTGRESQL_DATE_FORMATS = { year: 'YYYY-01-01', }; -const log = debug('umami:prisma'); - -const PRISMA_OPTIONS = { - log: [ - { - emit: 'event', - level: 'query', - }, - ], -}; - -function logQuery(e) { - log(chalk.yellow(e.params), '->', e.query, chalk.greenBright(`${e.duration}ms`)); -} - -function getClient(options) { - const prisma: PrismaClient = - new PrismaClient(options); - - if (process.env.LOG_QUERY) { - prisma.$on('query', logQuery); - } - - if (process.env.NODE_ENV !== 'production') { - global[PRISMA] = prisma; - } - - log('Prisma initialized'); - - return prisma; -} - -function getDateQuery(field, unit, timezone?): string { +function getDateQuery(field: string, unit: string, timezone?: string): string { const db = getDatabaseType(process.env.DATABASE_URL); if (db === POSTGRESQL) { @@ -75,7 +40,7 @@ function getDateQuery(field, unit, timezone?): string { } } -function getTimestampInterval(field): string { +function getTimestampInterval(field: string): string { const db = getDatabaseType(process.env.DATABASE_URL); if (db === POSTGRESQL) { @@ -207,7 +172,7 @@ function parseFilters( }; } -async function rawQuery(query, params = []): Promise { +async function rawQuery(query: string, params: never[] = []): Promise { const db = getDatabaseType(process.env.DATABASE_URL); if (db !== POSTGRESQL && db !== MYSQL) { @@ -216,20 +181,11 @@ async function rawQuery(query, params = []): Promise { const sql = db === MYSQL ? query.replace(/\$[0-9]+/g, '?') : query; - return prisma.$queryRawUnsafe.apply(prisma, [sql, ...params]); + return prisma.rawQuery(sql, params); } -async function transaction(queries): Promise { - return prisma.$transaction(queries); -} - -// Initialization -const prisma: PrismaClient = - global[PRISMA] || getClient(PRISMA_OPTIONS); - export default { - client: prisma, - log, + ...prisma, getDateQuery, getTimestampInterval, getFilterQuery, @@ -237,5 +193,4 @@ export default { getEventDataFilterQuery, parseFilters, rawQuery, - transaction, }; diff --git a/lib/redis.js b/lib/redis.js deleted file mode 100644 index 02eb9424..00000000 --- a/lib/redis.js +++ /dev/null @@ -1,62 +0,0 @@ -import { createClient } from 'redis'; -import debug from 'debug'; - -const log = debug('umami:redis'); -const REDIS = Symbol(); -const DELETED = 'DELETED'; - -let redis; -const url = process.env.REDIS_URL; -const enabled = Boolean(url); - -async function getClient() { - if (!enabled) { - return null; - } - - const client = createClient({ url }); - client.on('error', err => log(err)); - await client.connect(); - - if (process.env.NODE_ENV !== 'production') { - global[REDIS] = client; - } - - log('Redis initialized'); - - return client; -} - -async function get(key) { - await connect(); - - const data = await redis.get(key); - - try { - return JSON.parse(data); - } catch { - return null; - } -} - -async function set(key, value) { - await connect(); - - return redis.set(key, JSON.stringify(value)); -} - -async function del(key) { - await connect(); - - return redis.del(key); -} - -async function connect() { - if (!redis && enabled) { - redis = global[REDIS] || (await getClient()); - } - - return redis; -} - -export default { enabled, client: redis, log, connect, get, set, del, DELETED }; diff --git a/package.json b/package.json index 6733260b..f28eb038 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,8 @@ "@fontsource/inter": "4.5.7", "@prisma/client": "4.8.0", "@tanstack/react-query": "^4.16.1", + "@umami/prisma-client": "^0.1.0", + "@umami/redis-client": "^0.1.0", "chalk": "^4.1.1", "chart.js": "^2.9.4", "classnames": "^2.3.1", diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts index e5e0dab7..8494d388 100644 --- a/pages/api/auth/login.ts +++ b/pages/api/auth/login.ts @@ -7,9 +7,9 @@ import { methodNotAllowed, getRandomChars, } from 'next-basics'; +import redis from '@umami/redis-client'; import { getUser, User } from 'queries'; import { secret } from 'lib/crypto'; -import redis from 'lib/redis'; import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; diff --git a/pages/api/auth/logout.ts b/pages/api/auth/logout.ts index c05a05de..cbccce8d 100644 --- a/pages/api/auth/logout.ts +++ b/pages/api/auth/logout.ts @@ -1,6 +1,6 @@ import { methodNotAllowed, ok } from 'next-basics'; +import redis from '@umami/redis-client'; import { useAuth } from 'lib/middleware'; -import redis from 'lib/redis'; import { getAuthToken } from 'lib/auth'; import { NextApiRequest, NextApiResponse } from 'next'; diff --git a/yarn.lock b/yarn.lock index 4ce71edd..450c4744 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2290,6 +2290,21 @@ "@typescript-eslint/types" "5.45.0" eslint-visitor-keys "^3.3.0" +"@umami/prisma-client@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@umami/prisma-client/-/prisma-client-0.1.0.tgz#4ecc17b1998cb738b8f2027b80b003864beef6a4" + integrity sha512-2qTXN0dtMUT+HVhz37eVC02lDSwz9TGUGHRRO0LPRHdfJPfSkUF0D8pgksX7ETy3IZoIQP1h45tiXsM0pKBMZA== + dependencies: + debug "^4.3.4" + +"@umami/redis-client@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@umami/redis-client/-/redis-client-0.1.0.tgz#69599b1243406a3aef83927bb8655a3ef4c0c031" + integrity sha512-XCqCdc3xA5KDOorIUvOVlz+/F/SEyL9cKWfCCGYYZix1b9yFo+5BzM0C0q7Yu/qV+1jYd+viNsBQQSM6a8sfjg== + dependencies: + debug "^4.3.4" + redis "^4.5.1" + "@vercel/node-bridge@^2.1.0": version "2.2.2" resolved "https://registry.yarnpkg.com/@vercel/node-bridge/-/node-bridge-2.2.2.tgz#f63466ab6a2588afdc6262c2d060289bfe8baa6b" @@ -6632,7 +6647,7 @@ redis-parser@^3.0.0: dependencies: redis-errors "^1.0.0" -redis@^4.5.0: +redis@^4.5.0, redis@^4.5.1: version "4.5.1" resolved "https://registry.yarnpkg.com/redis/-/redis-4.5.1.tgz#f5a818970bb2dc5d60540bab41308640604c7d33" integrity sha512-oxXSoIqMJCQVBTfxP6BNTCtDMyh9G6Vi5wjdPdV/sRKkufyZslDqCScSGcOr6XGR/reAWZefz7E4leM31RgdBA==