Skip to content

Commit 2d55519

Browse files
Copilotmathiasrw
andauthored
Support OUTPUT for INSERT/DELETE/UPDATE to fix #48 (#2302)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: mathiasrw <[email protected]> Co-authored-by: M. Wulff <[email protected]>
1 parent 7020237 commit 2d55519

File tree

9 files changed

+1065
-602
lines changed

9 files changed

+1065
-602
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"mocha": "11.7.5",
7272
"mocha.parallel": "0.15.6",
7373
"open": "11.0.0",
74-
"prettier": "3.6.2",
74+
"prettier": "3.7.4",
7575
"react-native-fetch-blob": "^0.10.8",
7676
"rexreplace": "7.1.14",
7777
"strftime": "0.10.3",

src/70insert.js

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ yy.Insert.prototype.toString = function () {
2323
s += ' VALUES ' + values.join(',');
2424
}
2525
if (this.select) s += ' ' + this.select.toString();
26+
if (this.output) {
27+
s += ' OUTPUT ';
28+
s += this.output.columns.map(col => col.toString()).join(', ');
29+
if (this.output.intovar) {
30+
s += ' INTO ' + this.output.method + this.output.intovar;
31+
} else if (this.output.intotable) {
32+
s += ' INTO ' + this.output.intotable.toString();
33+
if (this.output.intocolumns) {
34+
s += '(' + this.output.intocolumns.map(col => col.toString()).join(', ') + ')';
35+
}
36+
}
37+
}
2638
return s;
2739
};
2840

