QueryAttributes reads multiple attributes from the storage based on the given filter.
(ctx context.Context, tenantID string, filter *base.AttributeFilter, snap string, pagination database.CursorPagination)
| 261 | |
| 262 | // QueryAttributes reads multiple attributes from the storage based on the given filter. |
| 263 | func (r *DataReader) QueryAttributes(ctx context.Context, tenantID string, filter *base.AttributeFilter, snap string, pagination database.CursorPagination) (it *database.AttributeIterator, err error) { |
| 264 | // Start a new trace span and end it when the function exits. |
| 265 | ctx, span := internal.Tracer.Start(ctx, "data-reader.query-attributes") |
| 266 | defer span.End() |
| 267 | // Log query operation |
| 268 | slog.DebugContext(ctx, "querying Attributes for tenant_id", slog.String("tenant_id", tenantID)) |
| 269 | // Decode snapshot token |
| 270 | // Decode the snapshot value. |
| 271 | var st token.SnapToken |
| 272 | st, err = snapshot.EncodedToken{Value: snap}.Decode() |
| 273 | if err != nil { |
| 274 | return nil, utils.HandleError(ctx, span, err, base.ErrorCode_ERROR_CODE_INTERNAL) |
| 275 | } |
| 276 | |
| 277 | // Build the attributes query based on the provided filter and snapshot value. |
| 278 | var args []interface{} |
| 279 | builder := r.database.Builder.Select("entity_type, entity_id, attribute, value").From(AttributesTable).Where(squirrel.Eq{"tenant_id": tenantID}) |
| 280 | builder = utils.AttributesFilterQueryForSelectBuilder(builder, filter) |
| 281 | builder = utils.SnapshotQuery(builder, st.(snapshot.Token).Value.Uint, st.(snapshot.Token).Snapshot) |
| 282 | |
| 283 | if pagination.Cursor() != "" { |
| 284 | var t database.ContinuousToken |
| 285 | t, err = utils.EncodedContinuousToken{Value: pagination.Cursor()}.Decode() |
| 286 | if err != nil { |
| 287 | return nil, utils.HandleError(ctx, span, err, base.ErrorCode_ERROR_CODE_INVALID_CONTINUOUS_TOKEN) |
| 288 | } |
| 289 | builder = builder.Where(squirrel.GtOrEq{pagination.Sort(): t.(utils.ContinuousToken).Value}) |
| 290 | } |
| 291 | |
| 292 | if pagination.Sort() != "" { |
| 293 | builder = builder.OrderBy(pagination.Sort()) |
| 294 | } |
| 295 | |
| 296 | // Apply limit if specified in pagination |
| 297 | limit := pagination.Limit() |
| 298 | if limit > 0 { |
| 299 | builder = builder.Limit(uint64(limit)) |
| 300 | } |
| 301 | |
| 302 | // Generate the SQL query and arguments. |
| 303 | var query string |
| 304 | query, args, err = builder.ToSql() |
| 305 | if err != nil { |
| 306 | return nil, utils.HandleError(ctx, span, err, base.ErrorCode_ERROR_CODE_SQL_BUILDER) |
| 307 | } |
| 308 | // Log generated query |
| 309 | slog.DebugContext(ctx, "generated sql query", slog.String("query", query), "with args", slog.Any("arguments", args)) |
| 310 | // Execute the SQL query and retrieve the result rows. |
| 311 | var rows pgx.Rows |
| 312 | rows, err = r.database.ReadPool.Query(ctx, query, args...) |
| 313 | if err != nil { |
| 314 | return nil, utils.HandleError(ctx, span, err, base.ErrorCode_ERROR_CODE_EXECUTION) |
| 315 | } |
| 316 | defer rows.Close() |
| 317 | |
| 318 | // Process the result rows and store the attributes in an AttributeCollection. |
| 319 | collection := database.NewAttributeCollection() |
| 320 | for rows.Next() { |
nothing calls this directly
no test coverage detected