{"id":13812172,"url":"https://github.com/supabase-community/postgrest-csharp","last_synced_at":"2025-05-15T12:06:16.436Z","repository":{"id":39743645,"uuid":"290070747","full_name":"supabase-community/postgrest-csharp","owner":"supabase-community","description":"A C# Client library for Postgrest","archived":false,"fork":false,"pushed_at":"2025-02-03T14:22:16.000Z","size":17854,"stargazers_count":146,"open_issues_count":18,"forks_count":30,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-05-08T08:02:47.521Z","etag":null,"topics":["csharp","postgresql","postgrest","supabase"],"latest_commit_sha":null,"homepage":"https://supabase-community.github.io/postgrest-csharp/api/Postgrest.html","language":"C#","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/supabase-community.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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":"2020-08-25T00:25:54.000Z","updated_at":"2025-05-07T03:33:17.000Z","dependencies_parsed_at":"2024-03-01T01:26:15.748Z","dependency_job_id":"09c554ac-f165-40a3-801d-8141accc94c2","html_url":"https://github.com/supabase-community/postgrest-csharp","commit_stats":null,"previous_names":["supabase/postgrest-csharp"],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase-community%2Fpostgrest-csharp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase-community%2Fpostgrest-csharp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase-community%2Fpostgrest-csharp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase-community%2Fpostgrest-csharp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/supabase-community","download_url":"https://codeload.github.com/supabase-community/postgrest-csharp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253910602,"owners_count":21982763,"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":["csharp","postgresql","postgrest","supabase"],"created_at":"2024-08-04T04:00:48.507Z","updated_at":"2025-05-15T12:06:16.400Z","avatar_url":"https://github.com/supabase-community.png","language":"C#","funding_links":[],"categories":["Postgrest"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cimg width=\"300\" src=\".github/logo.png\"/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/supabase/postgrest-csharp/workflows/Build%20And%20Test/badge.svg\"/\u003e\n  \u003ca href=\"https://www.nuget.org/packages/Supabase.Postgrest/\"\u003e\n    \u003cimg src=\"https://img.shields.io/nuget/vpre/Supabase.Postgrest\"/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## [Notice]: v4.0.0 renames this package from `postgrest-csharp` to `Supabase.Postgrest`. Which includes changing the namespace from `Postgrest` to `Supabase.Postgrest`.\n\n## Now supporting (many) LINQ expressions!\n\n```c#\nawait client.Table\u003cMovie\u003e()\n            .Select(x =\u003e new object[] { x.Id, x.Name, x.Tags, x.ReleaseDate })\n            .Where(x =\u003e x.Tags.Contains(\"Action\") || x.Tags.Contains(\"Adventure\"))\n            .Order(x =\u003e x.ReleaseDate, Ordering.Descending)\n            .Get();\n\nawait client.Table\u003cMovie\u003e()\n            .Set(x =\u003e x.WatchedAt, DateTime.Now)\n            .Where(x =\u003e x.Id == \"11111-22222-33333-44444\")\n            // Or .Filter(x =\u003e x.Id, Operator.Equals, \"11111-22222-33333-44444\")\n            .Update();\n\n```\n\n---\n\nDocumentation can be found [here](https://supabase-community.github.io/postgrest-csharp/api/Postgrest.html).\n\nPostgrest-csharp is written primarily as a helper library\nfor [supabase/supabase-csharp](https://github.com/supabase/supabase-csharp), however, it should be easy enough to use\noutside of the supabase ecosystem.\n\nThe bulk of this library is a translation and c-sharp-ification of\nthe [supabase/postgrest-js](https://github.com/supabase/postgrest-js) library.\n\n## Getting Started\n\nPostgrest-csharp is _heavily_ dependent on Models deriving from `BaseModel`. To interact with the API, one must have the\nassociated\nmodel specified.\n\nTo use this library on the Supabase Hosted service but separately from the `supabase-csharp`, you'll need to specify\nyour url and public key like so:\n\n```c#\nvar auth = new Supabase.Gotrue.Client(new ClientOptions\u003cSession\u003e\n{\n    Url = \"https://PROJECT_ID.supabase.co/auth/v1\",\n    Headers = new Dictionary\u003cstring, string\u003e\n    {\n        { \"apikey\", SUPABASE_PUBLIC_KEY },\n        { \"Authorization\", $\"Bearer {SUPABASE_USER_TOKEN}\" }\n    }\n})\n```\n\nLeverage `Table`,`PrimaryKey`, and `Column` attributes to specify names of classes/properties that are different from\ntheir C# Versions.\n\n```c#\n[Table(\"messages\")]\npublic class Message : BaseModel\n{\n    [PrimaryKey(\"id\")]\n    public int Id { get; set; }\n\n    [Column(\"username\")]\n    public string UserName { get; set; }\n\n    [Column(\"channel_id\")]\n    public int ChannelId { get; set; }\n\n    public override bool Equals(object obj)\n    {\n        return obj is Message message \u0026\u0026\n                Id == message.Id;\n    }\n\n    public override int GetHashCode()\n    {\n        return HashCode.Combine(Id);\n    }\n}\n```\n\nUtilizing the client is then just a matter of instantiating it and specifying the Model one is working with.\n\n```c#\nvoid Initialize()\n{\n    var client = new Client(\"http://localhost:3000\");\n\n    // Get All Messages\n    var response = await client.Table\u003cMessage\u003e().Get();\n    List\u003cMessage\u003e models = response.Models;\n\n    // Insert\n    var newMessage = new Message { UserName = \"acupofjose\", ChannelId = 1 };\n    await client.Table\u003cMessage\u003e().Insert();\n\n    // Update\n    var model = response.Models.First();\n    model.UserName = \"elrhomariyounes\";\n    await model.Update();\n\n    // Delete\n    await response.Models.Last().Delete();\n}\n```\n\n## Foreign Keys, Join Tables, and Relationships\n\nThe Postgrest server does introspection on relationships between tables and supports returning query data from\ntables with these included. **Foreign key constrains are required for postgrest to detect these relationships.**\n\nThis library implements the attribute, `Reference` to specify on a model when a relationship should be included in a\nquery.\n\n- [One-to-one Relationships](https://postgrest.org/en/stable/api.html#one-to-one-relationships): One-to-one\n  relationships are detected if there’s an unique constraint on a foreign key.\n- [One-to-many Relationships](https://postgrest.org/en/stable/api.html#one-to-many-relationships): The inverse\n  one-to-many relationship between two tables is detected based on the foreign key reference.\n- [Many-to-many Relationships](https://postgrest.org/en/stable/api.html#many-to-many-relationships): Many-to-many\n  relationships are detected based on the join table. The join table must contain foreign keys to other two tables and\n  they must be part of its composite key.\n\nGiven the following schema:\n\n![example schema](.github/postgrest-relationship-example.drawio.png)\n\nWe can define the following models:\n\n```c#\n[Table(\"movie\")]\npublic class Movie : BaseModel\n{\n    [PrimaryKey(\"id\")]\n    public int Id { get; set; }\n\n    [Column(\"name\")]\n    public string Name { get; set; }\n\n    [Reference(typeof(Person))]\n    public List\u003cPerson\u003e Persons { get; set; }\n\n    [Column(\"created_at\")]\n    public DateTime CreatedAt { get; set; }\n}\n\n[Table(\"person\")]\npublic class Person : BaseModel\n{\n    [PrimaryKey(\"id\")]\n    public int Id { get; set; }\n\n    [Column(\"first_name\")]\n    public string FirstName { get; set; }\n\n    [Column(\"last_name\")]\n    public string LastName { get; set; }\n\n    [Reference(typeof(Profile))]\n    public Profile Profile { get; set; }\n\n    [Column(\"created_at\")]\n    public DateTime CreatedAt { get; set; }\n}\n\n[Table(\"profile\")]\npublic class Profile : BaseModel\n{\n    [Column(\"email\")]\n    public string Email { get; set; }\n}\n```\n\n**Note that each related model should inherit `BaseModel` and specify its `Table` and `Column` attributes as usual.**\n\nThe `Reference` Attribute by default will include the referenced model in all GET queries on the table (this can be\ndisabled\nin its constructor).\n\nAs such, a query on the `Movie` model (given the above) would return something like:\n\n```js\n[\n    {\n        id: 1,\n        created_at: \"2022-08-20T00:29:45.400188\",\n        name: \"Top Gun: Maverick\",\n        person: [\n            {\n                id: 1,\n                created_at: \"2022-08-20T00:30:02.120528\",\n                first_name: \"Tom\",\n                last_name: \"Cruise\",\n                profile: {\n                    profile_id: 1,\n                    email: \"tom.cruise@supabase.io\",\n                    created_at: \"2022-08-20T00:30:33.72443\"\n                }\n            },\n            {\n                id: 3,\n                created_at: \"2022-08-20T00:30:33.72443\",\n                first_name: \"Bob\",\n                last_name: \"Saggett\",\n                profile: {\n                    profile_id: 3,\n                    email: \"bob.saggett@supabase.io\",\n                    created_at: \"2022-08-20T00:30:33.72443\"\n                }\n            }\n        ]\n    },\n    // ...\n]\n```\n\n### Circular References\n\nCircular relations can be added between models, however, circular relations should only be parsed one level deep for\nmodels. For example, given the\nmodels [here](https://github.com/supabase-community/postgrest-csharp/blob/master/PostgrestTests/Models/LinkedModels.cs),\na raw response would look like the following (note that the `Person` object returns the root `Movie` and\nthe `Person-\u003eProfile` returns its root `Person` object).\n\nIf desired, this can be avoided by making specific join models that do not have the circular references.\n\n```json\n[\n  {\n    \"id\": \"68722a22-6a6b-4410-a955-b4eb8ca7953f\",\n    \"created_at\": \"0001-01-01T05:51:00\",\n    \"name\": \"Supabase in Action\",\n    \"person\": [\n      {\n        \"id\": \"6aa849d8-dd09-4932-bc6f-6fe3b585e87f\",\n        \"first_name\": \"John\",\n        \"last_name\": \"Doe\",\n        \"created_at\": \"0001-01-01T05:51:00\",\n        \"movie\": [\n          {\n            \"id\": \"68722a22-6a6b-4410-a955-b4eb8ca7953f\",\n            \"name\": \"Supabase in Action\",\n            \"created_at\": \"0001-01-01T05:51:00\"\n          }\n        ],\n        \"profile\": {\n          \"person_id\": \"6aa849d8-dd09-4932-bc6f-6fe3b585e87f\",\n          \"email\": \"john.doe@email.com\",\n          \"created_at\": \"0001-01-01T05:51:00\",\n          \"person\": {\n            \"id\": \"6aa849d8-dd09-4932-bc6f-6fe3b585e87f\",\n            \"first_name\": \"John\",\n            \"last_name\": \"Doe\",\n            \"created_at\": \"0001-01-01T05:51:00\"\n          }\n        }\n      },\n      {\n        \"id\": \"07abc67f-bf7d-4865-b2c0-76013dc2811f\",\n        \"first_name\": \"Jane\",\n        \"last_name\": \"Buck\",\n        \"created_at\": \"0001-01-01T05:51:00\",\n        \"movie\": [\n          {\n            \"id\": \"68722a22-6a6b-4410-a955-b4eb8ca7953f\",\n            \"name\": \"Supabase in Action\",\n            \"created_at\": \"0001-01-01T05:51:00\"\n          }\n        ],\n        \"profile\": {\n          \"person_id\": \"07abc67f-bf7d-4865-b2c0-76013dc2811f\",\n          \"email\": \"jane.buck@email.com\",\n          \"created_at\": \"0001-01-01T05:51:00\",\n          \"person\": {\n            \"id\": \"07abc67f-bf7d-4865-b2c0-76013dc2811f\",\n            \"first_name\": \"Jane\",\n            \"last_name\": \"Buck\",\n            \"created_at\": \"0001-01-01T05:51:00\"\n          }\n        }\n      }\n    ]\n  }\n]\n```\n\n### Top Level Filtering\n\n**By default** relations expect to be used as top level filters on a query. If following the models above, this would\nmean that a `Movie` with no `Person` relations on it would not return on a query **unless** the `Relation`\nhas `useInnerJoin` set to `false`:\n\nThe following model would return any movie, even if there are no `Person` models associated with it:\n\n```c#\n[Table(\"movie\")]\npublic class Movie : BaseModel\n{\n    [PrimaryKey(\"id\")] \n    public string Id { get; set; }\n\n    [Column(\"name\")] \n    public string? Name { get; set; }\n\n    [Reference(typeof(Person), useInnerJoin: false)]\n    public List\u003cPerson\u003e People { get; set; } = new();\n}\n```\n\n**Further Notes**:\n\n- Postgrest _does not support nested inserts or upserts_. Relational keys on models will be ignored when attempting to\n  insert or upsert on a root model.\n- The `Relation` attribute uses reflection to only select the attributes specified on the Class Model (i.e.\n  the `Profile` model has a property only for `email`, only the property will be requested in the query).\n\n## Status\n\n- [x] Connects to PostgREST Server\n- [x] Authentication\n- [x] Basic Query Features\n    - [x] CRUD\n    - [x] Single\n    - [x] Range (to \u0026 from)\n    - [x] Limit\n    - [x] Limit w/ Foreign Key\n    - [x] Offset\n    - [x] Offset w/ Foreign Key\n- [x] Advanced Query Features\n    - [x] Filters\n    - [x] Ordering\n- [ ] Custom Serializers\n    - [ ] [Postgres Range](https://www.postgresql.org/docs/9.3/rangetypes.html)\n        - [x] `int4range`, `int8range`\n        - [ ] `numrange`\n        - [ ] `tsrange`, `tstzrange`, `daterange`\n- [x] Models\n    - [x] `BaseModel` to derive from\n    - [x] Coercion of data into Models\n- [x] Unit Testing\n- [x] Nuget Package and Release\n\n## Package made possible through the efforts of:\n\n| \u003cimg src=\"https://github.com/acupofjose.png\" width=\"150\" height=\"150\"\u003e | \u003cimg src=\"https://github.com/elrhomariyounes.png\" width=\"150\" height=\"150\"\u003e |\n|:----------------------------------------------------------------------:|:---------------------------------------------------------------------------:|\n|              [acupofjose](https://github.com/acupofjose)               |            [elrhomariyounes](https://github.com/elrhomariyounes)            |\n\n## Contributing\n\nWe are more than happy to have contributions! Please submit a PR.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupabase-community%2Fpostgrest-csharp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsupabase-community%2Fpostgrest-csharp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupabase-community%2Fpostgrest-csharp/lists"}