Skip to content

Commit 067d126

Browse files
committed
Swapped in PowerSync db over base sqlite database.
1 parent eb658d3 commit 067d126

File tree

8 files changed

+332
-109
lines changed

8 files changed

+332
-109
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
using PowerSync.Common.Client;
2+
using PowerSync.Common.Client.Connection;
3+
using PowerSync.Common.DB.Crud;
4+
5+
namespace TodoSQLite.Data;
6+
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Net.Http;
10+
using System.Text;
11+
using System.Text.Json;
12+
using System.Threading.Tasks;
13+
14+
public class NodeConnector : IPowerSyncBackendConnector
15+
{
16+
private static readonly string StorageFilePath = "user_id.txt"; // Simulating local storage
17+
private readonly HttpClient _httpClient;
18+
19+
public string BackendUrl { get; }
20+
public string PowerSyncUrl { get; }
21+
public string UserId { get; private set; }
22+
private string? clientId;
23+
24+
public NodeConnector()
25+
{
26+
_httpClient = new HttpClient();
27+
28+
// Load or generate User ID
29+
UserId = LoadOrGenerateUserId();
30+
31+
BackendUrl = "http://localhost:6060";
32+
PowerSyncUrl = "http://localhost:8080";
33+
34+
clientId = null;
35+
}
36+
37+
public string LoadOrGenerateUserId()
38+
{
39+
40+
return "78bb787c-ff0b-41b2-a297-6a7701648f4a";
41+
}
42+
43+
public async Task<PowerSyncCredentials?> FetchCredentials()
44+
{
45+
string tokenEndpoint = "api/auth/token";
46+
string url = $"{BackendUrl}/{tokenEndpoint}?user_id={UserId}";
47+
48+
HttpResponseMessage response = await _httpClient.GetAsync(url);
49+
if (!response.IsSuccessStatusCode)
50+
{
51+
throw new Exception($"Received {response.StatusCode} from {tokenEndpoint}: {await response.Content.ReadAsStringAsync()}");
52+
}
53+
54+
string responseBody = await response.Content.ReadAsStringAsync();
55+
var jsonResponse = JsonSerializer.Deserialize<Dictionary<string, string>>(responseBody);
56+
57+
if (jsonResponse == null || !jsonResponse.ContainsKey("token"))
58+
{
59+
throw new Exception("Invalid response received from authentication endpoint.");
60+
}
61+
62+
return new PowerSyncCredentials(PowerSyncUrl, jsonResponse["token"]);
63+
}
64+
65+
public async Task UploadData(IPowerSyncDatabase database)
66+
{
67+
CrudTransaction? transaction;
68+
try
69+
{
70+
transaction = await database.GetNextCrudTransaction();
71+
}
72+
catch (Exception ex)
73+
{
74+
Console.WriteLine($"UploadData Error: {ex.Message}");
75+
return;
76+
}
77+
78+
if (transaction == null)
79+
{
80+
return;
81+
}
82+
83+
clientId ??= await database.GetClientId();
84+
85+
try
86+
{
87+
var batch = new List<object>();
88+
89+
foreach (var operation in transaction.Crud)
90+
{
91+
batch.Add(new
92+
{
93+
op = operation.Op.ToString(),
94+
table = operation.Table,
95+
id = operation.Id,
96+
data = operation.OpData
97+
});
98+
}
99+
100+
var payload = JsonSerializer.Serialize(new { batch });
101+
var content = new StringContent(payload, Encoding.UTF8, "application/json");
102+
103+
HttpResponseMessage response = await _httpClient.PostAsync($"{BackendUrl}/api/data", content);
104+
105+
if (!response.IsSuccessStatusCode)
106+
{
107+
throw new Exception($"Received {response.StatusCode} from /api/data: {await response.Content.ReadAsStringAsync()}");
108+
}
109+
110+
await transaction.Complete();
111+
}
112+
catch (Exception ex)
113+
{
114+
Console.WriteLine($"UploadData Error: {ex.Message}");
115+
throw;
116+
}
117+
}
118+
}
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
using System.IO;
2+
using Microsoft.Extensions.Logging;
3+
using Microsoft.Maui.Storage;
4+
using Newtonsoft.Json;
5+
using PowerSync.Common.Client;
6+
using PowerSync.Common.MDSQLite;
7+
using PowerSync.Maui.SQLite;
8+
using SQLite;
9+
using TodoSQLite.Models;
10+
11+
namespace TodoSQLite.Data;
12+
13+
public class PowerSyncData
14+
{
15+
private PowerSyncDatabase _db;
16+
private ILogger _logger;
17+
18+
private record ListResult(string id, string name, string owner_id, string created_at);
19+
private record TodoResult(string id, string list_id, string description, string created_at, string completed_at, string created_by, string completed_by, int completed);
20+
21+
async Task Init()
22+
{
23+
if (_db != null) return;
24+
25+
ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
26+
{
27+
builder.AddConsole();
28+
builder.SetMinimumLevel(LogLevel.Trace);
29+
});
30+
_logger = loggerFactory.CreateLogger("PowerSyncLogger");
31+
32+
var dbPath = Path.Combine(FileSystem.AppDataDirectory, "mydb.db");
33+
var factory = new MAUISQLiteDBOpenFactory(new MDSQLiteOpenFactoryOptions()
34+
{
35+
DbFilename = dbPath
36+
});
37+
_db = new PowerSyncDatabase(new PowerSyncDatabaseOptions()
38+
{
39+
Database = factory,
40+
Schema = AppSchema.PowerSyncSchema,
41+
Logger = _logger
42+
});
43+
await _db.Init();
44+
45+
// var nodeConnector = new NodeConnector();
46+
// await _db.Connect(nodeConnector);
47+
}
48+
49+
// List operations
50+
public async Task<List<TodoList>> GetListsAsync()
51+
{
52+
await Init();
53+
var results = await _db.GetAll<ListResult>("SELECT * FROM lists ORDER BY created_at DESC");
54+
return results.Select(r => new TodoList
55+
{
56+
ID = r.id,
57+
Name = r.name,
58+
OwnerId = r.owner_id,
59+
CreatedAt = r.created_at
60+
}).ToList();
61+
}
62+
63+
public async Task<TodoList> GetListAsync(string id)
64+
{
65+
await Init();
66+
var result = await _db.GetAll<ListResult>("SELECT * FROM lists WHERE id = ?", [id.ToString()]);
67+
var list = result.FirstOrDefault();
68+
if (list == null) return null;
69+
70+
return new TodoList
71+
{
72+
ID = list.id,
73+
Name = list.name,
74+
OwnerId = list.owner_id,
75+
CreatedAt = list.created_at
76+
};
77+
}
78+
79+
public async Task<int> SaveListAsync(TodoList list)
80+
{
81+
await Init();
82+
if (list.ID != "")
83+
{
84+
await _db.Execute(
85+
"UPDATE lists SET name = ?, owner_id = ? WHERE id = ?",
86+
[list.Name, list.OwnerId, list.ID.ToString()]);
87+
return 1;
88+
}
89+
else
90+
{
91+
await _db.Execute(
92+
"INSERT INTO lists (id, name, owner_id, created_at) VALUES (uuid(), ?, ?, ?)",
93+
[list.Name, list.OwnerId, DateTime.UtcNow.ToString("o")]);
94+
return 1;
95+
}
96+
}
97+
98+
public async Task<int> DeleteListAsync(TodoList list)
99+
{
100+
await Init();
101+
string listId = list.ID.ToString();
102+
// First delete all todo items in this list
103+
await _db.Execute("DELETE FROM todos WHERE list_id = ?", [listId]);
104+
await _db.Execute("DELETE FROM lists WHERE id = ?", [listId]);
105+
return 1;
106+
}
107+
108+
// Todo item operations
109+
public async Task<List<TodoItem>> GetItemsAsync(string listId)
110+
{
111+
await Init();
112+
var results = await _db.GetAll<TodoResult>(
113+
"SELECT * FROM todos WHERE list_id = ? ORDER BY created_at DESC", [listId]);
114+
115+
return results.Select(r => new TodoItem
116+
{
117+
ID = r.id,
118+
ListId = r.list_id,
119+
Description = r.description,
120+
CreatedAt = r.created_at,
121+
CompletedAt = r.completed_at,
122+
CreatedBy = r.created_by,
123+
CompletedBy = r.completed_by,
124+
Completed = r.completed == 1
125+
}).ToList();
126+
}
127+
128+
public async Task<List<TodoItem>> GetItemsNotDoneAsync(string listId)
129+
{
130+
await Init();
131+
var results = await _db.GetAll<TodoResult>(
132+
"SELECT * FROM todos WHERE list_id = ? AND completed = 0 ORDER BY created_at DESC",
133+
[listId]);
134+
135+
return results.Select(r => new TodoItem
136+
{
137+
ID = r.id,
138+
ListId = r.list_id,
139+
Description = r.description,
140+
CreatedAt = r.created_at,
141+
CompletedAt = r.completed_at,
142+
CreatedBy = r.created_by,
143+
CompletedBy = r.completed_by,
144+
Completed = r.completed == 1
145+
}).ToList();
146+
}
147+
148+
public async Task<TodoItem> GetItemAsync(string id)
149+
{
150+
await Init();
151+
var results = await _db.GetAll<TodoResult>("SELECT * FROM todos WHERE id = ?", [id.ToString()]);
152+
var todo = results.FirstOrDefault();
153+
if (todo == null) return null;
154+
155+
return new TodoItem
156+
{
157+
ID = todo.id,
158+
ListId = todo.list_id,
159+
Description = todo.description,
160+
CreatedAt = todo.created_at,
161+
CompletedAt = todo.completed_at,
162+
CreatedBy = todo.created_by,
163+
CompletedBy = todo.completed_by,
164+
Completed = todo.completed == 1
165+
};
166+
}
167+
168+
public async Task<int> SaveItemAsync(TodoItem item)
169+
{
170+
await Init();
171+
if (item.ID != "")
172+
{
173+
await _db.Execute(
174+
@"UPDATE todos
175+
SET description = ?, completed = ?, completed_at = ?, completed_by = ?
176+
WHERE id = ?",
177+
[item.Description,
178+
item.Completed ? 1 : 0,
179+
item.CompletedAt,
180+
item.CompletedBy,
181+
item.ID.ToString()]);
182+
return 1;
183+
}
184+
else
185+
{
186+
await _db.Execute(
187+
@"INSERT INTO todos
188+
(id, list_id, description, created_at, completed, created_by)
189+
VALUES (uuid(), ?, ?, ?, ?, ?)",
190+
[item.ListId,
191+
item.Description,
192+
item.CreatedAt,
193+
item.Completed ? 1 : 0,
194+
item.CreatedBy]);
195+
return 1;
196+
}
197+
}
198+
199+
public async Task<int> DeleteItemAsync(TodoItem item)
200+
{
201+
await Init();
202+
await _db.Execute("DELETE FROM todos WHERE id = ?", [item.ID.ToString()]);
203+
return 1;
204+
}
205+
}

0 commit comments

Comments
 (0)