@sqg/sqg 0.16.2 → 0.17.3

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/index.mjs CHANGED
@@ -227,7 +227,7 @@ function formatGeneratorsList() {
227
227
  `
228
228
  SQL Annotation Syntax:
229
229
  -- QUERY <name> [:one] [:pluck] Select query (returns rows)
230
- -- EXEC <name> Execute statement (INSERT/UPDATE/DELETE)
230
+ -- EXEC <name> [:batch] Execute statement (INSERT/UPDATE/DELETE)
231
231
  -- MIGRATE <number> Schema migration (run in order)
232
232
  -- TESTDATA <name> Test data setup (not generated)
233
233
  -- TABLE <name> :appender Table for bulk insert appender (DuckDB, PostgreSQL)
@@ -239,6 +239,7 @@ Modifiers:
239
239
  :one Return single row (or null) instead of array
240
240
  :pluck Return single column value (requires exactly 1 column)
241
241
  :all Return all rows (default)
242
+ :batch Generate a JDBC batch method for an EXEC (Java only)
242
243
  :appender Generate bulk insert appender for TABLE annotation
243
244
 
244
245
  Example:
@@ -453,7 +454,7 @@ var SQLQuery = class {
453
454
  allColumns;
454
455
  /** Database-reported parameter types (variable name → SQL type), set by database adapters */
455
456
  parameterTypes;
456
- constructor(filename, id, rawQuery, queryAnonymous, queryNamed, queryPositional, type, isOne, isPluck, variables, config) {
457
+ constructor(filename, id, rawQuery, queryAnonymous, queryNamed, queryPositional, type, isOne, isPluck, isBatch, variables, config, line) {
457
458
  this.filename = filename;
458
459
  this.id = id;
459
460
  this.rawQuery = rawQuery;
@@ -463,8 +464,10 @@ var SQLQuery = class {
463
464
  this.type = type;
464
465
  this.isOne = isOne;
465
466
  this.isPluck = isPluck;
467
+ this.isBatch = isBatch;
466
468
  this.variables = variables;
467
469
  this.config = config;
470
+ this.line = line;
468
471
  this.columns = [];
469
472
  }
470
473
  get isQuery() {
@@ -502,12 +505,13 @@ var SQLQuery = class {
502
505
  var TableInfo = class {
503
506
  /** Columns introspected from the database table schema */
504
507
  columns = [];
505
- constructor(filename, id, tableName, includeColumns, hasAppender) {
508
+ constructor(filename, id, tableName, includeColumns, hasAppender, line) {
506
509
  this.filename = filename;
507
510
  this.id = id;
508
511
  this.tableName = tableName;
509
512
  this.includeColumns = includeColumns;
510
513
  this.hasAppender = hasAppender;
514
+ this.line = line;
511
515
  }
512
516
  get skipGenerateFunction() {
513
517
  return !this.hasAppender;
@@ -538,11 +542,14 @@ function parseSQLQueries(filePath, extraVariables) {
538
542
  const queryNames = /* @__PURE__ */ new Set();
539
543
  do
540
544
  if (cursor.name === "QueryBlock") {
545
+ const annotationNode = cursor.node.getChild("LineCommentStartSpecial") ?? cursor.node.getChild("BlockCommentStartSpecial");
546
+ const annotationLine = annotationNode ? getLineNumber(annotationNode.from) : getLineNumber(cursor.node.from);
541
547
  const queryType = (getStr("LineCommentStartSpecial", true) ?? getStr("BlockCommentStartSpecial")).replace("--", "").replace("/*", "").trim();
542
548
  const name = getStr("Name").trim();
543
549
  const modifiers = cursor.node.getChildren("Modifiers").map((node) => nodeStr(node));
544
550
  const isOne = modifiers.includes(":one");
545
551
  const isPluck = modifiers.includes(":pluck");
552
+ const isBatch = modifiers.includes(":batch");
546
553
  let configStr = getStr("Config", true);
547
554
  if (configStr?.endsWith("*/")) configStr = configStr.slice(0, -2);
548
555
  let config = null;
@@ -681,7 +688,7 @@ function parseSQLQueries(filePath, extraVariables) {
681
688
  const match = mod.match(/:appender\(([^)]+)\)/);
682
689
  if (match) includeColumns.push(...match[1].split(",").map((c) => c.trim()));
683
690
  }
684
- const table = new TableInfo(filePath, name, tableName, includeColumns, hasAppender);
691
+ const table = new TableInfo(filePath, name, tableName, includeColumns, hasAppender, annotationLine);
685
692
  if (queryNames.has(name)) throw SqgError.inFile(`Duplicate name '${name}'`, "DUPLICATE_QUERY", filePath, { suggestion: "Rename one of the tables/queries to have a unique name" });
686
693
  queryNames.add(name);
687
694
  tables.push(table);
@@ -697,7 +704,7 @@ function parseSQLQueries(filePath, extraVariables) {
697
704
  sql,
698
705
  config
699
706
  });
700
- const query = new SQLQuery(filePath, name, sqlContentStr, sql.toSqlWithAnonymousPlaceholders(), sql.toSqlWithNamedPlaceholders(), sql.toSqlWithPositionalPlaceholders(), queryType, isOne, isPluck, variables, config);
707
+ const query = new SQLQuery(filePath, name, sqlContentStr, sql.toSqlWithAnonymousPlaceholders(), sql.toSqlWithNamedPlaceholders(), sql.toSqlWithPositionalPlaceholders(), queryType, isOne, isPluck, isBatch, variables, config, annotationLine);
701
708
  if (queryNames.has(name)) throw SqgError.inFile(`Duplicate query name '${name}'`, "DUPLICATE_QUERY", filePath, { suggestion: "Rename one of the queries to have a unique name" });
702
709
  queryNames.add(name);
703
710
  queries.push(query);
@@ -1879,6 +1886,9 @@ var JavaGenerator = class extends BaseGenerator {
1879
1886
  return JavaTypeMapper.javaReservedKeywords.has(n) ? `${n}_` : n;
1880
1887
  });
1881
1888
  Handlebars.registerHelper("partsToString", (parts) => this.partsToString(parts));
1889
+ Handlebars.registerHelper("hasMultipleParams", (params) => params.length > 1);
1890
+ Handlebars.registerHelper("jdbcSet", (javaType, index, expr) => new Handlebars.SafeString(jdbcSetterStatement(javaType, index, expr)));
1891
+ Handlebars.registerHelper("concat", (...args) => args.slice(0, -1).join(""));
1882
1892
  Handlebars.registerHelper("declareTypes", (queryHelper) => {
1883
1893
  const query = queryHelper.query;
1884
1894
  if (queryHelper.isPluck) return queryHelper.typeMapper.getDeclarations({
@@ -1969,6 +1979,47 @@ var JavaGenerator = class extends BaseGenerator {
1969
1979
  }
1970
1980
  }
1971
1981
  };
1982
+ const JDBC_SETTER_MAP = {
1983
+ String: {
1984
+ setter: "setString",
1985
+ sqlType: "VARCHAR"
1986
+ },
1987
+ Integer: {
1988
+ setter: "setInt",
1989
+ sqlType: "INTEGER"
1990
+ },
1991
+ Long: {
1992
+ setter: "setLong",
1993
+ sqlType: "BIGINT"
1994
+ },
1995
+ Short: {
1996
+ setter: "setShort",
1997
+ sqlType: "SMALLINT"
1998
+ },
1999
+ Boolean: {
2000
+ setter: "setBoolean",
2001
+ sqlType: "BOOLEAN"
2002
+ },
2003
+ Double: {
2004
+ setter: "setDouble",
2005
+ sqlType: "DOUBLE"
2006
+ },
2007
+ Float: {
2008
+ setter: "setFloat",
2009
+ sqlType: "REAL"
2010
+ },
2011
+ "byte[]": {
2012
+ setter: "setBytes",
2013
+ sqlType: "VARBINARY"
2014
+ }
2015
+ };
2016
+ const NULL_SAFE_SETTERS = new Set(["setString", "setBytes"]);
2017
+ function jdbcSetterStatement(javaType, index, expr) {
2018
+ const entry = JDBC_SETTER_MAP[javaType];
2019
+ if (!entry) return `stmt.setObject(${index}, ${expr});`;
2020
+ if (NULL_SAFE_SETTERS.has(entry.setter)) return `stmt.${entry.setter}(${index}, ${expr});`;
2021
+ return `if (${expr} != null) stmt.${entry.setter}(${index}, ${expr}); else stmt.setNull(${index}, java.sql.Types.${entry.sqlType});`;
2022
+ }
1972
2023
  const PG_BULK_TYPE_MAP = {
1973
2024
  SMALLINT: "INT2",
1974
2025
  INTEGER: "INT4",
@@ -2599,6 +2650,12 @@ var SqlQueryHelper = class {
2599
2650
  get isOne() {
2600
2651
  return this.query.isOne;
2601
2652
  }
2653
+ get isBatch() {
2654
+ return this.query.isBatch;
2655
+ }
2656
+ get batchParamsType() {
2657
+ return this.generator.getClassName(`${this.query.id}_params`);
2658
+ }
2602
2659
  get parameterNames() {
2603
2660
  return this.statement.parameters.map((param) => param.name);
2604
2661
  }
package/dist/sqg.mjs CHANGED
@@ -219,7 +219,7 @@ function formatGeneratorsHelp() {
219
219
  const SQL_SYNTAX_REFERENCE = `
220
220
  SQL Annotation Syntax:
221
221
  -- QUERY <name> [:one] [:pluck] Select query (returns rows)
222
- -- EXEC <name> Execute statement (INSERT/UPDATE/DELETE)
222
+ -- EXEC <name> [:batch] Execute statement (INSERT/UPDATE/DELETE)
223
223
  -- MIGRATE <number> Schema migration (run in order)
224
224
  -- TESTDATA <name> Test data setup (not generated)
225
225
  -- TABLE <name> :appender Table for bulk insert appender (DuckDB, PostgreSQL)
@@ -231,6 +231,7 @@ Modifiers:
231
231
  :one Return single row (or null) instead of array
232
232
  :pluck Return single column value (requires exactly 1 column)
233
233
  :all Return all rows (default)
234
+ :batch Generate a JDBC batch method for an EXEC (Java only)
234
235
  :appender Generate bulk insert appender for TABLE annotation
235
236
 
236
237
  Example:
@@ -772,7 +773,7 @@ var SQLQuery = class {
772
773
  allColumns;
773
774
  /** Database-reported parameter types (variable name → SQL type), set by database adapters */
774
775
  parameterTypes;
775
- constructor(filename, id, rawQuery, queryAnonymous, queryNamed, queryPositional, type, isOne, isPluck, variables, config) {
776
+ constructor(filename, id, rawQuery, queryAnonymous, queryNamed, queryPositional, type, isOne, isPluck, isBatch, variables, config, line) {
776
777
  this.filename = filename;
777
778
  this.id = id;
778
779
  this.rawQuery = rawQuery;
@@ -782,8 +783,10 @@ var SQLQuery = class {
782
783
  this.type = type;
783
784
  this.isOne = isOne;
784
785
  this.isPluck = isPluck;
786
+ this.isBatch = isBatch;
785
787
  this.variables = variables;
786
788
  this.config = config;
789
+ this.line = line;
787
790
  this.columns = [];
788
791
  }
789
792
  get isQuery() {
@@ -821,12 +824,13 @@ var SQLQuery = class {
821
824
  var TableInfo = class {
822
825
  /** Columns introspected from the database table schema */
823
826
  columns = [];
824
- constructor(filename, id, tableName, includeColumns, hasAppender) {
827
+ constructor(filename, id, tableName, includeColumns, hasAppender, line) {
825
828
  this.filename = filename;
826
829
  this.id = id;
827
830
  this.tableName = tableName;
828
831
  this.includeColumns = includeColumns;
829
832
  this.hasAppender = hasAppender;
833
+ this.line = line;
830
834
  }
831
835
  get skipGenerateFunction() {
832
836
  return !this.hasAppender;
@@ -857,11 +861,14 @@ function parseSQLQueries(filePath, extraVariables) {
857
861
  const queryNames = /* @__PURE__ */ new Set();
858
862
  do
859
863
  if (cursor.name === "QueryBlock") {
864
+ const annotationNode = cursor.node.getChild("LineCommentStartSpecial") ?? cursor.node.getChild("BlockCommentStartSpecial");
865
+ const annotationLine = annotationNode ? getLineNumber(annotationNode.from) : getLineNumber(cursor.node.from);
860
866
  const queryType = (getStr("LineCommentStartSpecial", true) ?? getStr("BlockCommentStartSpecial")).replace("--", "").replace("/*", "").trim();
861
867
  const name = getStr("Name").trim();
862
868
  const modifiers = cursor.node.getChildren("Modifiers").map((node) => nodeStr(node));
863
869
  const isOne = modifiers.includes(":one");
864
870
  const isPluck = modifiers.includes(":pluck");
871
+ const isBatch = modifiers.includes(":batch");
865
872
  let configStr = getStr("Config", true);
866
873
  if (configStr?.endsWith("*/")) configStr = configStr.slice(0, -2);
867
874
  let config = null;
@@ -1000,7 +1007,7 @@ function parseSQLQueries(filePath, extraVariables) {
1000
1007
  const match = mod.match(/:appender\(([^)]+)\)/);
1001
1008
  if (match) includeColumns.push(...match[1].split(",").map((c) => c.trim()));
1002
1009
  }
1003
- const table = new TableInfo(filePath, name, tableName, includeColumns, hasAppender);
1010
+ const table = new TableInfo(filePath, name, tableName, includeColumns, hasAppender, annotationLine);
1004
1011
  if (queryNames.has(name)) throw SqgError.inFile(`Duplicate name '${name}'`, "DUPLICATE_QUERY", filePath, { suggestion: "Rename one of the tables/queries to have a unique name" });
1005
1012
  queryNames.add(name);
1006
1013
  tables.push(table);
@@ -1016,7 +1023,7 @@ function parseSQLQueries(filePath, extraVariables) {
1016
1023
  sql,
1017
1024
  config
1018
1025
  });
1019
- const query = new SQLQuery(filePath, name, sqlContentStr, sql.toSqlWithAnonymousPlaceholders(), sql.toSqlWithNamedPlaceholders(), sql.toSqlWithPositionalPlaceholders(), queryType, isOne, isPluck, variables, config);
1026
+ const query = new SQLQuery(filePath, name, sqlContentStr, sql.toSqlWithAnonymousPlaceholders(), sql.toSqlWithNamedPlaceholders(), sql.toSqlWithPositionalPlaceholders(), queryType, isOne, isPluck, isBatch, variables, config, annotationLine);
1020
1027
  if (queryNames.has(name)) throw SqgError.inFile(`Duplicate query name '${name}'`, "DUPLICATE_QUERY", filePath, { suggestion: "Rename one of the queries to have a unique name" });
1021
1028
  queryNames.add(name);
1022
1029
  queries.push(query);
@@ -2198,6 +2205,9 @@ var JavaGenerator = class extends BaseGenerator {
2198
2205
  return JavaTypeMapper.javaReservedKeywords.has(n) ? `${n}_` : n;
2199
2206
  });
2200
2207
  Handlebars.registerHelper("partsToString", (parts) => this.partsToString(parts));
2208
+ Handlebars.registerHelper("hasMultipleParams", (params) => params.length > 1);
2209
+ Handlebars.registerHelper("jdbcSet", (javaType, index, expr) => new Handlebars.SafeString(jdbcSetterStatement(javaType, index, expr)));
2210
+ Handlebars.registerHelper("concat", (...args) => args.slice(0, -1).join(""));
2201
2211
  Handlebars.registerHelper("declareTypes", (queryHelper) => {
2202
2212
  const query = queryHelper.query;
2203
2213
  if (queryHelper.isPluck) return queryHelper.typeMapper.getDeclarations({
@@ -2288,6 +2298,47 @@ var JavaGenerator = class extends BaseGenerator {
2288
2298
  }
2289
2299
  }
2290
2300
  };
2301
+ const JDBC_SETTER_MAP = {
2302
+ String: {
2303
+ setter: "setString",
2304
+ sqlType: "VARCHAR"
2305
+ },
2306
+ Integer: {
2307
+ setter: "setInt",
2308
+ sqlType: "INTEGER"
2309
+ },
2310
+ Long: {
2311
+ setter: "setLong",
2312
+ sqlType: "BIGINT"
2313
+ },
2314
+ Short: {
2315
+ setter: "setShort",
2316
+ sqlType: "SMALLINT"
2317
+ },
2318
+ Boolean: {
2319
+ setter: "setBoolean",
2320
+ sqlType: "BOOLEAN"
2321
+ },
2322
+ Double: {
2323
+ setter: "setDouble",
2324
+ sqlType: "DOUBLE"
2325
+ },
2326
+ Float: {
2327
+ setter: "setFloat",
2328
+ sqlType: "REAL"
2329
+ },
2330
+ "byte[]": {
2331
+ setter: "setBytes",
2332
+ sqlType: "VARBINARY"
2333
+ }
2334
+ };
2335
+ const NULL_SAFE_SETTERS = new Set(["setString", "setBytes"]);
2336
+ function jdbcSetterStatement(javaType, index, expr) {
2337
+ const entry = JDBC_SETTER_MAP[javaType];
2338
+ if (!entry) return `stmt.setObject(${index}, ${expr});`;
2339
+ if (NULL_SAFE_SETTERS.has(entry.setter)) return `stmt.${entry.setter}(${index}, ${expr});`;
2340
+ return `if (${expr} != null) stmt.${entry.setter}(${index}, ${expr}); else stmt.setNull(${index}, java.sql.Types.${entry.sqlType});`;
2341
+ }
2291
2342
  const PG_BULK_TYPE_MAP = {
2292
2343
  SMALLINT: "INT2",
2293
2344
  INTEGER: "INT4",
@@ -2918,6 +2969,12 @@ var SqlQueryHelper = class {
2918
2969
  get isOne() {
2919
2970
  return this.query.isOne;
2920
2971
  }
2972
+ get isBatch() {
2973
+ return this.query.isBatch;
2974
+ }
2975
+ get batchParamsType() {
2976
+ return this.generator.getClassName(`${this.query.id}_params`);
2977
+ }
2921
2978
  get parameterNames() {
2922
2979
  return this.statement.parameters.map((param) => param.name);
2923
2980
  }
@@ -3361,7 +3418,7 @@ async function processProject(projectPath, ui) {
3361
3418
  //#region src/mcp-server.ts
3362
3419
  const server = new Server({
3363
3420
  name: "sqg-mcp",
3364
- version: process.env.npm_package_version ?? "0.16.2"
3421
+ version: process.env.npm_package_version ?? "0.17.3"
3365
3422
  }, { capabilities: {
3366
3423
  tools: {},
3367
3424
  resources: {}
@@ -3826,7 +3883,7 @@ function formatMs(ms) {
3826
3883
  }
3827
3884
  //#endregion
3828
3885
  //#region src/sqg.ts
3829
- const version = process.env.npm_package_version ?? "0.16.2";
3886
+ const version = process.env.npm_package_version ?? "0.17.3";
3830
3887
  updateNotifier({ pkg: {
3831
3888
  name: "@sqg/sqg",
3832
3889
  version
@@ -3946,9 +4003,9 @@ program.command("init").description("Initialize a new SQG project with example c
3946
4003
  program.command("syntax").description("Show SQL annotation syntax reference").action(() => {
3947
4004
  console.log(SQL_SYNTAX_REFERENCE);
3948
4005
  });
3949
- program.command("ide").description("Start the SQG IDE — interactive SQL development environment").argument("[project]", "Path to sqg.yaml project config").option("-p, --port <port>", "Server port", "3000").action(async (project, options) => {
3950
- const { startIde } = await import("./ide-BieFvmwk.mjs");
3951
- await startIde({
4006
+ program.command("ui").description("Start the SQG UI — interactive SQL development environment").argument("[project]", "Path to sqg.yaml project config").option("-p, --port <port>", "Server port", "3000").action(async (project, options) => {
4007
+ const { startUi } = await import("./start-ui-DuHxwbjr.mjs");
4008
+ await startUi({
3952
4009
  project,
3953
4010
  port: parseInt(options.port, 10)
3954
4011
  });
@@ -3,12 +3,12 @@ import { existsSync } from "node:fs";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  import { spawn } from "node:child_process";
5
5
  import { fileURLToPath } from "node:url";
6
- //#region src/ide.ts
6
+ //#region src/start-ui.ts
7
7
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
- async function startIde(options) {
8
+ async function startUi(options) {
9
9
  const port = options.port ?? 3e3;
10
- const bundledServer = join(__dirname, "ide-server.mjs");
11
- const devServer = join(__dirname, "../../sql-ide/server/src/index.ts");
10
+ const bundledServer = join(__dirname, "ui-server.mjs");
11
+ const devServer = join(__dirname, "../../sqg-ui/server/src/index.ts");
12
12
  let serverPath;
13
13
  let args;
14
14
  if (existsSync(bundledServer)) {
@@ -22,7 +22,7 @@ async function startIde(options) {
22
22
  serverPath
23
23
  ];
24
24
  } else {
25
- console.error("SQL IDE server not found.");
25
+ console.error("SQG UI server not found.");
26
26
  console.error("Expected bundled server at:", bundledServer);
27
27
  console.error("Or dev server at:", devServer);
28
28
  process.exit(1);
@@ -32,7 +32,7 @@ async function startIde(options) {
32
32
  ...process.env,
33
33
  PORT: String(port)
34
34
  };
35
- console.log(`Starting SQG IDE on http://localhost:${port}`);
35
+ console.log(`Starting SQG UI on http://localhost:${port}`);
36
36
  if (options.project) console.log(`Project: ${resolve(options.project)}`);
37
37
  const child = spawn("node", args, {
38
38
  stdio: "inherit",
@@ -73,10 +73,10 @@ async function startIde(options) {
73
73
  await new Promise((resolve, reject) => {
74
74
  child.on("exit", (code) => {
75
75
  if (code === 0 || code === null) resolve();
76
- else reject(/* @__PURE__ */ new Error(`IDE server exited with code ${code}`));
76
+ else reject(/* @__PURE__ */ new Error(`UI server exited with code ${code}`));
77
77
  });
78
78
  child.on("error", reject);
79
79
  });
80
80
  }
81
81
  //#endregion
82
- export { startIde };
82
+ export { startUi };
@@ -46,6 +46,12 @@ public class {{className}} {
46
46
  this.connection = connection;
47
47
  }
48
48
 
49
+ /** Options for streaming queries. fetchSize hints at the JDBC driver's batch size; 0 means driver default. */
50
+ public record StreamOptions(int fetchSize) {
51
+ public static final StreamOptions DEFAULT = new StreamOptions({{#if (isPostgres)}}1000{{else}}0{{/if}});
52
+ public StreamOptions withFetchSize(int fetchSize) { return new StreamOptions(fetchSize); }
53
+ }
54
+
49
55
  private static Object[] getObjectArray(Array array) {
50
56
  if (array == null) {
51
57
  return null;
@@ -225,12 +231,52 @@ public class {{className}} {
225
231
  {{> execute}}
226
232
  }
227
233
  }
234
+ {{#if isBatch}}
235
+ {{#if (hasMultipleParams variables)}}
236
+ public record {{batchParamsType}}({{#each variables}}{{{type}}} {{name}}{{#unless @last}}, {{/unless}}{{/each}}) {}
237
+
238
+ public int[] {{functionName}}Batch(Iterable<{{batchParamsType}}> params) throws SQLException {
239
+ try (var stmt = connection.prepareStatement({{{partsToString sqlQueryParts}}})) {
240
+ for (var row : params) {
241
+ {{#each parameters}}{{#if isArray}}stmt.setArray({{plusOne @index}}, connection.createArrayOf("{{arrayBaseType}}", row.{{name}}().toArray()));
242
+ {{else if isEnum}}stmt.setObject({{plusOne @index}}, row.{{name}}().getValue());
243
+ {{else}}{{{jdbcSet type (plusOne @index) (concat "row." name "()")}}}
244
+ {{/if}}{{/each}}
245
+ stmt.addBatch();
246
+ }
247
+ return stmt.executeBatch();
248
+ }
249
+ }
250
+ {{else}}
251
+ public int[] {{functionName}}Batch(Iterable<{{#each variables}}{{{type}}}{{/each}}> params) throws SQLException {
252
+ try (var stmt = connection.prepareStatement({{{partsToString sqlQueryParts}}})) {
253
+ for (var value : params) {
254
+ {{#each parameters}}{{#if isArray}}stmt.setArray({{plusOne @index}}, connection.createArrayOf("{{arrayBaseType}}", value.toArray()));
255
+ {{else if isEnum}}stmt.setObject({{plusOne @index}}, value.getValue());
256
+ {{else}}{{{jdbcSet type (plusOne @index) "value"}}}
257
+ {{/if}}{{/each}}
258
+ stmt.addBatch();
259
+ }
260
+ return stmt.executeBatch();
261
+ }
262
+ }
263
+ {{/if}}
264
+ {{/if}}
228
265
  {{#if isQuery}}{{#unless isOne}}
229
266
  public Stream<{{rowType}}> {{functionName}}Stream({{#each variables}}{{{type}}} {{name}}{{#unless @last}}, {{/unless}}{{/each}}) throws SQLException {
267
+ return {{functionName}}Stream({{#each variables}}{{name}}, {{/each}}StreamOptions.DEFAULT);
268
+ }
269
+
270
+ public Stream<{{rowType}}> {{functionName}}Stream({{#each variables}}{{{type}}} {{name}}, {{/each}}StreamOptions options) throws SQLException {
271
+ {{#if (isPostgres)}}
272
+ boolean wasAutoCommit = connection.getAutoCommit();
273
+ if (wasAutoCommit) connection.setAutoCommit(false);
274
+ {{/if}}
230
275
  var stmt = connection.prepareStatement({{{partsToString sqlQueryParts}}});
276
+ if (options.fetchSize() > 0) stmt.setFetchSize(options.fetchSize());
231
277
  {{#each parameters}}{{#if isArray}}stmt.setArray({{plusOne @index}}, connection.createArrayOf("{{arrayBaseType}}", {{name}}.toArray()));
232
278
  {{else if isEnum}}stmt.setObject({{plusOne @index}}, {{name}}.getValue());
233
- {{else}}stmt.setObject({{plusOne @index}}, {{name}});
279
+ {{else}}{{{jdbcSet type (plusOne @index) name}}}
234
280
  {{/if}}{{/each}}
235
281
  var rs = stmt.executeQuery();
236
282
  var iter = new Iterator<{{rowType}}>() {
@@ -252,7 +298,13 @@ public class {{className}} {
252
298
  return StreamSupport.stream(
253
299
  Spliterators.spliteratorUnknownSize(iter, Spliterator.ORDERED), false
254
300
  ).onClose(() -> {
255
- try { rs.close(); stmt.close(); }
301
+ try {
302
+ rs.close();
303
+ stmt.close();
304
+ {{#if (isPostgres)}}
305
+ if (wasAutoCommit) connection.setAutoCommit(true);
306
+ {{/if}}
307
+ }
256
308
  catch (SQLException e) { throw new RuntimeException(e); }
257
309
  });
258
310
  }
@@ -369,7 +421,7 @@ int
369
421
  {{#*inline "execute"}}
370
422
  {{#each parameters}}{{#if isArray}}stmt.setArray({{plusOne @index}}, connection.createArrayOf("{{arrayBaseType}}", {{name}}.toArray()));
371
423
  {{else if isEnum}}stmt.setObject({{plusOne @index}}, {{name}}.getValue());
372
- {{else}}stmt.setObject({{plusOne @index}}, {{name}});
424
+ {{else}}{{{jdbcSet type (plusOne @index) name}}}
373
425
  {{/if}}{{/each}}
374
426
  {{#if isQuery}}
375
427
  try(var rs = stmt.executeQuery()) {