@@ -11,6 +11,7 @@ import (
1111 "github.com/jackc/pgx/v5"
1212 "github.com/jackc/pgx/v5/pgconn"
1313 "github.com/jackc/pgx/v5/pgxpool"
14+ "github.com/raphico/go-device-telemetry-api/internal/common/pagination"
1415 "github.com/raphico/go-device-telemetry-api/internal/domain/device"
1516 "github.com/raphico/go-device-telemetry-api/internal/domain/user"
1617)
@@ -61,7 +62,11 @@ func (r *DeviceRepository) Create(ctx context.Context, device *device.Device) er
6162 return nil
6263}
6364
64- func (r * DeviceRepository ) FindById (ctx context.Context , id device.DeviceID , userId user.UserID ) (* device.Device , error ) {
65+ func (r * DeviceRepository ) FindById (
66+ ctx context.Context ,
67+ id device.DeviceID ,
68+ userId user.UserID ,
69+ ) (* device.Device , error ) {
6570 var (
6671 deviceID uuid.UUID
6772 userID uuid.UUID
@@ -110,3 +115,99 @@ func (r *DeviceRepository) FindById(ctx context.Context, id device.DeviceID, use
110115 )
111116
112117}
118+
119+ func (r * DeviceRepository ) FindDevices (
120+ ctx context.Context ,
121+ userID user.UserID ,
122+ limit int ,
123+ cursor * pagination.Cursor ,
124+ ) ([]* device.Device , * pagination.Cursor , error ) {
125+ var (
126+ query string
127+ args []any
128+ )
129+
130+ if cursor == nil {
131+ query = `
132+ SELECT id, user_id, name, device_type, status, metadata, created_at, updated_at
133+ FROM devices
134+ WHERE user_id = $1
135+ ORDER BY created_at ASC, id ASC
136+ LIMIT $2
137+ `
138+ args = []any {userID , limit + 1 }
139+ } else {
140+ query = `
141+ SELECT id, user_id, name, device_type, status, metadata, created_at, updated_at
142+ FROM devices
143+ WHERE user_id = $1
144+ AND (created_at, id) > ($2, $3)
145+ ORDER BY created_at ASC, id ASC
146+ LIMIT $4
147+ `
148+ args = []any {userID , cursor .CreatedAt , cursor .ID , limit + 1 }
149+ }
150+
151+ rows , err := r .db .Query (ctx , query , args ... )
152+ if err != nil {
153+ return nil , nil , fmt .Errorf ("query devices: %w" , err )
154+ }
155+ defer rows .Close ()
156+
157+ var result []* device.Device
158+
159+ for rows .Next () {
160+ var (
161+ deviceID uuid.UUID
162+ uID uuid.UUID
163+ name string
164+ deviceType string
165+ status string
166+ metadata []byte
167+ createdAt time.Time
168+ updatedAt time.Time
169+ )
170+
171+ if err := rows .Scan (
172+ & deviceID ,
173+ & uID ,
174+ & name ,
175+ & deviceType ,
176+ & status ,
177+ & metadata ,
178+ & createdAt ,
179+ & updatedAt ,
180+ ); err != nil {
181+ return nil , nil , fmt .Errorf ("scan device: %w" , err )
182+ }
183+
184+ dev , err := device .RehydrateDevice (
185+ device .DeviceID (deviceID ),
186+ user .UserID (uID ),
187+ name ,
188+ deviceType ,
189+ status ,
190+ metadata ,
191+ createdAt ,
192+ updatedAt ,
193+ )
194+ if err != nil {
195+ return nil , nil , fmt .Errorf ("rehydrate device: %w" , err )
196+ }
197+
198+ result = append (result , dev )
199+ }
200+
201+ if err := rows .Err (); err != nil {
202+ return nil , nil , fmt .Errorf ("rows error: %w" , err )
203+ }
204+
205+ var nextCur * pagination.Cursor
206+ if len (result ) > limit {
207+ lastVisible := result [limit - 1 ]
208+ result = result [:limit ]
209+ nextCur = pagination .NewCursor (uuid .UUID (lastVisible .ID ), lastVisible .CreatedAt )
210+ }
211+
212+ return result , nextCur , nil
213+ }
0 commit comments