Supabase.Postgrest
4.0.0
See the version list below for details.
dotnet add package Supabase.Postgrest --version 4.0.0
NuGet\Install-Package Supabase.Postgrest -Version 4.0.0
<PackageReference Include="Supabase.Postgrest" Version="4.0.0" />
paket add Supabase.Postgrest --version 4.0.0
#r "nuget: Supabase.Postgrest, 4.0.0"
// Install Supabase.Postgrest as a Cake Addin #addin nuget:?package=Supabase.Postgrest&version=4.0.0 // Install Supabase.Postgrest as a Cake Tool #tool nuget:?package=Supabase.Postgrest&version=4.0.0
<p align="center"> <img width="300" src=".github/logo.png"/> </p>
<p align="center"> <img src="https://github.com/supabase/postgrest-csharp/workflows/Build%20And%20Test/badge.svg"/> <a href="https://www.nuget.org/packages/postgrest-csharp/"> <img src="https://img.shields.io/badge/dynamic/json?color=green&label=Nuget%20Release&query=data[0].version&url=https%3A%2F%2Fazuresearch-usnc.nuget.org%2Fquery%3Fq%3Dpackageid%3Apostgrest-csharp"/> </a> </p>
[Notice]: v4.0.0 renames this package from postgrest-csharp
to Supabase.Postgrest
. Which includes changing the namespace from Postgrest
to Supabase.Postgrest
.
Now supporting (many) LINQ expressions!
await client.Table<Movie>()
.Select(x => new object[] { x.Id, x.Name, x.Tags, x.ReleaseDate })
.Where(x => x.Tags.Contains("Action") || x.Tags.Contains("Adventure"))
.Order(x => x.ReleaseDate, Ordering.Descending)
.Get();
await client.Table<Movie>()
.Set(x => x.WatchedAt, DateTime.Now)
.Where(x => x.Id == "11111-22222-33333-44444")
// Or .Filter(x => x.Id, Operator.Equals, "11111-22222-33333-44444")
.Update();
Documentation can be found here.
Postgrest-csharp is written primarily as a helper library for supabase/supabase-csharp, however, it should be easy enough to use outside of the supabase ecosystem.
The bulk of this library is a translation and c-sharp-ification of the supabase/postgrest-js library.
Getting Started
Postgrest-csharp is heavily dependent on Models deriving from BaseModel
. To interact with the API, one must have the
associated
model specified.
To use this library on the Supabase Hosted service but separately from the supabase-csharp
, you'll need to specify
your url and public key like so:
var auth = new Supabase.Gotrue.Client(new ClientOptions<Session>
{
Url = "https://PROJECT_ID.supabase.co/auth/v1",
Headers = new Dictionary<string, string>
{
{ "apikey", SUPABASE_PUBLIC_KEY },
{ "Authorization", $"Bearer {SUPABASE_USER_TOKEN}" }
}
})
Leverage Table
,PrimaryKey
, and Column
attributes to specify names of classes/properties that are different from
their C# Versions.
[Table("messages")]
public class Message : BaseModel
{
[PrimaryKey("id")]
public int Id { get; set; }
[Column("username")]
public string UserName { get; set; }
[Column("channel_id")]
public int ChannelId { get; set; }
public override bool Equals(object obj)
{
return obj is Message message &&
Id == message.Id;
}
public override int GetHashCode()
{
return HashCode.Combine(Id);
}
}
Utilizing the client is then just a matter of instantiating it and specifying the Model one is working with.
void Initialize()
{
var client = new Client("http://localhost:3000");
// Get All Messages
var response = await client.Table<Message>().Get();
List<Message> models = response.Models;
// Insert
var newMessage = new Message { UserName = "acupofjose", ChannelId = 1 };
await client.Table<Message>().Insert();
// Update
var model = response.Models.First();
model.UserName = "elrhomariyounes";
await model.Update();
// Delete
await response.Models.Last().Delete();
}
Foreign Keys, Join Tables, and Relationships
The Postgrest server does introspection on relationships between tables and supports returning query data from tables with these included. Foreign key constrains are required for postgrest to detect these relationships.
This library implements the attribute, Reference
to specify on a model when a relationship should be included in a
query.
- One-to-one Relationships: One-to-one relationships are detected if there’s an unique constraint on a foreign key.
- One-to-many Relationships: The inverse one-to-many relationship between two tables is detected based on the foreign key reference.
- Many-to-many Relationships: Many-to-many relationships are detected based on the join table. The join table must contain foreign keys to other two tables and they must be part of its composite key.
Given the following schema:
We can define the following models:
[Table("movie")]
public class Movie : BaseModel
{
[PrimaryKey("id")]
public int Id { get; set; }
[Column("name")]
public string Name { get; set; }
[Reference(typeof(Person))]
public List<Person> Persons { get; set; }
[Column("created_at")]
public DateTime CreatedAt { get; set; }
}
[Table("person")]
public class Person : BaseModel
{
[PrimaryKey("id")]
public int Id { get; set; }
[Column("first_name")]
public string FirstName { get; set; }
[Column("last_name")]
public string LastName { get; set; }
[Reference(typeof(Profile))]
public Profile Profile { get; set; }
[Column("created_at")]
public DateTime CreatedAt { get; set; }
}
[Table("profile")]
public class Profile : BaseModel
{
[Column("email")]
public string Email { get; set; }
}
Note that each related model should inherit BaseModel
and specify its Table
and Column
attributes as usual.
The Reference
Attribute by default will include the referenced model in all GET queries on the table (this can be
disabled
in its constructor).
As such, a query on the Movie
model (given the above) would return something like:
[
{
id: 1,
created_at: "2022-08-20T00:29:45.400188",
name: "Top Gun: Maverick",
person: [
{
id: 1,
created_at: "2022-08-20T00:30:02.120528",
first_name: "Tom",
last_name: "Cruise",
profile: {
profile_id: 1,
email: "tom.cruise@supabase.io",
created_at: "2022-08-20T00:30:33.72443"
}
},
{
id: 3,
created_at: "2022-08-20T00:30:33.72443",
first_name: "Bob",
last_name: "Saggett",
profile: {
profile_id: 3,
email: "bob.saggett@supabase.io",
created_at: "2022-08-20T00:30:33.72443"
}
}
]
},
// ...
]
Circular References
Circular relations can be added between models, however, circular relations should only be parsed one level deep for
models. For example, given the
models here,
a raw response would look like the following (note that the Person
object returns the root Movie
and
the Person->Profile
returns its root Person
object).
If desired, this can be avoided by making specific join models that do not have the circular references.
[
{
"id": "68722a22-6a6b-4410-a955-b4eb8ca7953f",
"created_at": "0001-01-01T05:51:00",
"name": "Supabase in Action",
"person": [
{
"id": "6aa849d8-dd09-4932-bc6f-6fe3b585e87f",
"first_name": "John",
"last_name": "Doe",
"created_at": "0001-01-01T05:51:00",
"movie": [
{
"id": "68722a22-6a6b-4410-a955-b4eb8ca7953f",
"name": "Supabase in Action",
"created_at": "0001-01-01T05:51:00"
}
],
"profile": {
"person_id": "6aa849d8-dd09-4932-bc6f-6fe3b585e87f",
"email": "john.doe@email.com",
"created_at": "0001-01-01T05:51:00",
"person": {
"id": "6aa849d8-dd09-4932-bc6f-6fe3b585e87f",
"first_name": "John",
"last_name": "Doe",
"created_at": "0001-01-01T05:51:00"
}
}
},
{
"id": "07abc67f-bf7d-4865-b2c0-76013dc2811f",
"first_name": "Jane",
"last_name": "Buck",
"created_at": "0001-01-01T05:51:00",
"movie": [
{
"id": "68722a22-6a6b-4410-a955-b4eb8ca7953f",
"name": "Supabase in Action",
"created_at": "0001-01-01T05:51:00"
}
],
"profile": {
"person_id": "07abc67f-bf7d-4865-b2c0-76013dc2811f",
"email": "jane.buck@email.com",
"created_at": "0001-01-01T05:51:00",
"person": {
"id": "07abc67f-bf7d-4865-b2c0-76013dc2811f",
"first_name": "Jane",
"last_name": "Buck",
"created_at": "0001-01-01T05:51:00"
}
}
}
]
}
]
Top Level Filtering
By default relations expect to be used as top level filters on a query. If following the models above, this would
mean that a Movie
with no Person
relations on it would not return on a query unless the Relation
has useInnerJoin
set to false
:
The following model would return any movie, even if there are no Person
models associated with it:
[Table("movie")]
public class Movie : BaseModel
{
[PrimaryKey("id")]
public string Id { get; set; }
[Column("name")]
public string? Name { get; set; }
[Reference(typeof(Person), useInnerJoin: false)]
public List<Person> People { get; set; } = new();
}
Further Notes:
- Postgrest does not support nested inserts or upserts. Relational keys on models will be ignored when attempting to insert or upsert on a root model.
- The
Relation
attribute uses reflection to only select the attributes specified on the Class Model (i.e. theProfile
model has a property only foremail
, only the property will be requested in the query).
Status
- Connects to PostgREST Server
- Authentication
- Basic Query Features
- CRUD
- Single
- Range (to & from)
- Limit
- Limit w/ Foreign Key
- Offset
- Offset w/ Foreign Key
- Advanced Query Features
- Filters
- Ordering
- Custom Serializers
- Postgres Range
-
int4range
,int8range
-
numrange
-
tsrange
,tstzrange
,daterange
-
- Postgres Range
- Models
-
BaseModel
to derive from - Coercion of data into Models
-
- Unit Testing
- Nuget Package and Release
Package made possible through the efforts of:
<img src="https://github.com/acupofjose.png" width="150" height="150"> | <img src="https://github.com/elrhomariyounes.png" width="150" height="150"> |
---|---|
acupofjose | elrhomariyounes |
Contributing
We are more than happy to have contributions! Please submit a PR.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Newtonsoft.Json (>= 13.0.3)
- Supabase.Core (>= 1.0.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Supabase.Postgrest:
Package | Downloads |
---|---|
Supabase
A C# implementation of the Supabase client |
|
Supabase.Realtime
Realtime-csharp is written as a client library for supabase/realtime. |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on Supabase.Postgrest:
Repository | Stars |
---|---|
supabase-community/supabase-csharp
A C# Client library for Supabase
|