ホームページ > ウェブフロントエンド > jsチュートリアル > スーパーベース関数 (エッジではない)

スーパーベース関数 (エッジではない)

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
リリース: 2024-08-29 14:00:19
オリジナル
429 人が閲覧しました

スーパーベース

Firebase サービスに代わるオープンソースの代替手段

  • データベース
  • リアルタイム
  • 認証
  • 機能
  • エッジ関数

しかし、待ってください。すでに機能があるのに、なぜエッジ機能が必要なのでしょうか?

supabase functions (not edge)

Supabase 関数: PostgreSQL ツールボックス

データベース関数とも呼ばれる Supabase 関数は、本質的には PostgreSQL ストアド プロシージャです。これらは、SQL クエリ内から呼び出すことができる SQL コードの実行可能ブロックです。

エッジ機能: データベースを超えて

対照的に、Edge 関数は、Deno ランタイムで実行されるサーバー側の TypeScript 関数です。これらは Firebase Cloud Functions に似ていますが、より柔軟でオープンソースの代替手段を提供します。

Supabase: PostgreSQL プラットフォーム

Supabase は、Firebase のオープンソース代替としての役割を超えて、包括的な PostgreSQL プラットフォームに進化しました。 PostgreSQL 関数に対する最上級のサポートを提供し、それらの関数を組み込みユーティリティにシームレスに統合し、Supabase ダッシュボードから直接カスタム関数を作成および管理できるようにします。

基本的な postgres 関数の構造

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 postgres 関数

組み込み関数

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.

以上がスーパーベース関数 (エッジではない)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート