UNPKG

@types/ember-data

Version:
1,207 lines (1,191 loc) 84.5 kB
import EmberError from "@ember/error"; import Evented from "@ember/object/evented"; import PromiseProxyMixin from "@ember/object/promise-proxy-mixin"; import ObjectProxy from "@ember/object/proxy"; import Ember from "ember"; import AdapterRegistry from "ember-data/types/registries/adapter"; import ModelRegistry from "ember-data/types/registries/model"; import SerializerRegistry from "ember-data/types/registries/serializer"; import TransformRegistry from "ember-data/types/registries/transform"; import RSVP from "rsvp"; /** The keys from the actual Model class, removing all the keys which come from the base class. */ type ModelKeys<Model extends DS.Model> = Exclude<keyof Model, keyof DS.Model>; type AttributesFor<Model extends DS.Model> = ModelKeys<Model>; // TODO: filter to attr properties only (TS 2.8) type RelationshipsFor<Model extends DS.Model> = ModelKeys<Model>; // TODO: filter to hasMany/belongsTo properties only (TS 2.8) export interface ChangedAttributes { [key: string]: [any, any] | undefined; } interface AttributeMeta<Model extends DS.Model> { type: keyof TransformRegistry; options: object; name: AttributesFor<Model>; parentType: Model; isAttribute: true; } interface RelationshipMetaOptions { async?: boolean | undefined; inverse?: string | undefined; polymorphic?: boolean | undefined; [k: string]: any; } interface RelationshipMeta<Model extends DS.Model> { key: RelationshipsFor<Model>; kind: "belongsTo" | "hasMany"; type: keyof ModelRegistry; options: RelationshipMetaOptions; name: string; parentType: Model; isRelationship: true; } export interface ModelSchema<ModelName extends keyof ModelRegistry = keyof ModelRegistry> { modelName: ModelName; fields: Map<string, "attribute" | "belongsTo" | "hasMany">; attributes: Map<string, AttributeSchema>; relationshipsByName: Map<string, RelationshipSchema>; eachAttribute<T>(callback: (this: T, key: string, attribute: AttributeSchema) => void, binding?: T): void; eachRelationship<T>(callback: (this: T, key: string, relationship: RelationshipSchema) => void, binding?: T): void; eachTransformedAttribute<T>( callback: (this: T, key: string, relationship: RelationshipSchema) => void, binding?: T, ): void; } export interface RelationshipSchema { name: string; // property key for this relationship kind: "belongsTo" | "hasMany"; type: string; // related type options: { async: boolean; polymorphic?: boolean; as?: string; inverse: string | null; // property key on the related type (if any) [key: string]: unknown; }; } export interface AttributeSchema { name: string; kind?: "attribute"; options?: Record<string, unknown>; type?: string; } export namespace DS { /** * Convert an hash of errors into an array with errors in JSON-API format. */ function errorsHashToArray(errors: {}): any[]; /** * Convert an array of errors in JSON-API format into an object. */ function errorsArrayToHash(errors: any[]): {}; interface RelationshipOptions<M extends Model> { async?: boolean | undefined; inverse?: RelationshipsFor<M> | null | undefined; polymorphic?: boolean | undefined; as?: string; [key: string]: unknown; } interface Sync { async: false; } interface Async { async?: true | undefined; } type AsyncBelongsTo<T extends Model | null> = PromiseObject<T>; /** * `DS.belongsTo` is used to define One-To-One and One-To-Many * relationships on a [DS.Model](/api/data/classes/DS.Model.html). */ function belongsTo<K extends keyof ModelRegistry>( modelName: K, options: RelationshipOptions<ModelRegistry[K]> & Sync, ): Ember.ComputedProperty< ModelRegistry[K] | null, ModelRegistry[K] | PromiseObject<ModelRegistry[K] | null> | null >; function belongsTo<K extends keyof ModelRegistry>( modelName: K, options?: RelationshipOptions<ModelRegistry[K]> & Async, ): Ember.ComputedProperty< AsyncBelongsTo<ModelRegistry[K] | null>, ModelRegistry[K] | PromiseObject<ModelRegistry[K] | null> | null >; type AsyncHasMany<T extends Model> = PromiseManyArray<T>; type SyncHasMany<T extends Model> = ManyArray<T>; /** * `DS.hasMany` is used to define One-To-Many and Many-To-Many * relationships on a [DS.Model](/api/data/classes/DS.Model.html). */ function hasMany<K extends keyof ModelRegistry>( type: K, options: RelationshipOptions<ModelRegistry[K]> & Sync, ): Ember.ComputedProperty<SyncHasMany<ModelRegistry[K]>>; function hasMany<K extends keyof ModelRegistry>( type: K, options?: RelationshipOptions<ModelRegistry[K]> & Async, ): Ember.ComputedProperty<AsyncHasMany<ModelRegistry[K]>, Ember.Array<ModelRegistry[K]>>; /** * This method normalizes a modelName into the format Ember Data uses * internally. */ function normalizeModelName<K extends keyof ModelRegistry>(modelName: K): string; const VERSION: string; interface AttrOptions<T> { defaultValue?: T extends Exclude<object, null> ? () => T : T | (() => T) | null | undefined; allowNull?: boolean | undefined; // TODO: restrict to boolean transform (TS 2.8) [key: string]: unknown; } // The TransformRegistry should really only contain transforms, but historically people have just put the return type directly in. type TransformType<K extends keyof TransformRegistry> = TransformRegistry[K] extends Transform ? ReturnType<TransformRegistry[K]["deserialize"]> : TransformRegistry[K]; /** * `DS.attr` defines an attribute on a [DS.Model](/api/data/classes/DS.Model.html). * By default, attributes are passed through as-is, however you can specify an * optional type to have the value automatically transformed. * Ember Data ships with four basic transform types: `string`, `number`, * `boolean` and `date`. You can define your own transforms by subclassing * [DS.Transform](/api/data/classes/DS.Transform.html). */ function attr<K extends keyof TransformRegistry>( type: K, options?: AttrOptions<TransformType<K>>, ): Ember.ComputedProperty<TransformType<K>>; function attr(options?: AttrOptions<any>): Ember.ComputedProperty<any>; function attr(target: any, propertyKey: string): void; /** * WARNING: This interface is likely to change in order to accomodate https://github.com/emberjs/rfcs/pull/4 * ## Using BuildURLMixin * To use url building, include the mixin when extending an adapter, and call `buildURL` where needed. * The default behaviour is designed for RESTAdapter. * ### Example * ```javascript * export default DS.Adapter.extend(BuildURLMixin, { * findRecord: function(store, type, id, snapshot) { * var url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); * return this.ajax(url, 'GET'); * } * }); * ``` * ### Attributes * The `host` and `namespace` attributes will be used if defined, and are optional. */ class BuildURLMixin { /** * Builds a URL for a given type and optional ID. */ buildURL<K extends keyof ModelRegistry>( modelName?: K, id?: string | any[] | {} | null, snapshot?: Snapshot<K> | any[] | null, requestType?: string, query?: {}, ): string; /** * Used by `findAll` and `findRecord` to build the query's `data` hash supplied to the ajax method. */ buildQuery<K extends keyof ModelRegistry>(snapshot: Snapshot<K>): Record<string, unknown>; /** * Builds a URL for a `store.findRecord(type, id)` call. */ urlForFindRecord<K extends keyof ModelRegistry>(id: string, modelName: K, snapshot: Snapshot<K>): string; /** * Builds a URL for a `store.findAll(type)` call. */ urlForFindAll<K extends keyof ModelRegistry>(modelName: K, snapshot: SnapshotRecordArray<K>): string; /** * Builds a URL for a `store.query(type, query)` call. */ urlForQuery<K extends keyof ModelRegistry>(query: {}, modelName: K): string; /** * Builds a URL for a `store.queryRecord(type, query)` call. */ urlForQueryRecord<K extends keyof ModelRegistry>(query: {}, modelName: K): string; /** * Builds a URL for coalesceing multiple `store.findRecord(type, id)` * records into 1 request when the adapter's `coalesceFindRequests` * property is true. */ urlForFindMany<K extends keyof ModelRegistry>(ids: any[], modelName: K, snapshots: any[]): string; /** * Builds a URL for fetching a async hasMany relationship when a url * is not provided by the server. */ urlForFindHasMany<K extends keyof ModelRegistry>(id: string, modelName: K, snapshot: Snapshot<K>): string; /** * Builds a URL for fetching a async belongsTo relationship when a url * is not provided by the server. */ urlForFindBelongsTo<K extends keyof ModelRegistry>(id: string, modelName: K, snapshot: Snapshot<K>): string; /** * Builds a URL for a `record.save()` call when the record was created * locally using `store.createRecord()`. */ urlForCreateRecord<K extends keyof ModelRegistry>(modelName: K, snapshot: Snapshot<K>): string; /** * Builds a URL for a `record.save()` call when the record has been update locally. */ urlForUpdateRecord<K extends keyof ModelRegistry>(id: string, modelName: K, snapshot: Snapshot<K>): string; /** * Builds a URL for a `record.save()` call when the record has been deleted locally. */ urlForDeleteRecord<K extends keyof ModelRegistry>(id: string, modelName: K, snapshot: Snapshot<K>): string; /** * Determines the pathname for a given type. */ pathForType<K extends keyof ModelRegistry>(modelName: K): string; } /** * A `DS.AdapterError` is used by an adapter to signal that an error occurred * during a request to an external API. It indicates a generic error, and * subclasses are used to indicate specific error states. The following * subclasses are provided: */ class AdapterError extends EmberError { static extend(options?: { message?: string }): typeof AdapterError; } /** * A `DS.InvalidError` is used by an adapter to signal the external API * was unable to process a request because the content was not * semantically correct or meaningful per the API. Usually this means a * record failed some form of server side validation. When a promise * from an adapter is rejected with a `DS.InvalidError` the record will * transition to the `invalid` state and the errors will be set to the * `errors` property on the record. */ class InvalidError extends AdapterError { constructor(errors: any[]); } /** * A `DS.TimeoutError` is used by an adapter to signal that a request * to the external API has timed out. I.e. no response was received from * the external API within an allowed time period. */ class TimeoutError extends AdapterError {} /** * A `DS.AbortError` is used by an adapter to signal that a request to * the external API was aborted. For example, this can occur if the user * navigates away from the current page after a request to the external API * has been initiated but before a response has been received. */ class AbortError extends AdapterError {} /** * A `DS.UnauthorizedError` equates to a HTTP `401 Unauthorized` response * status. It is used by an adapter to signal that a request to the external * API was rejected because authorization is required and has failed or has not * yet been provided. */ class UnauthorizedError extends AdapterError {} /** * A `DS.ForbiddenError` equates to a HTTP `403 Forbidden` response status. * It is used by an adapter to signal that a request to the external API was * valid but the server is refusing to respond to it. If authorization was * provided and is valid, then the authenticated user does not have the * necessary permissions for the request. */ class ForbiddenError extends AdapterError {} /** * A `DS.NotFoundError` equates to a HTTP `404 Not Found` response status. * It is used by an adapter to signal that a request to the external API * was rejected because the resource could not be found on the API. */ class NotFoundError extends AdapterError {} /** * A `DS.ConflictError` equates to a HTTP `409 Conflict` response status. * It is used by an adapter to indicate that the request could not be processed * because of a conflict in the request. An example scenario would be when * creating a record with a client generated id but that id is already known * to the external API. */ class ConflictError extends AdapterError {} /** * A `DS.ServerError` equates to a HTTP `500 Internal Server Error` response * status. It is used by the adapter to indicate that a request has failed * because of an error in the external API. */ class ServerError extends AdapterError {} /** * Holds validation errors for a given record, organized by attribute names. */ interface Errors extends Ember.Enumerable<any>, Evented {} class Errors extends Ember.ArrayProxy<any> { /** * DEPRECATED: * Register with target handler */ registerHandlers(target: {}, becameInvalid: Function, becameValid: Function): any; /** * Returns errors for a given attribute */ errorsFor(attribute: string): any[]; /** * An array containing all of the error messages for this * record. This is useful for displaying all errors to the user. */ messages: Ember.ComputedProperty<any[]>; /** * Total number of errors. */ length: Ember.ComputedProperty<number>; isEmpty: Ember.ComputedProperty<boolean>; /** * DEPRECATED: * Adds error messages to a given attribute and sends * `becameInvalid` event to the record. */ add(attribute: string, messages: any[] | string): any; /** * DEPRECATED: * Removes all error messages from the given attribute and sends * `becameValid` event to the record if there no more errors left. */ remove(attribute: string): any; /** * DEPRECATED: * Removes all error messages and sends `becameValid` event * to the record. */ clear(): any; /** * Checks if there is error messages for the given attribute. */ has(attribute: string): boolean; } /** * The model class that all Ember Data records descend from. * This is the public API of Ember Data models. If you are using Ember Data * in your application, this is the class you should use. * If you are working on Ember Data internals, you most likely want to be dealing * with `InternalModel` */ class Model extends Ember.Object { /** * If this property is `true` the record is in the `empty` * state. Empty is the first state all records enter after they have * been created. Most records created by the store will quickly * transition to the `loading` state if data needs to be fetched from * the server or the `created` state if the record is created on the * client. A record can also enter the empty state if the adapter is * unable to locate the record. */ isEmpty: Ember.ComputedProperty<boolean>; /** * If this property is `true` the record is in the `loading` state. A * record enters this state when the store asks the adapter for its * data. It remains in this state until the adapter provides the * requested data. */ isLoading: Ember.ComputedProperty<boolean>; /** * If this property is `true` the record is in the `loaded` state. A * record enters this state when its data is populated. Most of a * record's lifecycle is spent inside substates of the `loaded` * state. */ isLoaded: Ember.ComputedProperty<boolean>; /** * If this property is `true` the record is in the `dirty` state. The * record has local changes that have not yet been saved by the * adapter. This includes records that have been created (but not yet * saved) or deleted. */ hasDirtyAttributes: Ember.ComputedProperty<boolean>; /** * If this property is `true` the record is in the `saving` state. A * record enters the saving state when `save` is called, but the * adapter has not yet acknowledged that the changes have been * persisted to the backend. */ isSaving: Ember.ComputedProperty<boolean>; /** * If this property is `true` the record is in the `deleted` state * and has been marked for deletion. When `isDeleted` is true and * `hasDirtyAttributes` is true, the record is deleted locally but the deletion * was not yet persisted. When `isSaving` is true, the change is * in-flight. When both `hasDirtyAttributes` and `isSaving` are false, the * change has persisted. */ isDeleted: Ember.ComputedProperty<boolean>; /** * If this property is `true` the record is in the `new` state. A * record will be in the `new` state when it has been created on the * client and the adapter has not yet report that it was successfully * saved. */ isNew: Ember.ComputedProperty<boolean>; /** * If this property is `true` the record is in the `valid` state. */ isValid: Ember.ComputedProperty<boolean>; /** * If the record is in the dirty state this property will report what * kind of change has caused it to move into the dirty * state. Possible values are: */ dirtyType: Ember.ComputedProperty<string>; /** * If `true` the adapter reported that it was unable to save local * changes to the backend for any reason other than a server-side * validation error. */ isError: boolean; /** * If `true` the store is attempting to reload the record from the adapter. */ isReloading: boolean; /** * All ember models have an id property. This is an identifier * managed by an external source. These are always coerced to be * strings before being used internally. Note when declaring the * attributes for a model it is an error to declare an id * attribute. */ id: string; /** * A reference to DS.Store service instance. */ store: Store; /** * When the record is in the `invalid` state this object will contain * any errors returned by the adapter. When present the errors hash * contains keys corresponding to the invalid property names * and values which are arrays of Javascript objects with two keys: */ errors: Errors; /** * This property holds the `DS.AdapterError` object with which * last adapter operation was rejected. */ adapterError: AdapterError; /** * Create a JSON representation of the record, using the serialization * strategy of the store's adapter. */ serialize(options?: { includeId?: boolean | undefined }): object; /** * Use [DS.JSONSerializer](DS.JSONSerializer.html) to * get the JSON representation of a record. */ toJSON(options?: { includeId?: boolean | undefined }): object; /** * Fired when the record is ready to be interacted with, * that is either loaded from the server or created locally. */ ready(): void; /** * Fired when the record is loaded from the server. */ didLoad(): void; /** * Fired when the record is updated. */ didUpdate(): void; /** * Fired when a new record is commited to the server. */ didCreate(): void; /** * Fired when the record is deleted. */ didDelete(): void; /** * Fired when the record becomes invalid. */ becameInvalid(): void; /** * Fired when the record enters the error state. */ becameError(): void; /** * Fired when the record is rolled back. */ rolledBack(): void; /** * Marks the record as deleted but does not save it. You must call * `save` afterwards if you want to persist it. You might use this * method if you want to allow the user to still `rollbackAttributes()` * after a delete was made. */ deleteRecord(): void; /** * Same as `deleteRecord`, but saves the record immediately. */ destroyRecord(options?: { adapterOptions?: object | undefined }): RSVP.Promise<this>; /** * Unloads the record from the store. This will cause the record to be destroyed and freed up for garbage collection. */ unloadRecord(): void; /** * Returns an object, whose keys are changed properties, and value is * an [oldProp, newProp] array. */ changedAttributes(): ChangedAttributes; /** * If the model `hasDirtyAttributes` this function will discard any unsaved * changes. If the model `isNew` it will be removed from the store. */ rollbackAttributes(): void; /** * Save the record and persist any changes to the record to an * external source via the adapter. */ save(options?: { adapterOptions?: object | undefined }): RSVP.Promise<this>; /** * Reload the record from the adapter. */ reload(options?: { adapterOptions?: object | undefined }): RSVP.Promise<this>; /** * Get the reference for the specified belongsTo relationship. */ belongsTo(name: RelationshipsFor<this>): BelongsToReference; /** * Get the reference for the specified hasMany relationship. */ hasMany(name: RelationshipsFor<this>): HasManyReference<any>; /** * Given a callback, iterates over each of the relationships in the model, * invoking the callback with the name of each relationship and its relationship * descriptor. */ eachRelationship<T extends Model>( this: T, callback: (name: ModelKeys<T>, details: RelationshipMeta<T>) => void, binding?: any, ): void; /** * Represents the model's class name as a string. This can be used to look up the model's class name through * `DS.Store`'s modelFor method. */ static modelName: keyof ModelRegistry; /** * For a given relationship name, returns the model type of the relationship. */ static typeForRelationship<K extends keyof ModelRegistry>(name: K, store: Store): ModelRegistry[K]; /** * Find the relationship which is the inverse of the one asked for. */ static inverseFor<K extends keyof ModelRegistry>(name: K, store: Store): {}; /** * The model's relationships as a map, keyed on the type of the * relationship. The value of each entry is an array containing a descriptor * for each relationship with that type, describing the name of the relationship * as well as the type. */ static relationships: Ember.ComputedProperty<Map<string, unknown>>; /** * A hash containing lists of the model's relationships, grouped * by the relationship kind. For example, given a model with this * definition: */ static relationshipNames: Ember.ComputedProperty<{}>; /** * An array of types directly related to a model. Each type will be * included once, regardless of the number of relationships it has with * the model. */ static relatedTypes: Ember.ComputedProperty<Ember.NativeArray<string>>; /** * A map whose keys are the relationships of a model and whose values are * relationship descriptors. */ static relationshipsByName: Ember.ComputedProperty<Map<string, unknown>>; /** * A map whose keys are the fields of the model and whose values are strings * describing the kind of the field. A model's fields are the union of all of its * attributes and relationships. */ static fields: Ember.ComputedProperty<Map<string, unknown>>; /** * Given a callback, iterates over each of the relationships in the model, * invoking the callback with the name of each relationship and its relationship * descriptor. */ static eachRelationship<M extends Model = Model>( callback: (name: ModelKeys<M>, details: RelationshipMeta<M>) => void, binding?: any, ): void; /** * Given a callback, iterates over each of the types related to a model, * invoking the callback with the related type's class. Each type will be * returned just once, regardless of how many different relationships it has * with a model. */ static eachRelatedType(callback: (name: string) => void, binding?: any): void; /** * A map whose keys are the attributes of the model (properties * described by DS.attr) and whose values are the meta object for the * property. */ static attributes: Ember.ComputedProperty<Map<string, unknown>>; /** * A map whose keys are the attributes of the model (properties * described by DS.attr) and whose values are type of transformation * applied to each attribute. This map does not include any * attributes that do not have an transformation type. */ static transformedAttributes: Ember.ComputedProperty<Map<string, unknown>>; /** * Iterates through the attributes of the model, calling the passed function on each * attribute. */ static eachAttribute<Class extends typeof Model, M extends InstanceType<Class>>( this: Class, callback: (name: ModelKeys<M>, meta: AttributeMeta<M>) => void, binding?: any, ): void; /** * Iterates through the transformedAttributes of the model, calling * the passed function on each attribute. Note the callback will not be * called for any attributes that do not have an transformation type. */ static eachTransformedAttribute<Class extends typeof Model>( this: Class, callback: (name: ModelKeys<InstanceType<Class>>, type: keyof TransformRegistry) => void, binding?: any, ): void; } /** * ### State */ class RootState {} /** * Represents an ordered list of records whose order and membership is * determined by the adapter. For example, a query sent to the adapter * may trigger a search on the server, whose results would be loaded * into an instance of the `AdapterPopulatedRecordArray`. */ class AdapterPopulatedRecordArray<T> extends RecordArray<T> {} /** * Represents a list of records whose membership is determined by the * store. As records are created, loaded, or modified, the store * evaluates them to determine if they should be part of the record * array. */ class FilteredRecordArray<T> extends RecordArray<T> { /** * The filterFunction is a function used to test records from the store to * determine if they should be part of the record array. */ filterFunction(record: Model): boolean; } /** * A record array is an array that contains records of a certain modelName. The record * array materializes records as needed when they are retrieved for the first * time. You should not create record arrays yourself. Instead, an instance of * `DS.RecordArray` or its subclasses will be returned by your application's store * in response to queries. */ interface RecordArray<T> extends Ember.ArrayProxy<T>, Evented {} class RecordArray<T> { /** * The flag to signal a `RecordArray` is finished loading data. */ isLoaded: boolean; /** * The flag to signal a `RecordArray` is currently loading data. */ isUpdating: boolean; /** * The modelClass represented by this record array. */ type: Ember.ComputedProperty<Model>; /** * Used to get the latest version of all of the records in this array * from the adapter. */ update(): PromiseArray<T>; /** * Saves all of the records in the `RecordArray`. */ save(): PromiseArray<T>; } /** * A BelongsToReference is a low level API that allows users and * addon author to perform meta-operations on a belongs-to * relationship. */ class BelongsToReference { /** * This returns a string that represents how the reference will be * looked up when it is loaded. If the relationship has a link it will * use the "link" otherwise it defaults to "id". */ remoteType(): string; /** * The `id` of the record that this reference refers to. Together, the * `type()` and `id()` methods form a composite key for the identity * map. This can be used to access the id of an async relationship * without triggering a fetch that would normally happen if you * attempted to use `record.get('relationship.id')`. */ id(): string; /** * The link Ember Data will use to fetch or reload this belongs-to * relationship. */ link(): string; /** * The meta data for the belongs-to relationship. */ meta(): {}; /** * `push` can be used to update the data in the relationship and Ember * Data will treat the new data as the conanical value of this * relationship on the backend. */ push(objectOrPromise: {} | RSVP.Promise<any>): RSVP.Promise<any>; /** * `value()` synchronously returns the current value of the belongs-to * relationship. Unlike `record.get('relationshipName')`, calling * `value()` on a reference does not trigger a fetch if the async * relationship is not yet loaded. If the relationship is not loaded * it will always return `null`. */ value(): Model | null; /** * Loads a record in a belongs to relationship if it is not already * loaded. If the relationship is already loaded this method does not * trigger a new load. */ load(): RSVP.Promise<any>; /** * Triggers a reload of the value in this relationship. If the * remoteType is `"link"` Ember Data will use the relationship link to * reload the relationship. Otherwise it will reload the record by its * id. */ reload(): RSVP.Promise<any>; } /** * A HasManyReference is a low level API that allows users and addon * author to perform meta-operations on a has-many relationship. */ class HasManyReference<T> { /** * This returns a string that represents how the reference will be * looked up when it is loaded. If the relationship has a link it will * use the "link" otherwise it defaults to "id". */ remoteType(): string; /** * The link Ember Data will use to fetch or reload this has-many * relationship. */ link(): string; /** * `ids()` returns an array of the record ids in this relationship. */ ids(): string[]; /** * The meta data for the has-many relationship. */ meta(): {}; /** * `push` can be used to update the data in the relationship and Ember * Data will treat the new data as the canonical value of this * relationship on the backend. */ push(objectOrPromise: T[] | RSVP.Promise<T[]>): ManyArray<T>; /** * `value()` synchronously returns the current value of the has-many * relationship. Unlike `record.get('relationshipName')`, calling * `value()` on a reference does not trigger a fetch if the async * relationship is not yet loaded. If the relationship is not loaded * it will always return `null`. */ value(): ManyArray<T> | null; /** * Loads the relationship if it is not already loaded. If the * relationship is already loaded this method does not trigger a new * load. */ load(): RSVP.Promise<any>; /** * Reloads this has-many relationship. */ reload(): RSVP.Promise<any>; } /** * An RecordReference is a low level API that allows users and * addon author to perform meta-operations on a record. */ class RecordReference<T extends Model> { /** * The `id` of the record that this reference refers to. */ id(): string; /** * How the reference will be looked up when it is loaded: Currently * this always return `identity` to signifying that a record will be * loaded by the `type` and `id`. */ remoteType(): string; /** * This API allows you to provide a reference with new data. The * simplest usage of this API is similar to `store.push`: you provide a * normalized hash of data and the object represented by the reference * will update. */ push(payload: RSVP.Promise<any> | {}): PromiseObject<T>; /** * If the entity referred to by the reference is already loaded, it is * present as `reference.value`. Otherwise the value returned by this function * is `null`. */ value(): T | null; /** * Triggers a fetch for the backing entity based on its `remoteType` * (see `remoteType` definitions per reference type). */ load(): PromiseObject<T>; /** * Reloads the record if it is already loaded. If the record is not * loaded it will load the record via `store.findRecord` */ reload(): PromiseObject<T>; } /** * A `ManyArray` is a `MutableArray` that represents the contents of a has-many * relationship. */ // eslint-disable-next-line @typescript-eslint/no-empty-interface -- used for declaration merge interface ManyArray<T> extends Ember.MutableArray<T>, Evented {} class ManyArray<T> extends Ember.Object { /** * The loading state of this array */ isLoaded: boolean; /** * Metadata associated with the request for async hasMany relationships. */ meta: {}; /** * Reloads all of the records in the manyArray. If the manyArray * holds a relationship that was originally fetched using a links url * Ember Data will revisit the original links url to repopulate the * relationship. */ reload(): PromiseArray<T>; /** * Saves all of the records in the `ManyArray`. */ save(): PromiseArray<T>; /** * Create a child record within the owner */ createRecord(inputProperties?: {}): T; } /** * A `PromiseArray` is an object that acts like both an `Ember.Array` * and a promise. When the promise is resolved the resulting value * will be set to the `PromiseArray`'s `content` property. This makes * it easy to create data bindings with the `PromiseArray` that will be * updated when the promise resolves. */ interface PromiseArray<T, ArrayType extends Ember.ArrayProxy<T>["content"] = Ember.Array<T>> extends Ember.ArrayProxy<T>, PromiseProxyMixin<ArrayType> {} class PromiseArray<T> extends Ember.ArrayProxy<T> {} /** * A `PromiseObject` is an object that acts like both an `Ember.Object` * and a promise. When the promise is resolved, then the resulting value * will be set to the `PromiseObject`'s `content` property. This makes * it easy to create data bindings with the `PromiseObject` that will * be updated when the promise resolves. */ interface PromiseObject<T extends object | null> extends PromiseProxyMixin<T> {} class PromiseObject<T> extends ObjectProxy<NonNullable<T>> {} /** * A PromiseManyArray is a PromiseArray that also proxies certain method calls * to the underlying manyArray. * Right now we proxy: */ class PromiseManyArray<T extends Model> extends PromiseArray<T, Ember.ArrayProxy<T>> { /** * Reloads all of the records in the manyArray. If the manyArray * holds a relationship that was originally fetched using a links url * Ember Data will revisit the original links url to repopulate the * relationship. */ reload(): PromiseManyArray<T>; /** * Create a child record within the owner */ createRecord(inputProperties?: {}): T; } class SnapshotRecordArray<K extends keyof ModelRegistry> { /** * Number of records in the array */ length: number; /** * Meta objects for the record array. */ meta: {}; /** * A hash of adapter options passed into the store method for this request. */ adapterOptions: {}; /** * The relationships to include for this request. */ include: string | any[]; /** * The type of the underlying records for the snapshots in the array, as a DS.Model */ type: ModelRegistry[K]; /** * Get snapshots of the underlying record array */ snapshots(): Snapshot[]; } class Snapshot<K extends keyof ModelRegistry = keyof ModelRegistry> { /** * The underlying record for this snapshot. Can be used to access methods and * properties defined on the record. */ record: ModelRegistry[K]; /** * The id of the snapshot's underlying record */ id: string; /** * A hash of adapter options */ adapterOptions: Record<string, unknown>; /** * The name of the type of the underlying record for this snapshot, as a string. */ modelName: K; /** * The type of the underlying record for this snapshot, as a DS.Model. */ type: ModelRegistry[K]; /** * Returns the value of an attribute. */ attr<L extends AttributesFor<ModelRegistry[K]>>(keyName: L): ModelRegistry[K][L]; /** * Returns all attributes and their corresponding values. */ attributes(): { [L in keyof ModelRegistry[K]]: ModelRegistry[K][L] }; /** * Returns all changed attributes and their old and new values. */ changedAttributes(): Partial<{ [L in keyof ModelRegistry[K]]: ModelRegistry[K][L] }>; /** * Returns the current value of a belongsTo relationship. */ belongsTo<L extends RelationshipsFor<ModelRegistry[K]>>(keyName: L, options?: {}): Snapshot | null | undefined; belongsTo<L extends RelationshipsFor<ModelRegistry[K]>>( keyName: L, options: { id: true }, ): string | null | undefined; /** * Returns the current value of a hasMany relationship. */ hasMany<L extends RelationshipsFor<ModelRegistry[K]>>( keyName: L, options?: { ids: false }, ): Snapshot[] | undefined; hasMany<L extends RelationshipsFor<ModelRegistry[K]>>(keyName: L, options: { ids: true }): string[] | undefined; /** * Iterates through all the attributes of the model, calling the passed * function on each attribute. */ eachAttribute<M extends ModelRegistry[K]>( callback: (key: ModelKeys<M>, meta: AttributeMeta<M>) => void, binding?: {}, ): void; /** * Iterates through all the relationships of the model, calling the passed * function on each relationship. */ eachRelationship<M extends ModelRegistry[K]>( callback: (key: ModelKeys<M>, meta: RelationshipMeta<M>) => void, binding?: {}, ): void; /** * Serializes the snapshot using the serializer for the model. */ serialize<O extends object>(options: O): object; } /** * The store contains all of the data for records loaded from the server. * It is also responsible for creating instances of `DS.Model` that wrap * the individual data for a record, so that they can be bound to in your * Handlebars templates. */ class Store extends Ember.Service { /** * The default adapter to use to communicate to a backend server or * other persistence layer. This will be overridden by an application * adapter if present. */ adapter: string; /** * Create a new record in the current store. The properties passed * to this method are set on the newly created record. */ createRecord<K extends keyof ModelRegistry>(modelName: K, inputProperties?: {}): ModelRegistry[K]; /** * For symmetry, a record can be deleted via the store. */ deleteRecord(record: Model): void; /** * For symmetry, a record can be unloaded via the store. * This will cause the record to be destroyed and freed up for garbage collection. */ unloadRecord(record: Model): void; /** * This method returns a record for a given type and id combination. */ findRecord<K extends keyof ModelRegistry>( modelName: K, id: string | number, options?: {}, ): PromiseObject<ModelRegistry[K]>; /** * Get the reference for the specified record. */ getReference<K extends keyof ModelRegistry>( modelName: K, id: string | number, ): RecordReference<ModelRegistry[K]>; /** * Get a record by a given type and ID without triggering a fetch. */ peekRecord<K extends keyof ModelRegistry>(modelName: K, id: string | number): ModelRegistry[K] | null; /** * This method returns true if a record for a given modelName and id is already * loaded in the store. Use this function to know beforehand if a findRecord() * will result in a request or that it will be a cache hit. */ hasRecordForId<K extends keyof ModelRegistry>(modelName: K, id: string | number): boolean; /** * This method delegates a query to the adapter. This is the one place where * adapter-level semantics are exposed to the application. */ query<K extends keyof ModelRegistry>( modelName: K, query: object, options?: { adapterOptions?: object | undefined }, ): PromiseArray<ModelRegistry[K], AdapterPopulatedRecordArray<ModelRegistry[K]>>; /** * This method makes a request for one record, where the `id` is not known * beforehand (if the `id` is known, use [`findRecord`](#method_findRecord) * instead). */ queryRecord<K extends keyof ModelRegistry>( modelName: K, query: object, options?: { adapterOptions?: object | undefined }, ): RSVP.Promise<ModelRegistry[K]>; /** * `findAll` asks the adapter's `findAll` method to find the records for the * given type, and returns a promise which will resolve with all records of * this type present in the store, even if the adapter only returns a subset * of them. */ findAll<K extends keyof ModelRegistry>( modelName: K, options?: { reload?: boolean | undefined; backgroundReload?: boolean | undefined; include?: string | undefined; adapterOptions?: any; }, ): PromiseArray<ModelRegistry[K], Ember.ArrayProxy<ModelRegistry[K]>>; /** * This method returns a filtered array that contains all of the * known records for a given type in the store. */ peekAll<K extends keyof ModelRegistry>(modelName: K): RecordArray<ModelRegistry[K]>; /** * This method unloads all records in the store. * It schedules unloading to happen during the next run loop. */ unloadAll<K extends keyof ModelRegistry>(modelName?: K): void; /** * DEPRECATED: * This method has been deprecated and is an alias for store.hasRecordForId, which should * be used instead. */ recordIsLoaded<K extends keyof ModelRegistry>(modelName: K, id: string): boolean; /** * Returns the model class for the particular `modelName`. */ modelFor<K extends keyof ModelRegistry>(modelName: K): ModelRegistry[K]; /** * Push some data for a given type into the store. */ push(data: {}): Model | any[]; /** * Push some raw data into the store. */ pushPayload<K extends keyof ModelRegistry>(modelName: K, inputPayload: {}): any; pushPayload(inputPayload: {}): any; /** * `normalize` converts a json payload into the normalized form that * [push](#method_push) expects. */ normalize<K extends keyof ModelRegistry>(modelName: K, payload: {}): {}; /** * Returns an instance of the adapter for a given type. For * example, `adapterFor('person')` will return an instance of * `App.PersonAdapter`. */ adapterFor<K extends keyof AdapterRegistry>(modelName: K): AdapterRegistry[K]; /** * Returns an instance of the serializer for a given type. For * example, `serializerFor('person')` will return an instance of * `App.PersonSerializer`. */ serializerFor<K extends keyof SerializerRegistry>(modelName: K): SerializerRegistry[K]; } /** * The `JSONAPIAdapter` is the default adapter used by Ember Data. It * is responsible for transforming the store's requests into HTTP * requests that follow the [JSON API](http://jsonapi.org/format/) * format. */ class JSONAPIAdapter extends RESTAdapter {} /** * The REST adapter allows your store to communicate with an HTTP server by * transmitting JSON via XHR. Most Ember.js apps that consume a JSON API * should use the REST adapter. */ class RESTAdapter extends Adapter implements BuildURLMixin { /** * Takes a URL, an HTTP method and a hash of data, and makes an HTTP request. */ ajax(url: string, type: string, options?: object): RSVP.Promise<any>; /** * Generate ajax options */ ajaxOptions(url: string, type: string, options?: object): object; /** * By default, the RESTAdapter will send the query params sorted alphabetically to the * server. */ sortQueryParams(obj: {}): {}; /** * Called by the store in order to fetch the JSON for a given * type and ID. */ findRecord<K extends keyof ModelRegistry>( store: Store, type: ModelSchema<K>, id: string, snapshot: Snapshot<K>, ): RSVP.Promise<any>; /** * Called by the store in order to fetch a JSON array for all * of the records for a given type. */ findAll<K extends keyof ModelRegistry>( store: Store, type: ModelSchema<K>, sinceToken: string, snapshotRecordArray: SnapshotRecordArray<K>,