CREATE SCHEMA IF NOT EXISTS storage AUTHORIZATION postgres; grant usage on schema storage to postgres, anon, authenticated, service_role; alter default privileges in schema storage grant all on tables to postgres, anon, authenticated, service_role; alter default privileges in schema storage grant all on functions to postgres, anon, authenticated, service_role; alter default privileges in schema storage grant all on sequences to postgres, anon, authenticated, service_role; DROP TABLE IF EXISTS "storage"."buckets"; CREATE TABLE "storage"."buckets" ( "id" text not NULL, "name" text NOT NULL, "owner" uuid, "created_at" timestamptz DEFAULT now(), "updated_at" timestamptz DEFAULT now(), CONSTRAINT "buckets_owner_fkey" FOREIGN KEY ("owner") REFERENCES "auth"."users"("id"), PRIMARY KEY ("id") ); CREATE UNIQUE INDEX "bname" ON "storage"."buckets" USING BTREE ("name"); DROP TABLE IF EXISTS "storage"."objects"; CREATE TABLE "storage"."objects" ( "id" uuid NOT NULL DEFAULT extensions.uuid_generate_v4(), "bucket_id" text, "name" text, "owner" uuid, "created_at" timestamptz DEFAULT now(), "updated_at" timestamptz DEFAULT now(), "last_accessed_at" timestamptz DEFAULT now(), "metadata" jsonb, CONSTRAINT "objects_bucketId_fkey" FOREIGN KEY ("bucket_id") REFERENCES "storage"."buckets"("id"), CONSTRAINT "objects_owner_fkey" FOREIGN KEY ("owner") REFERENCES "auth"."users"("id"), PRIMARY KEY ("id") ); CREATE UNIQUE INDEX "bucketid_objname" ON "storage"."objects" USING BTREE ("bucket_id","name"); CREATE INDEX name_prefix_search ON storage.objects(name text_pattern_ops); ALTER TABLE storage.objects ENABLE ROW LEVEL SECURITY; CREATE OR REPLACE FUNCTION storage.foldername(name text) RETURNS text[] LANGUAGE plpgsql AS $function$ DECLARE _parts text[]; BEGIN select string_to_array(name, '/') into _parts; return _parts[1:array_length(_parts,1)-1]; END $function$; CREATE OR REPLACE FUNCTION storage.filename(name text) RETURNS text LANGUAGE plpgsql AS $function$ DECLARE _parts text[]; BEGIN select string_to_array(name, '/') into _parts; return _parts[array_length(_parts,1)]; END $function$; CREATE OR REPLACE FUNCTION storage.extension(name text) RETURNS text LANGUAGE plpgsql AS $function$ DECLARE _parts text[]; _filename text; BEGIN select string_to_array(name, '/') into _parts; select _parts[array_length(_parts,1)] into _filename; return split_part(_filename, '.', 2); END $function$; CREATE OR REPLACE FUNCTION storage.search(prefix text, bucketname text, limits int DEFAULT 100, levels int DEFAULT 1, offsets int DEFAULT 0) RETURNS TABLE ( name text, id uuid, updated_at TIMESTAMPTZ, created_at TIMESTAMPTZ, last_accessed_at TIMESTAMPTZ, metadata jsonb ) LANGUAGE plpgsql AS $function$ DECLARE _bucketId text; BEGIN select buckets."id" from buckets where buckets.name=bucketname limit 1 into _bucketId; return query with files_folders as ( select ((string_to_array(objects.name, '/'))[levels]) as folder from objects where objects.name ilike prefix || '%' and bucket_id = _bucketId GROUP by folder limit limits offset offsets ) select files_folders.folder as name, objects.id, objects.updated_at, objects.created_at, objects.last_accessed_at, objects.metadata from files_folders left join objects on prefix || files_folders.folder = objects.name where objects.id is null or objects.bucket_id=_bucketId; END $function$; GRANT ALL PRIVILEGES ON SCHEMA storage TO postgres; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA storage TO postgres; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA storage TO postgres;