@voxgig/sdkgen-infrapack 0.0.13 → 0.0.14
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.
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
opRequestShape, opParams, ownPoint, entityPath,
|
|
7
7
|
collectDeps, repoInfo, packageName, packageVersion, apiName, envName,
|
|
8
8
|
authorInfo, contributorList, isAuthActive, isHttpBasicAuth, jsKey, jsProp,
|
|
9
|
+
resolveAuthIn, resolveAuthName, resolveAuthPrefix,
|
|
9
10
|
SdkGenError,
|
|
10
11
|
PUBLISHER, PUBLISHER_URL,
|
|
11
12
|
pointSegments,
|
|
@@ -155,16 +156,27 @@ function idSpec(ent: any): { parts: string[], sep: string, from?: Record<string,
|
|
|
155
156
|
return null
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
|
|
159
|
+
const from = ent?.id?.from
|
|
160
|
+
const path = null != from && 'object' === typeof from ? from[rk] : null
|
|
161
|
+
return {
|
|
162
|
+
parts: [rk],
|
|
163
|
+
sep: idSep(ent),
|
|
164
|
+
...(null != path && '' !== String(path) ? { from: { [rk]: String(path) } } : {}),
|
|
165
|
+
}
|
|
159
166
|
}
|
|
160
167
|
|
|
161
168
|
|
|
169
|
+
// The model's identifier when the load match carries it, else the terminal
|
|
170
|
+
// path parameter, else a lone required query parameter: the rule the SDK's
|
|
171
|
+
// offline transport keys its store by.
|
|
162
172
|
function recordKey(ent: any): string {
|
|
163
173
|
const idf = entityIdField(ent)
|
|
164
174
|
if (null != idf && '' !== idf) {
|
|
165
175
|
return String(idf)
|
|
166
176
|
}
|
|
167
177
|
|
|
178
|
+
let fallback = ''
|
|
179
|
+
|
|
168
180
|
for (const opname of ['load', 'remove', 'update']) {
|
|
169
181
|
const op = (ent.op || {})[opname]
|
|
170
182
|
if (null == op || 0 === (op.points || []).length) {
|
|
@@ -174,11 +186,11 @@ function recordKey(ent: any): string {
|
|
|
174
186
|
const canonical = op.points.filter((pt: any) =>
|
|
175
187
|
null == (pt && pt.q && pt.q['$action']))
|
|
176
188
|
const point = ownPoint(0 < canonical.length ? canonical : op.points)
|
|
177
|
-
const
|
|
178
|
-
|
|
189
|
+
const segs = pointSegments(point)
|
|
190
|
+
const last = segs[segs.length - 1]
|
|
179
191
|
|
|
180
|
-
if (
|
|
181
|
-
return String(
|
|
192
|
+
if (null != last && null != last.var) {
|
|
193
|
+
return String(last.var)
|
|
182
194
|
}
|
|
183
195
|
|
|
184
196
|
const query = (point && point.g && point.g.query) || []
|
|
@@ -186,9 +198,43 @@ function recordKey(ent: any): string {
|
|
|
186
198
|
if (1 === reqdQuery.length) {
|
|
187
199
|
return String(reqdQuery[0].n)
|
|
188
200
|
}
|
|
201
|
+
|
|
202
|
+
// A literal-terminal route names a facet of a record: a last resort.
|
|
203
|
+
if ('' === fallback) {
|
|
204
|
+
const vars = segs.filter((seg: any) => null != seg.var)
|
|
205
|
+
if (0 < vars.length) {
|
|
206
|
+
fallback = String(vars[vars.length - 1].var)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return '' !== fallback ? fallback : 'id'
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
// Does a create have to SEND the record key, or does the API assign it?
|
|
216
|
+
function rkOnCreate(ent: any): boolean {
|
|
217
|
+
const rk = recordKey(ent)
|
|
218
|
+
|
|
219
|
+
if ('id' === rk || 0 < idParts(ent).length || null == (ent.op || {}).create) {
|
|
220
|
+
return false
|
|
189
221
|
}
|
|
190
222
|
|
|
191
|
-
return '
|
|
223
|
+
return opRequestShape(ent, 'create').items
|
|
224
|
+
.some((it: any) => it.name === rk && !it.optional)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
// Is `<provider>_id` free for this entity, or a name it already uses itself?
|
|
229
|
+
function parkFree(ent: any, parked: string): boolean {
|
|
230
|
+
const taken = new Set<string>([
|
|
231
|
+
recordKey(ent),
|
|
232
|
+
...idParts(ent),
|
|
233
|
+
...parentKeys(ent),
|
|
234
|
+
...Object.values(ent.fields || {}).map((f: any) => String(f.n)),
|
|
235
|
+
])
|
|
236
|
+
|
|
237
|
+
return !taken.has(parked)
|
|
192
238
|
}
|
|
193
239
|
|
|
194
240
|
|
|
@@ -335,6 +381,8 @@ const Main = cmp(function Main(props: any) {
|
|
|
335
381
|
ops: entityOps(ent),
|
|
336
382
|
idf: entityIdField(ent),
|
|
337
383
|
rk: recordKey(ent),
|
|
384
|
+
rkoncreate: rkOnCreate(ent),
|
|
385
|
+
parkfree: parkFree(ent, lower + '_id'),
|
|
338
386
|
// The composite key, when this API addresses a record by several
|
|
339
387
|
// path params at once. The doc and test emitters in Extras need the
|
|
340
388
|
// same answer the handler emitters use: a test that addresses a
|
|
@@ -494,6 +542,11 @@ const Main = cmp(function Main(props: any) {
|
|
|
494
542
|
// plumbing one anyway produces a credential path that cannot work.
|
|
495
543
|
authActive: isAuthActive(model),
|
|
496
544
|
authBasic: isAuthActive(model) && isHttpBasicAuth(model),
|
|
545
|
+
// Where the credential goes, resolved as the SDK's auth stage does.
|
|
546
|
+
authIn: resolveAuthIn(model),
|
|
547
|
+
authName: 'header' === resolveAuthIn(model) ?
|
|
548
|
+
resolveAuthName(model).toLowerCase() : resolveAuthName(model),
|
|
549
|
+
authPrefix: resolveAuthPrefix(model),
|
|
497
550
|
}
|
|
498
551
|
|
|
499
552
|
// `.gitignore` is EMITTED rather than copied — npm strips that filename
|
|
@@ -662,6 +715,8 @@ const PackageJson = cmp(function PackageJson(props: any) {
|
|
|
662
715
|
const ProviderSource = cmp(function ProviderSource(props: any) {
|
|
663
716
|
const { provider } = props
|
|
664
717
|
|
|
718
|
+
const translated = provider.entities.filter((e: any) => null != idSpec(e.ent))
|
|
719
|
+
|
|
665
720
|
Folder({ name: 'src' }, () => {
|
|
666
721
|
File({ name: `${provider.fileBase}.ts` }, () => {
|
|
667
722
|
Content(`/* Generated by @voxgig/sdkgen. Do not edit. */
|
|
@@ -760,8 +815,8 @@ function ${provider.pluginName}(this: any, options: ${provider.pluginName}Option
|
|
|
760
815
|
|
|
761
816
|
|
|
762
817
|
// The SDK argument for an ACTION on a read cmd: everything the caller sent
|
|
763
|
-
// minus Seneca's own directives, with the
|
|
764
|
-
// the \`$action\` selector the SDK dispatches on.
|
|
818
|
+
// minus Seneca's own directives, with the id translated into the API's own
|
|
819
|
+
// keys, plus the \`$action\` selector the SDK dispatches on.
|
|
765
820
|
//
|
|
766
821
|
// WIDER than the canonical argument on purpose. An action route has its own
|
|
767
822
|
// parameters — GitHub's merge takes commit_title and merge_method, which the
|
|
@@ -769,14 +824,21 @@ function ${provider.pluginName}(this: any, options: ${provider.pluginName}Option
|
|
|
769
824
|
// required keys would strip the action's whole payload. The SDK still
|
|
770
825
|
// validates: an action whose own point cannot be built is refused with
|
|
771
826
|
// \`point_action_invalid\` rather than sent somewhere else.
|
|
772
|
-
function actionq(q: any,
|
|
827
|
+
function actionq(q: any, ${0 === translated.length ? '' : 'name: string, '}action: string) {
|
|
773
828
|
const out = cleanq(q)
|
|
829
|
+
${0 === translated.length ? '' : `
|
|
830
|
+
// An action addresses the SAME record the canonical route does, so the id
|
|
831
|
+
// is translated the same way a write translates it: split into the path
|
|
832
|
+
// parameters the API names, under the names it names them by. Sending the
|
|
833
|
+
// joined id as one terminal parameter asks for \`owner0/repo0\` as a repo.
|
|
834
|
+
const own = Object.prototype.hasOwnProperty
|
|
835
|
+
const spec = own.call(ID_SPEC, name) ? ID_SPEC[name] : null
|
|
774
836
|
|
|
775
|
-
if (
|
|
776
|
-
out
|
|
837
|
+
if (null != spec && null != out.id) {
|
|
838
|
+
Object.assign(out, splitid(name, out.id, 'action'))
|
|
777
839
|
delete out.id
|
|
778
840
|
}
|
|
779
|
-
|
|
841
|
+
`}
|
|
780
842
|
out.$action = action
|
|
781
843
|
return out
|
|
782
844
|
}
|
|
@@ -818,6 +880,15 @@ function ${provider.pluginName}(this: any, options: ${provider.pluginName}Option
|
|
|
818
880
|
'${provider.pkgName}: ${e.name} ' + cmd + ': ${k} is required'
|
|
819
881
|
)
|
|
820
882
|
}
|
|
883
|
+
|
|
884
|
+
// A path parameter is one value. A loaded record can carry an object
|
|
885
|
+
// under the same name, and that must not be sent as a URL segment.
|
|
886
|
+
if ('object' === typeof value) {
|
|
887
|
+
throw new Error(
|
|
888
|
+
'${provider.pkgName}: ${e.name} ' + cmd + ': ${k} must be a single ' +
|
|
889
|
+
'value to build the request path, not an object'
|
|
890
|
+
)
|
|
891
|
+
}
|
|
821
892
|
return value
|
|
822
893
|
}
|
|
823
894
|
|
|
@@ -827,16 +898,15 @@ function ${provider.pluginName}(this: any, options: ${provider.pluginName}Option
|
|
|
827
898
|
})
|
|
828
899
|
}
|
|
829
900
|
|
|
830
|
-
const translated = provider.entities.filter((e: any) => null != idSpec(e.ent))
|
|
831
|
-
|
|
832
901
|
if (0 < translated.length) {
|
|
833
902
|
const rows = translated.map((e: any) => {
|
|
834
903
|
const spec: any = idSpec(e.ent)
|
|
835
904
|
const from = null == spec.from ? '' :
|
|
836
905
|
`, from: { ${Object.keys(spec.from).sort()
|
|
837
906
|
.map((k: string) => `${jsKey(k)}: '${spec.from[k]}'`).join(', ')} }`
|
|
907
|
+
const park = false === e.parkfree ? ', park: false' : ''
|
|
838
908
|
return ` ${jsKey(e.name)}: { parts: [${
|
|
839
|
-
spec.parts.map((p: string) => `'${p}'`).join(', ')}], sep: '${spec.sep}'${from} },`
|
|
909
|
+
spec.parts.map((p: string) => `'${p}'`).join(', ')}], sep: '${spec.sep}'${from}${park} },`
|
|
840
910
|
}).join('\n')
|
|
841
911
|
|
|
842
912
|
Content(` // HOW EACH ENTITY'S id MAPS TO THE API'S OWN KEYS, from the model.
|
|
@@ -853,7 +923,9 @@ function ${provider.pluginName}(this: any, options: ${provider.pluginName}Option
|
|
|
853
923
|
// field's name: github returns a repo's owner as an OBJECT
|
|
854
924
|
// (\`owner.login\`) and its name as \`name\`, never \`repo\`.
|
|
855
925
|
// A part missing here cannot be read back off a response.
|
|
856
|
-
|
|
926
|
+
// \`park\` false where \`${provider.lower}_id\` is a name this entity
|
|
927
|
+
// already uses, so the API's own id is left where it is.
|
|
928
|
+
const ID_SPEC: Record<string, { parts: string[], sep: string, from?: Record<string, string>, park?: boolean }> = {
|
|
857
929
|
${rows}
|
|
858
930
|
}
|
|
859
931
|
|
|
@@ -904,7 +976,7 @@ ${rows}
|
|
|
904
976
|
// THE ADDRESSING KEY WINS over an \`id\` the response already carries. A
|
|
905
977
|
// response often has both — github's pull has a global database \`id\` and
|
|
906
978
|
// a repo-scoped \`number\` — and the unrelated one is no use for addressing
|
|
907
|
-
// anything. It is kept as \`${provider.lower}_id
|
|
979
|
+
// anything. It is kept as \`${provider.lower}_id\`, unless \`park\` forbids.
|
|
908
980
|
function joinid(name: string, data: any, vals?: any) {
|
|
909
981
|
const spec = ID_SPEC[name]
|
|
910
982
|
if (null == data) {
|
|
@@ -930,7 +1002,7 @@ ${rows}
|
|
|
930
1002
|
}
|
|
931
1003
|
|
|
932
1004
|
if (null != id) {
|
|
933
|
-
if (null != data.id && String(data.id) !== id &&
|
|
1005
|
+
if (false !== spec.park && null != data.id && String(data.id) !== id &&
|
|
934
1006
|
null == ${jsProp('data', provider.lower + '_id')}) {
|
|
935
1007
|
${jsProp('data', provider.lower + '_id')} = data.id
|
|
936
1008
|
}
|
|
@@ -1053,19 +1125,18 @@ ${rows}
|
|
|
1053
1125
|
each(provider.entities, (e: any) => {
|
|
1054
1126
|
const eparts = idParts(e.ent)
|
|
1055
1127
|
const espec = idSpec(e.ent)
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
(e.opParents[cmd] || [])
|
|
1128
|
+
// Guards of ONE op: save's create and update branches guard their own.
|
|
1129
|
+
const guard = (opname: string, src: string, label = opname, ind = ' ') => {
|
|
1130
|
+
const keys = e.opParents[opname] || []
|
|
1060
1131
|
|
|
1061
1132
|
return keys
|
|
1062
1133
|
.filter((k: string) => !eparts.includes(k))
|
|
1063
1134
|
.map((k: string) =>
|
|
1064
|
-
|
|
1135
|
+
`${ind}${guardName(e, k)}(${jsProp(src, k)}, '${label}')\n`)
|
|
1065
1136
|
.join('')
|
|
1066
1137
|
}
|
|
1067
1138
|
|
|
1068
|
-
const refuse = (cmd: string) => {
|
|
1139
|
+
const refuse = (cmd: string, ind = ' ') => {
|
|
1069
1140
|
if (true !== (e.idmisaddressed || {})[cmd]) {
|
|
1070
1141
|
return ''
|
|
1071
1142
|
}
|
|
@@ -1073,13 +1144,17 @@ ${rows}
|
|
|
1073
1144
|
recordKey(e.ent)
|
|
1074
1145
|
const addresses = addressKeys(e.ent, cmd)
|
|
1075
1146
|
|
|
1076
|
-
return
|
|
1147
|
+
return `${ind}misaddressed('${e.name}', '${cmd}', '${key}', ` +
|
|
1077
1148
|
`[${addresses.map((k: string) => `'${k}'`).join(', ')}])
|
|
1078
1149
|
`
|
|
1079
1150
|
}
|
|
1080
1151
|
|
|
1081
1152
|
const rk = recordKey(e.ent)
|
|
1082
1153
|
|
|
1154
|
+
// Named only where there is a spec to translate the id through.
|
|
1155
|
+
const aq = `actionq(msg.q, ${0 === translated.length ? '' :
|
|
1156
|
+
`'${e.name}', `}action$)`
|
|
1157
|
+
|
|
1083
1158
|
const sdkArg = (opname: string) => {
|
|
1084
1159
|
const keys = addressKeys(e.ent, opname)
|
|
1085
1160
|
if (0 === keys.length) {
|
|
@@ -1094,23 +1169,24 @@ ${rows}
|
|
|
1094
1169
|
`${jsKey(k)}: ${jsProp('q', k === rk ? 'id' : k)}`).join(', ')} }`
|
|
1095
1170
|
}
|
|
1096
1171
|
|
|
1097
|
-
//
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
//
|
|
1101
|
-
const entArg =
|
|
1102
|
-
`null == key ? undefined : { match: key }`
|
|
1172
|
+
// Seneca's `id` and the API's key differ: composite, or not called id.
|
|
1173
|
+
const keyed = null != espec
|
|
1174
|
+
|
|
1175
|
+
// The entity-options argument carrying a write's addressing values.
|
|
1176
|
+
const entArg = !keyed ? '' : `null == key ? undefined : { match: key }`
|
|
1103
1177
|
|
|
1104
1178
|
const splitLine = (cmd: string) => 0 === eparts.length ? '' :
|
|
1105
|
-
` const key = splitid('${e.name}',
|
|
1179
|
+
` const key = splitid('${e.name}', q.id, '${cmd}')\n`
|
|
1106
1180
|
|
|
1107
|
-
// The data hop, plus the id
|
|
1108
|
-
//
|
|
1109
|
-
// values through, because the response may not repeat them.
|
|
1181
|
+
// The data hop, plus the id from the values this request addressed the
|
|
1182
|
+
// record with, which the response need not repeat.
|
|
1110
1183
|
const out = (expr: string, vals?: string) =>
|
|
1111
|
-
|
|
1184
|
+
!keyed ? `plain(${expr})` :
|
|
1112
1185
|
`joinid('${e.name}', plain(${expr})${null == vals ? '' : ', ' + vals})`
|
|
1113
1186
|
|
|
1187
|
+
const loadVals = 0 < eparts.length ? 'key' :
|
|
1188
|
+
!keyed ? undefined : `{ ${jsKey(rk)}: q.id }`
|
|
1189
|
+
|
|
1114
1190
|
const actionBranch = (cmd: string, call: string) => ` const action$ = actionOf(msg)
|
|
1115
1191
|
if (null != action$) {
|
|
1116
1192
|
const op$ = actionop(action$, '${e.name}', '${cmd}')
|
|
@@ -1124,7 +1200,7 @@ ${call} }
|
|
|
1124
1200
|
async function list_${e.name}(this: any, entize: any, msg: any) {
|
|
1125
1201
|
const q = cleanq(msg.q)
|
|
1126
1202
|
${actionBranch('list',
|
|
1127
|
-
` const found = await this.shared.sdk.${e.acc}()[op$](
|
|
1203
|
+
` const found = await this.shared.sdk.${e.acc}()[op$](${aq})
|
|
1128
1204
|
return found.map((data: any) => entize(${out('data')}))
|
|
1129
1205
|
`)}${guard('list', 'q')} const list = await this.shared.sdk.${e.acc}().list(q)
|
|
1130
1206
|
return list.map((data: any) => entize(${out('data')}))
|
|
@@ -1139,10 +1215,10 @@ ${actionBranch('list',
|
|
|
1139
1215
|
async function load_${e.name}(this: any, entize: any, msg: any) {
|
|
1140
1216
|
const q = cleanq(msg.q)
|
|
1141
1217
|
${actionBranch('load',
|
|
1142
|
-
` const hit = await ornull(() => this.shared.sdk.${e.acc}()[op$](
|
|
1218
|
+
` const hit = await ornull(() => this.shared.sdk.${e.acc}()[op$](${aq}))
|
|
1143
1219
|
return null == hit ? null : entize(${out('hit')})
|
|
1144
1220
|
`)}${guard('load', 'q')}${splitLine('load')} const res = await ornull(() => this.shared.sdk.${e.acc}().load(${sdkArg('load')}))
|
|
1145
|
-
return null == res ? null : entize(${out('res',
|
|
1221
|
+
return null == res ? null : entize(${out('res', loadVals)})
|
|
1146
1222
|
}
|
|
1147
1223
|
|
|
1148
1224
|
`)
|
|
@@ -1152,22 +1228,19 @@ ${actionBranch('load',
|
|
|
1152
1228
|
const hasCreate = e.ops.includes('create')
|
|
1153
1229
|
const hasUpdate = e.ops.includes('update')
|
|
1154
1230
|
|
|
1155
|
-
const refuseUpdate = true === (e.idmisaddressed || {}).update
|
|
1156
|
-
refuse('update') : ''
|
|
1231
|
+
const refuseUpdate = true === (e.idmisaddressed || {}).update
|
|
1157
1232
|
|
|
1158
|
-
const
|
|
1159
|
-
? (('' === refuseUpdate) ? ` const res = null == data.id
|
|
1160
|
-
? await sdk.${e.acc}(${entArg}).create(data)
|
|
1161
|
-
: await sdk.${e.acc}(${entArg}).update(data)` : ` if (null != data.id) {
|
|
1162
|
-
${refuseUpdate.replace(/\n$/, '')}
|
|
1163
|
-
}
|
|
1233
|
+
const isUpdate = keyed ? 'null != key' : 'null != data.id'
|
|
1164
1234
|
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1235
|
+
// Deleting a name the entity owns strips a value the caller supplied.
|
|
1236
|
+
const dropPark = false === e.parkfree ? '' : `
|
|
1237
|
+
// \`${provider.lower}_id\` is this provider's own bookkeeping — the
|
|
1238
|
+
// API's unrelated \`id\`, parked by joinid(). It is not a field of the
|
|
1239
|
+
// API's write schema, so it must not travel in the request body.
|
|
1240
|
+
delete ${jsProp('data', provider.lower + '_id')}
|
|
1241
|
+
`
|
|
1169
1242
|
|
|
1170
|
-
const
|
|
1243
|
+
const keyBlock = 0 < eparts.length ? `
|
|
1171
1244
|
// Seneca carries this ${e.name}'s key as one \`id\`; the API addresses
|
|
1172
1245
|
// the record by ${eparts.map((p: string) => '`' + p + '`').join(' and ')}.
|
|
1173
1246
|
//
|
|
@@ -1186,13 +1259,7 @@ ${actionBranch('load',
|
|
|
1186
1259
|
if (null != data.id) {
|
|
1187
1260
|
key = splitid('${e.name}', data.id, 'save')
|
|
1188
1261
|
}
|
|
1189
|
-
|
|
1190
|
-
// \`${provider.lower}_id\` is this provider's own bookkeeping — the
|
|
1191
|
-
// API's unrelated \`id\`, parked by joinid() so it is not lost. It is
|
|
1192
|
-
// not a field of the API's write schema, so it must not travel in the
|
|
1193
|
-
// request body.
|
|
1194
|
-
delete ${jsProp('data', provider.lower + '_id')}
|
|
1195
|
-
|
|
1262
|
+
${dropPark}
|
|
1196
1263
|
// AND NEITHER DOES THE JOINED \`id\`. It is Seneca's key for this
|
|
1197
1264
|
// record, not the API's: a composite ${e.name} is addressed by
|
|
1198
1265
|
// \`${eparts.join('\` and \`')}\`, which travel as path parameters in
|
|
@@ -1201,39 +1268,61 @@ ${actionBranch('load',
|
|
|
1201
1268
|
// which matches a request against a stored record, then looked for a
|
|
1202
1269
|
// record whose own \`id\` was that joined string and found none.
|
|
1203
1270
|
delete data.id
|
|
1204
|
-
` : ''
|
|
1205
|
-
|
|
1206
|
-
const alias = 0 < eparts.length ? '' : 'id' === rk ? '' :
|
|
1207
|
-
`
|
|
1271
|
+
` : !keyed ? '' : `
|
|
1208
1272
|
// This API keys a ${e.name} by \`${rk}\`; Seneca carries it as \`id\`.
|
|
1209
|
-
|
|
1210
|
-
|
|
1273
|
+
// The key goes on the body under the API's own name, where the route
|
|
1274
|
+
// reads it, and into the match, which the SDK consults first.
|
|
1275
|
+
let key = null
|
|
1276
|
+
if (null != data.id) {
|
|
1277
|
+
key = { ${jsKey(rk)}: data.id }
|
|
1278
|
+
if (null == ${jsProp('data', rk)}) {
|
|
1279
|
+
${jsProp('data', rk)} = data.id
|
|
1280
|
+
}
|
|
1211
1281
|
}
|
|
1212
|
-
|
|
1213
|
-
// \`${
|
|
1214
|
-
//
|
|
1215
|
-
//
|
|
1216
|
-
//
|
|
1217
|
-
|
|
1218
|
-
delete ${jsProp('data', provider.lower + '_id')}
|
|
1282
|
+
${dropPark}
|
|
1283
|
+
// NOR DOES SENECA'S \`id\`. It holds the \`${rk}\` this API addresses
|
|
1284
|
+
// the record by, under a name this API's ${e.name} does not have: sent
|
|
1285
|
+
// on the body it is at best an unknown property, and to a store that
|
|
1286
|
+
// matches a write against the record it names the wrong one.
|
|
1287
|
+
delete data.id
|
|
1219
1288
|
`
|
|
1220
1289
|
|
|
1290
|
+
const saveVals = keyed ? 'key' : undefined
|
|
1291
|
+
|
|
1292
|
+
const call = (opname: string) =>
|
|
1293
|
+
`await sdk.${e.acc}(${entArg}).${opname}(data)`
|
|
1294
|
+
|
|
1295
|
+
const body = hasCreate && hasUpdate
|
|
1296
|
+
? (!refuseUpdate ? ` let res
|
|
1297
|
+
if (${isUpdate}) {
|
|
1298
|
+
${guard('update', 'data', 'save', ' ')} res = ${call('update')}
|
|
1299
|
+
}
|
|
1300
|
+
else {
|
|
1301
|
+
${guard('create', 'data', 'save', ' ')} res = ${call('create')}
|
|
1302
|
+
}` : ` if (${isUpdate}) {
|
|
1303
|
+
${refuse('update', ' ')} }
|
|
1304
|
+
|
|
1305
|
+
${guard('create', 'data', 'save')} const res = ${call('create')}`)
|
|
1306
|
+
: hasCreate
|
|
1307
|
+
? `${guard('create', 'data', 'save')} const res = ${call('create')}`
|
|
1308
|
+
: `${refuse('update')}${guard('update', 'data', 'save')} const res = ${call('update')}`
|
|
1309
|
+
|
|
1221
1310
|
Content(`
|
|
1222
1311
|
${jsProp('entity', e.name)}.cmd.save.action =
|
|
1223
1312
|
async function save_${e.name}(this: any, entize: any, msg: any) {
|
|
1224
1313
|
const data = msg.ent.data$(false)
|
|
1225
|
-
${
|
|
1314
|
+
${keyBlock} const sdk = this.shared.sdk
|
|
1226
1315
|
|
|
1227
1316
|
${actionBranch('save',
|
|
1228
1317
|
` // The action's OWN payload is the entity's own fields — data$(false)
|
|
1229
1318
|
// has already dropped every trailing-\`$\` key, \`action$\` included,
|
|
1230
1319
|
// so \`$action\` is the only thing added here.
|
|
1231
1320
|
data.$action = action$
|
|
1232
|
-
const done = await sdk.${e.acc}()[op$](data)
|
|
1233
|
-
return entize(${out('done')})
|
|
1234
|
-
`)}${
|
|
1321
|
+
const done = await sdk.${e.acc}(${entArg})[op$](data)
|
|
1322
|
+
return entize(${out('done', saveVals)})
|
|
1323
|
+
`)}${body}
|
|
1235
1324
|
|
|
1236
|
-
return entize(${out('res',
|
|
1325
|
+
return entize(${out('res', saveVals)})
|
|
1237
1326
|
}
|
|
1238
1327
|
|
|
1239
1328
|
`)
|
|
@@ -1245,7 +1334,7 @@ ${actionBranch('save',
|
|
|
1245
1334
|
async function remove_${e.name}(this: any, entize: any, msg: any) {
|
|
1246
1335
|
const q = cleanq(msg.q)
|
|
1247
1336
|
${actionBranch('remove',
|
|
1248
|
-
` const gone = await ornull(() => this.shared.sdk.${e.acc}()[op$](
|
|
1337
|
+
` const gone = await ornull(() => this.shared.sdk.${e.acc}()[op$](${aq}))
|
|
1249
1338
|
return null == gone ? null : entize(${out('gone')})
|
|
1250
1339
|
`)}${'' !== refuse('remove') ? refuse('remove') :
|
|
1251
1340
|
`${guard('remove', 'q')}${splitLine('remove')} await ornull(() => this.shared.sdk.${e.acc}().remove(${sdkArg('remove')}))
|
|
@@ -1405,6 +1494,7 @@ if ('undefined' !== typeof module) {
|
|
|
1405
1494
|
export {
|
|
1406
1495
|
Main,
|
|
1407
1496
|
recordKey,
|
|
1497
|
+
rkOnCreate,
|
|
1408
1498
|
cmdActions,
|
|
1409
1499
|
entityActionList,
|
|
1410
1500
|
}
|
package/package.json
CHANGED