/** @module @airtable/blocks/models: RecordQueryResult */ /** */
import { Color } from "../colors";
import Sdk from "../sdk";
import { RecordId } from "../types/record";
import { FieldId } from "../types/field";
import { ObjectValues, ObjectMap, FlowAnyFunction, FlowAnyObject } from "../private_utils";
import { NormalizedGroupLevel } from "../types/airtable_interface";
import AbstractModelWithAsyncData from "./abstract_model_with_async_data";
import Table from "./table";
import Field from "./field";
import Record from "./record";
import RecordStore from "./record_store";
import { RecordColorMode } from "./record_coloring";
declare const WatchableRecordQueryResultKeys: Readonly<{
    records: "records";
    recordIds: "recordIds";
    cellValues: "cellValues";
    recordColors: "recordColors";
    groups: "groups";
    groupLevels: "groupLevels";
    isDataLoaded: "isDataLoaded";
}>;
/**
 * A key in {@link RecordQueryResult} that can be watched
 * - `records`
 * - `recordIds`
 * - `cellValues`
 * - `recordColors`
 * - `isDataLoaded`
 * - `cellValuesInField:{FIELD_ID}`
 */
export declare type WatchableRecordQueryResultKey = ObjectValues<typeof WatchableRecordQueryResultKeys> | string;
/** */
interface SortConfig {
    /** A field, field id, or field name. */
    field: Field | FieldId | string;
    /** The order to sort in. Defaults to asc. */
    direction?: "asc" | "desc";
}
/** @hidden */
export interface NormalizedSortConfig {
    fieldId: string;
    direction: "asc" | "desc";
}
/**
 * NormalizedGroupLevel is in airtable_interface
 *
 * @hidden
 */
export interface GroupLevelForUpdate {
    /** A field, field id, or field name. */
    field: Field | FieldId | string;
    /** The order to sort this group in. Defaults to asc. */
    direction?: "asc" | "desc" | undefined;
}
/**
 * View Config that can be set by developer
 *
 * @hidden
 */
export interface ViewMetadataForUpdate {
    /** Groups config that can be set by developer; null will clear it, undefined will skip it*/
    groupLevels?: Array<GroupLevelForUpdate> | null | undefined;
}
/**
 * Used to control what data is loaded in a {@link RecordQueryResult}. Used when creating a
 * query result using `table/view.selectRecords()` and in convenience hooks {@link useRecords}.
 *
 * ## sorts
 * Pass an array of sorts to control the order of records. The first sort in the array has the
 * highest priority. If you don't specify sorts, the result will use the inherent order of the
 * source model: the same order you'd see in the main UI for views and linked record fields, and
 * an arbitrary (but stable) order for tables.
 *
 * Record creation time is used as a tiebreaker: pass an empty array to sort by creation time.
 *
 * ```js
 * const opts = {
 *     sorts: [
 *         // sort by someField in ascending order...
 *         {field: someField},
 *         // then by someOtherField in descending order
 *         {field: someOtherField, direction: 'desc'},
 *     ]
 * };
 * const records = useRecords(table, opts);
 * const queryResult = table.selectRecords(opts);
 * ```
 *
 * ## fields
 * Generally, it's a good idea to load as little data into your app as possible - Airtable bases
 * can get pretty big, and we have to keep all that information in memory and up to date if you ask
 * for it. The fields option lets you make sure that only data relevant to you is loaded.
 *
 * You can specify fields with a {@link Field}, by ID, or by name:
 * ```js
 * const opts = {
 *     fields: [
 *         // we want to only load fieldA:
 *         fieldA,
 *         // the field with this id:
 *         'fldXXXXXXXXXXXXXX',
 *         // and the field named 'Rating':
 *         'Rating',
 *     ],
 * };
 * const records = useRecords(table, opts);
 * const queryResult = table.selectRecords(opts);
 * ```
 *
 * ## recordColorMode
 * Just like a view in Airtable, you can control the colors of records in a field. There are three
 * supported record color modes: none, by a view, and by a select field.
 *
 * ```js
 * import {recordColoring} from '@airtable/blocks/models';
 * // No record coloring:
 * const opts = {
 *     recordColorMode: recordColoring.modes.none(),
 * };
 *
 * // Color according to the rules of a view:
 * const opts = {
 *     recordColorMode: recordColoring.modes.byView(someView),
 * };
 *
 * // Color by a single select field:
 * const opts = {
 *     recordColorMode: recordColoring.modes.bySelectField(someSelectField),
 * });
 * ```
 *
 * You can access view coloring information directly from a {@link RecordQueryResult} or a
 * {@link Record}, but you can only directly access single select coloring from a RecordQueryResult:
 *
 * ```
 * const queryResult = table.selectRecords(opts);
 * const records = useRecords(table, opts);
 *
 * // Returns based on opts coloring mode
 * queryResult.getRecordColor(recordId);
 *
 * // Returns based on view
 * // Will throw if you did not pass recordColoring.modes.byView(view) in opts
 * records[0].getColorInView(view);
 * ```
 *
 * Use `record.getCellValue(singleSelectField).color` to access the color of a single select field
 * for a record.
 *
 * By default, views will have whichever coloring is set up in Airtable and tables won't have any
 * record coloring:
 *
 * ```js
 * // these two are the same:
 * someView.selectRecords();
 * someView.selectRecords({
 *     recordColorMode: recordColoring.modes.byView(someView),
 * });
 *
 * // as are these two:
 * someTable.selectRecords();
 * someTable.selectRecords({
 *     recordColorMode: recordColoring.modes.none(),
 * });
 * ```
 *
 * */
