# SelectPromise

SelectPromise provides chainable methods for configuring SELECT queries.

The `SelectPromise` class provides a chainable interface for configuring SELECT queries before execution. It extends `Promise`, allowing you to `await` it directly or chain configuration methods.

**Returned by:** [`SurrealQueryable.select()`](/docs/reference/javascript/api/core/surreal-queryable.md#select)

**Source:** [query/select.ts](https://github.com/surrealdb/surrealdb.js/blob/main/packages/sdk/src/query/select.ts)

## Type parameters

- `T` - The result type
- `I` - The input type for field selection
- `J` - Boolean indicating if result is JSON (default: `false`)

## Configuration methods

### `.fields()` {#fields}

Specify which fields to select from the records.

```ts title="Method Syntax"
selectPromise.fields(...fields)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>fields</code> <label label="required" /></td>
            <td><code>Field&lt;I&gt;[]</code></td>
            <td>Field names to select.</td>
        </tr>
    </tbody>
</table>

#### Returns
`SelectPromise<T, I, J>` - Chainable promise

#### Examples

```ts title="Select Specific Fields"
const users = await db.select(new Table('users'))
    .fields('name', 'email', 'age');
// Returns: [{ name, email, age }, ...]
```

```ts title="Select Nested Fields"
const users = await db.select(new Table('users'))
    .fields('name', 'address.city', 'address.country');
```

```ts title="Select with Aggregations"
const stats = await db.select(new Table('orders'))
    .fields('count()', 'sum(total)', 'avg(items)');
```

---

### `.value()` {#value}

Select only the value of a specific field, unwrapping it from the record structure.

```ts title="Method Syntax"
selectPromise.value(field)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>field</code> <label label="required" /></td>
            <td><code>Field&lt;I&gt;</code></td>
            <td>The field name to extract.</td>
        </tr>
    </tbody>
</table>

#### Returns
`SelectPromise<T, I, J>` - Chainable promise

#### Example

```ts title="Get Array of Values"
const names = await db.select(new Table('users'))
    .value('name');
// Returns: ['John', 'Jane', 'Bob']

// Instead of: [{ name: 'John' }, { name: 'Jane' }, ...]
```

---

### `.where()` {#where}

Add a WHERE clause to filter results.

```ts title="Method Syntax"
selectPromise.where(expr)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>expr</code> <label label="required" /></td>
            <td><code>ExprLike</code></td>
            <td>The condition expression (string or <a href="/docs/reference/javascript/api/utilities/expr.md">Expression</a> object).</td>
        </tr>
    </tbody>
</table>

#### Returns
`SelectPromise<T, I, J>` - Chainable promise

#### Examples

```ts title="String Condition"
const adults = await db.select(new Table('users'))
    .where('age >= 18');
```

```ts title="With Expression Builder"
import { expr } from 'surrealdb';

const activeUsers = await db.select(new Table('users'))
    .where(expr(({ and, eq, gte, field }) =>
        and(
            eq(field('status'), 'active'),
            gte(field('last_login'), new DateTime('2024-01-01'))
        )
    ));
```

```ts title="Parameterised condition"
const users = await db.query(
    surql`SELECT * FROM users WHERE age >= ${minAge}`
).collect();
```

---

### `.fetch()` {#fetch}

Specify related fields to fetch (similar to SQL JOIN).

```ts title="Method Syntax"
selectPromise.fetch(...fields)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>fields</code> <label label="required" /></td>
            <td><code>string[]</code></td>
            <td>Field names representing relations to fetch.</td>
        </tr>
    </tbody>
</table>

#### Returns
`SelectPromise<T, I, J>` - Chainable promise

#### Examples

```ts title="Fetch Related Records"
const posts = await db.select(new Table('posts'))
    .fetch('author');
// Expands author RecordId to full user object
```

```ts title="Fetch Multiple Relations"
const posts = await db.select(new Table('posts'))
    .fetch('author', 'comments', 'tags');
```

```ts title="Fetch Nested Relations"
const posts = await db.select(new Table('posts'))
    .fetch('author', 'comments.author');
```

---

### `.start()` {#start}

Set the pagination offset (number of records to skip).

```ts title="Method Syntax"
selectPromise.start(start)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>start</code> <label label="required" /></td>
            <td><code>number</code></td>
            <td>Number of records to skip.</td>
        </tr>
    </tbody>
</table>

#### Returns
`SelectPromise<T, I, J>` - Chainable promise

#### Example

```ts title="Pagination"
const page = 2;
const pageSize = 10;

const users = await db.select(new Table('users'))
    .start((page - 1) * pageSize)
    .limit(pageSize);
```

---

### `.limit()` {#limit}

Limit the number of results returned.

```ts title="Method Syntax"
selectPromise.limit(limit)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>limit</code> <label label="required" /></td>
            <td><code>number</code></td>
            <td>Maximum number of records to return.</td>
        </tr>
    </tbody>
</table>

#### Returns
`SelectPromise<T, I, J>` - Chainable promise

#### Example

```ts title="Get Top 10"
const topUsers = await db.select(new Table('users'))
    .where('score > 0')
    .limit(10);
```

---

### `.timeout()` {#timeout}

Set a timeout for the query operation.

```ts title="Method Syntax"
selectPromise.timeout(duration)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>duration</code> <label label="required" /></td>
            <td><code><a href="/docs/reference/javascript/api/values/duration.md">Duration</a></code></td>
            <td>Maximum time to wait for query completion.</td>
        </tr>
    </tbody>
</table>

#### Returns
`SelectPromise<T, I, J>` - Chainable promise

#### Example

```ts
const users = await db.select(new Table('users'))
    .timeout(Duration.parse('5s'));
```

---

### `.version()` {#version}

Select records at a specific version/timestamp (time-travel queries).

```ts title="Method Syntax"
selectPromise.version(timestamp)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>timestamp</code> <label label="required" /></td>
            <td><code><a href="/docs/reference/javascript/api/values/datetime.md">DateTime</a></code></td>
            <td>The timestamp to query at.</td>
        </tr>
    </tbody>
</table>

#### Returns
`SelectPromise<T, I, J>` - Chainable promise

#### Example

```ts title="Query Historical Data"
const historicalUsers = await db.select(new Table('users'))
    .version(DateTime.parse('2024-01-01T00:00:00Z'));
```

---

### `.json()` {#json}

Return results as JSON strings instead of parsed objects.

```ts title="Method Syntax"
selectPromise.json()
```

#### Returns
`SelectPromise<T, I, true>` - Promise returning JSON string

#### Example

```ts
const jsonString = await db.select(new Table('users')).json();
console.log(typeof jsonString); // 'string'
```

---

### `.compile()` {#compile}

Compile the query into a `BoundQuery` without executing it.

```ts title="Method Syntax"
selectPromise.compile()
```

#### Returns
`BoundQuery<[T]>` - The compiled query

#### Example

```ts
const query = db.select(new Table('users'))
    .where('age >= 18')
    .compile();
```

---

### `.stream()` {#stream}

Stream results as they arrive instead of waiting for all results.

```ts title="Method Syntax"
selectPromise.stream()
```

#### Returns
`AsyncIterableIterator` - Async iterator for streaming results

#### Example

```ts
for await (const user of db.select(new Table('users')).stream()) {
    console.log('Received user:', user);
}
```

## Complete examples

### Basic selection

```ts
import { Surreal, Table } from 'surrealdb';

const db = new Surreal();
await db.connect('ws://localhost:8000');

// Select all
const allUsers = await db.select(new Table('users'));

// Select specific record
const user = await db.select(new RecordId('users', 'john'));
```

### Filtered selection

```ts
const activeAdults = await db.select(new Table('users'))
    .where('age >= 18 AND status = "active"')
    .fields('name', 'email', 'age');
```

### Paginated selection

```ts
function getPage(page: number, pageSize: number) {
    return db.select(new Table('users'))
        .start((page - 1) * pageSize)
        .limit(pageSize);
}

const page1 = await getPage(1, 20);
const page2 = await getPage(2, 20);
```

### Complex query with relations

```ts
const posts = await db.select(new Table('posts'))
    .where('published = true')
    .fields('title', 'content', 'author', 'created_at')
    .fetch('author', 'comments.author')
    .limit(10);

// posts[0].author is now a full User object
// posts[0].comments[0].author is also expanded
```

### Aggregation

```ts
import { expr, gte } from 'surrealdb';

const stats = await db.select(new Table('orders'))
    .where(expr(gte('created_at', DateTime.parse('2024-01-01'))))
    .fields('count() as total_orders', 'sum(amount) as total_revenue', 'avg(amount) as avg_order');
```

### Streaming large results

```ts
let count = 0;
for await (const user of db.select(new Table('users')).stream()) {
    await processUser(user);
    count++;
    if (count % 100 === 0) {
        console.log(`Processed ${count} users`);
    }
}
```

## Chaining pattern

All configuration methods return a new `SelectPromise`, allowing you to chain them in any order:

```ts
const result = await db.select(new Table('users'))
    .where('status = "active"')
    .fields('name', 'email')
    .fetch('profile')
    .start(0)
    .limit(10)
    .timeout(Duration.parse('5s'));
```

## See also

- [SurrealQueryable.select()](/docs/reference/javascript/api/core/surreal-queryable.md#select) - Method that returns SelectPromise
- [Query overview](/docs/reference/javascript/api/queries/) - All query builder classes
- [Expression builders](/docs/reference/javascript/api/utilities/expr.md) - Building complex conditions
