deno.land / x / pg_mem@2.8.1 / execution / records-mutations / mutation-base.ts

mutation-base.ts
نووسراو ببینە
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import { DataSourceBase } from '../../transforms/transform-base.ts';import { ArrayFilter } from '../../transforms/array-filter.ts';import { cleanResults } from '../clean-results.ts';import { _ISelection, _ISchema, _ITable, _Transaction, IValue, _IIndex, _Explainer, _IStatement, QueryError, _Column } from '../../interfaces-private.ts';import { InsertStatement, UpdateStatement, DeleteStatement, SetStatement, ExprRef } from 'https://deno.land/x/pgsql_ast_parser@12.0.1/mod.ts';import { buildSelection } from '../../transforms/selection.ts';import { MemoryTable } from '../../table.ts';import { buildValue } from '../../parser/expression-builder.ts';import { withSelection, buildCtx } from '../../parser/context.ts';import { colToStr } from '../../utils.ts';
type MutationStatement = InsertStatement | UpdateStatement | DeleteStatement;

export abstract class MutationDataSourceBase<T> extends DataSourceBase<T> { public static readonly affectedRows = Symbol('affectedRows');
/** Perform the mutation, and returns the affected elements */ protected abstract performMutation(t: _Transaction): T[];
private returningRows?: ArrayFilter; private returning?: _ISelection; private mutationResult = Symbol('mutationResult');
get isExecutionWithNoResult(): boolean { return !this.returning; }
isAggregation() { return false; }
get columns() { return this.returning?.columns ?? []; }
constructor(protected table: _ITable, protected mutatedSel: _ISelection, p: MutationStatement) { super(table.ownerSchema);
// prepare "returning" statement if (p.returning) { this.returningRows = new ArrayFilter(this.mutatedSel, []) this.returning = buildSelection(this.returningRows, p.returning); }
const { onFinishExecution } = buildCtx(); // force execution if it has not yet been executed once the current statement finishes its execution. // see "only inserts once with statement is executed" test onFinishExecution(t => { this._doExecuteOnce(t); }); }
private _doExecuteOnce(t: _Transaction): any[] { // check if this mutation has already been executed in the statement being executed // and get the result from cache to avoid re-excuting it // see unit test "can use delete result multiple times in select" let affected = t.getTransient<T[]>(this.mutationResult); if (!affected) { // execute mutation if nescessary affected = this.performMutation(t); t.setTransient(this.mutationResult, affected); }

// set the result count t.setTransient(MutationDataSourceBase.affectedRows, affected.length); return affected; }
*enumerate(t: _Transaction): Iterable<any> {
const affected = this._doExecuteOnce(t);
if (!this.returning) { return; }
// handle "returning" statement try { cleanResults(affected); this.returningRows!.rows = affected; yield* this.returning.enumerate(t); } finally { this.returningRows!.rows = [] } }
entropy(t: _Transaction): number { // To ensure that a muation will always be prioritary // on a join, then just return 0. return 0; }
getColumn(column: string | ExprRef, nullIfNotFound?: boolean | undefined): IValue<any> { if (!this.returning) { throw new Error(`Cannot get column "${colToStr(column)}" from a mutation that has no returning statement`); } return this.returning.getColumn(column, nullIfNotFound)!; }
hasItem(value: any, t: _Transaction): boolean { throw new Error('To fix: Joins cannot call hasItem on a mutation'); }
getIndex(forValue: IValue<any>): _IIndex<any> | null | undefined { return null; }
explain(e: _Explainer): never { throw new Error('not implemented'); }
isOriginOf(a: IValue<any>): boolean { return !!this.returning && a.origin === this.returning; }
stats(t: _Transaction): null { return null; }}

export type Setter = (t: _Transaction, target: any, source: any) => void;export function createSetter(this: void, setTable: _ITable, setSelection: _ISelection, _sets: SetStatement[]): Setter { return withSelection(setSelection, () => { const alreadySet = new Set<_Column>(); const sets = _sets.map(x => { const col = (setTable as MemoryTable).getColumnRef(x.column.name); if (alreadySet.has(col)) { throw new QueryError(` multiple assignments to same column "${col.name}"`, '42601'); } alreadySet.add(col); return { col, value: x.value, getter: x.value.type !== 'default' ? buildValue(x.value).cast(col.expression.type) : null, }; });
return (t: _Transaction, target: any, source: any) => { for (const s of sets) { if (s.value.type === 'default') { target[s.col.expression.id!] = s.col.default?.get() ?? undefined; } else { target[s.col.expression.id!] = s.getter?.get(source, t) ?? null; } } } });}
pg_mem

Version Info

Tagged at
a year ago