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