{"id":13548384,"url":"https://github.com/mmvergara/supadart","last_synced_at":"2025-04-09T12:04:16.973Z","repository":{"id":245016246,"uuid":"817012676","full_name":"mmvergara/supadart","owner":"mmvergara","description":"Typesafe queries in Supabase Flutter! Generate Flutter / Dart 🎯 classes from your Supabase schema.","archived":false,"fork":false,"pushed_at":"2025-03-17T23:58:13.000Z","size":1011,"stargazers_count":68,"open_issues_count":6,"forks_count":8,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-02T10:16:40.719Z","etag":null,"topics":["dart","flutter","generate-classes","postgresql","schema","supabase"],"latest_commit_sha":null,"homepage":"https://supadart.vercel.app","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mmvergara.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.MD","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-18T20:55:51.000Z","updated_at":"2025-03-22T13:18:40.000Z","dependencies_parsed_at":"2024-06-29T04:26:07.011Z","dependency_job_id":"5ca1937e-a321-4a6c-9db5-dc5e7e9a441a","html_url":"https://github.com/mmvergara/supadart","commit_stats":{"total_commits":457,"total_committers":5,"mean_commits":91.4,"dds":0.05908096280087527,"last_synced_commit":"f211e7cf8355cf8b6d7e64972e9ed96e9b245eed"},"previous_names":["mmvergara/supabase-schema-dart-class-generator","mmvergara/supadart"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmvergara%2Fsupadart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmvergara%2Fsupadart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmvergara%2Fsupadart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmvergara%2Fsupadart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mmvergara","download_url":"https://codeload.github.com/mmvergara/supadart/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248036064,"owners_count":21037092,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","flutter","generate-classes","postgresql","schema","supabase"],"created_at":"2024-08-01T12:01:09.617Z","updated_at":"2025-04-09T12:04:16.950Z","avatar_url":"https://github.com/mmvergara.png","language":"Dart","funding_links":[],"categories":["Dart"],"sub_categories":[],"readme":"[![Pub Version](https://img.shields.io/pub/v/supadart)](https://pub.dev/packages/supadart)\n[![Pub Points](https://img.shields.io/pub/points/supadart)](https://pub.dev/packages/supadart)\n[![GitHub Stars](https://img.shields.io/github/stars/mmvergara/supadart)](https://github.com/mmvergara/supadart/stargazers)\n[![Runtime Test](https://github.com/mmvergara/supadart/actions/workflows/dart.yml/badge.svg)](https://github.com/mmvergara/supadart/actions/workflows/dart.yml)\n[![GitHub License](https://img.shields.io/github/license/mmvergara/supadart)](https://github.com/mmvergara/supadart/blob/main/LICENSE)\n\n# Supadart 🎯\n\nTypesafe Supabase Flutter Queries \u003cbr/\u003e\nGenerate Flutter / Dart 🎯 classes from your Supabase schema.\n\n```dart\n// allBooks is a typeof List\u003cBooks\u003e\nfinal allBooks = await supabase\n      .books\n      .select(\"*\")\n      .withConverter(Books.converter);\n```\n\n### Table of Contents 📚\n\n- [**Generate Dart Classes**](#generating-dart-classes)\n  - [**Pre-requisites**](#1-pre-requisites)\n  - [**Generate Dart Classes**](#2-generate-dart-classes)\n- [**Example Usage**](#example-usage)\n  - [**Fetch Data**](#fetch-data)\n  - [**Fetch Single Data**](#fetch-single-data)\n  - [**Insert Data**](#insert-data)\n  - [**Insert Many Data**](#inset-many-data)\n  - [**Update Data**](#update-data)\n  - [**Delete Data**](#delete-data)\n- [**Working with Enums**](#working-with-enums)\n- [**Column Selection Queries**](#column-selection-queries)\n\n### Features 🚀\n\n- 🛠️ Typesafe Queries (Create, Read, Equality)\n- 🧱 Immutable Generated Classes\n- 🗂️ Roundtrip Serialization fromJson to toJson and back\n- 📊 Supports Column Selection Queries\n- 🔢 Supports all Supabase Major datatypes\n- 🗂️ Supports Defined as array types\n- 🗂️ Supports Enums\n\n### Conversion Table 📊\n\n| Supabase Identifier | PostgreSQL Format           | JSON Type | Dart Type            | Runtime Tested \u003cimg src=\"https://github.com/mmvergara/supadart/actions/workflows/dart.yml/badge.svg?branch=main%22\"/\u003e |\n| ------------------- | --------------------------- | --------- | -------------------- | --------------------------------------------------------------------------------------------------------------------- |\n| # int2              | smallint                    | integer   | int                  | type ✅ type[]✅                                                                                                      |\n| # int4              | integer                     | integer   | int                  | type ✅ type[]✅                                                                                                      |\n| # int8              | bigint                      | integer   | BigInt               | type ✅ type[]✅                                                                                                      |\n| # float4            | real                        | number    | double               | type ✅ type[]✅                                                                                                      |\n| # float8            | double precision            | number    | double               | type ✅ type[]✅                                                                                                      |\n| # numeric           | numeric                     | number    | num                  | type ✅ type[]✅                                                                                                      |\n| {} json             | json                        | object    | Map\u003cString, dynamic\u003e | type ✅ type[]✅                                                                                                      |\n| {} jsonb            | jsonb                       | object    | Map\u003cString, dynamic\u003e | type ✅ type[]✅                                                                                                      |\n| T text              | text                        | string    | String               | type ✅ type[]✅                                                                                                      |\n| T varchar           | character varying           | string    | String               | type ✅ type[]✅                                                                                                      |\n| T uuid              | uuid                        | string    | String               | type ✅ type[]✅                                                                                                      |\n| 🗓️ date             | date                        | string    | DateTime             | type ✅ type[]✅                                                                                                      |\n| 🗓️ time             | time without time zone      | string    | DateTime             | type ✅ type[]✅                                                                                                      |\n| 🗓️ timetz           | time with time zone         | string    | DateTime             | type ✅ type[]✅                                                                                                      |\n| 🗓️ timestamp        | timestamp without time zone | string    | DateTime             | type ✅ type[]✅                                                                                                      |\n| 🗓️ timestamptz      | timestamp with time zone    | string    | DateTime             | type ✅ type[]✅                                                                                                      |\n| 🕒 interval         | interval                    | string    | Duration             | type ✅ type[]✅                                                                                                      |\n| 💡 bool             | boolean                     | boolean   | bool                 | type ✅ type[]✅                                                                                                      |\n| 🗂️ ENUMS            | ENUM                        | string    | Enum                 | type ✅ type[]✅                                                                                                      |\n\n\u003e [Other Types](https://github.com/mmvergara/supadart/blob/main/other-types.md)\n\n# Generating Dart Classes\n\n## 1. Pre-requisites\n\n#### 1.2 Do you have serial types?\n\nWe don't recommend using serial types when using this package, if you have serial types you need to add a `[supadart:serial]` to the column like this\n\n\u003e You probably don't have them Serial types aren't available in the Supabase editor and must be added via SQL editor manually.\n\n```sql\nCOMMENT ON COLUMN test_table.bigserialx IS '[supadart:serial]';\nCOMMENT ON COLUMN test_table.smallserialx IS 'you can still add comment [supadart:serial]';\nCOMMENT ON COLUMN test_table.serialx IS 'this part [supadart:serial] just needs to be included';\n-- otherwise the insert method will always ask for a value even though serial types are auto-generated\n```\n\n\u003e [Why do we need this?](https://gist.github.com/mmvergara/5e3d42d73dd316f8ff809fb940163c1f)\n\n#### 1.3 Install `Internationalization` package\n\n```bash\n# This is an official package from dart and is used for parsing dates\nflutter pub add intl\n# or\ndart pub add intl\n```\n\n\u003e Unless you are not using any date types, you can skip this step\n\n#### 1.4 Use snake casing for table names and column names (Optional)\n\nthis tool will automatically convert snake_case to camelCase for both table (GeneratedClassName) and column (FieldName) generated names.\n\n```\nsnake_case  =\u003e camelCase\nuser_table  =\u003e UserTable\n```\n\n```\nsnake_case  =\u003e camelCase\nuser_id     =\u003e userId\n```\n\n---\n\n## 2. Generate Dart Classes\n\n#### Installation\n\n```bash\n# 🎯 Active from pub.dev\ndart pub global activate supadart\n\n# 🚀 Run via\nsupadart\n# or\ndart pub global run supadart\n```\n\n#### Quick Start\n\n```bash\n\n# Initialize supadart.yaml config file\nsupadart --init\n\n# Generate classes\nsupadart --url \u003csupabase_url\u003e --key \u003csupabase_anon_key\u003e\n\n# if SUPABASE_URL and SUPABASE_ANON_KEY are set in the environment variables\n# if SUPABASE_URL and SUPABASE_ANON_KEY are set in supadart.yaml\nsupadart\n```\n\n\u003e ENUMS: If you have enums, you need to specify them in the config file\n\n````yaml\n#### CLI Usage\n\n```bash\n-h, --help       Show usage information\n-i, --init       Initialize config file supadart.yaml\n-c, --config     Specify a path to config file of yaml   (default: ./supadart.yaml)\n-u, --url        Supabase URL                            (if not set in yaml)\n-k, --key        Supabase ANON KEY                       (if not set in yaml)\n-v, --version\n````\n\n\u003e Using the [Web App (deprecated)](https://supadart.vercel.app/)\n\n---\n\n# Example Usage\n\nAssuming the following table schema \u003cbr/\u003e\n\n```sql\ncreate table\n  public.books (\n    id bigint generated by default as identity,\n    name character varying not null,\n    description text null,\n    price integer not null,\n    created_at timestamp with time zone not null default now(),\n    constraint books_pkey primary key (id)\n  ) tablespace pg_default;\n```\n\n### 1. Use the CLI or the Web App to [generate dart classes](#generating-dart-classes)\n\n```dart\nclass Books implements SupadartClass\u003cBooks\u003e {\n  final BigInt id;\n  final String name;\n  final String? description;\n  final int price;\n  final DateTime? createdAt;\n\n  const Books({\n    required this.id,\n    required this.name,\n    this.description,\n    required this.price,\n    this.createdAt,\n  });\n\n  static String get table_name =\u003e 'books';\n  static String get c_id =\u003e 'id';\n  static String get c_name =\u003e 'name';\n  static String get c_description =\u003e 'description';\n  static String get c_price =\u003e 'price';\n  static String get c_createdAt =\u003e 'created_at';\n\n  static List\u003cBooks\u003e converter(List\u003cMap\u003cString, dynamic\u003e\u003e data) {\n    return data.map(Books.fromJson).toList();\n  }\n\n  static Books converterSingle(Map\u003cString, dynamic\u003e data) {\n    return Books.fromJson(data);\n  }\n\n  static Map\u003cString, dynamic\u003e _generateMap({\n    BigInt? id,\n    String? name,\n    String? description,\n    int? price,\n    DateTime? createdAt,\n  }) {\n    return {\n      if (id != null) 'id': id.toString(),\n      if (name != null) 'name': name.toString(),\n      if (description != null) 'description': description.toString(),\n      if (price != null) 'price': price.toString(),\n      if (createdAt != null) 'created_at': createdAt.toUtc().toString(),\n    };\n  }\n\n  static Map\u003cString, dynamic\u003e insert({\n    BigInt? id,\n    required String name,\n    String? description,\n    required int price,\n    DateTime? createdAt,\n  }) {\n    return _generateMap(\n      id: id,\n      name: name,\n      description: description,\n      price: price,\n      createdAt: createdAt,\n    );\n  }\n\n  static Map\u003cString, dynamic\u003e update({\n    BigInt? id,\n    String? name,\n    String? description,\n    int? price,\n    DateTime? createdAt,\n  }) {\n    return _generateMap(\n      id: id,\n      name: name,\n      description: description,\n      price: price,\n      createdAt: createdAt,\n    );\n  }\n\n  factory Books.fromJson(Map\u003cString, dynamic\u003e json) {\n    return Books(\n      id: json['id'] != null\n          ? BigInt.parse(json['id'].toString())\n          : BigInt.from(0),\n      name: json['name'] != null ? json['name'].toString() : '',\n      description:\n          json['description'] != null ? json['description'].toString() : '',\n      price: json['price'] != null ? json['price'] as int : 0,\n      createdAt: json['created_at'] != null\n          ? DateTime.tryParse(json['created_at'].toString()) as DateTime\n          : DateTime.fromMillisecondsSinceEpoch(0),\n    );\n  }\n\n  Map\u003cString, dynamic\u003e toJson() {\n    // Promotion doesn't work well with public fields due to the possibility of the field being modified elsewhere.\n    return _generateMap(\n      id: id,\n      name: name,\n      description: description,\n      price: price,\n      createdAt: createdAt,\n    );\n  }\n}\n```\n\n### 2. Using the generated class\n\nwe now have a typesafe'ish to interact with the database.\n\n#### Fetch Data\n\n```dart\n// allBooks is a typeof List\u003cBooks\u003e\nfinal allBooks = await supabase\n      .books\n      .select(\"*\")\n      .withConverter(Books.converter);\n```\n\n#### Fetch Single Data\n\n```dart\n// book is a typeof Books\nfinal book = await supabase\n      .books\n      .select(\"*\")\n      .eq(Books.c_id, 1)\n      .single()\n      .withConverter(Books.converterSingle);\n```\n\n#### Insert Data\n\n```dart\n// Yes we know which one's are optional or required.\nfinal data = Books.insert(\n  name: 'Learn Flutter',\n  description: 'Endless brackets and braces',\n  price: 2,\n);\nawait supabase.books.insert(data);\n```\n\n#### Inset Many Data\n\n```dart\nfinal many_data = [\n  Books.insert(\n    name: 'Learn Minecraft',\n    description: 'Endless blocks and bricks',\n    price: 2,\n  ),\n  Books.insert(\n    name: 'Description is optional',\n    created_at: DateTime.now(),\n    price: 2,\n  ),\n];\nawait supabase.books.insert(many_data);\n```\n\n#### Update Data\n\n```dart\nfinal newData = Books.update(\n  name: 'New Book Name',\n);\nawait supabase.books.update(newData).eq(Books.c_id, 1);\n```\n\n#### Delete Data\n\n```dart\nawait supabase.books.delete().eq(Books.c_id, 1);\n```\n\n# Working with Enums\n\n**IMPORTANT:**\n\n- You need to specify your enums on supadart.yaml config file\n- Enum `names` are converted to `UPPERCASE` to follow dart enum naming conventions\n- Enum `values` are case-sensitive in postgres, so you need to specify them as they are in the database\n- Optional: We recommend defining the enum values as lowercase to follow dart enum naming conventions\n\nAssuming the following schema\n\n```sql\n-- We recommend defining the enum values as lowercase to follow dart enum naming conventions\nCREATE TYPE mood AS ENUM ('happy', 'sad', 'neutral', 'excited', 'angry');\nCREATE TABLE enum_types (\n    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    mood mood NOT NULL\n);\n```\n\nIn your supadart.yaml config file\n\n```yaml\nenums:\n  # Case sensitive, define them as they are in the database\n  mood: [happy, sad, neutral, excited, angry]\n```\n\n### Generated Enum\n\n```dart\nenum MOOD { happy, sad, neutral, excited, angry }\n```\n\n### Create / Read / Update with Enums\n\n```dart\nMOOD firstEnumVal = MOOD.angry;\nMOOD newEnumVal = MOOD.excited;\n\n// Create\nawait supabase.enum_types.insert(EnumTypes.insert(\n      mood: firstEnumVal,\n    ));\n\nawait supabase.enum_types\n        // Update\n        .update(EnumTypes.update(mood: newEnumVal))\n        // Equality ⚠️ you need to do manual ⬇️ enum to string conversion\n        .eq(EnumTypes.c_mood, firstEnumVal.toString().split(\".\").last);\n\n// Read\nawait supabase.enum_types.select().withConverter(EnumTypes.converter);\n```\n\n# Column Selection Queries\n\n**IMPORTANT:**\n\n- When you select columns, the class will fill the missing columns with the default values\n\n```dart\nfinal book = await supabase\n      .from('books')\n      .select('${Books.c_id}, ${Books.c_name}')\n      .eq(Books.c_id, 69) // Assuming 69 is the id\n      .single()\n      .withConverter(Books.converterSingle);\n```\n\n```dart\nprint(book.id);           // 69\nprint(book.name);         // \"Supadart\"\nprint(book.description);  // \"\"\nprint(book.price);        // 0\nprint(book.created_at);   // 1970-01-01 00:00:00.000\n```\n\nif a value is an enum, the first value of that enum will be used as the default value\n\n# Contributors\n\n[![GitHub contributors](https://contrib.rocks/image?repo=mmvergara/supadart)](https://github.com/mmvergara/supadart/graphs/contributors)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmvergara%2Fsupadart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmmvergara%2Fsupadart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmvergara%2Fsupadart/lists"}