Skip to content

Commit

Permalink
Provides a built in caching solution for Get requests to enable eas…
Browse files Browse the repository at this point in the history
…ier querying for data in an offline context.
  • Loading branch information
acupofjose committed Sep 14, 2023
1 parent 8608ffc commit a079651
Show file tree
Hide file tree
Showing 16 changed files with 512 additions and 35 deletions.
34 changes: 22 additions & 12 deletions Postgrest/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,33 +92,43 @@ public Client(string baseUrl, ClientOptions? options = null)
public IPostgrestTable<T> Table<T>() where T : BaseModel, new() =>
new Table<T>(BaseUrl, SerializerSettings(Options), Options)
{
GetHeaders = GetHeaders
GetHeaders = GetHeaders
};

public IPostgrestTableWithCache<T> Table<T>(IPostgrestCacheProvider cacheProvider)

Check warning on line 98 in Postgrest/Client.cs

View workflow job for this annotation

GitHub Actions / buildAndTest

Missing XML comment for publicly visible type or member 'Client.Table<T>(IPostgrestCacheProvider)'

Check warning on line 98 in Postgrest/Client.cs

View workflow job for this annotation

GitHub Actions / buildAndTest

Missing XML comment for publicly visible type or member 'Client.Table<T>(IPostgrestCacheProvider)'

Check warning on line 98 in Postgrest/Client.cs

View workflow job for this annotation

GitHub Actions / buildAndTest

Missing XML comment for publicly visible type or member 'Client.Table<T>(IPostgrestCacheProvider)'
where T : BaseModel, new() =>
new TableWithCache<T>(BaseUrl, cacheProvider, SerializerSettings(Options), Options)
{
GetHeaders = GetHeaders
};


/// <inheritdoc />
public Task<BaseResponse> Rpc(string procedureName, object? parameters = null)
{
// Build Uri
var builder = new UriBuilder($"{BaseUrl}/rpc/{procedureName}");
/// <inheritdoc />
public Task<BaseResponse> Rpc(string procedureName, object? parameters = null)
{
// Build Uri
var builder = new UriBuilder($"{BaseUrl}/rpc/{procedureName}");

var canonicalUri = builder.Uri.ToString();

var serializerSettings = SerializerSettings(Options);

// Prepare parameters
Dictionary<string, object>? data = null;
if (parameters != null)
data = JsonConvert.DeserializeObject<Dictionary<string, object>>(JsonConvert.SerializeObject(parameters, serializerSettings));
// Prepare parameters
Dictionary<string, object>? data = null;
if (parameters != null)
data = JsonConvert.DeserializeObject<Dictionary<string, object>>(
JsonConvert.SerializeObject(parameters, serializerSettings));

// Prepare headers
var headers = Helpers.PrepareRequestHeaders(HttpMethod.Post, new Dictionary<string, string>(Options.Headers), Options);
var headers = Helpers.PrepareRequestHeaders(HttpMethod.Post,
new Dictionary<string, string>(Options.Headers), Options);

if (GetHeaders != null)
headers = GetHeaders().MergeLeft(headers);

// Send request
var request = Helpers.MakeRequest(Options, HttpMethod.Post, canonicalUri, serializerSettings, data, headers);
var request =
Helpers.MakeRequest(Options, HttpMethod.Post, canonicalUri, serializerSettings, data, headers);
return request;
}
}
Expand Down
14 changes: 8 additions & 6 deletions Postgrest/Hooks.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using Newtonsoft.Json;
using Postgrest.Interfaces;

