suparepo 1.3.2 copy "suparepo: ^1.3.2" to clipboard
suparepo: ^1.3.2 copied to clipboard

Generate repository/data access layer code from Supabase database schema. Automatically creates CRUD operations, queries, and type-safe API clients.

suparepo #

Generate repository, RPC client, and Edge Function client code from Supabase automatically.

Features #

  • Repository generation — CRUD operations (getAll, getById, create, update, delete), pagination, count, relation queries
  • RPC client generation — Type-safe Dart methods from Supabase SQL functions (auto-detected via OpenAPI spec)
  • Edge Function client generation — Typed or untyped clients from local supabase/functions/ directory
  • Type-safe when used with supafreeze models

Installation #

dependencies:
  suparepo: ^1.3.0

Quick Start #

1. Create Configuration #

Create suparepo.yaml in your project root:

url: ${SUPABASE_DATA_API_URL}
secret_key: ${SUPABASE_SECRET_KEY}
output: lib/repositories

# Optional: Link to model classes (generated by supafreeze)
# Use model_import_path for a barrel file import:
model_import_path: package:myapp/models/models.dart
# Or use model_import_prefix for individual file imports (recommended):
# model_import_prefix: package:myapp/

# Optional: Generate barrel file (default: false)
generate_barrel: false

# Optional: Generate Riverpod providers (default: false)
generate_providers: true

# Optional: Filter tables
include:
  - users
  - posts

2. Set Environment Variables #

Create .env file:

SUPABASE_DATA_API_URL=https://your-project.supabase.co
SUPABASE_SECRET_KEY=your-service-role-key

3. Run Generator #

dart run suparepo

CLI Options #

dart run suparepo              # Generate all enabled targets
dart run suparepo --repo       # Generate table repositories only
dart run suparepo --rpc        # Generate RPC client only
dart run suparepo --edge       # Generate Edge Function client only
dart run suparepo --force      # Force regenerate all

RPC Client Generation #

Automatically generates type-safe Dart methods for your Supabase SQL functions (RPC).

Configuration #

rpc:
  enabled: true
  output: lib/repositories/rpc_client.dart  # optional
  include:
    - get_user_posts
    - search_users
  exclude:
    - internal_cleanup

Generated Code Example #

For a SQL function get_user_posts(user_id uuid) returning setof json:

class SupabaseRpcClient {
  final SupabaseClient _client;

  const SupabaseRpcClient(this._client);

  Future<List<Map<String, dynamic>>> getUserPosts({
    required String userId,
  }) async {
    final response = await _client.rpc('get_user_posts', params: {
      'user_id': userId,
    });
    return (response as List).cast<Map<String, dynamic>>();
  }
}

Edge Function Client Generation #

Generates client code for your Supabase Edge Functions by scanning the local supabase/functions/ directory.

Configuration #

edge_functions:
  enabled: true
  functions_path: supabase/functions  # default
  output: lib/repositories/edge_function_client.dart  # optional
  include:
    - send-email
  models:
    send-email:
      request:
        to: { type: text, required: true }
        subject: { type: text, required: true }
        body_html: { type: text }
      response:
        success: { type: bool, required: true }
        message_id: { type: text }

Generated Code — Without Type Definitions #

class SupabaseEdgeFunctionClient {
  final SupabaseClient _client;

  const SupabaseEdgeFunctionClient(this._client);

  Future<FunctionResponse> sendEmail({
    Map<String, dynamic>? body,
    Map<String, String>? headers,
  }) async {
    return await _client.functions.invoke(
      'send-email', body: body, headers: headers,
    );
  }
}

Generated Code — With Type Definitions #

When models are defined in the config, typed request/response classes are generated:

class SendEmailRequest {
  final String to;
  final String subject;
  final String? bodyHtml;

  const SendEmailRequest({
    required this.to,
    required this.subject,
    this.bodyHtml,
  });

  Map<String, dynamic> toJson() => {
    'to': to,
    'subject': subject,
    if (bodyHtml != null) 'body_html': bodyHtml,
  };
}

class SendEmailResponse {
  final bool success;
  final String? messageId;

