postgresdk 0.7.6 → 0.8.0

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/dist/cli.js CHANGED
@@ -1914,18 +1914,211 @@ ${hasAuth ? `
1914
1914
 
1915
1915
  // src/emit-client.ts
1916
1916
  init_utils();
1917
- function emitClient(table, useJsExtensions) {
1917
+
1918
+ // src/emit-include-methods.ts
1919
+ init_utils();
1920
+ function isJunctionTable(table) {
1921
+ if (!table.name.includes("_"))
1922
+ return false;
1923
+ const fkColumns = new Set(table.fks.flatMap((fk) => fk.from));
1924
+ const nonPkColumns = table.columns.filter((c) => !table.pk.includes(c.name));
1925
+ return nonPkColumns.every((c) => fkColumns.has(c.name));
1926
+ }
1927
+ function pathToMethodSuffix(path) {
1928
+ return "With" + path.map((p) => pascal(p)).join("And");
1929
+ }
1930
+ function buildReturnType(baseTable, path, isMany, targets, graph) {
1931
+ const BaseType = `Select${pascal(baseTable)}`;
1932
+ if (path.length === 0)
1933
+ return BaseType;
1934
+ let type = BaseType;
1935
+ let currentTable = baseTable;
1936
+ const parts = [];
1937
+ for (let i = 0;i < path.length; i++) {
1938
+ const key = path[i];
1939
+ const target = targets[i];
1940
+ if (!key || !target)
1941
+ continue;
1942
+ const targetType = `Select${pascal(target)}`;
1943
+ if (i === 0) {
1944
+ parts.push(`${key}: ${isMany[i] ? `${targetType}[]` : targetType}`);
1945
+ } else {
1946
+ let nestedType = targetType;
1947
+ for (let j = i;j < path.length; j++) {
1948
+ if (j > i) {
1949
+ const nestedKey = path[j];
1950
+ const nestedTarget = targets[j];
1951
+ if (!nestedKey || !nestedTarget)
1952
+ continue;
1953
+ const nestedTargetType = `Select${pascal(nestedTarget)}`;
1954
+ nestedType = `${nestedType} & { ${nestedKey}: ${isMany[j] ? `${nestedTargetType}[]` : nestedTargetType} }`;
1955
+ }
1956
+ }
1957
+ const prevKey = path[i - 1];
1958
+ const prevTarget = targets[i - 1];
1959
+ if (prevKey && prevTarget) {
1960
+ parts[parts.length - 1] = `${prevKey}: ${isMany[i - 1] ? `(Select${pascal(prevTarget)} & { ${key}: ${isMany[i] ? `${targetType}[]` : targetType} })[]` : `Select${pascal(prevTarget)} & { ${key}: ${isMany[i] ? `${targetType}[]` : targetType} }`}`;
1961
+ }
1962
+ break;
1963
+ }
1964
+ }
1965
+ return `${type} & { ${parts.join("; ")} }`;
1966
+ }
1967
+ function buildIncludeSpec(path) {
1968
+ if (path.length === 0)
1969
+ return {};
1970
+ if (path.length === 1)
1971
+ return { [path[0]]: true };
1972
+ let spec = true;
1973
+ for (let i = path.length - 1;i > 0; i--) {
1974
+ const key = path[i];
1975
+ if (!key)
1976
+ continue;
1977
+ spec = { [key]: spec };
1978
+ }
1979
+ const rootKey = path[0];
1980
+ return rootKey ? { [rootKey]: spec } : {};
1981
+ }
1982
+ function generateIncludeMethods(table, graph, opts) {
1983
+ const methods = [];
1984
+ const baseTableName = table.name;
1985
+ if (opts.skipJunctionTables && isJunctionTable(table)) {
1986
+ return methods;
1987
+ }
1988
+ const edges = graph[baseTableName] || {};
1989
+ function explore(currentTable, path, isMany, targets, visited, depth) {
1990
+ if (depth > opts.maxDepth)
1991
+ return;
1992
+ const currentEdges = graph[currentTable] || {};
1993
+ for (const [key, edge] of Object.entries(currentEdges)) {
1994
+ if (visited.has(edge.target))
1995
+ continue;
1996
+ const targetTable = Object.values(graph).find((t) => Object.values(t).some((e) => e.target === edge.target));
1997
+ if (opts.skipJunctionTables && edge.target.includes("_")) {
1998
+ continue;
1999
+ }
2000
+ const newPath = [...path, key];
2001
+ const newIsMany = [...isMany, edge.kind === "many"];
2002
+ const newTargets = [...targets, edge.target];
2003
+ const methodSuffix = pathToMethodSuffix(newPath);
2004
+ methods.push({
2005
+ name: `list${methodSuffix}`,
2006
+ path: newPath,
2007
+ isMany: newIsMany,
2008
+ targets: newTargets,
2009
+ returnType: `(${buildReturnType(baseTableName, newPath, newIsMany, newTargets, graph)})[]`,
2010
+ includeSpec: buildIncludeSpec(newPath)
2011
+ });
2012
+ methods.push({
2013
+ name: `getByPk${methodSuffix}`,
2014
+ path: newPath,
2015
+ isMany: newIsMany,
2016
+ targets: newTargets,
2017
+ returnType: `${buildReturnType(baseTableName, newPath, newIsMany, newTargets, graph)} | null`,
2018
+ includeSpec: buildIncludeSpec(newPath)
2019
+ });
2020
+ explore(edge.target, newPath, newIsMany, newTargets, new Set([...visited, edge.target]), depth + 1);
2021
+ }
2022
+ if (depth === 1 && Object.keys(currentEdges).length > 1 && Object.keys(currentEdges).length <= 3) {
2023
+ const edgeEntries = Object.entries(currentEdges);
2024
+ if (edgeEntries.length >= 2) {
2025
+ for (let i = 0;i < edgeEntries.length - 1; i++) {
2026
+ for (let j = i + 1;j < edgeEntries.length; j++) {
2027
+ const entry1 = edgeEntries[i];
2028
+ const entry2 = edgeEntries[j];
2029
+ if (!entry1 || !entry2)
2030
+ continue;
2031
+ const [key1, edge1] = entry1;
2032
+ const [key2, edge2] = entry2;
2033
+ if (opts.skipJunctionTables && (edge1.target.includes("_") || edge2.target.includes("_"))) {
2034
+ continue;
2035
+ }
2036
+ const combinedPath = [key1, key2];
2037
+ const combinedSuffix = `With${pascal(key1)}And${pascal(key2)}`;
2038
+ const type1 = `${key1}: ${edge1.kind === "many" ? `Select${pascal(edge1.target)}[]` : `Select${pascal(edge1.target)}`}`;
2039
+ const type2 = `${key2}: ${edge2.kind === "many" ? `Select${pascal(edge2.target)}[]` : `Select${pascal(edge2.target)}`}`;
2040
+ methods.push({
2041
+ name: `list${combinedSuffix}`,
2042
+ path: combinedPath,
2043
+ isMany: [edge1.kind === "many", edge2.kind === "many"],
2044
+ targets: [edge1.target, edge2.target],
2045
+ returnType: `(Select${pascal(baseTableName)} & { ${type1}; ${type2} })[]`,
2046
+ includeSpec: { [key1]: true, [key2]: true }
2047
+ });
2048
+ methods.push({
2049
+ name: `getByPk${combinedSuffix}`,
2050
+ path: combinedPath,
2051
+ isMany: [edge1.kind === "many", edge2.kind === "many"],
2052
+ targets: [edge1.target, edge2.target],
2053
+ returnType: `(Select${pascal(baseTableName)} & { ${type1}; ${type2} }) | null`,
2054
+ includeSpec: { [key1]: true, [key2]: true }
2055
+ });
2056
+ }
2057
+ }
2058
+ }
2059
+ }
2060
+ }
2061
+ explore(baseTableName, [], [], [], new Set([baseTableName]), 1);
2062
+ return methods;
2063
+ }
2064
+
2065
+ // src/emit-client.ts
2066
+ function emitClient(table, graph, opts) {
1918
2067
  const Type = pascal(table.name);
1919
- const ext = useJsExtensions ? ".js" : "";
2068
+ const ext = opts.useJsExtensions ? ".js" : "";
1920
2069
  const pkCols = Array.isArray(table.pk) ? table.pk : table.pk ? [table.pk] : [];
1921
2070
  const safePk = pkCols.length ? pkCols : ["id"];
1922
2071
  const hasCompositePk = safePk.length > 1;
1923
2072
  const pkType = hasCompositePk ? `{ ${safePk.map((c) => `${c}: string`).join("; ")} }` : `string`;
1924
2073
  const pkPathExpr = hasCompositePk ? safePk.map((c) => `pk.${c}`).join(` + "/" + `) : `pk`;
2074
+ const includeMethods = generateIncludeMethods(table, graph, {
2075
+ maxDepth: opts.includeMethodsDepth ?? 2,
2076
+ skipJunctionTables: opts.skipJunctionTables ?? true
2077
+ });
2078
+ const importedTypes = new Set;
2079
+ importedTypes.add(table.name);
2080
+ for (const method of includeMethods) {
2081
+ for (const target of method.targets) {
2082
+ importedTypes.add(target);
2083
+ }
2084
+ }
2085
+ const typeImports = `import type { Insert${Type}, Update${Type}, Select${Type} } from "./types/${table.name}${ext}";`;
2086
+ const otherTableImports = [];
2087
+ for (const target of importedTypes) {
2088
+ if (target !== table.name) {
2089
+ otherTableImports.push(`import type { Select${pascal(target)} } from "./types/${target}${ext}";`);
2090
+ }
2091
+ }
2092
+ let includeMethodsCode = "";
2093
+ for (const method of includeMethods) {
2094
+ const isGetByPk = method.name.startsWith("getByPk");
2095
+ const baseParams = isGetByPk ? "" : `params?: Omit<{ limit?: number; offset?: number; where?: any; orderBy?: string; order?: "asc" | "desc"; }, "include">`;
2096
+ if (isGetByPk) {
2097
+ const pkWhere = hasCompositePk ? `{ ${safePk.map((col) => `${col}: pk.${col}`).join(", ")} }` : `{ ${safePk[0] || "id"}: pk }`;
2098
+ const baseReturnType = method.returnType.replace(" | null", "");
2099
+ includeMethodsCode += `
2100
+ async ${method.name}(pk: ${pkType}): Promise<${method.returnType}> {
2101
+ const results = await this.post<${baseReturnType}[]>(\`\${this.resource}/list\`, {
2102
+ where: ${pkWhere},
2103
+ include: ${JSON.stringify(method.includeSpec)},
2104
+ limit: 1
2105
+ });
2106
+ return (results[0] as ${baseReturnType}) ?? null;
2107
+ }
2108
+ `;
2109
+ } else {
2110
+ includeMethodsCode += `
2111
+ async ${method.name}(${baseParams}): Promise<${method.returnType}> {
2112
+ return this.post<${method.returnType}>(\`\${this.resource}/list\`, { ...params, include: ${JSON.stringify(method.includeSpec)} });
2113
+ }
2114
+ `;
2115
+ }
2116
+ }
1925
2117
  return `/* Generated. Do not edit. */
1926
2118
  import { BaseClient } from "./base-client${ext}";
1927
- import type { ${Type}IncludeSpec } from "./include-spec${ext}";
1928
- import type { Insert${Type}, Update${Type}, Select${Type} } from "./types/${table.name}${ext}";
2119
+ ${typeImports}
2120
+ ${otherTableImports.join(`
2121
+ `)}
1929
2122
 
1930
2123
  /**
1931
2124
  * Client for ${table.name} table operations
@@ -1943,7 +2136,6 @@ export class ${Type}Client extends BaseClient {
1943
2136
  }
1944
2137
 
1945
2138
  async list(params?: {
1946
- include?: ${Type}IncludeSpec;
1947
2139
  limit?: number;
1948
2140
  offset?: number;
1949
2141
  where?: any;
@@ -1962,7 +2154,7 @@ export class ${Type}Client extends BaseClient {
1962
2154
  const path = ${pkPathExpr};
1963
2155
  return this.del<Select${Type} | null>(\`\${this.resource}/\${path}\`);
1964
2156
  }
1965
- }
2157
+ ${includeMethodsCode}}
1966
2158
  `;
1967
2159
  }
