()
| 50 | } |
| 51 | |
| 52 | func (fn *n1qlInvocation) Iterate() (sgbucket.QueryResultIterator, error) { |
| 53 | var userArg n1qlUserArgument |
| 54 | if user := fn.db.User(); user != nil { |
| 55 | userArg.Name = base.Ptr(user.Name()) |
| 56 | userArg.Email = base.Ptr(user.Email()) |
| 57 | userArg.Channels = user.Channels().AllKeys() |
| 58 | userArg.Roles = user.RoleNames().AllKeys() |
| 59 | } |
| 60 | if fn.n1qlArgs == nil { |
| 61 | fn.n1qlArgs = map[string]any{} |
| 62 | } |
| 63 | fn.n1qlArgs["args"] = fn.args |
| 64 | fn.n1qlArgs["user"] = &userArg |
| 65 | |
| 66 | // Run the N1QL query: |
| 67 | // TODO: Multi-collection support for user functions is not implemented. |
| 68 | iter, err := db.N1QLQueryWithStats(fn.ctx, fn.db.Bucket.DefaultDataStore(), db.QueryTypeUserFunctionPrefix+fn.name, fn.Code, fn.n1qlArgs, |
| 69 | base.RequestPlus, false, fn.db.DbStats, fn.db.Options.SlowQueryWarningThreshold) |
| 70 | |
| 71 | if err != nil { |
| 72 | // Return a friendlier error: |
| 73 | var qe *gocb.QueryError |
| 74 | if errors.As(err, &qe) { |
| 75 | base.WarnfCtx(fn.ctx, "Error running query %q: %v", fn.name, err) |
| 76 | return nil, base.HTTPErrorf(http.StatusInternalServerError, "Query %q: %s", fn.name, qe.Errors[0].Message) |
| 77 | } else { |
| 78 | base.WarnfCtx(fn.ctx, "Unknown error running query %q: %T %#v", fn.name, err, err) |
| 79 | return nil, base.HTTPErrorf(http.StatusInternalServerError, "Unknown error running query %q (see logs)", fn.name) |
| 80 | } |
| 81 | } |
| 82 | // Do a final timeout check, so the caller will know not to do any more work if time's up: |
| 83 | return iter, db.CheckTimeout(fn.ctx) |
| 84 | } |
| 85 | |
| 86 | func (fn *n1qlInvocation) Run(ctx context.Context) (any, error) { |
| 87 | rows, err := fn.Iterate() |
no test coverage detected