From d429fba73f2da0907d1aeac2dcbed0cd4fa66201 Mon Sep 17 00:00:00 2001 From: Charis <26616127+charislam@users.noreply.github.com> Date: Thu, 7 Dec 2023 12:05:29 -0500 Subject: [PATCH] perf: remove edge function for faster fts (#19500) Unlike embeddings, FTS doesn't require a server-side secret, so the Edge Function is just adding an intermediate hop for no benefit. --- .../ui/src/components/Command/DocsSearch.tsx | 68 +++++++----- supabase/config.toml | 3 - supabase/functions/search-fts/index.ts | 102 ------------------ 3 files changed, 42 insertions(+), 131 deletions(-) delete mode 100644 supabase/functions/search-fts/index.ts diff --git a/packages/ui/src/components/Command/DocsSearch.tsx b/packages/ui/src/components/Command/DocsSearch.tsx index 72ac6392dd..d23990933b 100644 --- a/packages/ui/src/components/Command/DocsSearch.tsx +++ b/packages/ui/src/components/Command/DocsSearch.tsx @@ -248,35 +248,51 @@ const DocsSearch = () => { let sourcesLoaded = 0 - const sources = ['search-fts', 'search-embeddings'] - sources.forEach((source) => { - fetch(`${process.env.NEXT_PUBLIC_SUPABASE_URL}${FUNCTIONS_URL}${source}`, { - method: 'POST', - body: JSON.stringify({ query }), - }) - .then((response) => response.json()) - .then((results) => { - if (!Array.isArray(results)) { - throw Error("didn't get expected results array") - } - sourcesLoaded += 1 - dispatch({ - type: 'resultsReturned', - key: localKey, - sourcesLoaded, - results, - }) + supabaseClient.rpc('docs_search_fts', { query: query.trim() }).then(({ data, error }) => { + sourcesLoaded += 1 + if (error || !Array.isArray(data)) { + dispatch({ + type: 'errored', + key: localKey, + sourcesLoaded, + message: error?.message ?? '', }) - .catch((error) => { - sourcesLoaded += 1 - dispatch({ - type: 'errored', - key: localKey, - sourcesLoaded, - message: error.message ?? '', - }) + } else { + dispatch({ + type: 'resultsReturned', + key: localKey, + sourcesLoaded, + results: data, }) + } }) + + fetch(`${process.env.NEXT_PUBLIC_SUPABASE_URL}${FUNCTIONS_URL}search-embeddings`, { + method: 'POST', + body: JSON.stringify({ query }), + }) + .then((response) => response.json()) + .then((results) => { + if (!Array.isArray(results)) { + throw Error("didn't get expected results array") + } + sourcesLoaded += 1 + dispatch({ + type: 'resultsReturned', + key: localKey, + sourcesLoaded, + results, + }) + }) + .catch((error) => { + sourcesLoaded += 1 + dispatch({ + type: 'errored', + key: localKey, + sourcesLoaded, + message: error.message ?? '', + }) + }) }, [supabaseClient] ) diff --git a/supabase/config.toml b/supabase/config.toml index 214e724262..6f09899cc5 100644 --- a/supabase/config.toml +++ b/supabase/config.toml @@ -71,8 +71,5 @@ redirect_uri = "" # or any other third-party OIDC providers. url = "" -[functions.search-fts] -verify_jwt = false - [functions.search-embeddings] verify_jwt = false diff --git a/supabase/functions/search-fts/index.ts b/supabase/functions/search-fts/index.ts deleted file mode 100644 index def7c8c1f0..0000000000 --- a/supabase/functions/search-fts/index.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.8.0' -import { Database } from '../common/database-types.ts' -import { ApplicationError, UserError } from '../common/errors.ts' - -const isDev = Deno.env.get('DENO_ENV') === 'development' - -const supabaseUrl = Deno.env.get('SUPABASE_URL') -const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') - -function getCorsHeaders(req) { - const receivedOrigin = req.headers.get('Origin') - const resolvedOrigin = /^https:\/\/[^.\/]+-supabase.vercel.app$/.test(receivedOrigin) - ? receivedOrigin // Allow preview sites on Vercel to access function - : 'https://supabase.com' - - return { - 'Access-Control-Allow-Origin': isDev ? '*' : resolvedOrigin, - 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', - } -} - -Deno.serve(async (req) => { - try { - // Handle CORS - if (req.method === 'OPTIONS') { - return new Response('ok', { headers: getCorsHeaders(req) }) - } - - if (!supabaseUrl) { - throw new ApplicationError('Missing environment variable SUPABASE_URL') - } - - if (!supabaseServiceKey) { - throw new ApplicationError('Missing environment variable SUPABASE_SERVICE_ROLE_KEY') - } - const requestData = await req.json() - - if (!requestData) { - throw new UserError('Missing request data') - } - - const { query } = requestData - - if (!query) { - throw new UserError('Missing query in request data') - } - - // Intentionally log the query - console.log({ query }) - - const sanitizedQuery = query.trim() - - const supabaseClient = createClient(supabaseUrl, supabaseServiceKey) - - const { data: searchData, error: searchError } = await supabaseClient.rpc('docs_search_fts', { - query: sanitizedQuery, - }) - - if (searchError) { - throw new ApplicationError('Failed to find search results', searchError) - } - - return new Response(JSON.stringify(searchData), { - headers: { - ...getCorsHeaders(req), - 'Content-Type': 'application/json', - }, - }) - } catch (err) { - console.error(err) - - if (err instanceof UserError) { - return new Response( - JSON.stringify({ - error: err.message, - data: err.data, - }), - { - status: 400, - headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' }, - } - ) - } else if (err instanceof ApplicationError) { - // Print out application errors with their additional data - console.error(`${err.message}: ${JSON.stringify(err.data)}`) - } else { - // Print out unexpected errors as is to help with debugging - console.error(err) - } - - // TODO: include more response info in debug environments - return new Response( - JSON.stringify({ - error: 'There was an error processing your request', - }), - { - status: 500, - headers: { ...getCorsHeaders(req), 'Content-Type': 'application/json' }, - } - ) - } -})