1968
2160
  function emitClientIndex(tables, useJsExtensions) {
@@ -2006,8 +2198,6 @@ export type { AuthConfig, HeaderMap, AuthHeadersProvider } from "./base-client${
2006
2198
 
2007
2199
  `;
2008
2200
  out += `export { BaseClient } from "./base-client${ext}";
2009
- `;
2010
- out += `export * from "./include-spec${ext}";
2011
2201
  `;
2012
2202
  out += `
2013
2203
  // Zod schemas for form validation
@@ -3084,12 +3274,12 @@ function emitTableTest(table, model, clientPath, framework = "vitest") {
3084
3274
  const Type = pascal(table.name);
3085
3275
  const tableName = table.name;
3086
3276
  const imports = getFrameworkImports(framework);
3087
- const isJunctionTable = table.pk.length > 1;
3277
+ const isJunctionTable2 = table.pk.length > 1;
3088
3278
  const hasForeignKeys = table.fks.length > 0;
3089
3279
  const foreignKeySetup = hasForeignKeys ? generateForeignKeySetup(table, model, clientPath) : null;
3090
3280
  const sampleData = generateSampleDataFromSchema(table, hasForeignKeys);
3091
3281
  const updateData = generateUpdateDataFromSchema(table);
3092
- if (isJunctionTable) {
3282
+ if (isJunctionTable2) {
3093
3283
  return `${imports}
3094
3284
  import { SDK } from '${clientPath}';
3095
3285
  import type { Insert${Type}, Update${Type}, Select${Type} } from '${clientPath}/types/${tableName}';
@@ -3936,7 +4126,11 @@ async function generate(configPath) {
3936
4126
  });
3937
4127
  files.push({
3938
4128
  path: join(clientDir, `${table.name}.ts`),
3939
- content: emitClient(table, cfg.useJsExtensionsClient)
4129
+ content: emitClient(table, graph, {
4130
+ useJsExtensions: cfg.useJsExtensionsClient,
4131
+ includeMethodsDepth: cfg.includeMethodsDepth ?? 2,
4132
+ skipJunctionTables: cfg.skipJunctionTables ?? true
4133
+ })
3940
4134
  });
3941
4135
  }
3942
4136
  files.push({
@@ -1,3 +1,8 @@
1
1
  import type { Table } from "./introspect";
2
- export declare function emitClient(table: Table, useJsExtensions?: boolean): string;
2
+ import type { Graph } from "./rel-classify";
3
+ export declare function emitClient(table: Table, graph: Graph, opts: {
4
+ useJsExtensions?: boolean;
5
+ includeMethodsDepth?: number;
6
+ skipJunctionTables?: boolean;
7
+ }): string;
3
8
  export declare function emitClientIndex(tables: Table[], useJsExtensions?: boolean): string;
@@ -0,0 +1,17 @@
1
+ import type { Table } from "./introspect";
2
+ import type { Graph } from "./rel-classify";
3
+ export type IncludeMethod = {
4
+ name: string;
5
+ path: string[];
6
+ isMany: boolean[];
7
+ targets: string[];
8
+ returnType: string;
9
+ includeSpec: any;
10
+ };
11
+ /**
12
+ * Generate all include methods for a table
13
+ */
14
+ export declare function generateIncludeMethods(table: Table, graph: Graph, opts: {
15
+ maxDepth: number;
16
+ skipJunctionTables: boolean;
17
+ }): IncludeMethod[];
package/dist/index.js CHANGED
@@ -1651,18 +1651,211 @@ ${hasAuth ? `
1651
1651
 
1652
1652
  // src/emit-client.ts
1653
1653
  init_utils();
1654
- function emitClient(table, useJsExtensions) {
1654
+
1655
+ // src/emit-include-methods.ts
1656
+ init_utils();
1657
+ function isJunctionTable(table) {
1658
+ if (!table.name.includes("_"))
1659
+ return false;
1660
+ const fkColumns = new Set(table.fks.flatMap((fk) => fk.from));
1661
+ const nonPkColumns = table.columns.filter((c) => !table.pk.includes(c.name));
1662
+ return nonPkColumns.every((c) => fkColumns.has(c.name));
1663
+ }
1664
+ function pathToMethodSuffix(path) {
1665
+ return "With" + path.map((p) => pascal(p)).join("And");
1666
+ }
1667
+ function buildReturnType(baseTable, path, isMany, targets, graph) {
1668
+ const BaseType = `Select${pascal(baseTable)}`;
1669
+ if (path.length === 0)
1670
+ return BaseType;
1671
+ let type = BaseType;
1672
+ let currentTable = baseTable;
1673
+ const parts = [];
1674
+ for (let i = 0;i < path.length; i++) {
1675
+ const key = path[i];
1676
+ const target = targets[i];
1677
+ if (!key || !target)
1678
+ continue;
1679
+ const targetType = `Select${pascal(target)}`;
1680
+ if (i === 0) {
1681
+ parts.push(`${key}: ${isMany[i] ? `${targetType}[]` : targetType}`);
1682
+ } else {
1683
+ let nestedType = targetType;
1684
+ for (let j = i;j < path.length; j++) {
1685
+ if (j > i) {
1686
+ const nestedKey = path[j];
1687
+ const nestedTarget = targets[j];
1688
+ if (!nestedKey || !nestedTarget)
1689
+ continue;
1690
+ const nestedTargetType = `Select${pascal(nestedTarget)}`;
1691
+ nestedType = `${nestedType} & { ${nestedKey}: ${isMany[j] ? `${nestedTargetType}[]` : nestedTargetType} }`;
1692
+ }
1693
+ }
1694
+ const prevKey = path[i - 1];
1695
+ const prevTarget = targets[i - 1];
1696
+ if (prevKey && prevTarget) {
1697
+ parts[parts.length - 1] = `${prevKey}: ${isMany[i - 1] ? `(Select${pascal(prevTarget)} & { ${key}: ${isMany[i] ? `${targetType}[]` : targetType} })[]` : `Select${pascal(prevTarget)} & { ${key}: ${isMany[i] ? `${targetType}[]` : targetType} }`}`;
1698
+ }
1699
+ break;
1700
+ }
1701
+ }
1702
+ return `${type} & { ${parts.join("; ")} }`;
1703
+ }
1704
+ function buildIncludeSpec(path) {
1705
+ if (path.length === 0)
1706
+ return {};
1707
+ if (path.length === 1)
1708
+ return { [path[0]]: true };
1709
+ let spec = true;
1710
+ for (let i = path.length - 1;i > 0; i--) {
1711
+ const key = path[i];
1712
+ if (!key)
1713
+ continue;
1714
+ spec = { [key]: spec };
1715
+ }
1716
+ const rootKey = path[0];
1717
+ return rootKey ? { [rootKey]: spec } : {};
1718
+ }
1719
+ function generateIncludeMethods(table, graph, opts) {
1720
+ const methods = [];
1721
+ const baseTableName = table.name;
1722
+ if (opts.skipJunctionTables && isJunctionTable(table)) {
1723
+ return methods;
1724
+ }
1725
+ const edges = graph[baseTableName] || {};
1726
+ function explore(currentTable, path, isMany, targets, visited, depth) {
1727
+ if (depth > opts.maxDepth)
1728
+ return;
1729
+ const currentEdges = graph[currentTable] || {};
1730
+ for (const [key, edge] of Object.entries(currentEdges)) {
1731
+ if (visited.has(edge.target))
1732
+ continue;
1733
+ const targetTable = Object.values(graph).find((t) => Object.values(t).some((e) => e.target === edge.target));
1734
+ if (opts.skipJunctionTables && edge.target.includes("_")) {
1735
+ continue;
1736
+ }
1737
+ const newPath = [...path, key];
1738
+ const newIsMany = [...isMany, edge.kind === "many"];
1739
+ const newTargets = [...targets, edge.target];
1740
+ const methodSuffix = pathToMethodSuffix(newPath);
1741
+ methods.push({
1742
+ name: `list${methodSuffix}`,
1743
+ path: newPath,
1744
+ isMany: newIsMany,
1745
+ targets: newTargets,
1746
+ returnType: `(${buildReturnType(baseTableName, newPath, newIsMany, newTargets, graph)})[]`,
1747
+ includeSpec: buildIncludeSpec(newPath)
1748
+ });
1749
+ methods.push({
1750
+ name: `getByPk${methodSuffix}`,
1751
+ path: newPath,
1752
+ isMany: newIsMany,
1753
+ targets: newTargets,
1754
+ returnType: `${buildReturnType(baseTableName, newPath, newIsMany, newTargets, graph)} | null`,
1755
+ includeSpec: buildIncludeSpec(newPath)
1756
+ });
1757
+ explore(edge.target, newPath, newIsMany, newTargets, new Set([...visited, edge.target]), depth + 1);
1758
+ }
1759
+ if (depth === 1 && Object.keys(currentEdges).length > 1 && Object.keys(currentEdges).length <= 3) {
1760
+ const edgeEntries = Object.entries(currentEdges);
1761
+ if (edgeEntries.length >= 2) {
1762
+ for (let i = 0;i < edgeEntries.length - 1; i++) {
1763
+ for (let j = i + 1;j < edgeEntries.length; j++) {
1764
+ const entry1 = edgeEntries[i];
1765
+ const entry2 = edgeEntries[j];
1766
+ if (!entry1 || !entry2)
1767
+ continue;
1768
+ const [key1, edge1] = entry1;
1769
+ const [key2, edge2] = entry2;
1770
+ if (opts.skipJunctionTables && (edge1.target.includes("_") || edge2.target.includes("_"))) {
1771
+ continue;
1772
+ }
1773
+ const combinedPath = [key1, key2];
1774
+ const combinedSuffix = `With${pascal(key1)}And${pascal(key2)}`;
1775
+ const type1 = `${key1}: ${edge1.kind === "many" ? `Select${pascal(edge1.target)}[]` : `Select${pascal(edge1.target)}`}`;
1776
+ const type2 = `${key2}: ${edge2.kind === "many" ? `Select${pascal(edge2.target)}[]` : `Select${pascal(edge2.target)}`}`;
1777
+ methods.push({
1778
+ name: `list${combinedSuffix}`,
1779
+ path: combinedPath,
1780
+ isMany: [edge1.kind === "many", edge2.kind === "many"],
1781
+ targets: [edge1.target, edge2.target],
1782
+ returnType: `(Select${pascal(baseTableName)} & { ${type1}; ${type2} })[]`,
1783
+ includeSpec: { [key1]: true, [key2]: true }
1784
+ });
1785
+ methods.push({
1786
+ name: `getByPk${combinedSuffix}`,
1787
+ path: combinedPath,
1788
+ isMany: [edge1.kind === "many", edge2.kind === "many"],
1789
+ targets: [edge1.target, edge2.target],
1790
+ returnType: `(Select${pascal(baseTableName)} & { ${type1}; ${type2} }) | null`,
1791
+ includeSpec: { [key1]: true, [key2]: true }
1792
+ });
1793
+ }
1794
+ }
1795
+ }
1796
+ }
1797
+ }
1798
+ explore(baseTableName, [], [], [], new Set([baseTableName]), 1);
1799
+ return methods;
1800
+ }
1801
+
1802
+ // src/emit-client.ts
1803
+ function emitClient(table, graph, opts) {
1655
1804
  const Type = pascal(table.name);
1656
- const ext = useJsExtensions ? ".js" : "";
1805
+ const ext = opts.useJsExtensions ? ".js" : "";
1657
1806
  const pkCols = Array.isArray(table.pk) ? table.pk : table.pk ? [table.pk] : [];
1658
1807
  const safePk = pkCols.length ? pkCols : ["id"];
1659
1808
  const hasCompositePk = safePk.length > 1;
1660
1809
  const pkType = hasCompositePk ? `{ ${safePk.map((c) => `${c}: string`).join("; ")} }` : `string`;
1661
1810
  const pkPathExpr = hasCompositePk ? safePk.map((c) => `pk.${c}`).join(` + "/" + `) : `pk`;
1811
+ const includeMethods = generateIncludeMethods(table, graph, {
1812
+ maxDepth: opts.includeMethodsDepth ?? 2,
1813
+ skipJunctionTables: opts.skipJunctionTables ?? true
1814
+ });
1815
+ const importedTypes = new Set;
1816
+ importedTypes.add(table.name);
1817
+ for (const method of includeMethods) {
1818
+ for (const target of method.targets) {
1819
+ importedTypes.add(target);
1820
+ }
1821
+ }
1822
+ const typeImports = `import type { Insert${Type}, Update${Type}, Select${Type} } from "./types/${table.name}${ext}";`;
1823
+ const otherTableImports = [];
1824
+ for (const target of importedTypes) {
1825
+ if (target !== table.name) {
1826
+ otherTableImports.push(`import type { Select${pascal(target)} } from "./types/${target}${ext}";`);
1827
+ }
1828
+ }
1829
+ let includeMethodsCode = "";
1830
+ for (const method of includeMethods) {
1831
+ const isGetByPk = method.name.startsWith("getByPk");
1832
+ const baseParams = isGetByPk ? "" : `params?: Omit<{ limit?: number; offset?: number; where?: any; orderBy?: string; order?: "asc" | "desc"; }, "include">`;
1833
+ if (isGetByPk) {
1834
+ const pkWhere = hasCompositePk ? `{ ${safePk.map((col) => `${col}: pk.${col}`).join(", ")} }` : `{ ${safePk[0] || "id"}: pk }`;
1835
+ const baseReturnType = method.returnType.replace(" | null", "");
1836
+ includeMethodsCode += `
1837
+ async ${method.name}(pk: ${pkType}): Promise<${method.returnType}> {
1838
+ const results = await this.post<${baseReturnType}[]>(\`\${this.resource}/list\`, {
1839
+ where: ${pkWhere},
1840
+ include: ${JSON.stringify(method.includeSpec)},
1841
+ limit: 1
1842
+ });
1843
+ return (results[0] as ${baseReturnType}) ?? null;
1844
+ }
1845
+ `;
1846
+ } else {
1847
+ includeMethodsCode += `
1848
+ async ${method.name}(${baseParams}): Promise<${method.returnType}> {
1849
+ return this.post<${method.returnType}>(\`\${this.resource}/list\`, { ...params, include: ${JSON.stringify(method.includeSpec)} });
1850
+ }
1851
+ `;
1852
+ }
1853
+ }
1662
1854
  return `/* Generated. Do not edit. */
1663
1855
  import { BaseClient } from "./base-client${ext}";
1664
- import type { ${Type}IncludeSpec } from "./include-spec${ext}";
1665
- import type { Insert${Type}, Update${Type}, Select${Type} } from "./types/${table.name}${ext}";
1856
+ ${typeImports}
1857
+ ${otherTableImports.join(`
1858
+ `)}
1666
1859
 
1667
1860
  /**
1668
1861
  * Client for ${table.name} table operations
@@ -1680,7 +1873,6 @@ export class ${Type}Client extends BaseClient {
1680
1873
  }
1681
1874
 
1682
1875
  async list(params?: {
1683
- include?: ${Type}IncludeSpec;
1684
1876
  limit?: number;
1685
1877
  offset?: number;
1686
1878
  where?: any;
@@ -1699,7 +1891,7 @@ export class ${Type}Client extends BaseClient {
1699
1891
  const path = ${pkPathExpr};
1700
1892
  return this.del<Select${Type} | null>(\`\${this.resource}/\${path}\`);
1701
1893
  }
1702
- }
1894
+ ${includeMethodsCode}}
1703
1895
  `;
1704
1896
  }
1705
1897
  function emitClientIndex(tables, useJsExtensions) {
@@ -1743,8 +1935,6 @@ export type { AuthConfig, HeaderMap, AuthHeadersProvider } from "./base-client${
1743
1935
 
1744
1936
  `;
1745
1937
  out += `export { BaseClient } from "./base-client${ext}";
1746
- `;
1747
- out += `export * from "./include-spec${ext}";
1748
1938
  `;
1749
1939
  out += `
1750
1940
  // Zod schemas for form validation
@@ -2821,12 +3011,12 @@ function emitTableTest(table, model, clientPath, framework = "vitest") {
2821
3011
  const Type = pascal(table.name);
2822
3012
  const tableName = table.name;
2823
3013
  const imports = getFrameworkImports(framework);
2824
- const isJunctionTable = table.pk.length > 1;
3014
+ const isJunctionTable2 = table.pk.length > 1;
2825
3015
  const hasForeignKeys = table.fks.length > 0;
2826
3016
  const foreignKeySetup = hasForeignKeys ? generateForeignKeySetup(table, model, clientPath) : null;
2827
3017
  const sampleData = generateSampleDataFromSchema(table, hasForeignKeys);
2828
3018
  const updateData = generateUpdateDataFromSchema(table);
2829
- if (isJunctionTable) {
3019
+ if (isJunctionTable2) {
2830
3020
  return `${imports}
2831
3021
  import { SDK } from '${clientPath}';
2832
3022
  import type { Insert${Type}, Update${Type}, Select${Type} } from '${clientPath}/types/${tableName}';
@@ -3673,7 +3863,11 @@ async function generate(configPath) {
3673
3863
  });
3674
3864
  files.push({
3675
3865
  path: join(clientDir, `${table.name}.ts`),
3676
- content: emitClient(table, cfg.useJsExtensionsClient)
3866
+ content: emitClient(table, graph, {
3867
+ useJsExtensions: cfg.useJsExtensionsClient,
3868
+ includeMethodsDepth: cfg.includeMethodsDepth ?? 2,
3869
+ skipJunctionTables: cfg.skipJunctionTables ?? true
3870
+ })
3677
3871
  });
3678
3872
  }
3679
3873
  files.push({
package/dist/types.d.ts CHANGED
@@ -25,6 +25,8 @@ export interface Config {
25
25
  outClient?: string;
26
26
  softDeleteColumn?: string | null;
27
27
  includeDepthLimit?: number;
28
+ includeMethodsDepth?: number;
29
+ skipJunctionTables?: boolean;
28
30
  serverFramework?: "hono" | "express" | "fastify";
29
31
  auth?: AuthConfigInput;
30
32
  pull?: PullConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postgresdk",
3
- "version": "0.7.6",
3
+ "version": "0.8.0",
4
4
  "description": "Generate a typed server/client SDK from a Postgres schema (includes, Zod, Hono).",
5
5
  "type": "module",
6
6
  "bin": {