export interface RecordQueryResultOpts {
    /** The order in which to sort the query result */
    sorts?: Array<SortConfig>;
    /** The fields (or field names or field ids) to load. Falsey values will be removed. */
    fields?: Array<Field | FieldId | string | void | null | false>;
    /** How records in this QueryResult should be colored. */
    recordColorMode?: null | RecordColorMode;
}
/**
 * A subset of {@link RecordQueryResultOpts} used in {@link useRecordById} that omits sorts, as
 * there is only a single record.
 *
 * See RecordQueryResultOpts for full details and examples.
 *
 * ```js
 * const opts = {
 *     fields: ['My field'],
 *     recordColorMode: recordColoring.modes.byView(view),
 * };
 * const record = useRecordById(table, recordId, opts);
 * */
export declare type SingleRecordQueryResultOpts = Pick<RecordQueryResultOpts, "fields" | "recordColorMode">;
/**
 * A subset of {@link RecordQueryResultOpts} used in {@link useRecordIds} that omits fields and
 * recordColorMode, as record cell values and color are not accessible via this hook.
 *
 * See RecordQueryResultOpts for full details and examples.
 *
 * ```js
 * const opts = {
 *     sorts: [
 *         // sort by someField in ascending order...
 *         {field: someField},
 *         // then by someOtherField in descending order
 *         {field: someOtherField, direction: 'desc'},
 *     ]
 * };
 * const recordIds = useRecordIds(table, opts);
 * */
export declare type RecordIdQueryResultOpts = Pick<RecordQueryResultOpts, "sorts">;
/** @internal */
export interface NormalizedRecordQueryResultOpts {
    sorts: Array<NormalizedSortConfig> | null;
    fieldIdsOrNullIfAllFields: Array<string> | null;
    recordColorMode: RecordColorMode;
    table: Table;
    recordStore: RecordStore;
}
/**
 * @internal
 */
