DEV Community

Cover image for Typesafe Supabase Flutter Queries
mmvergara
mmvergara

Posted on

Typesafe Supabase Flutter Queries

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 / supabase-schema-dart-class-generator

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

Supabase Schema to Dart Classes 🎯

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

Conversion Table

Supabase Identifier Format JSON Type Dart Type Runtime Tested
# int2 smallint integer int
# int4 integer integer int
# int8 bigint integer BigInt
# float4 real number double
# float8 double precision number double
# numeric numeric number num
{} json json - Map<String, dynamic>
{} jsonb jsonb - Map<String, dynamic>
T text text string String
T varchar character varying string String
T uuid uuid string String
🗓️ date date string DateTime
🗓️ time time without time zone string DateTime
🗓️ timetz time with time zone string DateTime
🗓️ timestamp timestamp without time zone string DateTime
🗓️ timestamptz timestamp with time zone string DateTime
💡

Top comments (0)