QuerySingleAttribute retrieves a single attribute from the storage based on the given filter.
(ctx context.Context, tenantID string, filter *base.AttributeFilter, snap string)
| 202 | |
| 203 | // QuerySingleAttribute retrieves a single attribute from the storage based on the given filter. |
| 204 | func (r *DataReader) QuerySingleAttribute(ctx context.Context, tenantID string, filter *base.AttributeFilter, snap string) (attribute *base.Attribute, err error) { |
| 205 | // Start a new trace span and end it when the function exits. |
| 206 | ctx, span := internal.Tracer.Start(ctx, "data-reader.query-single-attribute") |
| 207 | defer span.End() |
| 208 | |
| 209 | slog.DebugContext(ctx, "querying single attribute for tenant_id", slog.String("tenant_id", tenantID)) |
| 210 | |
| 211 | // Decode the snapshot value. |
| 212 | var st token.SnapToken |
| 213 | st, err = snapshot.EncodedToken{Value: snap}.Decode() |
| 214 | if err != nil { |
| 215 | return nil, utils.HandleError(ctx, span, err, base.ErrorCode_ERROR_CODE_INTERNAL) |
| 216 | } |
| 217 | |
| 218 | // Build the relationships query based on the provided filter and snapshot value. |
| 219 | var args []interface{} |
| 220 | builder := r.database.Builder.Select("entity_type, entity_id, attribute, value").From(AttributesTable).Where(squirrel.Eq{"tenant_id": tenantID}) |
| 221 | builder = utils.AttributesFilterQueryForSelectBuilder(builder, filter) |
| 222 | builder = utils.SnapshotQuery(builder, st.(snapshot.Token).Value.Uint, st.(snapshot.Token).Snapshot) |
| 223 | |
| 224 | // Generate the SQL query and arguments. |
| 225 | var query string |
| 226 | query, args, err = builder.ToSql() |
| 227 | if err != nil { |
| 228 | return nil, utils.HandleError(ctx, span, err, base.ErrorCode_ERROR_CODE_SQL_BUILDER) |
| 229 | } |
| 230 | |
| 231 | slog.DebugContext(ctx, "generated sql query", slog.String("query", query), "with args", slog.Any("arguments", args)) |
| 232 | // Execute query |
| 233 | row := r.database.ReadPool.QueryRow(ctx, query, args...) |
| 234 | |
| 235 | rt := storage.Attribute{} |
| 236 | |
| 237 | // Suppose you have a struct `rt` with a field `Value` of type `*anypb.Any`. |
| 238 | var valueStr string |
| 239 | |
| 240 | // Scan the row from the database into the fields of `rt` and `valueStr`. |
| 241 | err = row.Scan(&rt.EntityType, &rt.EntityID, &rt.Attribute, &valueStr) |
| 242 | if err != nil { |
| 243 | if errors.Is(err, pgx.ErrNoRows) { |
| 244 | return nil, nil |
| 245 | } else { |
| 246 | return nil, utils.HandleError(ctx, span, err, base.ErrorCode_ERROR_CODE_SCAN) |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | // Unmarshal the JSON data from `valueStr` into `rt.Value`. |
| 251 | rt.Value = &anypb.Any{} |
| 252 | err = protojson.Unmarshal([]byte(valueStr), rt.Value) |
| 253 | if err != nil { |
| 254 | return nil, utils.HandleError(ctx, span, err, base.ErrorCode_ERROR_CODE_INTERNAL) |
| 255 | } |
| 256 | |
| 257 | slog.DebugContext(ctx, "successfully retrieved Single attribute from the database") |
| 258 | // Return attribute |
| 259 | return rt.ToAttribute(), nil |
| 260 | } |
| 261 |
nothing calls this directly
no test coverage detected