diff --git a/packages/api-client-core/package.json b/packages/api-client-core/package.json index 7894808ef..ee9e973fd 100644 --- a/packages/api-client-core/package.json +++ b/packages/api-client-core/package.json @@ -1,6 +1,6 @@ { "name": "@gadgetinc/api-client-core", - "version": "0.15.39", + "version": "0.15.40", "files": [ "Readme.md", "dist/**/*" diff --git a/packages/api-client-core/spec/GadgetRecord.spec.ts b/packages/api-client-core/spec/GadgetRecord.spec.ts index 7568338fe..36a6e70f9 100644 --- a/packages/api-client-core/spec/GadgetRecord.spec.ts +++ b/packages/api-client-core/spec/GadgetRecord.spec.ts @@ -1,4 +1,3 @@ -import type { AnyPublicModelManager } from "../src/AnyModelManager.js"; import { ChangeTracking, GadgetRecord } from "../src/GadgetRecord.js"; interface SampleBaseRecord { id?: string; @@ -39,8 +38,6 @@ const expectPersistedChanges = (record: GadgetRecord, ...prope return _expectChanges(record, ChangeTracking.SinceLastPersisted, ...properties); }; -const mockModelManager: AnyPublicModelManager = {} as any; - describe("GadgetRecord", () => { let productBaseRecord: SampleBaseRecord; beforeAll(() => { @@ -51,16 +48,6 @@ describe("GadgetRecord", () => { }; }); - it("can be constructed with a base record and no model manager for backwards compatibility", () => { - const product = new GadgetRecord(productBaseRecord); - expect(product.id).toEqual("123"); - expect(product.name).toEqual("A cool product"); - }); - - it("can be constructed with a base record and a model manager", () => { - new GadgetRecord(productBaseRecord, mockModelManager); - }); - it("should respond toJSON, which returns the inner __gadget.fields properties", () => { const product = new GadgetRecord(productBaseRecord); expect(product.toJSON()).toEqual({ diff --git a/packages/api-client-core/spec/operationRunners.spec.ts b/packages/api-client-core/spec/operationRunners.spec.ts index a09d06b30..88482391c 100644 --- a/packages/api-client-core/spec/operationRunners.spec.ts +++ b/packages/api-client-core/spec/operationRunners.spec.ts @@ -4,7 +4,7 @@ import { diff } from "@n1ru4l/json-patch-plus"; import { CombinedError } from "@urql/core"; import nock from "nock"; import { BackgroundActionHandle } from "../src/BackgroundActionHandle.js"; -import type { AnyPublicModelManager, GadgetErrorGroup, LimitToKnownKeys } from "../src/index.js"; +import type { AnyModelManager, GadgetErrorGroup, LimitToKnownKeys } from "../src/index.js"; import { GadgetConnection, actionRunner, @@ -48,7 +48,6 @@ describe("type checks", () => { // eslint-disable-next-line jest/no-export describe("operationRunners", () => { let connection: GadgetConnection; - let manager: AnyPublicModelManager; let query: string | undefined; let mockUrqlClient: MockUrqlClient; @@ -61,7 +60,6 @@ describe("operationRunners", () => { }, }); jest.spyOn(connection, "currentClient" as any, "get").mockReturnValue(mockUrqlClient as any); - manager = { connection } as AnyPublicModelManager; }); describe("findOneRunner", () => { @@ -69,18 +67,18 @@ describe("operationRunners", () => { const promise = findOneRunner({ connection }, "widget", "123", { id: true, name: true }, "widget"); expect(query).toMatchInlineSnapshot(` - "query widget($id: GadgetID!) { - widget(id: $id) { - id - name - __typename - } - gadgetMeta { - hydrations(modelName: - "widget") - } - }" - `); + "query widget($id: GadgetID!) { + widget(id: $id) { + id + name + __typename + } + gadgetMeta { + hydrations(modelName: + "widget") + } + }" + `); mockUrqlClient.executeQuery.pushResponse("widget", { data: { @@ -318,32 +316,32 @@ describe("operationRunners", () => { describe("findManyRunner", () => { test("can execute a findMany operation against a model", async () => { - const promise = findManyRunner({ connection } as AnyPublicModelManager, "widgets", { id: true, name: true }, "widget"); + const promise = findManyRunner({ connection } as AnyModelManager, "widgets", { id: true, name: true }, "widget"); expect(query).toMatchInlineSnapshot(` - "query widgets($after: String, $first: Int, $before: String, $last: Int) { - widgets(after: $after, first: $first, before: $before, last: $last) { - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - edges { - cursor - node { - id - name - __typename - } - } - } - gadgetMeta { - hydrations(modelName: - "widget") - } - }" - `); + "query widgets($after: String, $first: Int, $before: String, $last: Int) { + widgets(after: $after, first: $first, before: $before, last: $last) { + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + edges { + cursor + node { + id + name + __typename + } + } + } + gadgetMeta { + hydrations(modelName: + "widget") + } + }" + `); mockUrqlClient.executeQuery.pushResponse("widgets", { data: { @@ -371,7 +369,7 @@ describe("operationRunners", () => { test("can execute a findMany operation against a namespaced model", async () => { const promise = findManyRunner( - { connection } as AnyPublicModelManager, + { connection } as AnyModelManager, "widgets", { id: true, name: true }, "widget", @@ -438,7 +436,7 @@ describe("operationRunners", () => { test("can execute a findMany operation against a namespaced model when the namespace is a string", async () => { const promise = findManyRunner( - { connection } as AnyPublicModelManager, + { connection } as AnyModelManager, "widgets", { id: true, name: true }, "widget", @@ -504,7 +502,9 @@ describe("operationRunners", () => { describe("actionRunner", () => { test("can run a single create action", async () => { const promise = actionRunner<{ id: string; name: string }>( - manager, + { + connection, + }, "createWidget", { id: true, name: true }, "widget", @@ -544,7 +544,9 @@ describe("operationRunners", () => { test("can run a single update action", async () => { const promise = actionRunner<{ id: string; name: string }>( - manager, + { + connection, + }, "updateWidget", { id: true, name: true }, "widget", @@ -589,7 +591,9 @@ describe("operationRunners", () => { test("can run a single action with an object result type", async () => { const promise = actionRunner( - manager, + { + connection, + }, "upsertWidget", { id: true, name: true, eventAt: true }, "widget", @@ -642,7 +646,9 @@ describe("operationRunners", () => { test("can run a single action with an object result type that has an inner return type", async () => { const promise = actionRunner( - manager, + { + connection, + }, "upsertWidget", { id: true, name: true, eventAt: true }, "widget", @@ -687,7 +693,9 @@ describe("operationRunners", () => { test("can run an action with hasReturnType", async () => { const promise = actionRunner( - manager, + { + connection, + }, "createWidget", { id: true, name: true }, "widget", @@ -725,7 +733,9 @@ describe("operationRunners", () => { test("can throw the error returned by the server for a single action", async () => { const promise = actionRunner<{ id: string; name: string }>( - manager, + { + connection, + }, "updateWidget", { id: true, name: true }, "widget", @@ -770,7 +780,9 @@ describe("operationRunners", () => { test("can run a bulk action by ids", async () => { const promise = actionRunner<{ id: string; name: string }>( - manager, + { + connection, + }, "bulkFlipWidgets", { id: true, name: true }, "widget", @@ -818,7 +830,9 @@ describe("operationRunners", () => { test("can run a bulk action with params", async () => { const promise = actionRunner<{ id: string; name: string }>( - manager, + { + connection, + }, "bulkCreateWidgets", { id: true, name: true }, "widget", @@ -866,7 +880,9 @@ describe("operationRunners", () => { test("can run a bulk action with a returnType", async () => { const promise = actionRunner( - manager, + { + connection, + }, "bulkCreateWidgets", { id: true, name: true }, "widget", @@ -905,7 +921,9 @@ describe("operationRunners", () => { test("can run a bulk action with an object returnType", async () => { const promise = actionRunner( - manager, + { + connection, + }, "bulkUpsertWidgets", { id: true, name: true }, "widget", @@ -952,7 +970,9 @@ describe("operationRunners", () => { test("throws a nice error when a bulk action returns errors", async () => { const promise = actionRunner<{ id: string; name: string }>( - manager, + { + connection, + }, "bulkCreateWidgets", { id: true, name: true }, "widget", @@ -990,7 +1010,9 @@ describe("operationRunners", () => { test("throws a nice error when a bulk action returns errors and data", async () => { const promise = actionRunner<{ id: string; name: string }>( - manager, + { + connection, + }, "bulkCreateWidgets", { id: true, name: true }, "widget", @@ -1035,7 +1057,9 @@ describe("operationRunners", () => { test("returns undefined when bulk action does not have a result", async () => { const promise = actionRunner<{ id: string; name: string }>( - manager, + { + connection, + }, "bulkDeleteWidgets", null, "widget", @@ -1934,7 +1958,7 @@ describe("operationRunners", () => { test("can run a live findMany", async () => { const iterator = asyncIterableToIterator( findManyRunner<{ id: string; name: string }, { live: true }>( - { connection } as AnyPublicModelManager, + { connection } as AnyModelManager, "widgets", { id: true, name: true }, "widget", diff --git a/packages/api-client-core/src/AnyModelManager.ts b/packages/api-client-core/src/AnyModelManager.ts deleted file mode 100644 index 114d6520d..000000000 --- a/packages/api-client-core/src/AnyModelManager.ts +++ /dev/null @@ -1,61 +0,0 @@ -import type { GadgetConnection } from "./GadgetConnection.js"; -import type { FindFirstFunction, FindManyFunction, FindOneFunction, GetFunction } from "./GadgetFunctions.js"; -import type { GadgetRecord } from "./GadgetRecord.js"; -import type { InternalModelManager } from "./InternalModelManager.js"; - -export type AnyModelFinderMetadata = { - /** The name of the GraphQL API field that should be called for this operation */ - operationName: string; - /** The model's api identifier */ - modelApiIdentifier: string; - /** What fields to select from the GraphQL API if no explicit selection is passed */ - defaultSelection: Record; - /** A namespace this operation is nested in. Absent for old clients or root-namespaced operations */ - namespace?: string | string[] | null; - /** Type-time only type member used for strong typing of finders */ - selectionType: any; - /** Type-time only type member used for strong typing of finders */ - optionsType: any; - /** Type-time only type member used for strong typing of finders */ - schemaType: any | null; -}; - -export type AnyFindOneFunc = FindOneFunction; -export type AnyFindManyFunc = FindManyFunction; -export type AnyFindFirstFunc = FindFirstFunction; - -/** - * The manager class for a given model that uses the Public API, like `api.post` or `api.user` - **/ -export interface AnyPublicModelManager< - FindOneFunc extends AnyFindOneFunc = AnyFindOneFunc, - FindManyFunc extends AnyFindManyFunc = AnyFindManyFunc, - FindFirstFunc extends AnyFindFirstFunc = AnyFindFirstFunc -> { - connection: GadgetConnection; - findOne: FindOneFunc; - findMany: FindManyFunc; - findFirst: FindFirstFunc; - maybeFindFirst(options: any): Promise | null>; - maybeFindOne(id: string, options: any): Promise | null>; -} - -/** - * The manager class for a given single model that uses the Public API, like `api.session` - **/ -export interface AnyPublicSingletonModelManager = GetFunction> { - connection: GadgetConnection; - get: GetFunc; -} - -/** - * Prior to 1.1 actions were defined to accept just a connection - */ -export interface AnyLegacyModelManager { - connection: GadgetConnection; -} - -/** - * Any model manager, either public or internal - */ -export type AnyModelManager = AnyPublicModelManager | AnyPublicSingletonModelManager | AnyLegacyModelManager | InternalModelManager; diff --git a/packages/api-client-core/src/GadgetFunctions.ts b/packages/api-client-core/src/GadgetFunctions.ts index d93af3eb7..4789edb59 100644 --- a/packages/api-client-core/src/GadgetFunctions.ts +++ b/packages/api-client-core/src/GadgetFunctions.ts @@ -1,4 +1,3 @@ -import type { AnyPublicModelManager, AnyPublicSingletonModelManager } from "./AnyModelManager.js"; import type { GadgetRecord, RecordShape } from "./GadgetRecord.js"; import type { GadgetRecordList } from "./GadgetRecordList.js"; import type { LimitToKnownKeys, VariablesOptions } from "./types.js"; @@ -25,7 +24,6 @@ export interface FindOneFunction { optionsType: OptionsT; schemaType: SchemaT | null; plan?: (fieldValue: string, options?: LimitToKnownKeys) => GQLBuilderResult; - modelManager?: AnyPublicModelManager; } export interface MaybeFindOneFunction { @@ -41,7 +39,6 @@ export interface MaybeFindOneFunction optionsType: OptionsT; schemaType: SchemaT | null; plan?: (fieldValue: string, options?: LimitToKnownKeys) => GQLBuilderResult; - modelManager?: AnyPublicModelManager; } export interface FindManyFunction { @@ -56,7 +53,6 @@ export interface FindManyFunction { optionsType: OptionsT; schemaType: SchemaT | null; plan?: (options?: LimitToKnownKeys) => GQLBuilderResult; - modelManager?: AnyPublicModelManager; } export interface FindFirstFunction { @@ -71,7 +67,6 @@ export interface FindFirstFunction { optionsType: OptionsT; schemaType: SchemaT | null; plan?: (options?: LimitToKnownKeys) => GQLBuilderResult; - modelManager?: AnyPublicModelManager; } export interface MaybeFindFirstFunction { @@ -86,7 +81,6 @@ export interface MaybeFindFirstFunction(options?: LimitToKnownKeys) => GQLBuilderResult; - modelManager?: AnyPublicModelManager; } export interface ActionWithIdAndVariables { @@ -140,7 +134,6 @@ export interface ActionFunctionMetadata(options?: LimitToKnownKeys) => GQLBuilderResult; /** @deprecated */ hasCreateOrUpdateEffect?: boolean; - modelManager?: AnyPublicModelManager; } export type StubbedActionReason = "MissingApiTrigger"; @@ -196,7 +189,6 @@ export interface GetFunction { optionsType: OptionsT; schemaType: SchemaT | null; plan?: (options?: LimitToKnownKeys) => GQLBuilderResult; - modelManager?: AnyPublicSingletonModelManager>; } export interface GlobalActionFunction { diff --git a/packages/api-client-core/src/GadgetRecord.ts b/packages/api-client-core/src/GadgetRecord.ts index ec57cde01..7a3cd7a99 100644 --- a/packages/api-client-core/src/GadgetRecord.ts +++ b/packages/api-client-core/src/GadgetRecord.ts @@ -1,6 +1,5 @@ import { klona as cloneDeep } from "klona"; import type { Jsonify } from "type-fest"; -import type { AnyModelManager } from "./AnyModelManager.js"; import { isEqual, toPrimitiveObject } from "./support.js"; export enum ChangeTracking { @@ -15,7 +14,6 @@ const kInstantiatedFields = Symbol.for("g/if"); const kPersistedFields = Symbol.for("g/pf"); const kFieldKeys = Symbol.for("g/fk"); const kTouched = Symbol.for("g/t"); -const kModelManager = Symbol.for("g/mm"); /** Represents one record returned from a high level Gadget API call */ export class GadgetRecord_ { @@ -28,12 +26,10 @@ export class GadgetRecord_ { /** Storage of the keys and values of this record at the time it was last persisted */ [kFieldKeys]: Set; [kTouched] = false; - [kModelManager]: AnyModelManager | undefined; private empty = false; - constructor(data: Shape, modelManager?: AnyModelManager) { - this[kModelManager] = modelManager; + constructor(data: Shape) { this[kInstantiatedFields] = cloneDeep(data) ?? {}; this[kPersistedFields] = cloneDeep(data) ?? {}; Object.assign(this[kFields], data); @@ -225,8 +221,7 @@ export type GadgetRecord = GadgetRecord_ & Sha /** * Instantiates a `GadgetRecord` with the attributes of your model. A `GadgetRecord` can be used to track changes to your model and persist those changes via Gadget actions. **/ -export const GadgetRecord: new (data: Shape, modelManager?: AnyModelManager) => GadgetRecord_ & Shape = - GadgetRecord_ as any; +export const GadgetRecord: new (data: Shape) => GadgetRecord_ & Shape = GadgetRecord_ as any; /** * Legacy export for old generated clients expecting to find the class named this diff --git a/packages/api-client-core/src/GadgetRecordList.ts b/packages/api-client-core/src/GadgetRecordList.ts index ba03081f3..03144c5ce 100644 --- a/packages/api-client-core/src/GadgetRecordList.ts +++ b/packages/api-client-core/src/GadgetRecordList.ts @@ -1,9 +1,9 @@ /* eslint-disable no-throw-literal */ /* eslint-disable @typescript-eslint/require-await */ import type { Jsonify } from "type-fest"; -import type { AnyPublicModelManager } from "./AnyModelManager.js"; import type { GadgetRecord, RecordShape } from "./GadgetRecord.js"; import type { InternalModelManager } from "./InternalModelManager.js"; +import type { AnyModelManager } from "./ModelManager.js"; import { GadgetClientError, GadgetOperationError } from "./support.js"; import type { PaginateOptions } from "./types.js"; @@ -14,12 +14,12 @@ type PaginationConfig = { /** Represents a list of objects returned from the API. Facilitates iterating and paginating. */ export class GadgetRecordList extends Array> { - modelManager!: AnyPublicModelManager | InternalModelManager; + modelManager!: AnyModelManager | InternalModelManager; pagination!: PaginationConfig; /** Internal method used to create a list. Should not be used by applications. */ static boot( - modelManager: AnyPublicModelManager | InternalModelManager, + modelManager: AnyModelManager | InternalModelManager, records: GadgetRecord[], pagination: PaginationConfig ) { diff --git a/packages/api-client-core/src/InternalModelManager.ts b/packages/api-client-core/src/InternalModelManager.ts index 11e66d806..6a8e78217 100644 --- a/packages/api-client-core/src/InternalModelManager.ts +++ b/packages/api-client-core/src/InternalModelManager.ts @@ -22,13 +22,7 @@ import { namespacify, sortTypeName, } from "./support.js"; -import type { - AnySelection, - InternalFieldSelection, - InternalFindListOptions, - InternalFindManyOptions, - InternalFindOneOptions, -} from "./types.js"; +import type { InternalFieldSelection, InternalFindListOptions, InternalFindManyOptions, InternalFindOneOptions } from "./types.js"; export const internalFindOneQuery = (apiIdentifier: string, id: string, namespace: string[], select?: InternalFieldSelection) => { const capitalizedApiIdentifier = capitalizeIdentifier(apiIdentifier); @@ -277,7 +271,7 @@ export class InternalModelManager { private readonly namespace: string[]; constructor( - readonly apiIdentifier: string, + private readonly apiIdentifier: string, readonly connection: GadgetConnection, readonly options?: { pluralApiIdentifier: string; hasAmbiguousIdentifiers?: boolean; namespace?: string[] } ) { @@ -329,7 +323,7 @@ export class InternalModelManager { const response = await this.connection.currentClient.query(plan.query, plan.variables).toPromise(); const assertSuccess = throwOnEmptyData ? assertOperationSuccess : assertNullableOperationSuccess; const result = assertSuccess(response, this.dataPath(this.apiIdentifier)); - return hydrateRecord(response, result, this); + return hydrateRecord(response, result); } /** @@ -362,7 +356,7 @@ export class InternalModelManager { const plan = internalFindManyQuery(this.apiIdentifier, this.namespace, options); const response = await this.connection.currentClient.query(plan.query, plan.variables).toPromise(); const connection = assertNullableOperationSuccess(response, this.dataPath(`list${this.capitalizedApiIdentifier}`)); - const records = hydrateConnection(response, connection, this); + const records = hydrateConnection(response, connection); return GadgetRecordList.boot(this, records, { options, pageInfo: connection.pageInfo }); } @@ -392,7 +386,7 @@ export class InternalModelManager { connection = assertOperationSuccess(response, dataPath, throwOnEmptyData); } - const records = hydrateConnection(response, connection, this); + const records = hydrateConnection(response, connection); const recordList = GadgetRecordList.boot(this, records, { options, pageInfo: connection.pageInfo }); return recordList[0]; } @@ -427,7 +421,7 @@ export class InternalModelManager { const plan = internalCreateMutation(this.apiIdentifier, this.namespace, this.getRecordFromData(record, "create")); const response = await this.connection.currentClient.mutation(plan.query, plan.variables).toPromise(); const result = assertMutationSuccess(response, this.dataPath(`create${this.capitalizedApiIdentifier}`)); - return hydrateRecord(response, result[this.apiIdentifier], this); + return hydrateRecord(response, result[this.apiIdentifier]); } /** @@ -454,7 +448,7 @@ export class InternalModelManager { const plan = internalBulkCreateMutation(this.apiIdentifier, this.options.pluralApiIdentifier, this.namespace, records); const response = await this.connection.currentClient.mutation(plan.query, plan.variables).toPromise(); const result = assertMutationSuccess(response, this.dataPath(`bulkCreate${capitalizedPluralApiIdentifier}`)); - return hydrateRecordArray(response, result[this.options.pluralApiIdentifier], this); + return hydrateRecordArray(response, result[this.options.pluralApiIdentifier]); } /** @@ -475,7 +469,7 @@ export class InternalModelManager { const response = await this.connection.currentClient.mutation(plan.query, plan.variables).toPromise(); const result = assertMutationSuccess(response, this.dataPath(`update${this.capitalizedApiIdentifier}`)); - return hydrateRecord(response, result[this.apiIdentifier], this); + return hydrateRecord(response, result[this.apiIdentifier]); } /** @@ -507,7 +501,7 @@ export class InternalModelManager { const response = await this.connection.currentClient.mutation(plan.query, plan.variables).toPromise(); const result = assertMutationSuccess(response, this.dataPath(`upsert${this.capitalizedApiIdentifier}`)); - return hydrateRecord(response, result[this.apiIdentifier], this); + return hydrateRecord(response, result[this.apiIdentifier]); } /** @@ -550,7 +544,7 @@ export class InternalModelManager { } } -function formatInternalSelectVariable(select?: AnySelection | InternalFieldSelection | null): undefined | string[] { +function formatInternalSelectVariable(select: InternalFieldSelection | undefined): undefined | string[] { if (!select) return; if (Array.isArray(select)) return select; const result: string[] = []; diff --git a/packages/api-client-core/src/ModelManager.ts b/packages/api-client-core/src/ModelManager.ts new file mode 100644 index 000000000..4785e8147 --- /dev/null +++ b/packages/api-client-core/src/ModelManager.ts @@ -0,0 +1,32 @@ +import type { GadgetConnection } from "./GadgetConnection.js"; +import type { GadgetRecord } from "./GadgetRecord.js"; +import type { GadgetRecordList } from "./GadgetRecordList.js"; + +export type AnyModelFinderMetadata = { + /** The name of the GraphQL API field that should be called for this operation */ + operationName: string; + /** The model's api identifier */ + modelApiIdentifier: string; + /** What fields to select from the GraphQL API if no explicit selection is passed */ + defaultSelection: Record; + /** A namespace this operation is nested in. Absent for old clients or root-namespaced operations */ + namespace?: string | string[] | null; + /** Type-time only type member used for strong typing of finders */ + selectionType: any; + /** Type-time only type member used for strong typing of finders */ + optionsType: any; + /** Type-time only type member used for strong typing of finders */ + schemaType: any | null; +}; + +/** + * Object representing one model's API in a high level way + * This is a generic interface. Concrete ones are generated by Gadget, */ +export interface AnyModelManager { + connection: GadgetConnection; + findOne: ((id: string, options: any) => Promise>) & AnyModelFinderMetadata; + findMany: ((options: any) => Promise>) & AnyModelFinderMetadata; + findFirst: ((options: any) => Promise>) & AnyModelFinderMetadata; + maybeFindFirst(options: any): Promise | null>; + maybeFindOne(id: string, options: any): Promise | null>; +} diff --git a/packages/api-client-core/src/index.ts b/packages/api-client-core/src/index.ts index d365d134c..a652fb845 100644 --- a/packages/api-client-core/src/index.ts +++ b/packages/api-client-core/src/index.ts @@ -1,5 +1,4 @@ export * from "./AnyClient.js"; -export * from "./AnyModelManager.js"; export * from "./BackgroundActionHandle.js"; export * from "./ClientOptions.js"; export * from "./DataHydrator.js"; @@ -11,6 +10,7 @@ export * from "./GadgetRecordList.js"; export * from "./GadgetTransaction.js"; export * from "./InMemoryStorage.js"; export * from "./InternalModelManager.js"; +export * from "./ModelManager.js"; export * from "./operationBuilders.js"; export * from "./operationRunners.js"; export * from "./support.js"; diff --git a/packages/api-client-core/src/operationRunners.ts b/packages/api-client-core/src/operationRunners.ts index cf0701a26..bb1be7bae 100644 --- a/packages/api-client-core/src/operationRunners.ts +++ b/packages/api-client-core/src/operationRunners.ts @@ -4,7 +4,6 @@ import { BackgroundActionHandle } from "./BackgroundActionHandle.js"; /* eslint-disable @typescript-eslint/ban-types */ import type { OperationResult } from "@urql/core"; import type { Source } from "wonka"; -import type { AnyLegacyModelManager, AnyModelManager, AnyPublicModelManager, AnyPublicSingletonModelManager } from "./AnyModelManager.js"; import type { FieldSelection } from "./FieldSelection.js"; import type { GadgetConnection } from "./GadgetConnection.js"; import type { @@ -16,6 +15,7 @@ import type { } from "./GadgetFunctions.js"; import type { GadgetRecord, RecordShape } from "./GadgetRecord.js"; import { GadgetRecordList } from "./GadgetRecordList.js"; +import type { AnyModelManager } from "./ModelManager.js"; import { actionOperation, backgroundActionResultOperation, @@ -92,7 +92,7 @@ function maybeLiveStream( - modelManager: AnyPublicModelManager | AnyPublicSingletonModelManager | AnyLegacyModelManager, + modelManager: { connection: GadgetConnection }, operation: string, id: string | undefined, defaultSelection: FieldSelection, @@ -110,14 +110,14 @@ export const findOneRunner = (response, record, modelManager); + return hydrateRecord(response, record); }, options ); }; export const findOneByFieldRunner = ( - modelManager: AnyPublicModelManager | AnyLegacyModelManager, + modelManager: { connection: GadgetConnection }, operation: string, fieldName: string, fieldValue: string, @@ -151,7 +151,7 @@ export const findOneByFieldRunner = ( - modelManager: AnyPublicModelManager, + modelManager: AnyModelManager, operation: string, defaultSelection: FieldSelection, modelApiIdentifier: string, @@ -185,7 +185,7 @@ export const findManyRunner = ; ( - modelManager: AnyPublicModelManager | AnyPublicSingletonModelManager | AnyLegacyModelManager, + modelManager: { connection: GadgetConnection }, operation: string, defaultSelection: FieldSelection | null, modelApiIdentifier: string, @@ -211,7 +211,7 @@ export interface ActionRunner { ): Promise>; ( - modelManager: AnyPublicModelManager | AnyPublicSingletonModelManager | AnyLegacyModelManager, + modelManager: { connection: GadgetConnection }, operation: string, defaultSelection: FieldSelection | null, modelApiIdentifier: string, @@ -223,7 +223,7 @@ export interface ActionRunner { ): Promise>; ( - modelManager: AnyPublicModelManager | AnyPublicSingletonModelManager | AnyLegacyModelManager, + modelManager: { connection: GadgetConnection }, operation: string, defaultSelection: FieldSelection | null, modelApiIdentifier: string, @@ -235,7 +235,7 @@ export interface ActionRunner { ): Promise[]>; ( - modelManager: AnyPublicModelManager | AnyPublicSingletonModelManager | AnyLegacyModelManager, + modelManager: { connection: GadgetConnection }, operation: string, defaultSelection: FieldSelection | null, modelApiIdentifier: string, @@ -248,7 +248,7 @@ export interface ActionRunner { ): Promise; ( - modelManager: AnyPublicModelManager | AnyPublicSingletonModelManager | AnyLegacyModelManager, + modelManager: { connection: GadgetConnection }, operation: string, defaultSelection: FieldSelection | null, modelApiIdentifier: string, @@ -262,7 +262,7 @@ export interface ActionRunner { } export const actionRunner: ActionRunner = async ( - modelManager: AnyPublicModelManager | AnyPublicSingletonModelManager | AnyLegacyModelManager, + modelManager: { connection: GadgetConnection }, operation: string, defaultSelection: FieldSelection | null, modelApiIdentifier: string, @@ -293,11 +293,11 @@ export const actionRunner: ActionRunner = async ( if (!isBulkAction) { const mutationTriple = assertMutationSuccess(response, dataPath); - return processActionResponse(defaultSelection, response, mutationTriple, modelSelectionField, hasReturnType, modelManager); + return processActionResponse(defaultSelection, response, mutationTriple, modelSelectionField, hasReturnType); } else { const mutationTriple = get(response.data, dataPath); - const results = processBulkActionResponse(defaultSelection, response, mutationTriple, modelSelectionField, hasReturnType, modelManager); + const results = processBulkActionResponse(defaultSelection, response, mutationTriple, modelSelectionField, hasReturnType); if (mutationTriple.errors) { const errors = mutationTriple.errors.map((error: any) => gadgetErrorFor(error)); throw new GadgetErrorGroup(errors, results); @@ -312,12 +312,11 @@ const processBulkActionResponse = ( response: any, records: any, modelSelectionField: string, - hasReturnType?: HasReturnType | null, - modelManager?: AnyPublicModelManager | AnyPublicSingletonModelManager | AnyLegacyModelManager + hasReturnType?: HasReturnType | null ) => { if (defaultSelection == null) return; if (!hasReturnType) { - return hydrateRecordArray(response, records[modelSelectionField], modelManager); + return hydrateRecordArray(response, records[modelSelectionField]); } else if (typeof hasReturnType == "boolean") { return records.results; } else { @@ -333,7 +332,7 @@ const processBulkActionResponse = ( "hasReturnType" in innerHasReturnType ? returnTypeForRecord(result, innerHasReturnType.hasReturnType) : false; if (!returnTypeForResult) { - return hydrateRecord(response, result, modelManager); + return hydrateRecord(response, result); } else { return processActionResponse(defaultSelection, response, result, modelSelectionField, returnTypeForResult); } @@ -347,20 +346,19 @@ export const processActionResponse = ( response: any, record: any, modelSelectionField: string, - hasReturnType?: HasReturnType | null, - modelManager?: AnyPublicModelManager | AnyPublicSingletonModelManager | AnyLegacyModelManager + hasReturnType?: HasReturnType | null ): any => { // Delete actions have a null selection. We do an early return for this because `hydrateRecordArray` will fail // if there's nothing at `mutationResult[modelSelectionField]`, but the caller isn't expecting a return (void). if (defaultSelection == null) return; if (!hasReturnType) { - return hydrateRecord(response, record[modelSelectionField], modelManager); + return hydrateRecord(response, record[modelSelectionField]); } else if (typeof hasReturnType == "boolean") { return record.result; } else { const innerReturnType = returnTypeForRecord(record, hasReturnType); - return processActionResponse(defaultSelection, response, record, modelSelectionField, innerReturnType, modelManager); + return processActionResponse(defaultSelection, response, record, modelSelectionField, innerReturnType); } }; @@ -437,8 +435,7 @@ export const backgroundActionResultRunner = async < connection: GadgetConnection, id: string, action: Action, - options?: Options, - modelManager?: AnyModelManager + options?: Options ): Promise> => { const plan = backgroundActionResultOperation(id, action, options); const subscription = connection.currentClient.subscription(plan.query, plan.variables); @@ -461,8 +458,7 @@ export const backgroundActionResultRunner = async < response.data, backgroundAction.result, action.isBulk ? action.modelApiIdentifier : action.modelSelectionField, - action.hasReturnType, - modelManager + action.hasReturnType ); break; } diff --git a/packages/api-client-core/src/support.ts b/packages/api-client-core/src/support.ts index dd589ae55..d4188211e 100644 --- a/packages/api-client-core/src/support.ts +++ b/packages/api-client-core/src/support.ts @@ -1,7 +1,6 @@ import type { OperationResult } from "@urql/core"; import { CombinedError } from "@urql/core"; import { Call, type FieldSelection as BuilderFieldSelection } from "tiny-graphql-query-compiler"; -import type { AnyModelManager } from "./AnyModelManager.js"; import { DataHydrator } from "./DataHydrator.js"; import type { ActionFunctionMetadata, AnyActionFunction } from "./GadgetFunctions.js"; import type { RecordShape } from "./GadgetRecord.js"; @@ -387,37 +386,25 @@ export const getHydrator = (response: Result) => { } }; -export const hydrateRecord = ( - response: Result, - record: any, - modelManager?: AnyModelManager -): GadgetRecord => { +export const hydrateRecord = (response: Result, record: any): GadgetRecord => { const hydrator = getHydrator(response); if (hydrator) { record = hydrator.apply(record); } - return new GadgetRecord(record, modelManager); + return new GadgetRecord(record); }; -export const hydrateRecordArray = ( - response: Result, - records: Array, - modelManager?: AnyModelManager -) => { +export const hydrateRecordArray = (response: Result, records: Array) => { const hydrator = getHydrator(response); if (hydrator) { records = hydrator.apply(records) as any; } - return records?.map((record) => new GadgetRecord(record, modelManager)); + return records?.map((record) => new GadgetRecord(record)); }; -export const hydrateConnection = ( - response: Result, - connection: { edges: { node: Node }[] }, - modelManager?: AnyModelManager -) => { +export const hydrateConnection = (response: Result, connection: { edges: { node: Node }[] }) => { const nodes = connection.edges.map((edge) => edge.node); - return hydrateRecordArray(response, nodes, modelManager); + return hydrateRecordArray(response, nodes); }; const objObjType = "[object Object]"; diff --git a/packages/api-client-core/src/types.ts b/packages/api-client-core/src/types.ts index b5693387b..69baf1455 100644 --- a/packages/api-client-core/src/types.ts +++ b/packages/api-client-core/src/types.ts @@ -700,7 +700,7 @@ export interface InternalFindListOptions { * What fields to retrieve from the API for this API call * __Note__: This selection is different than the top level select option -- it just accepts a list of string fields, and not a nested selection. To use a nested selection, use the top level API. **/ - select?: AnySelection | InternalFieldSelection | null; + select?: InternalFieldSelection; } /** Options for functions that return a paginated list of records from an InternalModelManager */ diff --git a/packages/react/src/auth/useSession.ts b/packages/react/src/auth/useSession.ts index b02039fb4..fc7355536 100644 --- a/packages/react/src/auth/useSession.ts +++ b/packages/react/src/auth/useSession.ts @@ -1,6 +1,5 @@ import type { AnyClient, - AnyPublicSingletonModelManager, DefaultSelection, FindManyFunction, GadgetRecord, @@ -17,7 +16,7 @@ export type GadgetSession = GadgetRecord>; export type GadgetUser = GadgetRecord>; export type ClientWithSessionAndUserManagers = AnyClient & { - currentSession: AnyPublicSingletonModelManager>; + currentSession: { get: GetFunction }; user: { findMany: FindManyFunction }; }; diff --git a/packages/react/src/auto/AutoTable.tsx b/packages/react/src/auto/AutoTable.tsx index 80b2ea296..dc57d9d01 100644 --- a/packages/react/src/auto/AutoTable.tsx +++ b/packages/react/src/auto/AutoTable.tsx @@ -1,4 +1,4 @@ -import type { AnyFindOneFunc, AnyPublicModelManager, FindManyFunction, GadgetRecord } from "@gadgetinc/api-client-core"; +import type { FindManyFunction, GadgetRecord } from "@gadgetinc/api-client-core"; import { type DefaultSelection, type Select } from "@gadgetinc/api-client-core"; import type { TableOptions, TableRow } from "../use-table/types.js"; import type { OptionsType } from "../utils.js"; @@ -12,7 +12,7 @@ export type AutoTableProps< FinderFunction extends FindManyFunction, Options extends FinderFunction["optionsType"] > = { - model: { findMany: FinderFunction } & AnyPublicModelManager; + model: { findMany: FinderFunction }; select?: Options["select"]; pageSize?: number; initialCursor?: string; diff --git a/packages/react/src/auto/shadcn/table/ShadcnAutoTablePagination.tsx b/packages/react/src/auto/shadcn/table/ShadcnAutoTablePagination.tsx index afbb96c63..fd25a1a4a 100644 --- a/packages/react/src/auto/shadcn/table/ShadcnAutoTablePagination.tsx +++ b/packages/react/src/auto/shadcn/table/ShadcnAutoTablePagination.tsx @@ -1,7 +1,7 @@ import { ChevronLeft, ChevronRight } from "lucide-react"; import * as React from "react"; -import type { PaginationResult } from "../../../useList.js"; -import type { ShadcnElements } from "../elements.js"; +import { PaginationResult } from "../../../useList.js"; +import { ShadcnElements } from "../elements.js"; /** * Renders pagination controls for the ShadcnAutoTable diff --git a/packages/react/src/auto/shadcn/table/ShadcnAutoTableSearch.tsx b/packages/react/src/auto/shadcn/table/ShadcnAutoTableSearch.tsx index 024d2cf48..c267662c7 100644 --- a/packages/react/src/auto/shadcn/table/ShadcnAutoTableSearch.tsx +++ b/packages/react/src/auto/shadcn/table/ShadcnAutoTableSearch.tsx @@ -1,7 +1,7 @@ import { CircleX } from "lucide-react"; import * as React from "react"; -import type { SearchResult } from "../../../useDebouncedSearch.js"; -import type { ShadcnElements } from "../elements.js"; +import { SearchResult } from "../../../useDebouncedSearch.js"; +import { ShadcnElements } from "../elements.js"; /** * Renders table search controls for the ShadcnAutoTable diff --git a/packages/react/src/useAction.ts b/packages/react/src/useAction.ts index ea2ff907b..3f37c84cb 100644 --- a/packages/react/src/useAction.ts +++ b/packages/react/src/useAction.ts @@ -148,14 +148,7 @@ const processResult = ( if (errors && errors[0]) { error = ErrorWrapper.forErrorsResponse(errors, error?.response); } else { - data = processActionResponse( - action.defaultSelection, - result, - mutationData, - action.modelSelectionField, - action.hasReturnType, - action.modelManager - ); + data = processActionResponse(action.defaultSelection, result, mutationData, action.modelSelectionField, action.hasReturnType); } } } diff --git a/packages/react/src/useBulkAction.ts b/packages/react/src/useBulkAction.ts index 476daf6a9..ca9ce38e9 100644 --- a/packages/react/src/useBulkAction.ts +++ b/packages/react/src/useBulkAction.ts @@ -144,9 +144,7 @@ const processResult = (result: UseMutationState, action: BulkActionFun if (errors && errors[0]) { error = ErrorWrapper.forErrorsResponse(errors, (error as any)?.response); } else { - data = action.hasReturnType - ? mutationData.results - : hydrateRecordArray(result, mutationData[action.modelSelectionField], action.modelManager); + data = action.hasReturnType ? mutationData.results : hydrateRecordArray(result, mutationData[action.modelSelectionField]); } } else { // Delete action diff --git a/packages/react/src/useFindBy.ts b/packages/react/src/useFindBy.ts index 36d90aac4..2122ce8c4 100644 --- a/packages/react/src/useFindBy.ts +++ b/packages/react/src/useFindBy.ts @@ -71,7 +71,7 @@ export const useFindBy = < if (data) { const connection = get(rawResult.data, dataPath); if (connection) { - records = hydrateConnection(rawResult, connection, finder.modelManager); + records = hydrateConnection(rawResult, connection); data = records[0]; } } diff --git a/packages/react/src/useFindFirst.ts b/packages/react/src/useFindFirst.ts index 883346a50..cfae2d3f7 100644 --- a/packages/react/src/useFindFirst.ts +++ b/packages/react/src/useFindFirst.ts @@ -1,11 +1,4 @@ -import type { - AnyPublicModelManager, - DefaultSelection, - FindFirstFunction, - GadgetRecord, - LimitToKnownKeys, - Select, -} from "@gadgetinc/api-client-core"; +import type { DefaultSelection, FindFirstFunction, GadgetRecord, LimitToKnownKeys, Select } from "@gadgetinc/api-client-core"; import { findManyOperation, get, hydrateConnection, namespaceDataPath } from "@gadgetinc/api-client-core"; import { useMemo } from "react"; import { useGadgetQuery } from "./useGadgetQuery.js"; @@ -43,7 +36,7 @@ export const useFindFirst = < F extends FindFirstFunction, Options extends F["optionsType"] & ReadOperationOptions >( - manager: { findFirst: F } & AnyPublicModelManager, + manager: { findFirst: F }, options?: LimitToKnownKeys ): ReadHookResult< GadgetRecord, DefaultSelection>> @@ -68,7 +61,7 @@ export const useFindFirst = < if (data) { const connection = get(rawResult.data, dataPath); if (connection) { - data = hydrateConnection(rawResult, connection, manager)[0]; + data = hydrateConnection(rawResult, connection)[0]; } else { data = data[0]; } diff --git a/packages/react/src/useFindMany.ts b/packages/react/src/useFindMany.ts index 63657bddd..e71ebddb3 100644 --- a/packages/react/src/useFindMany.ts +++ b/packages/react/src/useFindMany.ts @@ -1,11 +1,4 @@ -import type { - AnyPublicModelManager, - DefaultSelection, - FindManyFunction, - FindOneFunction, - LimitToKnownKeys, - Select, -} from "@gadgetinc/api-client-core"; +import type { AnyModelManager, DefaultSelection, FindManyFunction, LimitToKnownKeys, Select } from "@gadgetinc/api-client-core"; import { GadgetRecordList, findManyOperation, get, hydrateConnection, namespaceDataPath } from "@gadgetinc/api-client-core"; import { useMemo } from "react"; import { useGadgetQuery } from "./useGadgetQuery.js"; @@ -43,7 +36,7 @@ export const useFindMany = < F extends FindManyFunction, Options extends F["optionsType"] & ReadOperationOptions >( - manager: { findMany: F } & AnyPublicModelManager, F>, + manager: { findMany: F }, options?: LimitToKnownKeys ): ReadHookResult< GadgetRecordList, DefaultSelection>> @@ -67,8 +60,8 @@ export const useFindMany = < if (data) { const connection = get(rawResult.data, dataPath); if (connection) { - const records = hydrateConnection(rawResult, connection, manager); - data = GadgetRecordList.boot(manager as unknown as AnyPublicModelManager, records, connection); + const records = hydrateConnection(rawResult, connection); + data = GadgetRecordList.boot(manager as unknown as AnyModelManager, records, connection); } } diff --git a/packages/react/src/useFindOne.ts b/packages/react/src/useFindOne.ts index 812f5c298..acd65b4d0 100644 --- a/packages/react/src/useFindOne.ts +++ b/packages/react/src/useFindOne.ts @@ -1,11 +1,4 @@ -import type { - AnyPublicModelManager, - DefaultSelection, - FindOneFunction, - GadgetRecord, - LimitToKnownKeys, - Select, -} from "@gadgetinc/api-client-core"; +import type { DefaultSelection, FindOneFunction, GadgetRecord, LimitToKnownKeys, Select } from "@gadgetinc/api-client-core"; import { findOneOperation, get, hydrateRecord, namespaceDataPath } from "@gadgetinc/api-client-core"; import { useMemo } from "react"; import { useGadgetQuery } from "./useGadgetQuery.js"; @@ -43,7 +36,7 @@ export const useFindOne = < F extends FindOneFunction, Options extends F["optionsType"] & ReadOperationOptions >( - manager: { findOne: F } & AnyPublicModelManager, + manager: { findOne: F }, id: string, options?: LimitToKnownKeys ): ReadHookResult< @@ -68,7 +61,7 @@ export const useFindOne = < let data = rawResult.data && get(rawResult.data, dataPath); if (data) { - data = hydrateRecord(rawResult, data, manager); + data = hydrateRecord(rawResult, data); } const error = ErrorWrapper.errorIfDataAbsent(rawResult, dataPath, options?.pause); diff --git a/packages/react/src/useGet.ts b/packages/react/src/useGet.ts index d6bcf49fc..104934419 100644 --- a/packages/react/src/useGet.ts +++ b/packages/react/src/useGet.ts @@ -1,11 +1,4 @@ -import type { - AnyPublicSingletonModelManager, - DefaultSelection, - GadgetRecord, - GetFunction, - LimitToKnownKeys, - Select, -} from "@gadgetinc/api-client-core"; +import type { DefaultSelection, GadgetRecord, GetFunction, LimitToKnownKeys, Select } from "@gadgetinc/api-client-core"; import { findOneOperation, get, hydrateRecord, namespaceDataPath } from "@gadgetinc/api-client-core"; import { useMemo } from "react"; import { useGadgetQuery } from "./useGadgetQuery.js"; @@ -43,7 +36,7 @@ export const useGet = < F extends GetFunction, Options extends F["optionsType"] & ReadOperationOptions >( - manager: { get: F } & AnyPublicSingletonModelManager, + manager: { get: F }, options?: LimitToKnownKeys ): ReadHookResult< GadgetRecord, DefaultSelection>> @@ -66,7 +59,7 @@ export const useGet = < let data = null; const rawRecord = rawResult.data && get(rawResult.data, dataPath); if (rawRecord) { - data = hydrateRecord(rawResult, rawRecord, manager); + data = hydrateRecord(rawResult, rawRecord); } const error = ErrorWrapper.forMaybeCombinedError(rawResult.error); diff --git a/packages/react/src/useList.ts b/packages/react/src/useList.ts index 1b4c17e95..49958bae7 100644 --- a/packages/react/src/useList.ts +++ b/packages/react/src/useList.ts @@ -1,12 +1,4 @@ -import type { - AnyFindOneFunc, - AnyPublicModelManager, - DefaultSelection, - FindManyFunction, - GadgetRecord, - LimitToKnownKeys, - Select, -} from "@gadgetinc/api-client-core"; +import type { DefaultSelection, FindManyFunction, GadgetRecord, LimitToKnownKeys, Select } from "@gadgetinc/api-client-core"; import type { OperationContext } from "@urql/core"; import { useCallback, useMemo, useState } from "react"; import type { SearchResult } from "./useDebouncedSearch.js"; @@ -54,7 +46,7 @@ export const useList = < F extends FindManyFunction, Options extends F["optionsType"] & ReadOperationOptions & ListOptions >( - manager: { findMany: F } & AnyPublicModelManager, + manager: { findMany: F }, options?: LimitToKnownKeys ): ListResult< Array< @@ -101,7 +93,6 @@ export const useList = < ...(search.debouncedValue && { search: search.debouncedValue }), }); - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion const selection = useSelectedRecordsController({ currentPageIds: data?.map((record) => (record as any).id) ?? [] }); const goToNextPage = useCallback(() => { diff --git a/packages/react/src/useMaybeFindFirst.ts b/packages/react/src/useMaybeFindFirst.ts index a84e9f759..e2702519b 100644 --- a/packages/react/src/useMaybeFindFirst.ts +++ b/packages/react/src/useMaybeFindFirst.ts @@ -1,13 +1,4 @@ -import type { - AnyFindManyFunc, - AnyFindOneFunc, - AnyPublicModelManager, - DefaultSelection, - FindFirstFunction, - GadgetRecord, - LimitToKnownKeys, - Select, -} from "@gadgetinc/api-client-core"; +import type { DefaultSelection, FindFirstFunction, GadgetRecord, LimitToKnownKeys, Select } from "@gadgetinc/api-client-core"; import { findManyOperation, get, hydrateConnection, namespaceDataPath } from "@gadgetinc/api-client-core"; import { useMemo } from "react"; import { useGadgetQuery } from "./useGadgetQuery.js"; @@ -45,7 +36,7 @@ export const useMaybeFindFirst = < F extends FindFirstFunction, Options extends F["optionsType"] & ReadOperationOptions >( - manager: { findFirst: F } & AnyPublicModelManager, + manager: { findFirst: F }, options?: LimitToKnownKeys ): ReadHookResult, DefaultSelection> @@ -70,7 +61,7 @@ export const useMaybeFindFirst = < if (data) { const connection = get(rawResult.data, dataPath); if (connection) { - data = hydrateConnection(rawResult, connection, manager)[0] ?? null; + data = hydrateConnection(rawResult, connection)[0] ?? null; } else { data = data[0] ?? null; } diff --git a/packages/react/src/useMaybeFindOne.ts b/packages/react/src/useMaybeFindOne.ts index 153d79b53..cf9477db8 100644 --- a/packages/react/src/useMaybeFindOne.ts +++ b/packages/react/src/useMaybeFindOne.ts @@ -1,11 +1,4 @@ -import type { - AnyPublicModelManager, - DefaultSelection, - FindOneFunction, - GadgetRecord, - LimitToKnownKeys, - Select, -} from "@gadgetinc/api-client-core"; +import type { DefaultSelection, FindOneFunction, GadgetRecord, LimitToKnownKeys, Select } from "@gadgetinc/api-client-core"; import { findOneOperation, get, hydrateRecord, namespaceDataPath } from "@gadgetinc/api-client-core"; import { useMemo } from "react"; import { useGadgetQuery } from "./useGadgetQuery.js"; @@ -43,7 +36,7 @@ export const useMaybeFindOne = < F extends FindOneFunction, Options extends F["optionsType"] & ReadOperationOptions >( - manager: { findOne: F } & AnyPublicModelManager, + manager: { findOne: F }, id: string, options?: LimitToKnownKeys ): ReadHookResult, Options extends F["optionsType"] & ReadOperationOptions & TableOptions >( - manager: { findMany: F } & AnyPublicModelManager, + manager: { findMany: F }, options?: LimitToKnownKeys< Options, Omit & ReadOperationOptions & TableOptions