@@ -56,6 +68,7 @@ yy.Insert.prototype.compile = function (databaseid) {
5668
var s = '';
5769
var sw = '';
5870
var s = "db.tables['" + tableid + "'].dirty=true;";
71+
// aa = array to accumulate inserted rows (used for OUTPUT clause and concat to table.data)
5972
var s3 = 'var a,aa=[],x;';
6073

6174
var s33;
@@ -191,6 +204,10 @@ yy.Insert.prototype.compile = function (databaseid) {
191204
if (db.tables[tableid].insert) {
192205
s += "var db=alasql.databases['" + databaseid + "'];";
193206
s += "db.tables['" + tableid + "'].insert(a," + (self.orreplace ? 'true' : 'false') + ');';
207+
// Also push to aa for OUTPUT clause
208+
if (self.output) {
209+
s += 'aa.push(a);';
210+
}
194211
} else {
195212
s += 'aa.push(a);';
196213
}
@@ -214,7 +231,27 @@ yy.Insert.prototype.compile = function (databaseid) {
214231
"'].data.concat(aa);";
215232
}
216233

217-
if (db.tables[tableid].insert) {
234+
// Handle OUTPUT clause
235+
if (self.output) {
236+
s += 'var output = [];';
237+
s += 'for(var i=0;i<aa.length;i++){';
238+
s += 'var r = aa[i];';
239+
s += 'var outputRow = {};';
240+
// Process each output column
241+
self.output.columns.forEach(function (col) {
242+
if (col.columnid === '*') {
243+
// For *, expand all properties
244+
s += 'for(var key in r){ outputRow[key] = r[key]; }';
245+
} else {
246+
var colname = col.as || col.columnid;
247+
// Direct property access for simple columns
248+
s += "outputRow['" + colname + "']=r['" + col.columnid + "'];";
249+
}
250+
});
251+
s += 'output.push(outputRow);';
252+
s += '}';
253+
s += 'return output;';
254+
} else if (db.tables[tableid].insert) {
218255
if (db.tables[tableid].isclass) {
219256
s += 'return a.$id;';
220257
} else {
@@ -250,16 +287,43 @@ yy.Insert.prototype.compile = function (databaseid) {
250287
var defaultfn = new Function('r,db,params,alasql', defaultfns);
251288
var insertfn = function (db, params, alasql) {
252289
var res = selectfn(params).data;
290+
var insertedRows = [];
253291
if (db.tables[tableid].insert) {
254292
// If insert() function exists (issue #92)
255293
for (var i = 0, ilen = res.length; i < ilen; i++) {
256294
var r = cloneDeep(res[i]);
257295
defaultfn(r, db, params, alasql);
258296
db.tables[tableid].insert(r, self.orreplace);
297+
insertedRows.push(r);
259298
}
260299
} else {
300+
insertedRows = res;
261301
db.tables[tableid].data = db.tables[tableid].data.concat(res);
262302
}
303+
304+
// Handle OUTPUT clause
305+
if (self.output) {
306+
var output = [];
307+
for (var i = 0; i < insertedRows.length; i++) {
308+
var r = insertedRows[i];
309+
var outputRow = {};
310+
self.output.columns.forEach(function (col) {
311+
if (col.columnid === '*') {
312+
// For *, expand all properties
313+
for (var key in r) {
314+
outputRow[key] = r[key];
315+
}
316+
} else {
317+
var colname = col.as || col.columnid;
318+
// Direct property access for simple columns
319+
outputRow[colname] = r[col.columnid];
320+
}
321+
});
322+
output.push(outputRow);
323+
}
324+
return output;
325+
}
326+
263327
if (alasql.options.nocount) return;
264328
else return res.length;
265329
};

src/72delete.js

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,23 @@ yy.Delete = function (params) {
1212
yy.Delete.prototype.toString = function () {
1313
var s = 'DELETE FROM ' + this.table.toString();
1414
if (this.where) s += ' WHERE ' + this.where.toString();
15+
if (this.output) {
16+
s += ' OUTPUT ';
17+
s += this.output.columns.map(col => col.toString()).join(', ');
18+
if (this.output.intovar) {
19+
s += ' INTO ' + this.output.method + this.output.intovar;
20+
} else if (this.output.intotable) {
21+
s += ' INTO ' + this.output.intotable.toString();
22+
if (this.output.intocolumns) {
23+
s += '(' + this.output.intocolumns.map(col => col.toString()).join(', ') + ')';
24+
}
25+
}
26+
}
1527
return s;
1628
};
1729

1830
yy.Delete.prototype.compile = function (databaseid) {
31+
var self = this;
1932
databaseid = this.table.databaseid || databaseid;
2033
var tableid = this.table.tableid;
2134
var statement;
@@ -66,8 +79,13 @@ yy.Delete.prototype.compile = function (databaseid) {
6679
var orignum = table.data.length;
6780

6881
var newtable = [];
82+
var deletedRows = [];
6983
for (var i = 0, ilen = table.data.length; i < ilen; i++) {
7084
if (wherefn(table.data[i], params, alasql)) {
85+
// Track deleted row for OUTPUT clause
86+
if (self.output) {
87+
deletedRows.push(cloneDeep(table.data[i]));
88+
}
7189
// Check for transaction - if it is not possible then return all back
7290
if (table.delete) {
7391
table.delete(i, params, alasql);
@@ -93,6 +111,30 @@ yy.Delete.prototype.compile = function (databaseid) {
93111
}
94112

95113
var res = orignum - table.data.length;
114+
115+
// Handle OUTPUT clause
116+
if (self.output) {
117+
var output = [];
118+
for (var i = 0; i < deletedRows.length; i++) {
119+
var r = deletedRows[i];
120+
var outputRow = {};
121+
self.output.columns.forEach(function (col) {
122+
if (col.columnid === '*') {
123+
// For *, expand all properties
124+
for (var key in r) {
125+
outputRow[key] = r[key];
126+
}
127+
} else {
128+
var colname = col.as || col.columnid;
129+
// Direct property access
130+
outputRow[colname] = r[col.columnid];
131+
}
132+
});
133+
output.push(outputRow);
134+
}
135+
res = output;
136+
}
137+
96138
if (
97139
alasql.options.autocommit &&
98140
db.engineid &&
@@ -114,6 +156,15 @@ yy.Delete.prototype.compile = function (databaseid) {
114156
var table = db.tables[tableid];
115157
table.dirty = true;
116158
var orignum = db.tables[tableid].data.length;
159+
160+
// Track deleted rows for OUTPUT clause
161+
var deletedRows = [];
162+
if (self.output) {
163+
deletedRows = table.data.map(function (row) {
164+
return cloneDeep(row);
165+
});
166+
}
167+
117168
// Delete all records from the array
118169
db.tables[tableid].data.length = 0;
119170

@@ -130,8 +181,33 @@ yy.Delete.prototype.compile = function (databaseid) {
130181
alasql.engines[db.engineid].saveTableData(databaseid, tableid);
131182
}
132183

133-
if (cb) cb(orignum);
134-
return orignum;
184+
var res = orignum;
185+
186+
// Handle OUTPUT clause
187+
if (self.output) {
188+
var output = [];
189+
for (var i = 0; i < deletedRows.length; i++) {
190+
var r = deletedRows[i];
191+
var outputRow = {};
192+
self.output.columns.forEach(function (col) {
193+
if (col.columnid === '*') {
194+
// For *, expand all properties
195+
for (var key in r) {
196+
outputRow[key] = r[key];
197+
}
198+
} else {
199+
var colname = col.as || col.columnid;
200+
// Direct property access
201+
outputRow[colname] = r[col.columnid];
202+
}
203+
});
204+
output.push(outputRow);
205+
}
206+
res = output;
207+
}
208+
209+
if (cb) cb(res);
210+
return res;
135211
};
136212
}
137213

src/74update.js

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ yy.Update.prototype.toString = function () {
1515
var s = 'UPDATE ' + this.table.toString();
1616
if (this.columns) s += ' SET ' + this.columns.toString();
1717
if (this.where) s += ' WHERE ' + this.where.toString();
18+
if (this.output) {
19+
s += ' OUTPUT ';
20+
s += this.output.columns.map(col => col.toString()).join(', ');
21+
if (this.output.intovar) {
22+
s += ' INTO ' + this.output.method + this.output.intovar;
23+
} else if (this.output.intotable) {
24+
s += ' INTO ' + this.output.intotable.toString();
25+
if (this.output.intocolumns) {
26+
s += '(' + this.output.intocolumns.map(col => col.toString()).join(', ') + ')';
27+
}
28+
}
29+
}
1830
return s;
1931
};
2032

@@ -26,6 +38,7 @@ yy.SetColumn.prototype.toString = function () {
2638
};
2739

2840
yy.Update.prototype.compile = function (databaseid) {
41+
var self = this;
2942
// console.log(this);
3043
databaseid = this.table.databaseid || databaseid;
3144
var tableid = this.table.tableid;
@@ -88,13 +101,26 @@ yy.Update.prototype.compile = function (databaseid) {
88101
}
89102
// table.dirty = true;
90103
var numrows = 0;
104+
var updatedRows = [];
91105
for (var i = 0, ilen = table.data.length; i < ilen; i++) {
92106
if (!wherefn || wherefn(table.data[i], params, alasql)) {
107+
// Track row state for OUTPUT clause (DELETED.*)
108+
var oldRow = self.output ? cloneDeep(table.data[i]) : null;
109+
93110
if (table.update) {
94111
table.update(assignfn, i, params);
95112
} else {
96113
assignfn(table.data[i], params, alasql);
97114
}
115+
116+
// Track updated row for OUTPUT clause (INSERTED.*)
117+
if (self.output) {
118+
updatedRows.push({
119+
deleted: oldRow,
120+
inserted: cloneDeep(table.data[i]),
121+
});
122+
}
123+
98124
numrows++;
99125
}
100126
}
@@ -103,8 +129,39 @@ yy.Update.prototype.compile = function (databaseid) {
103129
alasql.engines[db.engineid].saveTableData(databaseid, tableid);
104130
}
105131

106-
if (cb) cb(numrows);
107-
return numrows;
132+
var res = numrows;
133+
134+
// Handle OUTPUT clause
135+
if (self.output) {
136+
var output = [];
137+
for (var i = 0; i < updatedRows.length; i++) {
138+
var deleted = updatedRows[i].deleted;
139+
var inserted = updatedRows[i].inserted;
140+
var outputRow = {};
141+
self.output.columns.forEach(function (col) {
142+
if (col.columnid === '*') {
143+
// For *, use INSERTED values
144+
for (var key in inserted) {
145+
outputRow[key] = inserted[key];
146+
}
147+
} else {
148+
var colname = col.as || col.columnid;
149+
// Check tableid to determine which version to use
150+
if (col.tableid === 'DELETED') {
151+
outputRow[colname] = deleted[col.columnid];
152+
} else {
153+
// Default to INSERTED
154+
outputRow[colname] = inserted[col.columnid];
155+
}
156+
}
157+
});
158+
output.push(outputRow);
159+
}
160+
res = output;
161+
}
162+
163+
if (cb) cb(res);
164+
return res;
108165
};
109166
return statement;
110167
};

0 commit comments

Comments
 (0)