postgresdk 0.19.3 → 0.19.4
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/README.md +7 -6
- package/dist/cli.js +37 -22
- package/dist/emit-client.d.ts +1 -0
- package/dist/emit-params-zod.d.ts +3 -1
- package/dist/emit-routes-hono.d.ts +1 -0
- package/dist/emit-routes.d.ts +1 -0
- package/dist/emit-shared-params-zod.d.ts +3 -1
- package/dist/index.js +37 -22
- package/dist/types.d.ts +2 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -154,6 +154,7 @@ export default {
|
|
|
154
154
|
},
|
|
155
155
|
},
|
|
156
156
|
numericMode: "auto", // "auto" | "number" | "string" - How to type numeric columns
|
|
157
|
+
maxLimit: 1000, // Max allowed `limit` value (0 = no cap)
|
|
157
158
|
includeMethodsDepth: 2, // Max depth for nested includes
|
|
158
159
|
dateType: "date", // "date" | "string" - How to handle timestamps
|
|
159
160
|
serverFramework: "hono", // Currently only hono is supported
|
|
@@ -715,15 +716,15 @@ const result = await sdk.users.list({
|
|
|
715
716
|
// Access results
|
|
716
717
|
result.data; // User[] - array of records
|
|
717
718
|
result.total; // number - total matching records
|
|
718
|
-
result.limit; // number - page size used
|
|
719
|
+
result.limit; // number | undefined - page size used (absent when no limit specified)
|
|
719
720
|
result.offset; // number - offset used
|
|
720
|
-
result.hasMore; // boolean - more pages available
|
|
721
|
+
result.hasMore; // boolean - more pages available (false when no limit)
|
|
721
722
|
|
|
722
|
-
// Note:
|
|
723
|
+
// Note: Omitting `limit` returns all matching records. Max limit is controlled by `maxLimit` config (default: 1000).
|
|
723
724
|
|
|
724
|
-
// Calculate pagination info
|
|
725
|
-
const totalPages = Math.ceil(result.total / result.limit);
|
|
726
|
-
const currentPage = Math.floor(result.offset / result.limit) + 1;
|
|
725
|
+
// Calculate pagination info (when using explicit limit)
|
|
726
|
+
const totalPages = result.limit ? Math.ceil(result.total / result.limit) : 1;
|
|
727
|
+
const currentPage = result.limit ? Math.floor(result.offset / result.limit) + 1 : 1;
|
|
727
728
|
|
|
728
729
|
// Multi-column sorting
|
|
729
730
|
const sorted = await sdk.users.list({
|
package/dist/cli.js
CHANGED
|
@@ -1221,7 +1221,7 @@ function generateExampleValue(column) {
|
|
|
1221
1221
|
}
|
|
1222
1222
|
function generateQueryParams(table, enums) {
|
|
1223
1223
|
const params = {
|
|
1224
|
-
limit: "number - Max records to return (
|
|
1224
|
+
limit: "number - Max records to return (omit for all)",
|
|
1225
1225
|
offset: "number - Records to skip",
|
|
1226
1226
|
orderBy: "string | string[] - Field(s) to sort by",
|
|
1227
1227
|
order: "'asc' | 'desc' | ('asc' | 'desc')[] - Sort direction(s)"
|
|
@@ -2920,7 +2920,7 @@ export const Upsert${Type}Schema = z.object({
|
|
|
2920
2920
|
|
|
2921
2921
|
// src/emit-params-zod.ts
|
|
2922
2922
|
init_utils();
|
|
2923
|
-
function emitParamsZod(table, graph) {
|
|
2923
|
+
function emitParamsZod(table, graph, opts) {
|
|
2924
2924
|
const Type = pascal(table.name);
|
|
2925
2925
|
const columnNames = table.columns.map((c) => `"${c.name}"`).join(", ");
|
|
2926
2926
|
const pkCols = Array.isArray(table.pk) ? table.pk : table.pk ? [table.pk] : [];
|
|
@@ -2937,7 +2937,7 @@ export const ${Type}PkSchema = ${pkSchema};
|
|
|
2937
2937
|
// Schema for list query parameters
|
|
2938
2938
|
export const ${Type}ListParamsSchema = z.object({
|
|
2939
2939
|
include: ${includeSpecSchema}.optional(),
|
|
2940
|
-
limit: z.number().int().positive().max(
|
|
2940
|
+
limit: z.number().int().positive()${opts.maxLimit > 0 ? `.max(${opts.maxLimit})` : ""}.optional(),
|
|
2941
2941
|
offset: z.number().int().nonnegative().optional(),
|
|
2942
2942
|
where: z.any().optional(),
|
|
2943
2943
|
vector: VectorSearchParamsSchema.optional(),
|
|
@@ -2959,12 +2959,12 @@ export type ${Type}OrderParams = z.infer<typeof ${Type}OrderParamsSchema>;
|
|
|
2959
2959
|
}
|
|
2960
2960
|
|
|
2961
2961
|
// src/emit-shared-params-zod.ts
|
|
2962
|
-
function emitSharedParamsZod() {
|
|
2962
|
+
function emitSharedParamsZod(opts) {
|
|
2963
2963
|
return `import { z } from "zod";
|
|
2964
2964
|
|
|
2965
2965
|
// Shared pagination schema (used across all tables)
|
|
2966
2966
|
export const PaginationParamsSchema = z.object({
|
|
2967
|
-
limit: z.number().int().positive().max(
|
|
2967
|
+
limit: z.number().int().positive()${opts.maxLimit > 0 ? `.max(${opts.maxLimit})` : ""}.optional(),
|
|
2968
2968
|
offset: z.number().int().nonnegative().optional()
|
|
2969
2969
|
}).strict();
|
|
2970
2970
|
|
|
@@ -2996,8 +2996,8 @@ export interface PaginatedResponse<T> {
|
|
|
2996
2996
|
data: T[];
|
|
2997
2997
|
/** Total number of records matching the query (across all pages) */
|
|
2998
2998
|
total: number;
|
|
2999
|
-
/** Maximum number of records per page */
|
|
3000
|
-
limit
|
|
2999
|
+
/** Maximum number of records per page (absent when no limit was specified) */
|
|
3000
|
+
limit?: number;
|
|
3001
3001
|
/** Number of records skipped (for pagination) */
|
|
3002
3002
|
offset: number;
|
|
3003
3003
|
/** Whether there are more records available after this page */
|
|
@@ -3072,7 +3072,7 @@ const listSchema = z.object({
|
|
|
3072
3072
|
include: z.any().optional(),
|
|
3073
3073
|
select: z.array(z.string()).min(1).optional(),
|
|
3074
3074
|
exclude: z.array(z.string()).min(1).optional(),
|
|
3075
|
-
limit: z.number().int().positive().max(
|
|
3075
|
+
limit: z.number().int().positive()${opts.maxLimit > 0 ? `.max(${opts.maxLimit})` : ""}.optional(),
|
|
3076
3076
|
offset: z.number().int().min(0).optional(),
|
|
3077
3077
|
orderBy: z.union([columnEnum, z.array(columnEnum)]).optional(),
|
|
3078
3078
|
order: z.union([z.enum(["asc", "desc"]), z.array(z.enum(["asc", "desc"]))]).optional(),
|
|
@@ -3985,7 +3985,7 @@ ${hasJsonbColumns ? ` /**
|
|
|
3985
3985
|
* @param params.where - Filter conditions using operators like $eq, $gt, $in, $like, etc.
|
|
3986
3986
|
* @param params.orderBy - Column(s) to sort by
|
|
3987
3987
|
* @param params.order - Sort direction(s): "asc" or "desc"
|
|
3988
|
-
* @param params.limit - Maximum number of records to return (
|
|
3988
|
+
* @param params.limit - Maximum number of records to return${opts.maxLimit > 0 ? ` (max: ${opts.maxLimit})` : ""}. Omit to return all matching records.
|
|
3989
3989
|
* @param params.offset - Number of records to skip for pagination
|
|
3990
3990
|
* @param params.include - Related records to include (return type automatically infers included relations)
|
|
3991
3991
|
* @returns Paginated results with all fields (and included relations if specified)
|
|
@@ -4085,7 +4085,7 @@ ${hasJsonbColumns ? ` /**
|
|
|
4085
4085
|
* @param params.where - Filter conditions using operators like $eq, $gt, $in, $like, etc.
|
|
4086
4086
|
* @param params.orderBy - Column(s) to sort by
|
|
4087
4087
|
* @param params.order - Sort direction(s): "asc" or "desc"
|
|
4088
|
-
* @param params.limit - Maximum number of records to return (
|
|
4088
|
+
* @param params.limit - Maximum number of records to return${opts.maxLimit > 0 ? ` (max: ${opts.maxLimit})` : ""}. Omit to return all matching records.
|
|
4089
4089
|
* @param params.offset - Number of records to skip for pagination
|
|
4090
4090
|
* @param params.include - Related records to include (return type automatically infers included relations)
|
|
4091
4091
|
* @returns Paginated results with all fields (and included relations if specified)
|
|
@@ -6579,7 +6579,7 @@ export async function listRecords(
|
|
|
6579
6579
|
}
|
|
6580
6580
|
): Promise<{ data?: any; total?: number; limit?: number; offset?: number; hasMore?: boolean; error?: string; issues?: any; needsIncludes?: boolean; includeSpec?: any; status: number }> {
|
|
6581
6581
|
try {
|
|
6582
|
-
const { where: whereClause, limit
|
|
6582
|
+
const { where: whereClause, limit, offset = 0, include, orderBy, order, vector, trigram, distinctOn, includeSoftDeleted } = params;
|
|
6583
6583
|
|
|
6584
6584
|
// DISTINCT ON support
|
|
6585
6585
|
const distinctCols: string[] | null = distinctOn ? (Array.isArray(distinctOn) ? distinctOn : [distinctOn]) : null;
|
|
@@ -6715,10 +6715,22 @@ export async function listRecords(
|
|
|
6715
6715
|
orderBySQL = buildOrderBySQL(userOrderCols, userDirs);
|
|
6716
6716
|
}
|
|
6717
6717
|
|
|
6718
|
-
// Add limit and offset params
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6718
|
+
// Add limit and offset params (conditional — omit LIMIT clause when limit is undefined)
|
|
6719
|
+
let limitOffsetSQL: string;
|
|
6720
|
+
let allParams: any[];
|
|
6721
|
+
if (limit !== undefined) {
|
|
6722
|
+
const limitParam = \`$\${paramIndex}\`;
|
|
6723
|
+
const offsetParam = \`$\${paramIndex + 1}\`;
|
|
6724
|
+
limitOffsetSQL = \`LIMIT \${limitParam} OFFSET \${offsetParam}\`;
|
|
6725
|
+
allParams = [...queryParams, ...whereParams, limit, offset];
|
|
6726
|
+
} else if (offset > 0) {
|
|
6727
|
+
const offsetParam = \`$\${paramIndex}\`;
|
|
6728
|
+
limitOffsetSQL = \`OFFSET \${offsetParam}\`;
|
|
6729
|
+
allParams = [...queryParams, ...whereParams, offset];
|
|
6730
|
+
} else {
|
|
6731
|
+
limitOffsetSQL = '';
|
|
6732
|
+
allParams = [...queryParams, ...whereParams];
|
|
6733
|
+
}
|
|
6722
6734
|
|
|
6723
6735
|
// Get total count for pagination
|
|
6724
6736
|
const countText = distinctCols
|
|
@@ -6734,9 +6746,9 @@ export async function listRecords(
|
|
|
6734
6746
|
// Inner query: DISTINCT ON with only the distinctCols ORDER BY prefix (PG requirement).
|
|
6735
6747
|
// Outer query: free ORDER BY from the user's full orderBy list, plus LIMIT/OFFSET.
|
|
6736
6748
|
const innerQuery = \`SELECT DISTINCT ON (\${_distinctOnColsSQL}) \${baseColumns} FROM "\${ctx.table}" \${whereSQL} ORDER BY \${_distinctOnColsSQL}\`;
|
|
6737
|
-
text = \`SELECT * FROM (\${innerQuery}) __distinct \${orderBySQL}
|
|
6749
|
+
text = \`SELECT * FROM (\${innerQuery}) __distinct \${orderBySQL} \${limitOffsetSQL}\`.trim();
|
|
6738
6750
|
} else {
|
|
6739
|
-
text = \`SELECT \${selectClause} FROM "\${ctx.table}" \${whereSQL} \${orderBySQL}
|
|
6751
|
+
text = \`SELECT \${selectClause} FROM "\${ctx.table}" \${whereSQL} \${orderBySQL} \${limitOffsetSQL}\`.trim();
|
|
6740
6752
|
}
|
|
6741
6753
|
log.debug(\`LIST \${ctx.table} SQL:\`, text, "params:", allParams);
|
|
6742
6754
|
|
|
@@ -6744,7 +6756,7 @@ export async function listRecords(
|
|
|
6744
6756
|
const parsedRows = parseVectorColumns(rows, ctx.vectorColumns);
|
|
6745
6757
|
|
|
6746
6758
|
// Calculate hasMore
|
|
6747
|
-
const hasMore = offset + limit < total;
|
|
6759
|
+
const hasMore = limit !== undefined ? offset + limit < total : false;
|
|
6748
6760
|
|
|
6749
6761
|
const metadata = {
|
|
6750
6762
|
data: parsedRows,
|
|
@@ -7784,6 +7796,7 @@ async function generate(configPath, options) {
|
|
|
7784
7796
|
clientDir = join2(originalClientDir, "sdk");
|
|
7785
7797
|
}
|
|
7786
7798
|
const serverFramework = cfg.serverFramework || "hono";
|
|
7799
|
+
const maxLimit = cfg.maxLimit ?? 1000;
|
|
7787
7800
|
const generateTests = cfg.tests?.generate ?? false;
|
|
7788
7801
|
const originalTestDir = cfg.tests?.output || "./api/tests";
|
|
7789
7802
|
let testDir = originalTestDir;
|
|
@@ -7812,7 +7825,7 @@ async function generate(configPath, options) {
|
|
|
7812
7825
|
files.push({ path: join2(clientDir, "include-spec.ts"), content: includeSpec });
|
|
7813
7826
|
const includeResolver = emitIncludeResolver(graph, cfg.useJsExtensions);
|
|
7814
7827
|
files.push({ path: join2(clientDir, "include-resolver.ts"), content: includeResolver });
|
|
7815
|
-
files.push({ path: join2(clientDir, "params", "shared.ts"), content: emitSharedParamsZod() });
|
|
7828
|
+
files.push({ path: join2(clientDir, "params", "shared.ts"), content: emitSharedParamsZod({ maxLimit }) });
|
|
7816
7829
|
files.push({ path: join2(clientDir, "types", "shared.ts"), content: emitSharedTypes() });
|
|
7817
7830
|
files.push({ path: join2(clientDir, "base-client.ts"), content: emitBaseClient() });
|
|
7818
7831
|
files.push({ path: join2(clientDir, "where-types.ts"), content: emitWhereTypes() });
|
|
@@ -7849,7 +7862,7 @@ async function generate(configPath, options) {
|
|
|
7849
7862
|
const zodSrc = emitZod(table, { numericMode }, model.enums);
|
|
7850
7863
|
files.push({ path: join2(serverDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
7851
7864
|
files.push({ path: join2(clientDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
7852
|
-
const paramsZodSrc = emitParamsZod(table, graph);
|
|
7865
|
+
const paramsZodSrc = emitParamsZod(table, graph, { maxLimit });
|
|
7853
7866
|
files.push({ path: join2(clientDir, "params", `${table.name}.ts`), content: paramsZodSrc });
|
|
7854
7867
|
let routeContent;
|
|
7855
7868
|
if (serverFramework === "hono") {
|
|
@@ -7859,7 +7872,8 @@ async function generate(configPath, options) {
|
|
|
7859
7872
|
includeMethodsDepth: cfg.includeMethodsDepth || 2,
|
|
7860
7873
|
authStrategy: getAuthStrategy(normalizedAuth),
|
|
7861
7874
|
useJsExtensions: cfg.useJsExtensions,
|
|
7862
|
-
apiPathPrefix: cfg.apiPathPrefix || "/v1"
|
|
7875
|
+
apiPathPrefix: cfg.apiPathPrefix || "/v1",
|
|
7876
|
+
maxLimit
|
|
7863
7877
|
});
|
|
7864
7878
|
} else {
|
|
7865
7879
|
throw new Error(`Framework "${serverFramework}" is not yet supported. Currently only "hono" is available.`);
|
|
@@ -7875,7 +7889,8 @@ async function generate(configPath, options) {
|
|
|
7875
7889
|
exposeHardDelete,
|
|
7876
7890
|
useJsExtensions: cfg.useJsExtensionsClient,
|
|
7877
7891
|
includeMethodsDepth: cfg.includeMethodsDepth ?? 2,
|
|
7878
|
-
skipJunctionTables: cfg.skipJunctionTables ?? true
|
|
7892
|
+
skipJunctionTables: cfg.skipJunctionTables ?? true,
|
|
7893
|
+
maxLimit
|
|
7879
7894
|
}, model)
|
|
7880
7895
|
});
|
|
7881
7896
|
}
|
package/dist/emit-client.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare function emitClient(table: Table, graph: Graph, opts: {
|
|
|
6
6
|
useJsExtensions?: boolean;
|
|
7
7
|
includeMethodsDepth?: number;
|
|
8
8
|
skipJunctionTables?: boolean;
|
|
9
|
+
maxLimit: number;
|
|
9
10
|
}, model?: Model): string;
|
|
10
11
|
export declare function emitClientIndex(tables: Table[], useJsExtensions?: boolean, graph?: Graph, includeOpts?: {
|
|
11
12
|
maxDepth: number;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { Table } from "./introspect";
|
|
2
2
|
import type { Graph } from "./rel-classify";
|
|
3
|
-
export declare function emitParamsZod(table: Table, graph: Graph
|
|
3
|
+
export declare function emitParamsZod(table: Table, graph: Graph, opts: {
|
|
4
|
+
maxLimit: number;
|
|
5
|
+
}): string;
|
package/dist/emit-routes.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1220,7 +1220,7 @@ function generateExampleValue(column) {
|
|
|
1220
1220
|
}
|
|
1221
1221
|
function generateQueryParams(table, enums) {
|
|
1222
1222
|
const params = {
|
|
1223
|
-
limit: "number - Max records to return (
|
|
1223
|
+
limit: "number - Max records to return (omit for all)",
|
|
1224
1224
|
offset: "number - Records to skip",
|
|
1225
1225
|
orderBy: "string | string[] - Field(s) to sort by",
|
|
1226
1226
|
order: "'asc' | 'desc' | ('asc' | 'desc')[] - Sort direction(s)"
|
|
@@ -1960,7 +1960,7 @@ export const Upsert${Type}Schema = z.object({
|
|
|
1960
1960
|
|
|
1961
1961
|
// src/emit-params-zod.ts
|
|
1962
1962
|
init_utils();
|
|
1963
|
-
function emitParamsZod(table, graph) {
|
|
1963
|
+
function emitParamsZod(table, graph, opts) {
|
|
1964
1964
|
const Type = pascal(table.name);
|
|
1965
1965
|
const columnNames = table.columns.map((c) => `"${c.name}"`).join(", ");
|
|
1966
1966
|
const pkCols = Array.isArray(table.pk) ? table.pk : table.pk ? [table.pk] : [];
|
|
@@ -1977,7 +1977,7 @@ export const ${Type}PkSchema = ${pkSchema};
|
|
|
1977
1977
|
// Schema for list query parameters
|
|
1978
1978
|
export const ${Type}ListParamsSchema = z.object({
|
|
1979
1979
|
include: ${includeSpecSchema}.optional(),
|
|
1980
|
-
limit: z.number().int().positive().max(
|
|
1980
|
+
limit: z.number().int().positive()${opts.maxLimit > 0 ? `.max(${opts.maxLimit})` : ""}.optional(),
|
|
1981
1981
|
offset: z.number().int().nonnegative().optional(),
|
|
1982
1982
|
where: z.any().optional(),
|
|
1983
1983
|
vector: VectorSearchParamsSchema.optional(),
|
|
@@ -1999,12 +1999,12 @@ export type ${Type}OrderParams = z.infer<typeof ${Type}OrderParamsSchema>;
|
|
|
1999
1999
|
}
|
|
2000
2000
|
|
|
2001
2001
|
// src/emit-shared-params-zod.ts
|
|
2002
|
-
function emitSharedParamsZod() {
|
|
2002
|
+
function emitSharedParamsZod(opts) {
|
|
2003
2003
|
return `import { z } from "zod";
|
|
2004
2004
|
|
|
2005
2005
|
// Shared pagination schema (used across all tables)
|
|
2006
2006
|
export const PaginationParamsSchema = z.object({
|
|
2007
|
-
limit: z.number().int().positive().max(
|
|
2007
|
+
limit: z.number().int().positive()${opts.maxLimit > 0 ? `.max(${opts.maxLimit})` : ""}.optional(),
|
|
2008
2008
|
offset: z.number().int().nonnegative().optional()
|
|
2009
2009
|
}).strict();
|
|
2010
2010
|
|
|
@@ -2036,8 +2036,8 @@ export interface PaginatedResponse<T> {
|
|
|
2036
2036
|
data: T[];
|
|
2037
2037
|
/** Total number of records matching the query (across all pages) */
|
|
2038
2038
|
total: number;
|
|
2039
|
-
/** Maximum number of records per page */
|
|
2040
|
-
limit
|
|
2039
|
+
/** Maximum number of records per page (absent when no limit was specified) */
|
|
2040
|
+
limit?: number;
|
|
2041
2041
|
/** Number of records skipped (for pagination) */
|
|
2042
2042
|
offset: number;
|
|
2043
2043
|
/** Whether there are more records available after this page */
|
|
@@ -2112,7 +2112,7 @@ const listSchema = z.object({
|
|
|
2112
2112
|
include: z.any().optional(),
|
|
2113
2113
|
select: z.array(z.string()).min(1).optional(),
|
|
2114
2114
|
exclude: z.array(z.string()).min(1).optional(),
|
|
2115
|
-
limit: z.number().int().positive().max(
|
|
2115
|
+
limit: z.number().int().positive()${opts.maxLimit > 0 ? `.max(${opts.maxLimit})` : ""}.optional(),
|
|
2116
2116
|
offset: z.number().int().min(0).optional(),
|
|
2117
2117
|
orderBy: z.union([columnEnum, z.array(columnEnum)]).optional(),
|
|
2118
2118
|
order: z.union([z.enum(["asc", "desc"]), z.array(z.enum(["asc", "desc"]))]).optional(),
|
|
@@ -3025,7 +3025,7 @@ ${hasJsonbColumns ? ` /**
|
|
|
3025
3025
|
* @param params.where - Filter conditions using operators like $eq, $gt, $in, $like, etc.
|
|
3026
3026
|
* @param params.orderBy - Column(s) to sort by
|
|
3027
3027
|
* @param params.order - Sort direction(s): "asc" or "desc"
|
|
3028
|
-
* @param params.limit - Maximum number of records to return (
|
|
3028
|
+
* @param params.limit - Maximum number of records to return${opts.maxLimit > 0 ? ` (max: ${opts.maxLimit})` : ""}. Omit to return all matching records.
|
|
3029
3029
|
* @param params.offset - Number of records to skip for pagination
|
|
3030
3030
|
* @param params.include - Related records to include (return type automatically infers included relations)
|
|
3031
3031
|
* @returns Paginated results with all fields (and included relations if specified)
|
|
@@ -3125,7 +3125,7 @@ ${hasJsonbColumns ? ` /**
|
|
|
3125
3125
|
* @param params.where - Filter conditions using operators like $eq, $gt, $in, $like, etc.
|
|
3126
3126
|
* @param params.orderBy - Column(s) to sort by
|
|
3127
3127
|
* @param params.order - Sort direction(s): "asc" or "desc"
|
|
3128
|
-
* @param params.limit - Maximum number of records to return (
|
|
3128
|
+
* @param params.limit - Maximum number of records to return${opts.maxLimit > 0 ? ` (max: ${opts.maxLimit})` : ""}. Omit to return all matching records.
|
|
3129
3129
|
* @param params.offset - Number of records to skip for pagination
|
|
3130
3130
|
* @param params.include - Related records to include (return type automatically infers included relations)
|
|
3131
3131
|
* @returns Paginated results with all fields (and included relations if specified)
|
|
@@ -5619,7 +5619,7 @@ export async function listRecords(
|
|
|
5619
5619
|
}
|
|
5620
5620
|
): Promise<{ data?: any; total?: number; limit?: number; offset?: number; hasMore?: boolean; error?: string; issues?: any; needsIncludes?: boolean; includeSpec?: any; status: number }> {
|
|
5621
5621
|
try {
|
|
5622
|
-
const { where: whereClause, limit
|
|
5622
|
+
const { where: whereClause, limit, offset = 0, include, orderBy, order, vector, trigram, distinctOn, includeSoftDeleted } = params;
|
|
5623
5623
|
|
|
5624
5624
|
// DISTINCT ON support
|
|
5625
5625
|
const distinctCols: string[] | null = distinctOn ? (Array.isArray(distinctOn) ? distinctOn : [distinctOn]) : null;
|
|
@@ -5755,10 +5755,22 @@ export async function listRecords(
|
|
|
5755
5755
|
orderBySQL = buildOrderBySQL(userOrderCols, userDirs);
|
|
5756
5756
|
}
|
|
5757
5757
|
|
|
5758
|
-
// Add limit and offset params
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5758
|
+
// Add limit and offset params (conditional — omit LIMIT clause when limit is undefined)
|
|
5759
|
+
let limitOffsetSQL: string;
|
|
5760
|
+
let allParams: any[];
|
|
5761
|
+
if (limit !== undefined) {
|
|
5762
|
+
const limitParam = \`$\${paramIndex}\`;
|
|
5763
|
+
const offsetParam = \`$\${paramIndex + 1}\`;
|
|
5764
|
+
limitOffsetSQL = \`LIMIT \${limitParam} OFFSET \${offsetParam}\`;
|
|
5765
|
+
allParams = [...queryParams, ...whereParams, limit, offset];
|
|
5766
|
+
} else if (offset > 0) {
|
|
5767
|
+
const offsetParam = \`$\${paramIndex}\`;
|
|
5768
|
+
limitOffsetSQL = \`OFFSET \${offsetParam}\`;
|
|
5769
|
+
allParams = [...queryParams, ...whereParams, offset];
|
|
5770
|
+
} else {
|
|
5771
|
+
limitOffsetSQL = '';
|
|
5772
|
+
allParams = [...queryParams, ...whereParams];
|
|
5773
|
+
}
|
|
5762
5774
|
|
|
5763
5775
|
// Get total count for pagination
|
|
5764
5776
|
const countText = distinctCols
|
|
@@ -5774,9 +5786,9 @@ export async function listRecords(
|
|
|
5774
5786
|
// Inner query: DISTINCT ON with only the distinctCols ORDER BY prefix (PG requirement).
|
|
5775
5787
|
// Outer query: free ORDER BY from the user's full orderBy list, plus LIMIT/OFFSET.
|
|
5776
5788
|
const innerQuery = \`SELECT DISTINCT ON (\${_distinctOnColsSQL}) \${baseColumns} FROM "\${ctx.table}" \${whereSQL} ORDER BY \${_distinctOnColsSQL}\`;
|
|
5777
|
-
text = \`SELECT * FROM (\${innerQuery}) __distinct \${orderBySQL}
|
|
5789
|
+
text = \`SELECT * FROM (\${innerQuery}) __distinct \${orderBySQL} \${limitOffsetSQL}\`.trim();
|
|
5778
5790
|
} else {
|
|
5779
|
-
text = \`SELECT \${selectClause} FROM "\${ctx.table}" \${whereSQL} \${orderBySQL}
|
|
5791
|
+
text = \`SELECT \${selectClause} FROM "\${ctx.table}" \${whereSQL} \${orderBySQL} \${limitOffsetSQL}\`.trim();
|
|
5780
5792
|
}
|
|
5781
5793
|
log.debug(\`LIST \${ctx.table} SQL:\`, text, "params:", allParams);
|
|
5782
5794
|
|
|
@@ -5784,7 +5796,7 @@ export async function listRecords(
|
|
|
5784
5796
|
const parsedRows = parseVectorColumns(rows, ctx.vectorColumns);
|
|
5785
5797
|
|
|
5786
5798
|
// Calculate hasMore
|
|
5787
|
-
const hasMore = offset + limit < total;
|
|
5799
|
+
const hasMore = limit !== undefined ? offset + limit < total : false;
|
|
5788
5800
|
|
|
5789
5801
|
const metadata = {
|
|
5790
5802
|
data: parsedRows,
|
|
@@ -6824,6 +6836,7 @@ async function generate(configPath, options) {
|
|
|
6824
6836
|
clientDir = join2(originalClientDir, "sdk");
|
|
6825
6837
|
}
|
|
6826
6838
|
const serverFramework = cfg.serverFramework || "hono";
|
|
6839
|
+
const maxLimit = cfg.maxLimit ?? 1000;
|
|
6827
6840
|
const generateTests = cfg.tests?.generate ?? false;
|
|
6828
6841
|
const originalTestDir = cfg.tests?.output || "./api/tests";
|
|
6829
6842
|
let testDir = originalTestDir;
|
|
@@ -6852,7 +6865,7 @@ async function generate(configPath, options) {
|
|
|
6852
6865
|
files.push({ path: join2(clientDir, "include-spec.ts"), content: includeSpec });
|
|
6853
6866
|
const includeResolver = emitIncludeResolver(graph, cfg.useJsExtensions);
|
|
6854
6867
|
files.push({ path: join2(clientDir, "include-resolver.ts"), content: includeResolver });
|
|
6855
|
-
files.push({ path: join2(clientDir, "params", "shared.ts"), content: emitSharedParamsZod() });
|
|
6868
|
+
files.push({ path: join2(clientDir, "params", "shared.ts"), content: emitSharedParamsZod({ maxLimit }) });
|
|
6856
6869
|
files.push({ path: join2(clientDir, "types", "shared.ts"), content: emitSharedTypes() });
|
|
6857
6870
|
files.push({ path: join2(clientDir, "base-client.ts"), content: emitBaseClient() });
|
|
6858
6871
|
files.push({ path: join2(clientDir, "where-types.ts"), content: emitWhereTypes() });
|
|
@@ -6889,7 +6902,7 @@ async function generate(configPath, options) {
|
|
|
6889
6902
|
const zodSrc = emitZod(table, { numericMode }, model.enums);
|
|
6890
6903
|
files.push({ path: join2(serverDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
6891
6904
|
files.push({ path: join2(clientDir, "zod", `${table.name}.ts`), content: zodSrc });
|
|
6892
|
-
const paramsZodSrc = emitParamsZod(table, graph);
|
|
6905
|
+
const paramsZodSrc = emitParamsZod(table, graph, { maxLimit });
|
|
6893
6906
|
files.push({ path: join2(clientDir, "params", `${table.name}.ts`), content: paramsZodSrc });
|
|
6894
6907
|
let routeContent;
|
|
6895
6908
|
if (serverFramework === "hono") {
|
|
@@ -6899,7 +6912,8 @@ async function generate(configPath, options) {
|
|
|
6899
6912
|
includeMethodsDepth: cfg.includeMethodsDepth || 2,
|
|
6900
6913
|
authStrategy: getAuthStrategy(normalizedAuth),
|
|
6901
6914
|
useJsExtensions: cfg.useJsExtensions,
|
|
6902
|
-
apiPathPrefix: cfg.apiPathPrefix || "/v1"
|
|
6915
|
+
apiPathPrefix: cfg.apiPathPrefix || "/v1",
|
|
6916
|
+
maxLimit
|
|
6903
6917
|
});
|
|
6904
6918
|
} else {
|
|
6905
6919
|
throw new Error(`Framework "${serverFramework}" is not yet supported. Currently only "hono" is available.`);
|
|
@@ -6915,7 +6929,8 @@ async function generate(configPath, options) {
|
|
|
6915
6929
|
exposeHardDelete,
|
|
6916
6930
|
useJsExtensions: cfg.useJsExtensionsClient,
|
|
6917
6931
|
includeMethodsDepth: cfg.includeMethodsDepth ?? 2,
|
|
6918
|
-
skipJunctionTables: cfg.skipJunctionTables ?? true
|
|
6932
|
+
skipJunctionTables: cfg.skipJunctionTables ?? true,
|
|
6933
|
+
maxLimit
|
|
6919
6934
|
}, model)
|
|
6920
6935
|
});
|
|
6921
6936
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -38,6 +38,8 @@ export interface Config {
|
|
|
38
38
|
skipJunctionTables?: boolean;
|
|
39
39
|
serverFramework?: "hono" | "express" | "fastify";
|
|
40
40
|
apiPathPrefix?: string;
|
|
41
|
+
/** Maximum allowed value for the `limit` parameter in list operations (default: 1000). Set to 0 to disable. */
|
|
42
|
+
maxLimit?: number;
|
|
41
43
|
auth?: AuthConfigInput;
|
|
42
44
|
pullToken?: string;
|
|
43
45
|
pull?: PullConfig;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postgresdk",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.4",
|
|
4
4
|
"description": "Generate a typed server/client SDK from a Postgres schema (includes, Zod, Hono).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "bun build src/cli.ts src/index.ts --outdir dist --target node --format esm --external=pg --external=zod --external=hono --external=prompts --external=node:* && tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
25
|
-
"test": "bun test:write-files && bun test:init && bun test:gen && bun test test/test-where-clause.test.ts && bun test test/test-where-or-and.test.ts && bun test test/test-nested-include-options.test.ts && bun test test/test-include-methods-with-options.test.ts && bun test:gen-with-tests && bun test:pull && bun test:enums && bun test:typecheck && bun test:drizzle-e2e && bun test test/test-numeric-mode-integration.test.ts && bun test test/test-jsonb-array-serialization.test.ts && bun test test/test-trigram-search.test.ts && bun test test/test-soft-delete-config.test.ts && bun test test/test-soft-delete-include-loader.test.ts && bun test test/test-soft-delete-nested-include.test.ts && bun test test/test-transaction.test.ts && bun test test/test-nullable-belongs-to.test.ts",
|
|
25
|
+
"test": "bun test:write-files && bun test:init && bun test:gen && bun test test/test-where-clause.test.ts && bun test test/test-where-or-and.test.ts && bun test test/test-nested-include-options.test.ts && bun test test/test-include-methods-with-options.test.ts && bun test:gen-with-tests && bun test:pull && bun test:enums && bun test:typecheck && bun test:drizzle-e2e && bun test test/test-numeric-mode-integration.test.ts && bun test test/test-jsonb-array-serialization.test.ts && bun test test/test-trigram-search.test.ts && bun test test/test-soft-delete-config.test.ts && bun test test/test-soft-delete-include-loader.test.ts && bun test test/test-soft-delete-nested-include.test.ts && bun test test/test-transaction.test.ts && bun test test/test-nullable-belongs-to.test.ts && bun test test/test-no-default-limit.test.ts",
|
|
26
26
|
"test:write-files": "bun test/test-write-files-if-changed.ts",
|
|
27
27
|
"test:init": "bun test/test-init.ts",
|
|
28
28
|
"test:gen": "bun test/test-gen.ts",
|