Typesafe Supabase Flutter Queries

mmvergara - Jun 24 - - Dev Community

Supabase Flutter Types? In web development, supabase provide you with an API to generate typescript types to make typesafe queries. But what about for flutter? for dart? That's what this is all about

Yes we can generate dart classes directly from you supabase schema in order to achieve Typesafe Queries Flutter Supabase

Supabase Schema Dart Class Generator using this tool you can generate dart class via WebApp or CLI

1. Assuming the following table schema

create table
  public.books (
    id bigint generated by default as identity,
    name character varying not null,
    description text null,
    price integer not null,
    created_at timestamp with time zone not null default now(),
    constraint books_pkey primary key (id)
  ) tablespace pg_default;
Enter fullscreen mode Exit fullscreen mode

2. Use the CLI or the Web App to generate dart classes

class Books {
  final BigInt id;
  final String name;
  final String? description;
  final int price;
  final DateTime created_at;

  const Books({
    required this.id,
    required this.name,
    this.description,
    required this.price,
    required this.created_at,
  });

  static String get table_name => 'books';
  static String get c_id => 'id';
  static String get c_name => 'name';
  static String get c_description => 'description';
  static String get c_price => 'price';
  static String get c_created_at => 'created_at';
  static Map<String, dynamic> insert({
    BigInt? id,
    required String name,
    String? description,
    required int price,
    DateTime? created_at,
  }) {
    return {
      if (id != null) 'id': id.toString(),
      'name': name.toString(),
      if (description != null) 'description': description.toString(),
      'price': price.toString(),
      if (created_at != null) 'created_at': created_at.toUtc().toString(),
    };
  }

  static Map<String, dynamic> update({
    BigInt? id,
    String? name,
    String? description,
    int? price,
    DateTime? created_at,
  }) {
    return {
      if (id != null) 'id': id.toString(),
      if (name != null) 'name': name.toString(),
      if (description != null) 'description': description.toString(),
      if (price != null) 'price': price.toString(),
      if (created_at != null) 'created_at': created_at.toUtc().toString(),
    };
  }

  factory Books.fromJson(Map<String, dynamic> json) {
    return Books(
      id: BigInt.parse(json['id'].toString()),
      name: json['name'] as String,
      description:
          json['description'] != null ? json['description'] as String : null,
      price: json['price'] as int,
      created_at: DateTime.parse(json['created_at'].toString()),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Using the generated class

we now have a typesafe'ish to interact with the database.

Getting Table Name

  Books.table_name // "books"
Enter fullscreen mode Exit fullscreen mode

Fetch Data

// fetchedBooks is a typeof List<Books>
final books = await supabase
      .books
      .select("*")
      .withConverter((data) => data.map(Books.fromJson).toList());
Enter fullscreen mode Exit fullscreen mode

Insert Data

yes, we know which ones is required and which ones are optional

final data = Books.insert(
  name: 'Learn Flutter',
  description: 'Endless brackets and braces',
  price: 2,
);
await supabase.books.insert(data);
Enter fullscreen mode Exit fullscreen mode

Inset Many Data

final many_data = [
  Books.insert(
    name: 'Learn Minecraft',
    description: 'Endless blocks and bricks',
    price: 2,
  ),
  Books.insert(
    name: 'Description is optional',
    created_at: DateTime.now(),
    price: 2,
  ),
];
await supabase.books.insert(many_data);
Enter fullscreen mode Exit fullscreen mode

Update Data

final newData = Books.update(
  name: 'New Book Name',
);
await supabase.books.update(newData).eq(Books.c_id, 1);
Enter fullscreen mode Exit fullscreen mode

Delete Data

await supabase.books.delete().eq(Books.c_id, 1);
Enter fullscreen mode Exit fullscreen mode

How it works is that it uses the rest api to fetch for your schemas and then constructs the dart classes for you. Is it safe? yes first of all the project is open source and they api is used by other tools like this one that visualizes your database.

Is this only for flutter? no you can use it in a normal Dart Project.

Im trying to make it better for the community i would really appreciate some help and suggestions to improve it. especially the process of parsing the data to dart types, but either way the generated classes are tested for runtime for most supabase / postgres types

GitHub logo mmvergara / supadart

Type safe queries in Supabase Flutter! Generate Flutter / Dart 🎯 classes from your Supabase schema.

Supadart 🎯

Typesafe Supabase Flutter Queries
Generate Flutter / Dart 🎯 classes from your Supabase schema.

Features

  • 🛠️ Typesafe Queries (Create, Read, Equality)
  • 🧱 Immutable Generated Classes
  • 📊 Supports Column Selection Queries
  • 🔢 Supports all Supabase Major datatypes
  • 🗂️ Supports Defined as array types
  • 🌐 Cli and Web App

Table of Contents

Conversion Table

Supabase Identifier PostgreSQL Format JSON Type Dart Type Runtime Tested
# int2 smallint integer int type ✅ type[]✅
# int4 integer integer int type ✅ type[]✅
# int8 bigint integer BigInt type ✅ type[]✅
# float4 real number double type ✅ type[]✅
# float8 double precision number double type ✅ type[]✅
# numeric numeric number num type ✅ type[]✅
{} json json - Map<String, dynamic> type ✅ type[]✅
{} jsonb jsonb - Map<String, dynamic> type ✅ type[]✅
T text text string String type ✅ type[]✅
T varchar
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player