”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > SUPABASE 函数(非边缘)

SUPABASE 函数(非边缘)

发布于2024-11-01
浏览:308

Supabase

An open source alternative to firebase offering

  • database
  • realtime
  • auth
  • functions
  • edge-functions

But wait,if they already have functions why do they need edge functions?

supabase functions (not edge)

Supabase Functions: Your PostgreSQL Toolbox

Supabase functions, also known as database functions, are essentially PostgreSQL stored procedures. They are executable blocks of SQL code that can be called from within SQL queries.

Edge Functions: Beyond the Database

In contrast, Edge functions are server-side TypeScript functions that run on the Deno runtime. They are similar to Firebase Cloud Functions but offer a more flexible and open-source alternative.

Supabase: A PostgreSQL Platform

Beyond its role as an open-source alternative to Firebase, Supabase has evolved into a comprehensive PostgreSQL platform. It provides first-class support for PostgreSQL functions, integrating them seamlessly into its built-in utilities and allowing you to create and manage custom functions directly from the Supabase dashboard.

Structure of a basic postgres functon

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

Breakdown:

  1. CREATE FUNCTION: This keyword indicates that we're defining a new function.
  2. my_function(): This is the name of the function. You can choose any meaningful name you prefer.
  3. RETURNS int: This specifies the return type of the function. In this case, the function will return an integer value.
  4. AS $$: This begins the function body, enclosed within double dollar signs ($$) to delimit it.
  5. BEGIN: This marks the start of the function's executable code.
  6. RETURN 42;: This statement specifies the value that the function will return. In this case, it's the integer 42.
  7. END;: This marks the end of the function's executable code.
  8. $$ LANGUAGE sql;: This specifies the language in which the function is written. In this case, it's SQL.

Purpose:

This function defines a simple SQL function named my_function that returns the integer value 42. It's a basic example to demonstrate the structure and syntax of a function definition in PostgreSQL.

Key points to remember:

  • You can replace my_function with any desired function name.
  • The return type can be any valid data type, such as text, boolean, date, or a user-defined type.
  • The function body can contain complex logic, including conditional statements, loops, and calls to other functions.
  • The $$ delimiters are used to enclose the function body in a language-independent manner.

  • Postgres functions can also be called by postgres TRIGGERS which are like functions but react to specific events like insert, update or delete on a table

  • to execute this function

SELECT my_function();
  • to list this function
SELECT
    proname AS function_name,
    prokind AS function_type
FROM pg_proc
WHERE proname = 'my_function';
  • to drop this function
DROP FUNCTION my_function();

Supabase postgres functions

Built-in functions

Supabase makes use of postgres functions to perform certain tasks within your database.

short list of exampales includes

--  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 functions view on the dashboard
To view some of these functions in Supabase, you can check under database > functions

supabase functions (not edge)

Useful Supabase PostgreSQL Functions

Creating a user_profile Table on User Signup

Supabase stores user data in the auth.users table, which is private and should not be accessed or modified directly. A recommended approach is to create a public users or user_profiles table and link it to the auth.users table.

While this can be done using client-side SDKs by chaining a create user request with a successful signup request, it's more reliable and efficient to handle it on the Supabase side. This can be achieved using a combination of a TRIGGER and a 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('*')
  • Add custom claims on jwt creation (RBAC) supabse has a detailed article and video on this .

we need 2 tabbles

  • public.roles and 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.';

