(ctx context.Context, result interface{}, opts ...model.QueryOption)
| 165 | } |
| 166 | |
| 167 | func (d *postgresModel) List(ctx context.Context, result interface{}, opts ...model.QueryOption) error { |
| 168 | rv := reflect.ValueOf(result) |
| 169 | if rv.Kind() != reflect.Ptr || rv.Elem().Kind() != reflect.Slice { |
| 170 | return fmt.Errorf("model/postgres: result must be a pointer to a slice") |
| 171 | } |
| 172 | sliceVal := rv.Elem() |
| 173 | elemType := sliceVal.Type().Elem() |
| 174 | structType := elemType |
| 175 | if structType.Kind() == reflect.Ptr { |
| 176 | structType = structType.Elem() |
| 177 | } |
| 178 | |
| 179 | d.mu.RLock() |
| 180 | schema, ok := d.types[structType] |
| 181 | d.mu.RUnlock() |
| 182 | if !ok { |
| 183 | return model.ErrNotRegistered |
| 184 | } |
| 185 | |
| 186 | q := model.ApplyQueryOptions(opts...) |
| 187 | cols := columnList(schema) |
| 188 | |
| 189 | query := fmt.Sprintf("SELECT %s FROM %s", cols, quoteIdent(schema.Table)) |
| 190 | var args []any |
| 191 | paramN := 1 |
| 192 | |
| 193 | if len(q.Filters) > 0 { |
| 194 | where, fArgs, _ := buildWhere(q.Filters, paramN) |
| 195 | query += " WHERE " + where |
| 196 | args = append(args, fArgs...) |
| 197 | } |
| 198 | |
| 199 | if q.OrderBy != "" { |
| 200 | dir := "ASC" |
| 201 | if q.Desc { |
| 202 | dir = "DESC" |
| 203 | } |
| 204 | query += fmt.Sprintf(" ORDER BY %s %s", quoteIdent(q.OrderBy), dir) |
| 205 | } |
| 206 | |
| 207 | if q.Limit > 0 { |
| 208 | query += fmt.Sprintf(" LIMIT %d", q.Limit) |
| 209 | } |
| 210 | if q.Offset > 0 { |
| 211 | query += fmt.Sprintf(" OFFSET %d", q.Offset) |
| 212 | } |
| 213 | |
| 214 | rows, err := d.db.QueryContext(ctx, query, args...) |
| 215 | if err != nil { |
| 216 | return fmt.Errorf("model/postgres: list: %w", err) |
| 217 | } |
| 218 | defer rows.Close() |
| 219 | |
| 220 | fieldMaps, err := scanRows(schema, rows) |
| 221 | if err != nil { |
| 222 | return err |
| 223 | } |
| 224 |
nothing calls this directly
no test coverage detected