  const SendEmailResponse({required this.success, this.messageId});

  factory SendEmailResponse.fromJson(Map<String, dynamic> json) {
    return SendEmailResponse(
      success: json['success'] as bool,
      messageId: json['message_id'] as String?,
    );
  }
}

Repository Generation #

Generated Code Example #

For a users table with columns id, email, name:

class UsersRepository {
  final SupabaseClient _client;

  UsersRepository(this._client);

  Future<List<User>> getAll() async {
    final response = await _client.from('users').select();
    return response.map((e) => User.fromJson(e)).toList();
  }

  Future<User?> getById(String id) async {
    final response = await _client
        .from('users')
        .select()
        .eq('id', id)
        .maybeSingle();
    return response != null ? User.fromJson(response) : null;
  }

  Future<User> create(User data) async { ... }
  Future<User> update(String id, User data) async { ... }
  Future<void> delete(String id) async { ... }
  Future<int> count() async { ... }
  Future<List<User>> paginate({int page = 1, int perPage = 20}) async { ... }
}

Riverpod Provider Generation #

When generate_providers: true is set, each repository and RPC client gets a @Riverpod(keepAlive: true) provider:

@Riverpod(keepAlive: true)
UsersRepository usersRepository(Ref ref) {
  final client = ref.watch(supabaseClientProvider);
  return UsersRepository(client);
}

A supabase_client_provider.dart is also generated, which must be overridden in your ProviderScope:

@Riverpod(keepAlive: true)
SupabaseClient supabaseClient(Ref ref) {
  throw UnimplementedError(
    'supabaseClientProvider must be overridden in ProviderScope.',
  );
}

Model Import Options #

There are two ways to link generated repositories to supafreeze models:

Barrel file import (model_import_path):

model_import_path: package:myapp/models/models.dart

All repositories import from a single barrel file.

Individual file import (model_import_prefix, recommended):

model_import_prefix: package:myapp/

Each repository imports its own model file (e.g., package:myapp/users.supafreeze.dart). Takes precedence over model_import_path.

Full Configuration Reference #

url: ${SUPABASE_DATA_API_URL}
secret_key: ${SUPABASE_SECRET_KEY}
output: lib/repositories
schema: public
fetch: always                # always | if_no_cache | never
generate_barrel: false       # Generate barrel file for repositories (default: false)
generate_providers: true     # Generate Riverpod providers (default: false)
model_import_path: package:myapp/models/models.dart       # Barrel file import
model_import_prefix: package:myapp/                       # Individual file import (takes precedence)
supabase_import: package:supabase_flutter/supabase_flutter.dart  # or package:supabase/supabase.dart for pure Dart

# Table filter (for repository generation)
include: [users, posts]
# exclude: [_migrations]

# RPC function client
rpc:
  enabled: true
  output: lib/repositories/rpc_client.dart
  include: [get_user_posts]
  exclude: [internal_cleanup]

# Edge Function client
edge_functions:
  enabled: true
  output: lib/repositories/edge_function_client.dart
  functions_path: supabase/functions
  include: [send-email]
  models:
    send-email:
      request:
        to: { type: text, required: true }
        subject: { type: text, required: true }
      response:
        success: { type: bool, required: true }

Using with supafreeze #

For the best experience, use suparepo together with supafreeze:

  1. Generate models with supafreeze
  2. Set model_import_prefix (or model_import_path) in suparepo.yaml to point to your models
  3. Optionally enable generate_providers: true for Riverpod DI
  4. Generate repositories with suparepo

This gives you fully type-safe repositories with Freezed models and optional Riverpod providers.

License #

MIT

0
likes
0
points
625
downloads

Publisher

unverified uploader

Weekly Downloads

Generate repository/data access layer code from Supabase database schema. Automatically creates CRUD operations, queries, and type-safe API clients.

Homepage
Repository (GitHub)
View/report issues

Topics

#supabase #repository #code-generation #data-access #postgresql

License

unknown (license)

Dependencies

http, path, recase, supabase_schema_core, yaml

More

Packages that depend on suparepo