joist-graphql-resolver-utils 2.3.0-next.88 → 2.3.0-next.89
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cursorPagination.cjs +7 -1
- package/build/cursorPagination.cjs.map +1 -1
- package/build/cursorPagination.js +7 -1
- package/build/cursorPagination.js.map +1 -1
- package/build/paginationUtils.cjs +2 -2
- package/build/paginationUtils.cjs.map +1 -1
- package/build/paginationUtils.js +2 -2
- package/build/paginationUtils.js.map +1 -1
- package/package.json +3 -3
|
@@ -12,7 +12,13 @@ async function paginateCursor(ctx, type, args) {
|
|
|
12
12
|
orderBy
|
|
13
13
|
}) : await require_paginationUtils.queryEntities(ctx, {
|
|
14
14
|
...withCursorQuery(type, args),
|
|
15
|
-
orderBy: [args.last ? {
|
|
15
|
+
orderBy: [args.last ? {
|
|
16
|
+
sort: type.select.id,
|
|
17
|
+
order: "DESC"
|
|
18
|
+
} : {
|
|
19
|
+
sort: type.select.id,
|
|
20
|
+
order: "ASC"
|
|
21
|
+
}],
|
|
16
22
|
limit,
|
|
17
23
|
offset: void 0
|
|
18
24
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursorPagination.cjs","names":["queryEntities","#ctx","#type","#filter","#edges","#hasNextPagePromise","#countPastCursor","#hasPreviousPagePromise","#totalCountPromise","countQuery"],"sources":["../src/cursorPagination.ts"],"sourcesContent":["import {\n type Entity,\n type FindGqlFilterOptions,\n type IdOf,\n type MaybeAbstractEntityConstructor,\n type ValueGraphQLFilter,\n} from \"joist-core\";\n\nimport {\n type ContextWithEm,\n type PaginationFilter,\n type PaginationQuery,\n countQuery,\n defaultLimit,\n queryEntities,\n} from \"./paginationUtils.ts\";\n\ntype CursorArgs<T extends Entity, F extends object = PaginationFilter<T>> = {\n filter?: F | null;\n first?: number | null;\n after?: string | null;\n last?: number | null;\n before?: string | null;\n};\n\n/** Returns an ID-ordered cursor connection for a resolver, replacing the entity query's ordering. */\nexport function paginateCursor<T extends Entity>(\n ctx: ContextWithEm,\n query: PaginationQuery<T>,\n args: Omit<CursorArgs<T>, \"filter\">,\n): Promise<{ edges: { node: T; cursor: string }[]; nodes: T[]; pageInfo: CursorPageInfo<T> }>;\nexport function paginateCursor<T extends Entity, F extends object = PaginationFilter<T>>(\n ctx: ContextWithEm,\n type: MaybeAbstractEntityConstructor<T>,\n args: CursorArgs<T, F>,\n): Promise<{ edges: { node: T; cursor: string }[]; nodes: T[]; pageInfo: CursorPageInfo<T> }>;\nexport async function paginateCursor<T extends Entity, F extends object = PaginationFilter<T>>(\n ctx: ContextWithEm,\n type: MaybeAbstractEntityConstructor<T> | PaginationQuery<T>,\n args: CursorArgs<T, F>,\n): Promise<{ edges: { node: T; cursor: string }[]; nodes: T[]; pageInfo: CursorPageInfo<T> }> {\n const limit = args.first ?? args.last ?? defaultLimit;\n const baseFilter = (args.filter ?? {}) as PaginationFilter<T>;\n const filter = withCursorFilter(baseFilter, args);\n const orderBy = { id: args.last ? \"DESC\" : \"ASC\" } as FindGqlFilterOptions<T>[\"orderBy\"];\n const nodes =\n typeof type === \"function\"\n ? await ctx.em.findGql(type, filter, { limit, orderBy })\n : await queryEntities(ctx, {\n ...withCursorQuery(type, args),\n orderBy: [args.last ? {
|
|
1
|
+
{"version":3,"file":"cursorPagination.cjs","names":["queryEntities","#ctx","#type","#filter","#edges","#hasNextPagePromise","#countPastCursor","#hasPreviousPagePromise","#totalCountPromise","countQuery"],"sources":["../src/cursorPagination.ts"],"sourcesContent":["import {\n type Entity,\n type FindGqlFilterOptions,\n type IdOf,\n type MaybeAbstractEntityConstructor,\n type ValueGraphQLFilter,\n} from \"joist-core\";\n\nimport {\n type ContextWithEm,\n type PaginationFilter,\n type PaginationQuery,\n countQuery,\n defaultLimit,\n queryEntities,\n} from \"./paginationUtils.ts\";\n\ntype CursorArgs<T extends Entity, F extends object = PaginationFilter<T>> = {\n filter?: F | null;\n first?: number | null;\n after?: string | null;\n last?: number | null;\n before?: string | null;\n};\n\n/** Returns an ID-ordered cursor connection for a resolver, replacing the entity query's ordering. */\nexport function paginateCursor<T extends Entity>(\n ctx: ContextWithEm,\n query: PaginationQuery<T>,\n args: Omit<CursorArgs<T>, \"filter\">,\n): Promise<{ edges: { node: T; cursor: string }[]; nodes: T[]; pageInfo: CursorPageInfo<T> }>;\nexport function paginateCursor<T extends Entity, F extends object = PaginationFilter<T>>(\n ctx: ContextWithEm,\n type: MaybeAbstractEntityConstructor<T>,\n args: CursorArgs<T, F>,\n): Promise<{ edges: { node: T; cursor: string }[]; nodes: T[]; pageInfo: CursorPageInfo<T> }>;\nexport async function paginateCursor<T extends Entity, F extends object = PaginationFilter<T>>(\n ctx: ContextWithEm,\n type: MaybeAbstractEntityConstructor<T> | PaginationQuery<T>,\n args: CursorArgs<T, F>,\n): Promise<{ edges: { node: T; cursor: string }[]; nodes: T[]; pageInfo: CursorPageInfo<T> }> {\n const limit = args.first ?? args.last ?? defaultLimit;\n const baseFilter = (args.filter ?? {}) as PaginationFilter<T>;\n const filter = withCursorFilter(baseFilter, args);\n const orderBy = { id: args.last ? \"DESC\" : \"ASC\" } as FindGqlFilterOptions<T>[\"orderBy\"];\n const nodes =\n typeof type === \"function\"\n ? await ctx.em.findGql(type, filter, { limit, orderBy })\n : await queryEntities(ctx, {\n ...withCursorQuery(type, args),\n orderBy: [args.last ? { sort: type.select.id, order: \"DESC\" } : { sort: type.select.id, order: \"ASC\" }],\n limit,\n offset: undefined,\n });\n const orderedNodes = args.last ? [...nodes].reverse() : nodes;\n const edges = orderedNodes.map((node) => ({ node, cursor: encodeCursor(String(node.id)) }));\n return {\n edges,\n nodes: orderedNodes,\n pageInfo: new CursorPageInfo(\n ctx,\n typeof type === \"function\" ? type : { ...type, orderBy: undefined },\n baseFilter,\n edges,\n ),\n };\n}\n\n/** Lazily computes cursor page fields. */\nexport class CursorPageInfo<T extends Entity = Entity> {\n #ctx: ContextWithEm;\n #edges: { node: T; cursor: string }[];\n #filter: PaginationFilter<T>;\n #hasNextPagePromise: Promise<boolean> | undefined;\n #hasPreviousPagePromise: Promise<boolean> | undefined;\n #totalCountPromise: Promise<number> | undefined;\n #type: MaybeAbstractEntityConstructor<T> | PaginationQuery<T>;\n\n constructor(\n ctx: ContextWithEm,\n type: MaybeAbstractEntityConstructor<T> | PaginationQuery<T>,\n filter: PaginationFilter<T>,\n edges: { node: T; cursor: string }[],\n ) {\n this.#ctx = ctx;\n this.#type = type;\n this.#filter = filter;\n this.#edges = edges;\n }\n\n get startCursor(): string | undefined {\n return this.#edges[0]?.cursor;\n }\n\n get endCursor(): string | undefined {\n return this.#edges[this.#edges.length - 1]?.cursor;\n }\n\n get hasNextPage(): Promise<boolean> {\n return (this.#hasNextPagePromise ??= this.#countPastCursor(\"after\", this.endCursor));\n }\n\n get hasPreviousPage(): Promise<boolean> {\n return (this.#hasPreviousPagePromise ??= this.#countPastCursor(\"before\", this.startCursor));\n }\n\n get totalCount(): Promise<number> {\n return (this.#totalCountPromise ??=\n typeof this.#type === \"function\"\n ? this.#ctx.em.findCount(this.#type, this.#filter)\n : countQuery(this.#ctx, this.#type));\n }\n\n /** Counts rows past a cursor only when the field is requested. */\n async #countPastCursor(direction: \"after\" | \"before\", cursor: string | undefined): Promise<boolean> {\n if (!cursor) return false;\n if (typeof this.#type !== \"function\") {\n return (await countQuery(this.#ctx, withCursorQuery(this.#type, { [direction]: cursor }))) > 0;\n }\n const filter = withCursorFilter(this.#filter, { [direction]: cursor });\n return (await this.#ctx.em.findCount(this.#type, filter)) > 0;\n }\n}\n\n/** Adds both cursor bounds without replacing the query's existing conditions. */\nfunction withCursorQuery<T extends Entity>(\n base: PaginationQuery<T>,\n args: { after?: string | null; before?: string | null },\n): PaginationQuery<T> {\n return {\n ...base,\n where: {\n and: [\n base.where,\n args.after ? base.select.id.gt(decodeCursor(args.after) as IdOf<T>) : undefined,\n args.before ? base.select.id.lt(decodeCursor(args.before) as IdOf<T>) : undefined,\n ],\n },\n };\n}\n\n/** Adds cursor bounds to a filter. */\nfunction withCursorFilter<T extends Entity>(\n filter: PaginationFilter<T>,\n args: { after?: string | null; before?: string | null },\n): PaginationFilter<T> {\n const cursor = args.after ?? args.before;\n if (!cursor) return filter;\n const op = args.after ? \"gt\" : \"lt\";\n return { ...filter, id: { [op]: decodeCursor(cursor) } as ValueGraphQLFilter<string> } as PaginationFilter<T>;\n}\n\n/** Encodes an entity id as an opaque cursor. */\nfunction encodeCursor(id: string): string {\n return Buffer.from(id).toString(\"base64\");\n}\n\n/** Decodes an opaque cursor back into an entity id. */\nfunction decodeCursor(cursor: string): string {\n return Buffer.from(cursor, \"base64\").toString(\"utf8\");\n}\n"],"mappings":"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"}
|
|
@@ -11,7 +11,13 @@ async function paginateCursor(ctx, type, args) {
|
|
|
11
11
|
orderBy
|
|
12
12
|
}) : await queryEntities(ctx, {
|
|
13
13
|
...withCursorQuery(type, args),
|
|
14
|
-
orderBy: [args.last ? {
|
|
14
|
+
orderBy: [args.last ? {
|
|
15
|
+
sort: type.select.id,
|
|
16
|
+
order: "DESC"
|
|
17
|
+
} : {
|
|
18
|
+
sort: type.select.id,
|
|
19
|
+
order: "ASC"
|
|
20
|
+
}],
|
|
15
21
|
limit,
|
|
16
22
|
offset: void 0
|
|
17
23
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursorPagination.js","names":["#ctx","#type","#filter","#edges","#hasNextPagePromise","#countPastCursor","#hasPreviousPagePromise","#totalCountPromise"],"sources":["../src/cursorPagination.ts"],"sourcesContent":["import {\n type Entity,\n type FindGqlFilterOptions,\n type IdOf,\n type MaybeAbstractEntityConstructor,\n type ValueGraphQLFilter,\n} from \"joist-core\";\n\nimport {\n type ContextWithEm,\n type PaginationFilter,\n type PaginationQuery,\n countQuery,\n defaultLimit,\n queryEntities,\n} from \"./paginationUtils.ts\";\n\ntype CursorArgs<T extends Entity, F extends object = PaginationFilter<T>> = {\n filter?: F | null;\n first?: number | null;\n after?: string | null;\n last?: number | null;\n before?: string | null;\n};\n\n/** Returns an ID-ordered cursor connection for a resolver, replacing the entity query's ordering. */\nexport function paginateCursor<T extends Entity>(\n ctx: ContextWithEm,\n query: PaginationQuery<T>,\n args: Omit<CursorArgs<T>, \"filter\">,\n): Promise<{ edges: { node: T; cursor: string }[]; nodes: T[]; pageInfo: CursorPageInfo<T> }>;\nexport function paginateCursor<T extends Entity, F extends object = PaginationFilter<T>>(\n ctx: ContextWithEm,\n type: MaybeAbstractEntityConstructor<T>,\n args: CursorArgs<T, F>,\n): Promise<{ edges: { node: T; cursor: string }[]; nodes: T[]; pageInfo: CursorPageInfo<T> }>;\nexport async function paginateCursor<T extends Entity, F extends object = PaginationFilter<T>>(\n ctx: ContextWithEm,\n type: MaybeAbstractEntityConstructor<T> | PaginationQuery<T>,\n args: CursorArgs<T, F>,\n): Promise<{ edges: { node: T; cursor: string }[]; nodes: T[]; pageInfo: CursorPageInfo<T> }> {\n const limit = args.first ?? args.last ?? defaultLimit;\n const baseFilter = (args.filter ?? {}) as PaginationFilter<T>;\n const filter = withCursorFilter(baseFilter, args);\n const orderBy = { id: args.last ? \"DESC\" : \"ASC\" } as FindGqlFilterOptions<T>[\"orderBy\"];\n const nodes =\n typeof type === \"function\"\n ? await ctx.em.findGql(type, filter, { limit, orderBy })\n : await queryEntities(ctx, {\n ...withCursorQuery(type, args),\n orderBy: [args.last ? {
|
|
1
|
+
{"version":3,"file":"cursorPagination.js","names":["#ctx","#type","#filter","#edges","#hasNextPagePromise","#countPastCursor","#hasPreviousPagePromise","#totalCountPromise"],"sources":["../src/cursorPagination.ts"],"sourcesContent":["import {\n type Entity,\n type FindGqlFilterOptions,\n type IdOf,\n type MaybeAbstractEntityConstructor,\n type ValueGraphQLFilter,\n} from \"joist-core\";\n\nimport {\n type ContextWithEm,\n type PaginationFilter,\n type PaginationQuery,\n countQuery,\n defaultLimit,\n queryEntities,\n} from \"./paginationUtils.ts\";\n\ntype CursorArgs<T extends Entity, F extends object = PaginationFilter<T>> = {\n filter?: F | null;\n first?: number | null;\n after?: string | null;\n last?: number | null;\n before?: string | null;\n};\n\n/** Returns an ID-ordered cursor connection for a resolver, replacing the entity query's ordering. */\nexport function paginateCursor<T extends Entity>(\n ctx: ContextWithEm,\n query: PaginationQuery<T>,\n args: Omit<CursorArgs<T>, \"filter\">,\n): Promise<{ edges: { node: T; cursor: string }[]; nodes: T[]; pageInfo: CursorPageInfo<T> }>;\nexport function paginateCursor<T extends Entity, F extends object = PaginationFilter<T>>(\n ctx: ContextWithEm,\n type: MaybeAbstractEntityConstructor<T>,\n args: CursorArgs<T, F>,\n): Promise<{ edges: { node: T; cursor: string }[]; nodes: T[]; pageInfo: CursorPageInfo<T> }>;\nexport async function paginateCursor<T extends Entity, F extends object = PaginationFilter<T>>(\n ctx: ContextWithEm,\n type: MaybeAbstractEntityConstructor<T> | PaginationQuery<T>,\n args: CursorArgs<T, F>,\n): Promise<{ edges: { node: T; cursor: string }[]; nodes: T[]; pageInfo: CursorPageInfo<T> }> {\n const limit = args.first ?? args.last ?? defaultLimit;\n const baseFilter = (args.filter ?? {}) as PaginationFilter<T>;\n const filter = withCursorFilter(baseFilter, args);\n const orderBy = { id: args.last ? \"DESC\" : \"ASC\" } as FindGqlFilterOptions<T>[\"orderBy\"];\n const nodes =\n typeof type === \"function\"\n ? await ctx.em.findGql(type, filter, { limit, orderBy })\n : await queryEntities(ctx, {\n ...withCursorQuery(type, args),\n orderBy: [args.last ? { sort: type.select.id, order: \"DESC\" } : { sort: type.select.id, order: \"ASC\" }],\n limit,\n offset: undefined,\n });\n const orderedNodes = args.last ? [...nodes].reverse() : nodes;\n const edges = orderedNodes.map((node) => ({ node, cursor: encodeCursor(String(node.id)) }));\n return {\n edges,\n nodes: orderedNodes,\n pageInfo: new CursorPageInfo(\n ctx,\n typeof type === \"function\" ? type : { ...type, orderBy: undefined },\n baseFilter,\n edges,\n ),\n };\n}\n\n/** Lazily computes cursor page fields. */\nexport class CursorPageInfo<T extends Entity = Entity> {\n #ctx: ContextWithEm;\n #edges: { node: T; cursor: string }[];\n #filter: PaginationFilter<T>;\n #hasNextPagePromise: Promise<boolean> | undefined;\n #hasPreviousPagePromise: Promise<boolean> | undefined;\n #totalCountPromise: Promise<number> | undefined;\n #type: MaybeAbstractEntityConstructor<T> | PaginationQuery<T>;\n\n constructor(\n ctx: ContextWithEm,\n type: MaybeAbstractEntityConstructor<T> | PaginationQuery<T>,\n filter: PaginationFilter<T>,\n edges: { node: T; cursor: string }[],\n ) {\n this.#ctx = ctx;\n this.#type = type;\n this.#filter = filter;\n this.#edges = edges;\n }\n\n get startCursor(): string | undefined {\n return this.#edges[0]?.cursor;\n }\n\n get endCursor(): string | undefined {\n return this.#edges[this.#edges.length - 1]?.cursor;\n }\n\n get hasNextPage(): Promise<boolean> {\n return (this.#hasNextPagePromise ??= this.#countPastCursor(\"after\", this.endCursor));\n }\n\n get hasPreviousPage(): Promise<boolean> {\n return (this.#hasPreviousPagePromise ??= this.#countPastCursor(\"before\", this.startCursor));\n }\n\n get totalCount(): Promise<number> {\n return (this.#totalCountPromise ??=\n typeof this.#type === \"function\"\n ? this.#ctx.em.findCount(this.#type, this.#filter)\n : countQuery(this.#ctx, this.#type));\n }\n\n /** Counts rows past a cursor only when the field is requested. */\n async #countPastCursor(direction: \"after\" | \"before\", cursor: string | undefined): Promise<boolean> {\n if (!cursor) return false;\n if (typeof this.#type !== \"function\") {\n return (await countQuery(this.#ctx, withCursorQuery(this.#type, { [direction]: cursor }))) > 0;\n }\n const filter = withCursorFilter(this.#filter, { [direction]: cursor });\n return (await this.#ctx.em.findCount(this.#type, filter)) > 0;\n }\n}\n\n/** Adds both cursor bounds without replacing the query's existing conditions. */\nfunction withCursorQuery<T extends Entity>(\n base: PaginationQuery<T>,\n args: { after?: string | null; before?: string | null },\n): PaginationQuery<T> {\n return {\n ...base,\n where: {\n and: [\n base.where,\n args.after ? base.select.id.gt(decodeCursor(args.after) as IdOf<T>) : undefined,\n args.before ? base.select.id.lt(decodeCursor(args.before) as IdOf<T>) : undefined,\n ],\n },\n };\n}\n\n/** Adds cursor bounds to a filter. */\nfunction withCursorFilter<T extends Entity>(\n filter: PaginationFilter<T>,\n args: { after?: string | null; before?: string | null },\n): PaginationFilter<T> {\n const cursor = args.after ?? args.before;\n if (!cursor) return filter;\n const op = args.after ? \"gt\" : \"lt\";\n return { ...filter, id: { [op]: decodeCursor(cursor) } as ValueGraphQLFilter<string> } as PaginationFilter<T>;\n}\n\n/** Encodes an entity id as an opaque cursor. */\nfunction encodeCursor(id: string): string {\n return Buffer.from(id).toString(\"base64\");\n}\n\n/** Decodes an opaque cursor back into an entity id. */\nfunction decodeCursor(cursor: string): string {\n return Buffer.from(cursor, \"base64\").toString(\"utf8\");\n}\n"],"mappings":"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"}
|
|
@@ -10,8 +10,8 @@ function queryEntities(ctx, base) {
|
|
|
10
10
|
async function countQuery(ctx, base) {
|
|
11
11
|
const select = { id: base.select.id };
|
|
12
12
|
if (Array.isArray(base.orderBy)) for (const [index, order] of base.orderBy.entries()) {
|
|
13
|
-
const
|
|
14
|
-
if (
|
|
13
|
+
const sort = order?.sort;
|
|
14
|
+
if (typeof sort === "object" && sort !== null && order.order !== void 0) select[`order${index}`] = sort;
|
|
15
15
|
}
|
|
16
16
|
const rows = (0, joist_core.query)({
|
|
17
17
|
...base,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paginationUtils.cjs","names":["query"],"sources":["../src/paginationUtils.ts"],"sourcesContent":["import {\n type Entity,\n type EntityColumn,\n type EntityManager,\n type ExprLike,\n type GraphQLFilterWithAlias,\n type Query,\n type TableFor,\n query,\n} from \"joist-core\";\n\nexport type ContextWithEm = { em: EntityManager };\nexport type PaginationFilter<T extends Entity> = GraphQLFilterWithAlias<T>;\nexport type PaginationQuery<T extends Entity> = Query<TableFor<T> & { readonly id: EntityColumn<T, never, string> }>;\n\nexport const defaultLimit = 100;\n\n/** Executes an entity selection after pagination has been applied. */\nexport function queryEntities<T extends Entity>(ctx: ContextWithEm, base: PaginationQuery<T>): Promise<T[]> {\n // Widen the phantom entity type so em.query can resolve its conditional scope checks.\n return ctx.em.query(base as PaginationQuery<Entity>) as Promise<T[]>;\n}\n\n/** Counts the unpaginated rows, preserving distinct, grouping, and join semantics. */\nexport async function countQuery<T extends Entity>(ctx: ContextWithEm, base: PaginationQuery<T>): Promise<number> {\n const select: { id: EntityColumn<T, never, string> } & Record<string, ExprLike<unknown>> = { id: base.select.id };\n // Keep references from expression ordering so removing ORDER BY does not prune a join.\n // I.e. ordering Authors by Book title must still count the joined Author/Book rows.\n if (Array.isArray(base.orderBy)) {\n for (const [index, order] of base.orderBy.entries()) {\n const
|
|
1
|
+
{"version":3,"file":"paginationUtils.cjs","names":["query"],"sources":["../src/paginationUtils.ts"],"sourcesContent":["import {\n type Entity,\n type EntityColumn,\n type EntityManager,\n type ExprLike,\n type GraphQLFilterWithAlias,\n type Query,\n type TableFor,\n query,\n} from \"joist-core\";\n\nexport type ContextWithEm = { em: EntityManager };\nexport type PaginationFilter<T extends Entity> = GraphQLFilterWithAlias<T>;\nexport type PaginationQuery<T extends Entity> = Query<TableFor<T> & { readonly id: EntityColumn<T, never, string> }>;\n\nexport const defaultLimit = 100;\n\n/** Executes an entity selection after pagination has been applied. */\nexport function queryEntities<T extends Entity>(ctx: ContextWithEm, base: PaginationQuery<T>): Promise<T[]> {\n // Widen the phantom entity type so em.query can resolve its conditional scope checks.\n return ctx.em.query(base as PaginationQuery<Entity>) as Promise<T[]>;\n}\n\n/** Counts the unpaginated rows, preserving distinct, grouping, and join semantics. */\nexport async function countQuery<T extends Entity>(ctx: ContextWithEm, base: PaginationQuery<T>): Promise<number> {\n const select: { id: EntityColumn<T, never, string> } & Record<string, ExprLike<unknown>> = { id: base.select.id };\n // Keep references from expression ordering so removing ORDER BY does not prune a join.\n // I.e. ordering Authors by Book title must still count the joined Author/Book rows.\n if (Array.isArray(base.orderBy)) {\n for (const [index, order] of base.orderBy.entries()) {\n const sort = order?.sort;\n if (typeof sort === \"object\" && sort !== null && order.order !== undefined) select[`order${index}`] = sort;\n }\n }\n const rows = query({ ...base, select, orderBy: undefined, limit: undefined, offset: undefined });\n const [result] = await ctx.em.query({ from: rows, select: { count: rows.id.count() } });\n return result.count;\n}\n"],"mappings":";;;AAeA,MAAa,eAAe;;AAG5B,SAAgB,cAAgC,KAAoB,MAAwC;CAE1G,OAAO,IAAI,GAAG,MAAM,IAA+B;AACrD;;AAGA,eAAsB,WAA6B,KAAoB,MAA2C;CAChH,MAAM,SAAqF,EAAE,IAAI,KAAK,OAAO,GAAG;CAGhH,IAAI,MAAM,QAAQ,KAAK,OAAO,GAC5B,KAAK,MAAM,CAAC,OAAO,UAAU,KAAK,QAAQ,QAAQ,GAAG;EACnD,MAAM,OAAO,OAAO;EACpB,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,UAAU,KAAA,GAAW,OAAO,QAAQ,WAAW;CACxG;CAEF,MAAM,QAAA,GAAOA,WAAAA,MAAAA,CAAM;EAAE,GAAG;EAAM;EAAQ,SAAS,KAAA;EAAW,OAAO,KAAA;EAAW,QAAQ,KAAA;CAAU,CAAC;CAC/F,MAAM,CAAC,UAAU,MAAM,IAAI,GAAG,MAAM;EAAE,MAAM;EAAM,QAAQ,EAAE,OAAO,KAAK,GAAG,MAAM,EAAE;CAAE,CAAC;CACtF,OAAO,OAAO;AAChB"}
|
package/build/paginationUtils.js
CHANGED
|
@@ -9,8 +9,8 @@ function queryEntities(ctx, base) {
|
|
|
9
9
|
async function countQuery(ctx, base) {
|
|
10
10
|
const select = { id: base.select.id };
|
|
11
11
|
if (Array.isArray(base.orderBy)) for (const [index, order] of base.orderBy.entries()) {
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
12
|
+
const sort = order?.sort;
|
|
13
|
+
if (typeof sort === "object" && sort !== null && order.order !== void 0) select[`order${index}`] = sort;
|
|
14
14
|
}
|
|
15
15
|
const rows = query({
|
|
16
16
|
...base,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paginationUtils.js","names":[],"sources":["../src/paginationUtils.ts"],"sourcesContent":["import {\n type Entity,\n type EntityColumn,\n type EntityManager,\n type ExprLike,\n type GraphQLFilterWithAlias,\n type Query,\n type TableFor,\n query,\n} from \"joist-core\";\n\nexport type ContextWithEm = { em: EntityManager };\nexport type PaginationFilter<T extends Entity> = GraphQLFilterWithAlias<T>;\nexport type PaginationQuery<T extends Entity> = Query<TableFor<T> & { readonly id: EntityColumn<T, never, string> }>;\n\nexport const defaultLimit = 100;\n\n/** Executes an entity selection after pagination has been applied. */\nexport function queryEntities<T extends Entity>(ctx: ContextWithEm, base: PaginationQuery<T>): Promise<T[]> {\n // Widen the phantom entity type so em.query can resolve its conditional scope checks.\n return ctx.em.query(base as PaginationQuery<Entity>) as Promise<T[]>;\n}\n\n/** Counts the unpaginated rows, preserving distinct, grouping, and join semantics. */\nexport async function countQuery<T extends Entity>(ctx: ContextWithEm, base: PaginationQuery<T>): Promise<number> {\n const select: { id: EntityColumn<T, never, string> } & Record<string, ExprLike<unknown>> = { id: base.select.id };\n // Keep references from expression ordering so removing ORDER BY does not prune a join.\n // I.e. ordering Authors by Book title must still count the joined Author/Book rows.\n if (Array.isArray(base.orderBy)) {\n for (const [index, order] of base.orderBy.entries()) {\n const
|
|
1
|
+
{"version":3,"file":"paginationUtils.js","names":[],"sources":["../src/paginationUtils.ts"],"sourcesContent":["import {\n type Entity,\n type EntityColumn,\n type EntityManager,\n type ExprLike,\n type GraphQLFilterWithAlias,\n type Query,\n type TableFor,\n query,\n} from \"joist-core\";\n\nexport type ContextWithEm = { em: EntityManager };\nexport type PaginationFilter<T extends Entity> = GraphQLFilterWithAlias<T>;\nexport type PaginationQuery<T extends Entity> = Query<TableFor<T> & { readonly id: EntityColumn<T, never, string> }>;\n\nexport const defaultLimit = 100;\n\n/** Executes an entity selection after pagination has been applied. */\nexport function queryEntities<T extends Entity>(ctx: ContextWithEm, base: PaginationQuery<T>): Promise<T[]> {\n // Widen the phantom entity type so em.query can resolve its conditional scope checks.\n return ctx.em.query(base as PaginationQuery<Entity>) as Promise<T[]>;\n}\n\n/** Counts the unpaginated rows, preserving distinct, grouping, and join semantics. */\nexport async function countQuery<T extends Entity>(ctx: ContextWithEm, base: PaginationQuery<T>): Promise<number> {\n const select: { id: EntityColumn<T, never, string> } & Record<string, ExprLike<unknown>> = { id: base.select.id };\n // Keep references from expression ordering so removing ORDER BY does not prune a join.\n // I.e. ordering Authors by Book title must still count the joined Author/Book rows.\n if (Array.isArray(base.orderBy)) {\n for (const [index, order] of base.orderBy.entries()) {\n const sort = order?.sort;\n if (typeof sort === \"object\" && sort !== null && order.order !== undefined) select[`order${index}`] = sort;\n }\n }\n const rows = query({ ...base, select, orderBy: undefined, limit: undefined, offset: undefined });\n const [result] = await ctx.em.query({ from: rows, select: { count: rows.id.count() } });\n return result.count;\n}\n"],"mappings":";;AAeA,MAAa,eAAe;;AAG5B,SAAgB,cAAgC,KAAoB,MAAwC;CAE1G,OAAO,IAAI,GAAG,MAAM,IAA+B;AACrD;;AAGA,eAAsB,WAA6B,KAAoB,MAA2C;CAChH,MAAM,SAAqF,EAAE,IAAI,KAAK,OAAO,GAAG;CAGhH,IAAI,MAAM,QAAQ,KAAK,OAAO,GAC5B,KAAK,MAAM,CAAC,OAAO,UAAU,KAAK,QAAQ,QAAQ,GAAG;EACnD,MAAM,OAAO,OAAO;EACpB,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,UAAU,KAAA,GAAW,OAAO,QAAQ,WAAW;CACxG;CAEF,MAAM,OAAO,MAAM;EAAE,GAAG;EAAM;EAAQ,SAAS,KAAA;EAAW,OAAO,KAAA;EAAW,QAAQ,KAAA;CAAU,CAAC;CAC/F,MAAM,CAAC,UAAU,MAAM,IAAI,GAAG,MAAM;EAAE,MAAM;EAAM,QAAQ,EAAE,OAAO,KAAK,GAAG,MAAM,EAAE;CAAE,CAAC;CACtF,OAAO,OAAO;AAChB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "joist-graphql-resolver-utils",
|
|
3
|
-
"version": "2.3.0-next.
|
|
3
|
+
"version": "2.3.0-next.89",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -84,8 +84,8 @@
|
|
|
84
84
|
"build"
|
|
85
85
|
],
|
|
86
86
|
"peerDependencies": {
|
|
87
|
-
"joist-core": "2.3.0-next.
|
|
88
|
-
"joist-test-utils": "2.3.0-next.
|
|
87
|
+
"joist-core": "2.3.0-next.89",
|
|
88
|
+
"joist-test-utils": "2.3.0-next.89"
|
|
89
89
|
},
|
|
90
90
|
"dependencies": {
|
|
91
91
|
"graphql": "^17.0.2"
|