>웹 프론트엔드 >JS 튜토리얼 >Supabase 함수(가장자리 아님)

Supabase 함수(가장자리 아님)

WBOY
WBOY원래의
2024-08-29 14:00:19365검색

수파베이스

Firebase 제품에 대한 오픈소스 대안

  • 데이터베이스
  • 실시간
  • 인증
  • 기능
  • 가장자리 기능

그런데 이미 기능이 있는데 왜 엣지 기능이 필요한가요?

supabase functions (not edge)

Supabase 함수: PostgreSQL 도구 상자

데이터베이스 함수라고도 알려진 Supabase 함수는 본질적으로 PostgreSQL 저장 프로시저입니다. 이는 SQL 쿼리 내에서 호출할 수 있는 실행 가능한 SQL 코드 블록입니다.

엣지 기능: 데이터베이스를 넘어서

반대로 Edge 함수는 Deno 런타임에서 실행되는 서버측 TypeScript 함수입니다. Firebase Cloud Functions와 유사하지만 더 유연한 오픈 소스 대안을 제공합니다.

Supabase: PostgreSQL 플랫폼

Supabase는 Firebase에 대한 오픈소스 대안으로서의 역할을 넘어 포괄적인 PostgreSQL 플랫폼으로 발전했습니다. PostgreSQL 기능에 대한 최고 수준의 지원을 제공하여 내장 유틸리티에 원활하게 통합하고 Supabase 대시보드에서 직접 사용자 정의 기능을 생성 및 관리할 수 있도록 해줍니다.

기본 포스트그레스 함수의 구조

CREATE FUNCTION my_function() RETURNS int AS $$
BEGIN
    RETURN 42;
END;
$$ LANGUAGE sql;

분류:

  1. CREATE FUNCTION: 이 키워드는 새 함수를 정의하고 있음을 나타냅니다.
  2. my_function(): 함수의 이름입니다. 원하는 의미 있는 이름을 선택할 수 있습니다.
  3. RETURNS int: 함수의 반환 유형을 지정합니다. 이 경우 함수는 정수 값을 반환합니다.
  4. AS $$: 이는 함수 본문을 시작하고 이를 구분하기 위해 이중 달러 기호($$)로 묶입니다.
  5. BEGIN: 함수 실행 코드의 시작을 표시합니다.
  6. RETURN 42;: 이 문은 함수가 반환할 값을 지정합니다. 이 경우에는 정수 42입니다.
  7. END;: 이는 함수 실행 코드의 끝을 표시합니다.
  8. $$ LANGUAGE sql;: 함수가 작성되는 언어를 지정합니다. 이 경우에는 SQL입니다.

목적:

이 함수는 정수 값 42를 반환하는 my_function이라는 간단한 SQL 함수를 정의합니다. PostgreSQL에서 함수 정의의 구조와 구문을 보여주는 기본 예입니다.

기억해야 할 핵심 사항:

  • my_function을 원하는 함수 이름으로 바꿀 수 있습니다.
  • 반환 유형은 텍스트, 부울, 날짜 또는 사용자 정의 유형과 같은 유효한 데이터 유형일 수 있습니다.
  • 함수 본문에는 조건문, 루프, 다른 함수 호출 등 복잡한 논리가 포함될 수 있습니다.
  • $$ 구분 기호는 언어 독립적인 방식으로 함수 본문을 묶는 데 사용됩니다.

  • Postgres 함수는 함수와 유사하지만 테이블 삽입, 업데이트, 삭제와 같은 특정 이벤트에 반응하는 postgres TRIGGERS에 의해 호출될 수도 있습니다

  • 이 기능을 실행하려면

SELECT my_function();
  • 이 기능을 나열하려면
SELECT
    proname AS function_name,
    prokind AS function_type
FROM pg_proc
WHERE proname = 'my_function';
  • 이 기능을 삭제하려면
DROP FUNCTION my_function();

Supabase 포스트그레스 함수

내장 기능

Supabase는 postgres 기능을 사용하여 데이터베이스 내에서 특정 작업을 수행합니다.

짧은 시험 목록에는 다음이 포함됩니다

