Eric Bower
·
2026-08-17
1package pgsdb
2
3import (
4 "fmt"
5 "log/slog"
6 "time"
7
8 "github.com/google/uuid"
9 "github.com/picosh/pico/pkg/db"
10 "github.com/picosh/pico/pkg/shared"
11)
12
13type MemoryDB struct {
14 Logger *slog.Logger
15 Users []*db.User
16 Projects []*db.Project
17 Pubkeys []*db.PublicKey
18 Feature *db.FeatureFlag
19 Features []*db.FeatureFlag
20 FormEntries []*db.FormEntry
21}
22
23var _ PgsDB = (*MemoryDB)(nil)
24
25func NewDBMemory(logger *slog.Logger) *MemoryDB {
26 d := &MemoryDB{
27 Logger: logger,
28 }
29 d.Logger.Info("connecting to our in-memory database. All data created during runtime will be lost on exit.")
30 return d
31}
32
33func (me *MemoryDB) SetupTestData() {
34 user := &db.User{
35 ID: uuid.NewString(),
36 Name: "testusr",
37 }
38 me.Users = append(me.Users, user)
39 feature := db.NewFeatureFlag(
40 user.ID,
41 "plus",
42 uint64(25*shared.MB),
43 int64(10*shared.MB),
44 int64(5*shared.KB),
45 )
46 expiresAt := time.Now().Add(time.Hour * 24)
47 feature.ExpiresAt = &expiresAt
48 me.Feature = feature
49}
50
51var errNotImpl = fmt.Errorf("not implemented")
52
53func (me *MemoryDB) FindUsers() ([]*db.User, error) {
54 users := []*db.User{}
55 return users, errNotImpl
56}
57
58func (me *MemoryDB) FindUserByPubkey(key string) (*db.User, error) {
59 for _, pk := range me.Pubkeys {
60 if pk.Key == key {
61 return me.FindUser(pk.UserID)
62 }
63 }
64 return nil, fmt.Errorf("user not found")
65}
66
67func (me *MemoryDB) FindUser(userID string) (*db.User, error) {
68 for _, user := range me.Users {
69 if user.ID == userID {
70 return user, nil
71 }
72 }
73 return nil, fmt.Errorf("user not found")
74}
75
76func (me *MemoryDB) FindUserByName(name string) (*db.User, error) {
77 for _, user := range me.Users {
78 if user.Name == name {
79 return user, nil
80 }
81 }
82 return nil, fmt.Errorf("user not found")
83}
84
85func (me *MemoryDB) FindFeature(userID, name string) (*db.FeatureFlag, error) {
86 for _, ff := range me.Features {
87 if ff.UserID == userID && ff.Name == name {
88 return ff, nil
89 }
90 }
91 if me.Feature != nil && (me.Feature.Name == name || me.Feature.Name == "") {
92 return me.Feature, nil
93 }
94 return nil, fmt.Errorf("feature flag not found")
95}
96
97func (me *MemoryDB) Close() error {
98 return nil
99}
100
101func (me *MemoryDB) FindTotalSizeForUser(userID string) (int, error) {
102 return 0, errNotImpl
103}
104
105func (me *MemoryDB) InsertProject(userID, name, projectDir string) (string, error) {
106 id := uuid.NewString()
107 now := time.Now()
108 me.Projects = append(me.Projects, &db.Project{
109 ID: id,
110 UserID: userID,
111 Name: name,
112 ProjectDir: projectDir,
113 CreatedAt: &now,
114 UpdatedAt: &now,
115 })
116 return id, nil
117}
118
119func (me *MemoryDB) UpdateProject(userID, name string) error {
120 project, err := me.FindProjectByName(userID, name)
121 if err != nil {
122 return err
123 }
124
125 now := time.Now()
126 project.UpdatedAt = &now
127
128 return nil
129}
130
131func (me *MemoryDB) UpsertProject(userID, projectName, projectDir string) (*db.Project, error) {
132 project, err := me.FindProjectByName(userID, projectName)
133 if err == nil {
134 // this just updates the `createdAt` timestamp, useful for book-keeping
135 err = me.UpdateProject(userID, projectName)
136 if err != nil {
137 me.Logger.Error("could not update project", "err", err)
138 return nil, err
139 }
140 return project, nil
141 }
142
143 _, err = me.InsertProject(userID, projectName, projectName)
144 if err != nil {
145 me.Logger.Error("could not create project", "err", err)
146 return nil, err
147 }
148 return me.FindProjectByName(userID, projectName)
149}
150
151func (me *MemoryDB) LinkToProject(userID, projectID, projectDir string, commit bool) error {
152 return errNotImpl
153}
154
155func (me *MemoryDB) RemoveProject(projectID string) error {
156 return errNotImpl
157}
158
159func (me *MemoryDB) FindProjectByName(userID, name string) (*db.Project, error) {
160 for _, project := range me.Projects {
161 if project.UserID != userID {
162 continue
163 }
164
165 if project.Name != name {
166 continue
167 }
168
169 return project, nil
170 }
171 return nil, fmt.Errorf("project not found by name %s", name)
172}
173
174func (me *MemoryDB) FindProjectLinks(userID, name string) ([]*db.Project, error) {
175 return []*db.Project{}, errNotImpl
176}
177
178func (me *MemoryDB) FindProjectsByPrefix(userID, prefix string) ([]*db.Project, error) {
179 return []*db.Project{}, errNotImpl
180}
181
182func (me *MemoryDB) FindProjectsByUser(userID string) ([]*db.Project, error) {
183 pjs := []*db.Project{}
184 for _, project := range me.Projects {
185 if project.UserID != userID {
186 continue
187 }
188 pjs = append(pjs, project)
189 }
190 return pjs, nil
191}
192
193func (me *MemoryDB) FindProjects(userID string) ([]*db.Project, error) {
194 return []*db.Project{}, errNotImpl
195}
196
197func (me *MemoryDB) UpdateProjectAcl(userID, name string, acl db.ProjectAcl) error {
198 return errNotImpl
199}
200
201func (me *MemoryDB) RegisterAdmin(username, pubkey, pubkeyName string) error {
202 return errNotImpl
203}
204
205func (me *MemoryDB) InsertAccessLog(*db.AccessLog) error {
206 return errNotImpl
207}
208
209func (me *MemoryDB) InsertFormEntry(userID, name string, data map[string]interface{}) error {
210 id := uuid.NewString()
211 now := time.Now()
212 entry := &db.FormEntry{
213 ID: id,
214 UserID: userID,
215 Name: name,
216 Data: data,
217 CreatedAt: &now,
218 }
219 me.FormEntries = append(me.FormEntries, entry)
220 return nil
221}
222
223func (me *MemoryDB) FindFormEntriesByUserAndName(userID, name string) ([]*db.FormEntry, error) {
224 entries := []*db.FormEntry{}
225 for _, entry := range me.FormEntries {
226 if entry.UserID == userID && entry.Name == name {
227 entries = append(entries, entry)
228 }
229 }
230 return entries, nil
231}
232
233func (me *MemoryDB) FindFormNamesByUser(userID string) ([]string, error) {
234 names := make(map[string]bool)
235 for _, entry := range me.FormEntries {
236 if entry.UserID == userID {
237 names[entry.Name] = true
238 }
239 }
240 result := []string{}
241 for name := range names {
242 result = append(result, name)
243 }
244 return result, nil
245}
246
247func (me *MemoryDB) RemoveFormEntriesByUserAndName(userID, name string) error {
248 filtered := []*db.FormEntry{}
249 for _, entry := range me.FormEntries {
250 if entry.UserID != userID || entry.Name != name {
251 filtered = append(filtered, entry)
252 }
253 }
254 me.FormEntries = filtered
255 return nil
256}