example of user 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.
版本声明 本文转载于:https://dev.to/tigawanna/supabase-functions-not-edge-2o1?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    在时间戳列上使用current_timestamp或MySQL版本中的current_timestamp或在5.6.5 此限制源于遗留实现的关注,这些限制需要对当前的_timestamp功能进行特定的实现。 创建表`foo`( `Productid` int(10)unsigned not n...
    编程 发布于2025-04-28
  • 如何使用Java.net.urlConnection和Multipart/form-data编码使用其他参数上传文件?
    如何使用Java.net.urlConnection和Multipart/form-data编码使用其他参数上传文件?
    使用http request 上传文件上传到http server,同时也提交其他参数,java.net.net.urlconnection and Multipart/form-data Encoding是普遍的。 Here's a breakdown of the process:Mu...
    编程 发布于2025-04-28
  • 为什么我的CSS背景图像出现?
    为什么我的CSS背景图像出现?
    故障排除:CSS背景图像未出现 ,您的背景图像尽管遵循教程说明,但您的背景图像仍未加载。图像和样式表位于相同的目录中,但背景仍然是空白的白色帆布。而不是不弃用的,您已经使用了CSS样式: bockent {背景:封闭图像文件名:背景图:url(nickcage.jpg); 如果您的html,css...
    编程 发布于2025-04-28
  • Android如何向PHP服务器发送POST数据?
    Android如何向PHP服务器发送POST数据?
    在android apache httpclient(已弃用) httpclient httpclient = new defaulthttpclient(); httppost httppost = new httppost(“ http://www.yoursite.com/script.p...
    编程 发布于2025-04-28
  • 如何在Java字符串中有效替换多个子字符串?
    如何在Java字符串中有效替换多个子字符串?
    在java 中有效地替换多个substring,需要在需要替换一个字符串中的多个substring的情况下,很容易求助于重复应用字符串的刺激力量。 However, this can be inefficient for large strings or when working with nu...
    编程 发布于2025-04-28
  • 在JavaScript中如何获取实际渲染的字体,当CSS字体属性未定义时?
    在JavaScript中如何获取实际渲染的字体,当CSS字体属性未定义时?
    Accessing Actual Rendered Font when Undefined in CSSWhen accessing the font properties of an element, the JavaScript object.style.fontFamily and objec...
    编程 发布于2025-04-28
  • Java开发者如何保护数据库凭证免受反编译?
    Java开发者如何保护数据库凭证免受反编译?
    在java 在单独的配置文件保护数据库凭证的最有效方法中存储凭据是将它们存储在单独的配置文件中。该文件可以在运行时加载,从而使登录数据从编译的二进制文件中远离。使用prevereness class import java.util.prefs.preferences; 公共类示例{ 首选项...
    编程 发布于2025-04-28
  • 如何在JavaScript对象中动态设置键?
    如何在JavaScript对象中动态设置键?
    在尝试为JavaScript对象创建动态键时,如何使用此Syntax jsObj['key' i] = 'example' 1;不工作。正确的方法采用方括号: jsobj ['key''i] ='example'1; 在JavaScript中,数组是一...
    编程 发布于2025-04-28
  • 如何为PostgreSQL中的每个唯一标识符有效地检索最后一行?
    如何为PostgreSQL中的每个唯一标识符有效地检索最后一行?
    postgresql:为每个唯一标识符在postgresql中提取最后一行,您可能需要遇到与数据集合中每个不同标识的信息相关的信息。考虑以下数据:[ 1 2014-02-01 kjkj 在数据集中的每个唯一ID中检索最后一行的信息,您可以在操作员上使用Postgres的有效效率: id dat...
    编程 发布于2025-04-28
  • 如何从PHP中的数组中提取随机元素?
    如何从PHP中的数组中提取随机元素?
    从阵列中的随机选择,可以轻松从数组中获取随机项目。考虑以下数组:; 从此数组中检索一个随机项目,利用array_rand( array_rand()函数从数组返回一个随机键。通过将$项目数组索引使用此键,我们可以从数组中访问一个随机元素。这种方法为选择随机项目提供了一种直接且可靠的方法。
    编程 发布于2025-04-28
  • PHP与C++函数重载处理的区别
    PHP与C++函数重载处理的区别
    作为经验丰富的C开发人员脱离谜题,您可能会遇到功能超载的概念。这个概念虽然在C中普遍,但在PHP中构成了独特的挑战。让我们深入研究PHP功能过载的复杂性,并探索其提供的可能性。在PHP中理解php的方法在PHP中,函数超载的概念(如C等语言)不存在。函数签名仅由其名称定义,而与他们的参数列表无关。...
    编程 发布于2025-04-28
  • 表单刷新后如何防止重复提交?
    表单刷新后如何防止重复提交?
    在Web开发中预防重复提交 在表格提交后刷新页面时,遇到重复提交的问题是常见的。要解决这个问题,请考虑以下方法: 想象一下具有这样的代码段,看起来像这样的代码段:)){ //数据库操作... 回声“操作完成”; 死(); } ?> ...
    编程 发布于2025-04-28
  • 在Java中如何为PNG文件添加坐标轴和标签?
    在Java中如何为PNG文件添加坐标轴和标签?
    如何用java 在现有png映像中添加轴和标签的axes和labels如何注释png文件可能具有挑战性。与其尝试可能导致错误和不一致的修改,不如建议在图表创建过程中集成注释。使用JFReechArt import java.awt.color; 导入java.awt.eventqueue; 导入...
    编程 发布于2025-04-28
  • 如何在其容器中为DIV创建平滑的左右CSS动画?
    如何在其容器中为DIV创建平滑的左右CSS动画?
    通用CSS动画,用于左右运动 ,我们将探索创建一个通用的CSS动画,以向左和右移动DIV,从而到达其容器的边缘。该动画可以应用于具有绝对定位的任何div,无论其未知长度如何。问题:使用左直接导致瞬时消失 更加流畅的解决方案:混合转换和左 [并实现平稳的,线性的运动,我们介绍了线性的转换。这...
    编程 发布于2025-04-28
  • 如何使用PHP将斑点(图像)正确插入MySQL?
    如何使用PHP将斑点(图像)正确插入MySQL?
    essue VALUES('$this->image_id','file_get_contents($tmp_image)')";This code builds a string in PHP, but the function call ...
    编程 发布于2025-04-28

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3