--  list all the supabase functions
SELECT
    proname AS function_name,
    prokind AS function_type
FROM pg_proc;

--  filter for the session supabase functions function
SELECT
    proname AS function_name,
    prokind AS function_type
FROM pg_proc
WHERE proname ILIKE '%session%';

--  selects the curremt jwt
select auth.jwt()

-- select what role is callig the function (anon or authenticated)
select auth.role();

-- select the session user
select session_use;

대시보드의 Supabase 기능 보기
Supabase에서 이러한 기능 중 일부를 보려면 데이터베이스 > 기능

supabase functions (not edge)

유용한 Supabase PostgreSQL 함수

사용자 가입 시 user_profile 테이블 생성

Supabase는 auth.users 테이블에 사용자 데이터를 저장합니다. 이 테이블은 비공개이므로 직접 액세스하거나 수정해서는 안 됩니다. 권장되는 접근 방식은 공용 사용자 또는 user_profiles 테이블을 생성하고 이를 auth.users 테이블에 연결하는 것입니다.

클라이언트 측 SDK를 사용하여 사용자 생성 요청과 성공적인 가입 요청을 연결하여 이 작업을 수행할 수 있지만 Supabase 측에서 처리하는 것이 더 안정적이고 효율적입니다. 이는 TRIGGER와 FUNCTION의 조합을 사용하여 달성할 수 있습니다.

--   create the user_profiles table
CREATE TABLE user_profiles (
  id uuid PRIMARY KEY,
  FOREIGN KEY (id) REFERENCES auth.users(id),
  name text,
  email text
);

-- create a function that returns a trigger on auth.users
CREATE 
OR REPLACE FUNCTION public.create_public_user_profile_table() 
RETURNS TRIGGER AS $$ 
BEGIN INSERT INTO public.user_profiles (id,name,email) 
VALUES 
  (
    NEW.id,
    NEW.raw_user_meta_data ->> 'name',
    NEW.raw_user_meta_data ->> 'email'
    -- other fields accessible here 
--     NEW.raw_user_meta_data ->> 'name',
-- NEW.raw_user_meta_data ->> 'picture',

);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- create the trigger that executes the function on every new user rowcteation(signup)
CREATE TRIGGER create_public_user_profiles_trigger 
AFTER INSERT ON auth.users FOR EACH ROW WHEN (
        NEW.raw_user_meta_data IS NOT NULL
    )
EXECUTE FUNCTION public.create_public_user_profile_table ();

let { data: user_profiles, error } = await supabase
  .from('user_profiles')
  .select('*')
  • jwt 생성(RBAC)에 대한 사용자 정의 클레임 추가 supabse에는 이에 대한 자세한 기사와 동영상이 있습니다.

2정이 필요합니다

  • public.roles 및 public.role_permissions
-- Custom types
create type public.app_permission as enum ('channels.delete', 'channels.update', 'messages.update', 'messages.delete');
create type public.app_role as enum ('admin', 'moderator');

-- USER ROLES
create table public.user_roles (
  id        bigint generated by default as identity primary key,
  user_id   uuid references public.users on delete cascade not null,
  role      app_role not null,
  unique (user_id, role)
);
comment on table public.user_roles is 'Application roles for each user.';

-- ROLE PERMISSIONS
create table public.role_permissions (
  id           bigint generated by default as identity primary key,
  role         app_role not null,
  permission   app_permission not null,
  unique (role, permission)
);
comment on table public.role_permissions is 'Application permissions for each role.';

사용자 역할 예시

id user_id role
1 user-1 admin
2 user-2 moderator

example of a role permission table

id role permission
1 admin channels.update
2 admin messages.update
3 admin messages.delete
4 admin messages.delete
5 moderator channels.update
6 moderator messages.update

user with user_id = user-1 will have admin and moderator roles and can delete channels and messages

users with user_id = user-2 can only update channels and messages with the moderator role