export declare function normalizeSortsOrGroups(table: Table, sortsOrGroups: Array<SortConfig | GroupLevelForUpdate> | null | undefined): Array<NormalizedGroupLevel | NormalizedSortConfig> | null | undefined;
/**
 * A RecordQueryResult represents a set of records. It's a little bit like a one-off View in Airtable: it
 * contains a bunch of records, filtered to a useful subset of the records in the table. Those
 * records can be sorted according to your specification, and they can be colored by a select field
 * or using the color from a view. Just like a view, you can either have all the fields in a table
 * available, or you can just ask for the fields that are relevant to you. There are two types of
 * QueryResult:
 *
 * - {@link TableOrViewQueryResult} is the most common, and is a query result filtered to all the
 *   records in a specific {@link Table} or {@link View}. You can get one of these with
 *   `table.selectRecords()` or `view.selectRecords()`.
 * - {@link LinkedRecordsQueryResult} is a query result of all the records in a particular
 *   [linked record cell](https://support.airtable.com/hc/en-us/articles/206452848-Linked-record-fields).
 *   You can get one of these with `record.selectLinkedRecordsFromCell(someField)`.
 *
 * Once you've got a query result, you need to load it before you can start working with it -
 * apps don't load record data by default. We recommend using {@link useRecords},
 * {@link useRecordIds}, {@link useRecordById} or {@link useLoadable} to handle this.
 *
 * If you're not using a query result in a React component, you can manually load the data and
 * unload it when you're finished:
 *
 * ```js
 * async function fetchRecordsAndDoSomethingAsync(myTable) {
 *     // query for all the records in "myTable"
 *     const queryResult = myTable.selectRecords();
 *
 *     // load the data in the query result:
 *     await queryResult.loadDataAsync();
 *
 *     // work with the data in the query result
 *     doSomething(queryResult);
 *
 *     // when you're done, unload the data:
 *     queryResult.unloadData();
 * }
 * ```
 *
 * Whilst loaded, a query result will automatically keep up to date with what's in Airtable:
 * records will get added or removed, the order will change, cell values will be updated, etc.
 * Again, if you're writing a React component then our hooks will look after that for you. If not,
 * you can get notified of these changes with `.watch()`.
 *
 * When calling a `.select*` method, you can pass in a number of options to control the sort order,
 * fields loaded and coloring mode of records: see {@link RecordQueryResultOpts} for examples.
 *
 * @docsPath models/query results/RecordQueryResult
 */
