package notificationstore import ( "encoding/json" "fmt" ) // marshalRecipientUserIDs returns the JSONB bytes for the // `records.recipient_user_ids` column. A nil/empty slice round-trips as `[]` // to keep the column NOT NULL across equality tests. func marshalRecipientUserIDs(userIDs []string) ([]byte, error) { if userIDs == nil { userIDs = []string{} } payload, err := json.Marshal(userIDs) if err != nil { return nil, fmt.Errorf("marshal recipient user ids: %w", err) } return payload, nil } // unmarshalRecipientUserIDs decodes the JSONB recipient user-id list. nil // payloads round-trip as a nil slice so the read path matches what the // service layer accepts (`nil` and an empty `[]` are equivalent for // audience_kind != user_set). func unmarshalRecipientUserIDs(payload []byte) ([]string, error) { if len(payload) == 0 { return nil, nil } var userIDs []string if err := json.Unmarshal(payload, &userIDs); err != nil { return nil, fmt.Errorf("unmarshal recipient user ids: %w", err) } if len(userIDs) == 0 { return nil, nil } return userIDs, nil } // marshalRawFields returns the JSONB bytes for the // `malformed_intents.raw_fields` column. The map is serialised verbatim so // future operator queries can match arbitrary keys. func marshalRawFields(fields map[string]any) ([]byte, error) { if fields == nil { fields = map[string]any{} } payload, err := json.Marshal(fields) if err != nil { return nil, fmt.Errorf("marshal raw fields: %w", err) } return payload, nil } // unmarshalRawFields decodes the malformed_intents.raw_fields column into a // non-nil map (empty {} when the column is null/empty). func unmarshalRawFields(payload []byte) (map[string]any, error) { out := map[string]any{} if len(payload) == 0 { return out, nil } if err := json.Unmarshal(payload, &out); err != nil { return nil, fmt.Errorf("unmarshal raw fields: %w", err) } return out, nil }