@@ -2,9 +2,16 @@ package check
22
33import (
44 "context"
5+ "encoding/json"
6+ "errors"
7+ "time"
58
6- "github.com/pixel365/pulse/internal/model"
9+ "github.com/jackc/pgx/v5"
10+
11+ "github.com/pixel365/pulse/internal/e"
712 "github.com/pixel365/pulse/internal/repository"
13+
14+ "github.com/pixel365/pulse/internal/model"
815)
916
1017var _ CheckStateRepository = (* StateCheck )(nil )
@@ -13,12 +20,169 @@ type StateCheck struct {
1320 db repository.QueryExecutor
1421}
1522
16- func (s * StateCheck ) GetCheckState (ctx context.Context , service string ) (* model.CheckState , error ) {
17- return nil , nil
23+ func (s * StateCheck ) GetCheckState (
24+ ctx context.Context ,
25+ checkID string ,
26+ serviceID string ,
27+ ) (* model.CheckState , error ) {
28+ query := `
29+ SELECT
30+ check_type,
31+ status,
32+ last_execution_id,
33+ last_status,
34+ last_error_kind,
35+ last_error_message,
36+ last_duration,
37+ last_details,
38+ last_success_at,
39+ last_failure_at,
40+ consecutive_successes,
41+ consecutive_failures,
42+ updated_at
43+ FROM pulse.check_states
44+ WHERE check_id = $1 AND service_id = $2
45+ `
46+
47+ state := model.CheckState {
48+ CheckID : checkID ,
49+ ServiceID : serviceID ,
50+ }
51+
52+ var (
53+ rawDetails []byte
54+ rawErrorKind * string
55+ rawErrorMessage * string
56+ rawDurationUs int64
57+ )
58+
59+ err := s .db .QueryRow (ctx , query , checkID , serviceID ).Scan (
60+ & state .CheckType ,
61+ & state .Status ,
62+ & state .LastExecutionID ,
63+ & state .LastStatus ,
64+ & rawErrorKind ,
65+ & rawErrorMessage ,
66+ & rawDurationUs ,
67+ & rawDetails ,
68+ & state .LastSuccessAt ,
69+ & state .LastFailureAt ,
70+ & state .ConsecutiveSuccesses ,
71+ & state .ConsecutiveFailures ,
72+ & state .UpdatedAt ,
73+ )
74+ if errors .Is (err , pgx .ErrNoRows ) {
75+ return nil , e .ErrNotFound
76+ }
77+
78+ if err != nil {
79+ return nil , err
80+ }
81+
82+ if rawErrorKind != nil {
83+ state .LastErrorKind = e .ErrorKind (* rawErrorKind )
84+ }
85+
86+ if rawErrorMessage != nil {
87+ state .LastErrorMessage = * rawErrorMessage
88+ }
89+ state .LastDuration = time .Duration (rawDurationUs ) * time .Microsecond
90+
91+ if rawDetails != nil {
92+ if err = json .Unmarshal (rawDetails , & state .LastDetails ); err != nil {
93+ return nil , err
94+ }
95+ }
96+
97+ return & state , nil
1898}
1999
20- func (s * StateCheck ) UpdateCheckState (ctx context.Context , state model.CheckState ) error {
21- return nil
100+ func (s * StateCheck ) UpsertCheckState (
101+ ctx context.Context ,
102+ state * model.CheckState ,
103+ ) error {
104+ if state == nil {
105+ return errors .New ("check state is nil" )
106+ }
107+
108+ query := `
109+ INSERT INTO pulse.check_states (
110+ check_id,
111+ service_id,
112+ check_type,
113+ status,
114+ last_execution_id,
115+ last_status,
116+ last_error_kind,
117+ last_error_message,
118+ last_duration,
119+ last_details,
120+ last_success_at,
121+ last_failure_at,
122+ consecutive_successes,
123+ consecutive_failures,
124+ updated_at
125+ ) VALUES (
126+ $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15
127+ )
128+ ON CONFLICT (check_id, service_id) DO UPDATE SET
129+ check_type = EXCLUDED.check_type,
130+ status = EXCLUDED.status,
131+ last_execution_id = EXCLUDED.last_execution_id,
132+ last_status = EXCLUDED.last_status,
133+ last_error_kind = EXCLUDED.last_error_kind,
134+ last_error_message = EXCLUDED.last_error_message,
135+ last_duration = EXCLUDED.last_duration,
136+ last_details = EXCLUDED.last_details,
137+ last_success_at = EXCLUDED.last_success_at,
138+ last_failure_at = EXCLUDED.last_failure_at,
139+ consecutive_successes = EXCLUDED.consecutive_successes,
140+ consecutive_failures = EXCLUDED.consecutive_failures,
141+ updated_at = EXCLUDED.updated_at
142+ `
143+
144+ var (
145+ details []byte
146+ errorKind * string
147+ errorMessage * string
148+ )
149+
150+ if state .LastDetails != nil {
151+ data , err := json .Marshal (state .LastDetails )
152+ if err != nil {
153+ return err
154+ }
155+ details = data
156+ }
157+
158+ if state .LastErrorKind != e .ErrNone {
159+ value := string (state .LastErrorKind )
160+ errorKind = & value
161+ }
162+
163+ if state .LastErrorMessage != "" {
164+ errorMessage = & state .LastErrorMessage
165+ }
166+
167+ _ , err := s .db .Exec (ctx , query ,
168+ state .CheckID ,
169+ state .ServiceID ,
170+ state .CheckType ,
171+ state .Status ,
172+ state .LastExecutionID ,
173+ state .LastStatus ,
174+ errorKind ,
175+ errorMessage ,
176+ state .LastDuration .Microseconds (),
177+ details ,
178+ state .LastSuccessAt ,
179+ state .LastFailureAt ,
180+ state .ConsecutiveSuccesses ,
181+ state .ConsecutiveFailures ,
182+ state .UpdatedAt ,
183+ )
184+
185+ return err
22186}
23187
24188func NewStateRepository (db repository.QueryExecutor ) * StateCheck {
0 commit comments