Простое разворачивание и откат функций PostgreSQL с помощью Supabase

Простое разворачивание и откат функций PostgreSQL с помощью Supabase

В мире управления базами данных версионный контроль и развертывание имеют решающее значение. Эффективное развертывание и управление функциями баз данных необходимо для поддержания целостности ваших приложений, работающих с данными. В то время как миграции баз данных, как подробно описано в руководстве по миграциям Supabase, идеальны для долгосрочных проектов, существуют сценарии, такие как прототипирование и быстрая разработка, где требуется большая гибкость.

В этой статье мы исследуем подход, созданный для быстрого прототипирования и гибкой разработки - как легко разворачивать и откатывать функции PostgreSQL с использованием Supabase. Supabase, мощная альтернатива традиционным системам управления базами данных с открытым исходным кодом, упрощает процесс развертывания и управления функциями в таких сценариях.

Если вы работаете над более сложными рабочими процессами или долгосрочными проектами, мы настоятельно рекомендуем обратиться к руководству по миграциям Supabase для оптимальных практик версионного контроля и развертывания.

PostgreSQL и Supabase в современных веб-приложениях

PostgreSQL, надежная система управления реляционными базами данных с открытым исходным кодом (RDBMS), завоевала популярность в веб-разработке благодаря своей надежности, расширяемости и поддержке сложных типов данных.

Supabase, платформа с открытым исходным кодом, предоставляет различные инструменты и услуги для современных веб-приложений. Она использует PostgreSQL как свой основной базовый движок базы данных и предоставляет удобный интерфейс для управления данными, аутентификации и многими другими возможностями.

Мы исследуем, как Supabase дополняет PostgreSQL, упрощая развертывание функций и их откат. Вы можете обратиться к документации PostgreSQL, чтобы узнать больше о PostgreSQL.

Отслеживание истории функций в PostgreSQL

При управлении базой данных PostgreSQL важно отслеживать изменения, внесенные в функции со временем. Эта история позволяет вам просматривать, аудитить и возвращаться к предыдущим версиям при необходимости.

Для облегчения этого, мы создадим таблицу archive.function_history, в которой будут храниться важные сведения о каждой функции, включая ее имя, аргументы, возвращаемый тип, исходный код и настройки языка.

Вот SQL-код для создания этой таблицы:

CREATE SCHEMA archive;

CREATE TABLE archive.function_history (
  schema_name text,
  function_name text,
  args text,
  return_type text,
  source_code text,
  lang_settings text,
  updated_at timestamp default now()
);

Сохранение истории функций

Функция archive.save_function_history

Для автоматизации записи изменений в функциях мы создадим функцию PostgreSQL с названием archive.save_function_history. Эта функция принимает параметры, такие как имя функции, аргументы, возвращаемый тип, исходный код, имя схемы и настройки языка.

Вот SQL-код для создания функции archive.save_function_history:

CREATE OR REPLACE
FUNCTION archive.save_function_history(
  function_name text,
  args text,
  return_type text,
  source_code text,
  schema_name text default 'public',
  lang_settings text default 'plpgsql'
) RETURNS void
SET search_path = public, archive
SECURITY DEFINER
AS
$
BEGIN
  INSERT INTO archive.function_history (
        schema_name,
        function_name,
        args,
        return_type,
        source_code,
        lang_settings)
  VALUES (schema_name, function_name, args, return_type, source_code, lang_settings);
END;
$
LANGUAGE plpgsql;
-- Protecting the function:
REVOKE EXECUTE ON FUNCTION
archive.save_function_history FROM public;

REVOKE EXECUTE ON FUNCTION
archive.save_function_history FROM anon, authenticated;


Эта функция позволяет нам легко сохранять снимок функции каждый раз, когда она изменяется.

Развертывание функций из исходного кода

Функция create_function_from_source

Управление функциями часто включает в себя их развертывание из исходного кода. PostgreSQL требует конкретного синтаксиса для создания функций, и Supabase упрощает это с помощью функции create_function_from_source.

CREATE OR REPLACE FUNCTION
create_function_from_source(
  function_text text,
  schema_name text default 'public'
) RETURNS text
SECURITY DEFINER
AS $
DECLARE
  function_name text;
  argument_types text;
  return_type text;
  function_source text;
  lang_settings text;
BEGIN
  -- Execute the function text to create the function
  EXECUTE function_text;

  -- Extract function name from function text
  SELECT (regexp_matches(function_text, 'create (or replace )?function (public\.)?(\w+)', 'i'))[3]
  INTO function_name;

  -- Get function details from the system catalog
  SELECT pg_get_function_result(p.oid),
                pg_get_function_arguments(p.oid), p.prosrc, l.lanname
  INTO return_type, argument_types, function_source, lang_settings
  FROM pg_proc p
  JOIN pg_namespace n ON n.oid = p.pronamespace
  JOIN pg_language l ON l.oid = p.prolang
  WHERE n.nspname = schema_name AND p.proname = function_name;

  -- Save function history
  PERFORM archive.save_function_history(function_name, argument_types, return_type, function_text, schema_name, lang_settings);

  RETURN 'Function created successfully.';
EXCEPTION
  WHEN others THEN
    RAISE EXCEPTION 'Error creating function: %', sqlerrm;