-- Create the auth hook function
create or replace function public.custom_access_token_hook(event jsonb)
returns jsonb
language plpgsql
stable
as $$
  declare
    claims jsonb;
    user_role public.app_role;
  begin
    -- Fetch the user role in the user_roles table
    select role into user_role from public.user_roles where user_id = (event->>'user_id')::uuid;

    claims := event->'claims';

    if user_role is not null then
      -- Set the claim
      claims := jsonb_set(claims, '{user_role}', to_jsonb(user_role));
    else
      claims := jsonb_set(claims, '{user_role}', 'null');
    end if;

    -- Update the 'claims' object in the original event
    event := jsonb_set(event, '{claims}', claims);

    -- Return the modified or original event
    return event;
  end;
$$;

grant usage on schema public to supabase_auth_admin;

grant execute
  on function public.custom_access_token_hook
  to supabase_auth_admin;

revoke execute
  on function public.custom_access_token_hook
  from authenticated, anon, public;

grant all
  on table public.user_roles
to supabase_auth_admin;

revoke all
  on table public.user_roles
  from authenticated, anon, public;

create policy "Allow auth admin to read user roles" ON public.user_roles
as permissive for select
to supabase_auth_admin
using (true)

then create a function that will be called to authorize on RLS policies

create or replace function public.authorize(
  requested_permission app_permission
)
returns boolean as $$
declare
  bind_permissions int;
  user_role public.app_role;
begin
  -- Fetch user role once and store it to reduce number of calls
  select (auth.jwt() ->> 'user_role')::public.app_role into user_role;

  select count(*)
  into bind_permissions
  from public.role_permissions
  where role_permissions.permission = requested_permission
    and role_permissions.role = user_role;

  return bind_permissions > 0;
end;
$$ language plpgsql stable security definer set search_path = '';

--  example RLS policies
create policy "Allow authorized delete access" on public.channels for delete using ( (SELECT authorize('channels.delete')) );
create policy "Allow authorized delete access" on public.messages for delete using ( (SELECT authorize('messages.delete')) );


Improved Text:

Creating RPC Endpoints

Supabase functions can be invoked using the rpc function. This is especially useful for writing custom SQL queries when the built-in PostgreSQL APIs are insufficient, such as calculating vector cosine similarity using pg_vector.

create or replace function match_documents (
  query_embedding vector(384),
  match_threshold float,
  match_count int
)
returns table (
  id bigint,
  title text,
  body text,
  similarity float
)
language sql stable
as $$
  select
    documents.id,
    documents.title,
    documents.body,
    1 - (documents.embedding <=> query_embedding) as similarity
  from documents
  where 1 - (documents.embedding <=> query_embedding) > match_threshold
  order by (documents.embedding <=> query_embedding) asc
  limit match_count;
$$;

and call it client side

const { data: documents } = await supabaseClient.rpc('match_documents', {
  query_embedding: embedding, // Pass the embedding you want to compare
  match_threshold: 0.78, // Choose an appropriate threshold for your data
  match_count: 10, // Choose the number of matches
})

Improved Text:

Filtering Out Columns

To prevent certain columns from being modified on the client, create a simple function that triggers on every insert. This function can omit any extra fields the user might send in the request.

-- check if user with roles authenticated or anon submitted an updatedat column and replace it with the current time , if not (thta is an admin) allow it
CREATE
or REPLACE function public.omit_updated__at () returns trigger as 
$$ BEGIN 
IF auth.role() IS NOT NULL AND auth.role() IN ('anon', 'authenticated') 
THEN NEW.updated_at = now();
END IF; 
RETURN NEW; 
END; $$ language plpgsql;

Summary

With a little experimentation, you can unlock the power of Supabase functions and their AI-powered SQL editor. This lowers the barrier to entry for the niche knowledge required to get this working.

Why choose Supabase functions?

  • Extend Supabase's API: Supabase can only expose so much through its API. Postgres, however, is a powerful database. Any action you can perform with SQL statements can be wrapped in a function and called from the client or by a trigger.
  • Reduce the need for dedicated backends: Supabase functions can fill the simple gaps left by the client SDKs, allowing you to focus on shipping.
  • Avoid vendor lock-in: Supabase functions are just Postgres. If you ever need to move to another hosting provider, these functionalities will continue to work.

위 내용은 Supabase 함수(가장자리 아님)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.