declare abstract class RecordQueryResult<DataType = {}> extends AbstractModelWithAsyncData<DataType, WatchableRecordQueryResultKey> {
    /** @internal */
    static _className: string;
    /**
     * The record IDs in this QueryResult.
     * Throws if data is not loaded yet.
     * Can be watched.
     */
    abstract get recordIds(): Array<RecordId>;
    /**
     * The set of record IDs in this QueryResult.
     * Throws if data is not loaded yet.
     *
     * @internal
     */
    abstract _getOrGenerateRecordIdsSet(): ObjectMap<RecordId, true | void>;
    /**
     * The fields that were used to create this QueryResult.
     * Null if fields were not specified, which means the QueryResult
     * will load all fields in the table.
     */
    abstract get fields(): Array<Field> | null;
    /**
     * @internal (since we may not be able to return parent model instances in the immutable models world)
     * The table that records in this QueryResult are part of
     */
    abstract get parentTable(): Table;
    /** @internal */
    static WatchableKeys: Readonly<{
        records: "records";
        recordIds: "recordIds";
        cellValues: "cellValues";
        recordColors: "recordColors";
        groups: "groups";
        groupLevels: "groupLevels";
        isDataLoaded: "isDataLoaded";
    }>;
    /** @internal */
    static WatchableCellValuesInFieldKeyPrefix: string;
    /** @internal */
    static _isWatchableKey(key: string): boolean;
    /** @internal */
    static _shouldLoadDataForKey(key: WatchableRecordQueryResultKey): boolean;
    /** @internal */
    static _normalizeOpts(table: Table, recordStore: RecordStore, opts: RecordQueryResultOpts): NormalizedRecordQueryResultOpts;
    /** @internal */
    _normalizedOpts: NormalizedRecordQueryResultOpts;
    /** @internal */
    _recordStore: RecordStore;
    /** @internal */
    _recordColorChangeHandler: FlowAnyFunction | null;
    /**
     * @internal
     */
    constructor(sdk: Sdk, normalizedOpts: NormalizedRecordQueryResultOpts);
    /**
     * @internal
     */
    get _serializedOpts(): string;
    /**
     * The records in this RecordQueryResult.
     * Throws if data is not loaded yet.
     * Can be watched.
     */
    get records(): Array<Record>;
    /**
     * Get a specific record in the query result, or null if that record doesn't exist or is
     * filtered out. Throws if data is not loaded yet. Watch using `'recordIds'`.
     *
     * @param recordId the ID of the {@link Record} you want
     */
    getRecordByIdIfExists(recordId: RecordId): Record | null;
    /**
     * Get a specific record in the query result, or throws if that record doesn't exist or is
     * filtered out. Throws if data is not loaded yet. Watch using `'recordIds'`.
     *
     * @param recordId the ID of the {@link Record} you want
     */
    getRecordById(recordId: RecordId): Record;
    /**
     * @internal
     */
    _getRecord(recordOrRecordId: RecordId | Record): Record;
    /**
     * Check to see if a particular record or record id is present in this query result. Returns
     * false if the record has been deleted or is filtered out.
     *
     * @param recordOrRecordId the record or record id to check the presence of
     */
    hasRecord(recordOrRecordId: RecordId | Record): boolean;
    /**
     * Get the {@link Color} of a specific record in the query result. Returns null if the record
     * has no color in this query result. Throws if the record isn't in the RecordQueryResult. Watch
     * with the `'recordColors'` and `'recordIds` keys.
     *
     * @param recordOrRecordId the record or record ID you want the color of.
     */
    getRecordColor(recordOrRecordId: RecordId | Record): Color | null;
    /**
     * @internal
     */
    _onChangeIsDataLoaded(): void;
    /**
     * Get notified of changes to the query result.
     *
     * Watchable keys are:
     * - `'records'`
     * - `'recordIds'`
     * - `'cellValues'`
     * - `'recordColors'`
     * - `'isDataLoaded'`
     * - `'cellValuesInField:' + someFieldId`
     *
     * Every call to `.watch` should have a matching call to `.unwatch`.
     *
     * Watching a key that needs to load data asynchronously will automatically
     * cause the data to be fetched. Once the data is available, the `callback`
     * will be called.
     *
     * Returns the array of keys that were watched.
     *
     * @param keys the keys to watch
     * @param callback a function to call when those keys change
     * @param context an optional context for `this` in `callback`.
     */
    watch(keys: WatchableRecordQueryResultKey | ReadonlyArray<WatchableRecordQueryResultKey>, callback: FlowAnyFunction, context?: FlowAnyObject | null): Array<WatchableRecordQueryResultKey>;
    /**
     * Unwatch keys watched with `.watch`.
     *
     * Should be called with the same arguments given to `.watch`.
     *
     * Unwatching a key that needs to load data asynchronously will automatically
     * cause the data to be unloaded.
     *
     * Returns the array of keys that were unwatched
     *
     * @param keys the keys to unwatch
     * @param callback the function passed to `.watch` for these keys
     * @param context the context that was passed to `.watch` for this `callback`
     */
    unwatch(keys: WatchableRecordQueryResultKey | ReadonlyArray<WatchableRecordQueryResultKey>, callback: FlowAnyFunction, context?: FlowAnyObject | null): Array<WatchableRecordQueryResultKey>;
    /**
     * @internal
     */
    _watchRecordColorsIfNeeded(): void;
    /**
     * @internal
     */
    _watchRecordColors(): void;
    /**
     * @internal
     */
    _unwatchRecordColorsIfPossible(): void;
    /**
     * @internal
     */
    _unwatchRecordColors(): void;
    /**
     * @internal
     */
    _loadRecordColorsAsync(): Promise<void>;
    /**
     * @internal
     */
    _unloadRecordColors(): void;
}
export default RecordQueryResult;