END;
$ LANGUAGE plpgsql;
-- Protecting the function:
REVOKE EXECUTE ON FUNCTION
create_function_from_source FROM public;

REVOKE EXECUTE ON FUNCTION
create_function_from_source FROM anon, authenticated;


Эта функция принимает исходный код SQL функции и имя схемы в качестве параметров, создавая функцию в базе данных. Это мощное средство для динамического создания функций.

Вот пример развертывания функции с использованием create_function_from_source:


SELECT create_function_from_source(
$
-- Note that you can just paste the function below:
CREATE OR REPLACE FUNCTION public.convert_to_uuid(input_value text)
 RETURNS uuid
AS $function$
DECLARE
  hash_hex text;
BEGIN
  -- Return null if input_value is null or an empty string
  IF input_value IS NULL OR NULLIF(input_value, '') IS NULL THEN
    RETURN NULL;
  END IF;
  hash_hex := substring(encode(digest(input_value::bytea, 'sha512'), 'hex'), 1, 36);
  RETURN (left(hash_hex, 8) || '-' || right(hash_hex, 4) || '-4' || right(hash_hex, 3) || '-a' || right(hash_hex, 3) || '-' || right(hash_hex, 12))::uuid;
END;
$function$
LANGUAGE plpgsql
IMMUTABLE
SECURITY DEFINER;
-- End of the function above
$
);


Откат функций так же важен, как и их разворачивание. Ошибки случаются, и возможность вернуться к предыдущей версии может сэкономить много времени и предотвратить повреждение данных.

В этом случае на помощь приходит функция rollback_function. Она извлекает самую последнюю версию функции из таблицы archive.function_history и выполняет ее. Если предыдущей версии нет, она обрабатывает ситуацию грациозно.

Вот SQL-код для создания и использования функции rollback_function:


CREATE OR REPLACE FUNCTION rollback_function(
  func_name text,
  schema_n text default 'public'
) RETURNS text
SECURITY DEFINER
AS $
DECLARE
  function_text text;
BEGIN
  -- Get the most recent function version from the function_history table
  SELECT source_code
  INTO function_text
  FROM archive.function_history
  WHERE function_name = func_name AND schema_name = schema_n
  ORDER BY updated_at DESC
  LIMIT 1;

  -- If no previous version is found, raise an error
  IF function_text IS NULL THEN
    RAISE EXCEPTION 'No previous version of function % found.', func_name;
  END IF;

  -- Add 'or replace' to the function text if it's not already there (case-insensitive search and replace)
  IF NOT function_text ~* 'or replace' THEN
    function_text := regexp_replace(function_text, 'create function', 'create or replace function', 'i');
  END IF;

  -- Execute the function text to create the function
  EXECUTE function_text;

  RETURN 'Function rolled back successfully.';
EXCEPTION
  WHEN others THEN
    RAISE EXCEPTION 'Error rolling back function: %', sqlerrm;
END;
$ LANGUAGE plpgsql;

-- Protecting the function:
REVOKE EXECUTE ON FUNCTION rollback_function FROM public;
REVOKE EXECUTE ON FUNCTION rollback_function FROM anon, authenticated;

-- Example of rolling back a function
SELECT rollback_function('convert_to_uuid');


Настройка существующих функций в качестве первой версии

Если у вас уже есть база данных, но вы хотите начать версионирование с текущего момента, вы можете использовать следующую функцию для архивирования всех функций в схеме public.

CREATE OR REPLACE FUNCTION archive.setup_function_history(schema_name text default 'public')
RETURNS VOID AS
$$
DECLARE
  function_record record;
BEGIN
  -- Loop through existing functions in the specified schema
  FOR function_record IN (
    SELECT
      n.nspname AS schema_name,
      p.proname AS function_name,
      pg_catalog.pg_get_function_arguments(p.oid) AS args,
      pg_catalog.pg_get_function_result(p.oid) AS return_type,
      pg_catalog.pg_get_functiondef(p.oid) AS source_code,
      l.lanname AS lang_settings
    FROM pg_catalog.pg_proc p
    LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
    LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang
    WHERE n.nspname = schema_name
  )
  LOOP
    -- Insert information about the function into the history table
    PERFORM archive.save_function_history(
      function_record.function_name,
      function_record.args,
      function_record.return_type,
      function_record.source_code,
      function_record.schema_name,
      function_record.lang_settings
    );
  END LOOP;
END;
$$
LANGUAGE plpgsql;

SELECT archive.setup_function_history();

В заключение

В заключение можно сказать, что эффективное управление функциями PostgreSQL критически важно для разработки веб-приложений. Supabase, с его интеграцией с PostgreSQL и рассмотренными нами инструментами, предлагает упрощенный подход к развертыванию и откату функций.

Основные выводы из этой статьи включают важность отслеживания истории функций, создание таблицы archive.function_history, функцию archive.save_function_history для записи изменений, а также удобство функций create_function_from_text и rollback_function для развертывания и отката.

Если вы нашли эту статью полезной, вас также может заинтересовать изучение связанных тем:

Мы призываем вас глубже изучить Supabase и PostgreSQL, чтобы раскрыть полный потенциал эффективного управления базой данных.

Дополнительные ресурсы

Для дополнительной информации и исследований предоставляются следующие дополнительные ресурсы:

Не стесняйтесь погрузиться в эти ресурсы для углубленного понимания этих мощных инструментов управления базой данных.