namespace Postgrest
{
/// <summary>
/// Delegate representing the request to be sent to the remote server.
/// </summary>
public delegate void OnRequestPreparedEventHandler(ClientOptions clientOptions, HttpMethod method, string url,
public delegate void OnRequestPreparedEventHandler(object sender, ClientOptions clientOptions,
HttpMethod method, string url,
JsonSerializerSettings serializerSettings, object? data = null,
Dictionary<string, string>? headers = null);

Expand Down Expand Up @@ -75,14 +76,15 @@ public void ClearRequestPreparedHandlers()
/// <param name="serializerSettings"></param>
/// <param name="data"></param>
/// <param name="headers"></param>
public void NotifyOnRequestPreparedHandlers(ClientOptions clientOptions, HttpMethod method, string url,
public void NotifyOnRequestPreparedHandlers(object sender, ClientOptions clientOptions, HttpMethod method,

Check warning on line 79 in Postgrest/Hooks.cs

View workflow job for this annotation

GitHub Actions / buildAndTest

Parameter 'sender' has no matching param tag in the XML comment for 'Hooks.NotifyOnRequestPreparedHandlers(object, ClientOptions, HttpMethod, string, JsonSerializerSettings, object?, Dictionary<string, string>?)' (but other parameters do)

Check warning on line 79 in Postgrest/Hooks.cs

View workflow job for this annotation

GitHub Actions / buildAndTest

Parameter 'sender' has no matching param tag in the XML comment for 'Hooks.NotifyOnRequestPreparedHandlers(object, ClientOptions, HttpMethod, string, JsonSerializerSettings, object?, Dictionary<string, string>?)' (but other parameters do)

Check warning on line 79 in Postgrest/Hooks.cs

View workflow job for this annotation

GitHub Actions / buildAndTest

Parameter 'sender' has no matching param tag in the XML comment for 'Hooks.NotifyOnRequestPreparedHandlers(object, ClientOptions, HttpMethod, string, JsonSerializerSettings, object?, Dictionary<string, string>?)' (but other parameters do)
string url,
JsonSerializerSettings serializerSettings, object? data = null,
Dictionary<string, string>? headers = null)
{
Debugger.Instance.Log(this, $"{nameof(NotifyOnRequestPreparedHandlers)} called for [{method}] to {url}");
foreach (var handler in _requestPreparedEventHandlers)
handler.Invoke(clientOptions, method, url, serializerSettings, data, headers);

foreach (var handler in _requestPreparedEventHandlers.ToList())
handler.Invoke(sender, clientOptions, method, url, serializerSettings, data, headers);
}
}
}
43 changes: 43 additions & 0 deletions Postgrest/Interfaces/IPostgrestCacheProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Threading.Tasks;

namespace Postgrest.Interfaces
{
/// <summary>
/// A caching provider than can be used by postgrest to store requests.
/// </summary>
public interface IPostgrestCacheProvider
{
/// <summary>
/// Gets an item from a caching solution, should coerce into a datatype.
///
/// This will most likely be a JSON deserialization approach.
/// </summary>
/// <param name="key">A reproducible key for a defined query.</param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public Task<T?> GetItem<T>(string key);

/// <summary>
/// Sets an item within a caching solution, should store in a way that the data can be retrieved and coerced into a generic type by <see cref="GetItem{T}"/>
///
/// This will most likely be a JSON serialization approach.
/// </summary>
/// <param name="key">A reproducible key for a defined query.</param>
/// <param name="value">An object of serializable data.</param>
/// <returns></returns>
public Task SetItem(string key, object value);

/// <summary>
/// Clear an item within a caching solution by a key.
/// </summary>
/// <param name="key">A reproducible key for a defined query.</param>
/// <returns></returns>
public Task ClearItem(string key);

/// <summary>
/// An empty/clear cache implementation.
/// </summary>
/// <returns></returns>
public Task Empty();
}
}
11 changes: 9 additions & 2 deletions Postgrest/Interfaces/IPostgrestClient.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Postgrest.Models;
using Postgrest.Responses;
using Supabase.Core.Interfaces;
Expand Down Expand Up @@ -69,5 +68,13 @@ public interface IPostgrestClient : IGettableHeaders
/// <typeparam name="T">Custom Model derived from `BaseModel`</typeparam>
/// <returns></returns>
IPostgrestTable<T> Table<T>() where T : BaseModel, new();

/// <summary>
/// Returns a Table Query Builder instance with a Cache Provider for a defined model - representative of `USE #$TABLE`
/// </summary>
/// <param name="cacheProvider"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
IPostgrestTableWithCache<T> Table<T>(IPostgrestCacheProvider cacheProvider) where T : BaseModel, new();
}
}
7 changes: 6 additions & 1 deletion Postgrest/Interfaces/IPostgrestTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@ namespace Postgrest.Interfaces
/// API Base Url for subsequent calls.
/// </summary>
string BaseUrl { get; }

/// <summary>
/// Name of the Table parsed by the Model.
/// </summary>
string TableName { get; }

/// <summary>
/// Generates the encoded URL with defined query parameters that will be sent to the Postgrest API.
/// </summary>
string GenerateUrl();

/// <summary>
/// Adds an AND Filter to the current query args.
/// </summary>
Expand Down
21 changes: 21 additions & 0 deletions Postgrest/Interfaces/IPostgrestTableWithCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Threading;
using System.Threading.Tasks;
using Postgrest.Models;
using Postgrest.Requests;

namespace Postgrest.Interfaces
{
/// <summary>
/// Client interface for Postgrest
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IPostgrestTableWithCache<T> : IPostgrestTable<T> where T : BaseModel, new()
{
/// <summary>
/// Performs a Get request, returning a <see cref="CacheBackedRequest{TModel}"/> which populates from the cache, if applicable.
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public new Task<CacheBackedRequest<T>> Get(CancellationToken cancellationToken = default);
}
}
23 changes: 23 additions & 0 deletions Postgrest/Models/CachedModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Postgrest.Models
{
/// <summary>
/// Represents a cacheable model
/// </summary>
/// <typeparam name="TModel"></typeparam>
public class CachedModel<TModel> where TModel : BaseModel, new()
{
/// <summary>
/// The stored Models
/// </summary>
[JsonProperty("response")] public List<TModel>? Models { get; set; }

/// <summary>
/// Cache time in UTC.
/// </summary>
[JsonProperty("cachedAt")] public DateTime CachedAt { get; set; }
}
}
Loading

0 comments on commit a079651

Please sign in to comment.