Skip to content

Commit

Permalink
Backport #9319 to lts-4-12: Add @ember-data/legacy-compat/builders (#…
Browse files Browse the repository at this point in the history
…9386)

* Copy-pasta from #9319

* Make it work
  • Loading branch information
gitKrystan authored Apr 29, 2024
1 parent 690eb1c commit 9779c67
Show file tree
Hide file tree
Showing 21 changed files with 1,223 additions and 23 deletions.
8 changes: 7 additions & 1 deletion packages/legacy-compat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,15 @@
"dependenciesMeta": {
"@ember-data/private-build-infra": {
"injected": true
},
"@ember/string": {
"injected": true
}
},
"peerDependencies": {
"@ember-data/graph": "workspace:4.12.7",
"@ember-data/json-api": "workspace:4.12.7"
"@ember-data/json-api": "workspace:4.12.7",
"@ember/string": "^3.0.1"
},
"peerDependenciesMeta": {
"@ember-data/graph": {
Expand All @@ -74,8 +78,10 @@
"@babel/preset-typescript": "^7.21.4",
"@babel/preset-env": "^7.21.4",
"@babel/runtime": "^7.21.0",
"@ember/string": "^3.0.1",
"@rollup/plugin-babel": "^6.0.3",
"@rollup/plugin-node-resolve": "^15.0.1",
"@types/ember__string": "^3.0.15",
"tslib": "^2.5.0",
"walk-sync": "^3.0.0",
"typescript": "^5.0.3"
Expand Down
2 changes: 1 addition & 1 deletion packages/legacy-compat/rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default {
plugins: [
// These are the modules that users should be able to import from your
// addon. Anything not listed here may get optimized away.
addon.publicEntrypoints(['index.js', '-private.js']),
addon.publicEntrypoints(['index.js', 'builders.js', '-private.js']),

nodeResolve({ extensions: ['.ts'] }),
babel({
Expand Down
17 changes: 17 additions & 0 deletions packages/legacy-compat/src/builders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
Builders for migrating from `store` methods to `store.request`.
These builders enable you to migrate your codebase to using the correct syntax for `store.request` while temporarily preserving legacy behaviors.
This is useful for quickly upgrading an entire app to a unified syntax while a longer incremental migration is made to shift off of adapters and serializers.
To that end, these builders are deprecated and will be removed in a future version of Ember Data.
@module @ember-data/legacy-compat/builders
@main @ember-data/legacy-compat/builders
@deprecated
*/

export { findAllBuilder as findAll } from './builders/find-all';

export { findRecordBuilder as findRecord } from './builders/find-record';

export { queryBuilder as query, queryRecordBuilder as queryRecord } from './builders/query';

export { saveRecordBuilder as saveRecord } from './builders/save-record';
67 changes: 67 additions & 0 deletions packages/legacy-compat/src/builders/find-all.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* @module @ember-data/legacy-compat/builders
*/
import { assert } from '@ember/debug';

Check failure on line 4 in packages/legacy-compat/src/builders/find-all.ts

View workflow job for this annotation

GitHub Actions / lint

Run autofix to sort these imports!

import type Model from '@ember-data/model';
import { SkipCache } from '@ember-data/request';
import type { ImmutableRequestInfo } from '@ember-data/request/-private/types';
import { normalizeModelName } from './utils';

// Keeping unused generics for consistency with 5x types
type FindAllRequestInput<T extends string = string, RT = unknown[]> = ImmutableRequestInfo & {

Check failure on line 12 in packages/legacy-compat/src/builders/find-all.ts

View workflow job for this annotation

GitHub Actions / lint

'RT' is defined but never used
op: 'findAll';
data: {
type: T;
options: FindAllBuilderOptions;
};
};

type FindAllBuilderOptions = {
reload?: boolean;
backgroundReload?: boolean;
include?: string | string[];
adapterOptions?: Record<string, unknown>;
};

/**
This function builds a request config to perform a `findAll` request for the given type.
When passed to `store.request`, this config will result in the same behavior as a `store.findAll` request.
Additionally, it takes the same options as `store.findAll`.
All `@ember-data/legacy-compat` builders exist to enable you to migrate your codebase to using the correct syntax for `store.request` while temporarily preserving legacy behaviors.
This is useful for quickly upgrading an entire app to a unified syntax while a longer incremental migration is made to shift off of adapters and serializers.
To that end, these builders are deprecated and will be removed in a future version of Ember Data.
@method findAll
@deprecated
@public
@static
@for @ember-data/legacy-compat/builders
@param {string} type the name of the resource
@param {object} query a query to be used by the adapter
@param {FindAllBuilderOptions} [options] optional, may include `adapterOptions` hash which will be passed to adapter.findAll
@return {FindAllRequestInput} request config
*/
// Keeping this generic for consistency with 5x types
export function findAllBuilder<T extends Model>(

Check failure on line 47 in packages/legacy-compat/src/builders/find-all.ts

View workflow job for this annotation

GitHub Actions / lint

'T' is defined but never used
type: string,
options?: FindAllBuilderOptions
): FindAllRequestInput<string, Model[]>;
export function findAllBuilder(type: string, options?: FindAllBuilderOptions): FindAllRequestInput;
export function findAllBuilder(type: string, options: FindAllBuilderOptions = {}): FindAllRequestInput {
assert(`You need to pass a model name to the findAll builder`, type);
assert(
`Model name passed to the findAll builder must be a dasherized string instead of ${type}`,
typeof type === 'string'
);

return {
op: 'findAll',
data: {
type: normalizeModelName(type),
options: options || {},
},
cacheOptions: { [SkipCache as symbol]: true },
};
}
117 changes: 117 additions & 0 deletions packages/legacy-compat/src/builders/find-record.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* @module @ember-data/legacy-compat/builders
*/
import { assert } from '@ember/debug';

Check failure on line 4 in packages/legacy-compat/src/builders/find-record.ts

View workflow job for this annotation

GitHub Actions / lint

Run autofix to sort these imports!

import type Model from '@ember-data/model';
import { SkipCache } from '@ember-data/request';
import type { ImmutableRequestInfo } from '@ember-data/request/-private/types';
import { constructResource, ensureStringId } from '@ember-data/store/-private';
import type { ResourceIdentifierObject } from '@ember-data/types/q/ember-data-json-api';
import { isMaybeIdentifier, normalizeModelName } from './utils';

// Keeping unused generics for consistency with 5x types
type FindRecordRequestInput<T extends string = string, RT = unknown> = ImmutableRequestInfo & {

Check failure on line 14 in packages/legacy-compat/src/builders/find-record.ts

View workflow job for this annotation

GitHub Actions / lint

'T' is defined but never used

Check failure on line 14 in packages/legacy-compat/src/builders/find-record.ts

View workflow job for this annotation

GitHub Actions / lint

'RT' is defined but never used
op: 'findRecord';
data: {
record: ResourceIdentifierObject;
options: FindRecordBuilderOptions;
};
};

type FindRecordBuilderOptions = {
reload?: boolean;
backgroundReload?: boolean;
include?: string | string[];
adapterOptions?: Record<string, unknown>;
};

/**
This function builds a request config to find the record for a given identifier or type and id combination.
When passed to `store.request`, this config will result in the same behavior as a `store.findRecord` request.
Additionally, it takes the same options as `store.findRecord`, with the exception of `preload` (which is unsupported).
**Example 1**
```ts
import { findRecord } from '@ember-data/legacy-compat/builders';
const { content: post } = await store.request<Post>(findRecord<Post>('post', '1'));
```
**Example 2**
`findRecord` can be called with a single identifier argument instead of the combination
of `type` (modelName) and `id` as separate arguments. You may recognize this combo as
the typical pairing from [JSON:API](https://jsonapi.org/format/#document-resource-object-identification)
```ts
import { findRecord } from '@ember-data/legacy-compat/builders';
const { content: post } = await store.request<Post>(findRecord<Post>({ type: 'post', id }));
```
All `@ember-data/legacy-compat` builders exist to enable you to migrate your codebase to using the correct syntax for `store.request` while temporarily preserving legacy behaviors.
This is useful for quickly upgrading an entire app to a unified syntax while a longer incremental migration is made to shift off of adapters and serializers.
To that end, these builders are deprecated and will be removed in a future version of Ember Data.
@method findRecord
@deprecated
@public
@static
@for @ember-data/legacy-compat/builders
@param {string|object} type - either a string representing the name of the resource or a ResourceIdentifier object containing both the type (a string) and the id (a string) for the record or an lid (a string) of an existing record
@param {string|number|object} id - optional object with options for the request only if the first param is a ResourceIdentifier, else the string id of the record to be retrieved
@param {FindRecordBuilderOptions} [options] - if the first param is a string this will be the optional options for the request. See examples for available options.
@return {FindRecordRequestInput} request config
*/
export function findRecordBuilder<T extends Model>(
resource: string,
id: string,
options?: FindRecordBuilderOptions
): FindRecordRequestInput<string, T>;
export function findRecordBuilder(
resource: string,
id: string,
options?: FindRecordBuilderOptions
): FindRecordRequestInput;
export function findRecordBuilder<T extends Model>(
resource: ResourceIdentifierObject,
options?: FindRecordBuilderOptions
): FindRecordRequestInput<string, T>;
export function findRecordBuilder(
resource: ResourceIdentifierObject,
options?: FindRecordBuilderOptions
): FindRecordRequestInput;
export function findRecordBuilder(
resource: string | ResourceIdentifierObject,
idOrOptions?: string | FindRecordBuilderOptions,
options?: FindRecordBuilderOptions
): FindRecordRequestInput {
assert(
`You need to pass a modelName or resource identifier as the first argument to the findRecord builder`,
resource
);
if (isMaybeIdentifier(resource)) {
options = idOrOptions as FindRecordBuilderOptions | undefined;
} else {
assert(
`You need to pass a modelName or resource identifier as the first argument to the findRecord builder (passed ${resource})`,
typeof resource === 'string'
);
const type = normalizeModelName(resource);
const normalizedId = ensureStringId(idOrOptions as string | number);
resource = constructResource(type, normalizedId);
}

options = options || {};

assert('findRecord builder does not support options.preload', !(options as any).preload);

Check failure on line 107 in packages/legacy-compat/src/builders/find-record.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe member access .preload on an `any` value

Check failure on line 107 in packages/legacy-compat/src/builders/find-record.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

return {
op: 'findRecord' as const,
data: {
record: resource,
options,
},
cacheOptions: { [SkipCache as symbol]: true },
};
}
135 changes: 135 additions & 0 deletions packages/legacy-compat/src/builders/query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/**
* @module @ember-data/legacy-compat/builders
*/
import { assert } from '@ember/debug';

Check failure on line 4 in packages/legacy-compat/src/builders/query.ts

View workflow job for this annotation

GitHub Actions / lint

Run autofix to sort these imports!

import type Model from '@ember-data/model';
import { SkipCache } from '@ember-data/request';
import type { ImmutableRequestInfo } from '@ember-data/request/-private/types';
import { normalizeModelName } from './utils';

type QueryRequestInput<T extends string = string, RT = unknown[]> = ImmutableRequestInfo & {

Check failure on line 11 in packages/legacy-compat/src/builders/query.ts

View workflow job for this annotation

GitHub Actions / lint

'RT' is defined but never used
op: 'query';
data: {
type: T;
query: Record<string, unknown>;
options: QueryBuilderOptions;
};
};

type QueryBuilderOptions = {
[K in string | 'adapterOptions']?: K extends 'adapterOptions' ? Record<string, unknown> : unknown;
};

/**
This function builds a request config for a given type and query object.
When passed to `store.request`, this config will result in the same behavior as a `store.query` request.
Additionally, it takes the same options as `store.query`.
All `@ember-data/legacy-compat` builders exist to enable you to migrate your codebase to using the correct syntax for `store.request` while temporarily preserving legacy behaviors.
This is useful for quickly upgrading an entire app to a unified syntax while a longer incremental migration is made to shift off of adapters and serializers.
To that end, these builders are deprecated and will be removed in a future version of Ember Data.
@method query
@deprecated
@public
@static
@for @ember-data/legacy-compat/builders
@param {string} type the name of the resource
@param {object} query a query to be used by the adapter
@param {QueryBuilderOptions} [options] optional, may include `adapterOptions` hash which will be passed to adapter.query
@return {QueryRequestInput} request config
*/
export function queryBuilder<T extends Model>(
type: string,
query: Record<string, unknown>,
options?: QueryBuilderOptions
): QueryRequestInput<string, T[]>;
export function queryBuilder(
type: string,
query: Record<string, unknown>,
options?: QueryBuilderOptions
): QueryRequestInput;
export function queryBuilder(
type: string,
query: Record<string, unknown>,
options: QueryBuilderOptions = {}
): QueryRequestInput {
assert(`You need to pass a model name to the query builder`, type);
assert(`You need to pass a query hash to the query builder`, query);
assert(
`Model name passed to the query builder must be a dasherized string instead of ${type}`,
typeof type === 'string'
);

return {
op: 'query' as const,
data: {
type: normalizeModelName(type),
query,
options: options,
},
cacheOptions: { [SkipCache as symbol]: true },
};
}

type QueryRecordRequestInput<T extends string = string, RT = unknown> = ImmutableRequestInfo & {
op: 'queryRecord';
data: {
type: T;
query: Record<string, unknown>;
options: QueryBuilderOptions;
};
};

/**
This function builds a request config for a given type and query object.
When passed to `store.request`, this config will result in the same behavior as a `store.queryRecord` request.
Additionally, it takes the same options as `store.queryRecord`.
All `@ember-data/legacy-compat` builders exist to enable you to migrate your codebase to using the correct syntax for `store.request` while temporarily preserving legacy behaviors.
This is useful for quickly upgrading an entire app to a unified syntax while a longer incremental migration is made to shift off of adapters and serializers.
To that end, these builders are deprecated and will be removed in a future version of Ember Data.
@method queryRecord
@deprecated
@public
@static
@for @ember-data/legacy-compat/builders
@param {string} type the name of the resource
@param {object} query a query to be used by the adapter
@param {QueryBuilderOptions} [options] optional, may include `adapterOptions` hash which will be passed to adapter.query
@return {QueryRecordRequestInput} request config
*/
export function queryRecordBuilder<T extends Model>(
type: string,
query: Record<string, unknown>,
options?: QueryBuilderOptions
): QueryRecordRequestInput<string, T | null>;
export function queryRecordBuilder(
type: string,
query: Record<string, unknown>,
options?: QueryBuilderOptions
): QueryRecordRequestInput;
export function queryRecordBuilder(
type: string,
query: Record<string, unknown>,
options?: QueryBuilderOptions
): QueryRecordRequestInput {
assert(`You need to pass a model name to the queryRecord builder`, type);
assert(`You need to pass a query hash to the queryRecord builder`, query);
assert(
`Model name passed to the queryRecord builder must be a dasherized string instead of ${type}`,
typeof type === 'string'
);

return {
op: 'queryRecord',
data: {
type: normalizeModelName(type),
query,
options: options || {},
},
cacheOptions: { [SkipCache as symbol]: true },
};
}
Loading

0 comments on commit 9779c67

Please sign in to comment.