sfobjects-basic-client 1.1.3 → 1.1.5

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.d.ts CHANGED
@@ -74,6 +74,13 @@ type MandatoryCreateProps<O> = {
74
74
  -readonly [P in K]: O[P];
75
75
  }, K>) : never) : never;
76
76
  }[KeyOf<O>];
77
+ type UpdateableProps<O> = {
78
+ [K in keyof O]: NonNullable<O[K]> extends SfPrimitiveType ? (IsMutable<{
79
+ [P in K]: O[P];
80
+ }, {
81
+ -readonly [P in K]: O[P];
82
+ }, K>) : never;
83
+ }[KeyOf<O>];
77
84
  export type SfRootSelect<OI, N extends KeyOf<OI>> = SfSelect<GetObjectTypes<OI>, OI[N]>;
78
85
  export type SfRootWhere<OI, N extends KeyOf<OI>> = SfWhere<GetObjectTypes<OI>, OI[N]>;
79
86
  export type SfRootOrderBy<OI, N extends KeyOf<OI>> = SfOrderBy<GetObjectTypes<OI>, OI[N]>;
@@ -88,7 +95,9 @@ export type SfUpsert<O, K extends MandatoryCreateProps<O>> = SfCreate<O> & {
88
95
  };
89
96
  export type SfUpdate<O> = {
90
97
  Id: string;
91
- } & SfCreate<O>;
98
+ } & {
99
+ [K in UpdateableProps<O>]+?: O[K];
100
+ };
92
101
  export type SfObjCfg = {
93
102
  objectPrefix: string;
94
103
  dateTypes: string[];
@@ -124,6 +133,11 @@ export type SfDmlOptions = {
124
133
  };
125
134
  };
126
135
  };
136
+ export type SfClientOptions = {
137
+ breakOnError?: boolean;
138
+ query?: SfQueryOptions;
139
+ dml?: SfDmlOptions;
140
+ };
127
141
  export type SfQueryResult<R> = {
128
142
  records: R[];
129
143
  };
@@ -159,6 +173,7 @@ export interface SfWhereActions<OI, N extends KeyOf<OI>, S extends SfRootSelect<
159
173
  }
160
174
  export interface SfSelectAditionalActions<OI, N extends KeyOf<OI>, S extends SfRootSelect<OI, N>> {
161
175
  find: (id: string, options?: SfQueryOptions) => Promise<SfRootSelectProjection<OI, N, S> | undefined>;
176
+ retrieve: (id: string, options?: SfQueryOptions) => Promise<SfRootSelectProjection<OI, N, S>>;
162
177
  selection: S[];
163
178
  }
164
179
  export interface SfObjActions<OI, N extends KeyOf<OI>> {
@@ -174,10 +189,14 @@ export interface SfObjActions<OI, N extends KeyOf<OI>> {
174
189
  upsert: <K extends MandatoryCreateProps<OI[N]>>(records: SfUpsert<OI[N], K>[], key: K, options?: SfDmlOptions) => PromiseLike<SfSaveResult[]>;
175
190
  select: <S extends SfRootSelect<OI, N>>(select: S[]) => (SfSelectActions<OI, N, S> & SfWhereActions<OI, N, S> & SfSelectAditionalActions<OI, N, S>);
176
191
  }
192
+ export declare class SfBasicClientError extends Error {
193
+ errors: SfSaveError[];
194
+ constructor(errors: SfSaveError[]);
195
+ }
177
196
  export declare function isPlainObject(value: unknown): value is Record<string, any>;
178
197
  export declare function constructSoql<OI>(_cfg: SfObjCfgIndex<OI>): (objName: string, from: string, select: (string | {})[], where?: string | Record<string, any>, orderBy?: Record<string, any>, limit?: number) => string;
179
- export declare function getSfObject<OI>(_cfg: SfObjCfgIndex<OI>): <N extends KeyOf<OI>>(from: N, _conn: ISfConnection) => SfObjActions<OI, N>;
180
- export declare const getSfObjects: <OI>(cfg: SfObjCfgIndex<OI>) => (conn: ISfConnection) => { [N in KeyOf<OI>]: SfObjActions<OI, N>; };
198
+ export declare function getSfObject<OI>(_cfg: SfObjCfgIndex<OI>, o?: SfClientOptions): <N extends KeyOf<OI>>(from: N, _conn: ISfConnection) => SfObjActions<OI, N>;
199
+ export declare const getSfObjects: <OI>(cfg: SfObjCfgIndex<OI>) => (conn: ISfConnection, options?: SfClientOptions) => { [N in KeyOf<OI>]: SfObjActions<OI, N>; };
181
200
  export declare const sfObject: <OI, N extends KeyOf<OI>>(cfg: SfObjCfgIndex<OI>, n: N) => {
182
201
  info: SfObjCfgIndex<OI>[N];
183
202
  select: <S extends SfRootSelect<OI, N>>(s: S[]) => S[];
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ var __rest = (this && this.__rest) || function (s, e) {
21
21
  return t;
22
22
  };
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
- exports.sfObject = exports.getSfObjects = void 0;
24
+ exports.sfObject = exports.getSfObjects = exports.SfBasicClientError = void 0;
25
25
  exports.isPlainObject = isPlainObject;
26
26
  exports.constructSoql = constructSoql;
27
27
  exports.getSfObject = getSfObject;
@@ -70,6 +70,15 @@ const OP_RULES = [
70
70
  { ops: OP_KEYS_LIKE, soqlOp: 'like' },
71
71
  { ops: OP_KEYS_NLIKE, soqlOp: 'like', isNot: true },
72
72
  ];
73
+ class SfBasicClientError extends Error {
74
+ constructor(errors) {
75
+ super('Salesforce error(s): ' + errors.map(e => { var _a; return `[${e.errorCode}] ${e.message}, field(s): ${(_a = e.fields) === null || _a === void 0 ? void 0 : _a.join(',')}`; }).join(';\r\n'));
76
+ this.errors = errors;
77
+ this.name = 'SfBasicClientError';
78
+ Object.setPrototypeOf(this, new.target.prototype);
79
+ }
80
+ }
81
+ exports.SfBasicClientError = SfBasicClientError;
73
82
  // functions
74
83
  function isPlainObject(value) {
75
84
  if (typeof value !== 'object' || value === null)
@@ -222,36 +231,54 @@ function constructSoql(_cfg) {
222
231
  }
223
232
  return _constructFullQuery;
224
233
  }
225
- function getSfObject(_cfg) {
234
+ function processSaveResult(sr, breakOnError) {
235
+ if (breakOnError) {
236
+ const _errors = sr.filter(r => (r.success !== true)).map(r => r.errors).flat();
237
+ if (_errors.length) {
238
+ throw new SfBasicClientError(_errors);
239
+ }
240
+ }
241
+ return sr;
242
+ }
243
+ function getSfObject(_cfg, o) {
226
244
  function _query(conn, from, select, where, orderBy, limit) {
227
245
  const soql = () => constructSoql(_cfg)(from, from, select, where, orderBy, limit);
228
246
  return ({
229
247
  soql,
230
- get: (options) => __awaiter(this, void 0, void 0, function* () { return yield conn.query(soql(), options); }), // to get rid of promiselike,
248
+ get: (...args_1) => __awaiter(this, [...args_1], void 0, function* (options = o === null || o === void 0 ? void 0 : o.query) { return yield conn.query(soql(), options); }), // to get rid of promiselike,
231
249
  limit: (limit) => _query(conn, from, select, where, orderBy, limit)
232
250
  });
233
251
  }
252
+ function _queryOne(conn, from, select, id, options = o === null || o === void 0 ? void 0 : o.query) {
253
+ return _query(conn, from, select, `Id = '${id}'`).limit(1).get(options);
254
+ }
234
255
  return (from, _conn) => {
235
256
  return ({
236
257
  query: (q) => {
237
258
  const { select, where, orderBy, limit } = q;
238
259
  return _query(_conn, from, select, where, orderBy, limit);
239
260
  },
240
- delete: (ids, options) => _conn.delete(from, ids, options),
241
- update: (records, options) => _conn.update(from, records, options),
242
- create: (records, options) => _conn.create(from, records, options),
243
- upsert: (records, key, options) => _conn.upsert(from, records, key, options),
244
- select: (select) => (Object.assign(Object.assign({}, _query(_conn, from, select)), { orderBy: (orderBy) => _query(_conn, from, select, undefined, orderBy), where: (where) => (Object.assign(Object.assign({}, _query(_conn, from, select, where)), { orderBy: (orderBy) => _query(_conn, from, select, where, orderBy) })), find: (id, options) => __awaiter(this, void 0, void 0, function* () {
245
- const result = yield _query(_conn, from, select, `Id = '${id}'`).limit(1).get(options);
261
+ delete: (ids_1, ...args_1) => __awaiter(this, [ids_1, ...args_1], void 0, function* (ids, options = o === null || o === void 0 ? void 0 : o.dml) { return processSaveResult(yield _conn.delete(from, ids, options), o === null || o === void 0 ? void 0 : o.breakOnError); }),
262
+ update: (records_1, ...args_1) => __awaiter(this, [records_1, ...args_1], void 0, function* (records, options = o === null || o === void 0 ? void 0 : o.dml) { return processSaveResult(yield _conn.update(from, records, options), o === null || o === void 0 ? void 0 : o.breakOnError); }),
263
+ create: (records_1, ...args_1) => __awaiter(this, [records_1, ...args_1], void 0, function* (records, options = o === null || o === void 0 ? void 0 : o.dml) { return processSaveResult(yield _conn.create(from, records, options), o === null || o === void 0 ? void 0 : o.breakOnError); }),
264
+ upsert: (records_1, key_1, ...args_1) => __awaiter(this, [records_1, key_1, ...args_1], void 0, function* (records, key, options = o === null || o === void 0 ? void 0 : o.dml) { return processSaveResult(yield _conn.upsert(from, records, key, options), o === null || o === void 0 ? void 0 : o.breakOnError); }),
265
+ select: (select) => (Object.assign(Object.assign({}, _query(_conn, from, select)), { orderBy: (orderBy) => _query(_conn, from, select, undefined, orderBy), where: (where) => (Object.assign(Object.assign({}, _query(_conn, from, select, where)), { orderBy: (orderBy) => _query(_conn, from, select, where, orderBy) })), find: (id_1, ...args_1) => __awaiter(this, [id_1, ...args_1], void 0, function* (id, options = o === null || o === void 0 ? void 0 : o.query) {
266
+ const result = yield _queryOne(_conn, from, select, id, options);
246
267
  if (result.records.length) {
247
268
  return result.records[0];
248
269
  }
270
+ }), retrieve: (id_1, ...args_1) => __awaiter(this, [id_1, ...args_1], void 0, function* (id, options = o === null || o === void 0 ? void 0 : o.query) {
271
+ const result = yield _queryOne(_conn, from, select, id, options);
272
+ if (!result.records.length) {
273
+ throw new Error(`Record with id '${id}' is not found in '${from}'.`);
274
+ }
275
+ return result.records[0];
249
276
  }), selection: select }))
250
277
  });
251
278
  };
252
279
  }
253
- const getSfObjects = (cfg) => (conn) => {
254
- const _func = getSfObject(cfg);
280
+ const getSfObjects = (cfg) => (conn, options) => {
281
+ const _func = getSfObject(cfg, options);
255
282
  return Object.keys(cfg).reduce((p, n) => (Object.assign(Object.assign({}, p), { [n]: _func(n, conn) })), {});
256
283
  };
257
284
  exports.getSfObjects = getSfObjects;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sfobjects-basic-client",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "Basic Salesforce Client to use together with sfobjects-to-typescript lib",
5
5
  "license": "ISC",
6
6
  "author": "Murad Aliyev",
package/src/index.ts CHANGED
@@ -149,6 +149,16 @@ type MandatoryCreateProps<O> = {
149
149
  }[KeyOf<O>];
150
150
 
151
151
 
152
+ // Update
153
+
154
+ type UpdateableProps<O> = {
155
+ [K in keyof O]: NonNullable<O[K]> extends SfPrimitiveType ? (
156
+ IsMutable<{ [P in K]: O[P] }, { -readonly [P in K]: O[P] }, K>
157
+ ) : never
158
+
159
+ }[KeyOf<O>];
160
+
161
+
152
162
 
153
163
  // Select
154
164
 
@@ -169,11 +179,11 @@ export type SfCreate<O> = { [K in MandatoryCreateProps<O>]: O[K] } & { [K in Opt
169
179
 
170
180
  // Upsert
171
181
 
172
- export type SfUpsert<O, K extends MandatoryCreateProps<O>> = SfCreate<O> & { [P in K]: O[P] };
182
+ export type SfUpsert<O, K extends MandatoryCreateProps<O>/* external keys */> = SfCreate<O> & { [P in K]: O[P] };
173
183
 
174
184
  // Update
175
185
 
176
- export type SfUpdate<O> = { Id: string } & SfCreate<O>;
186
+ export type SfUpdate<O> = { Id: string } & { [K in UpdateableProps<O>]+?: O[K] };
177
187
 
178
188
 
179
189
  // Basic Client
@@ -218,6 +228,12 @@ export type SfDmlOptions = {
218
228
  };
219
229
  };
220
230
 
231
+ export type SfClientOptions = {
232
+ breakOnError?: boolean
233
+ query?: SfQueryOptions;
234
+ dml?: SfDmlOptions;
235
+ }
236
+
221
237
  export type SfQueryResult<R> = { records: R[] };
222
238
 
223
239
  export type SfSaveResult = {
@@ -258,6 +274,7 @@ export interface SfWhereActions<OI, N extends KeyOf<OI>, S extends SfRootSelect<
258
274
 
259
275
  export interface SfSelectAditionalActions<OI, N extends KeyOf<OI>, S extends SfRootSelect<OI, N>> {
260
276
  find: (id: string, options?: SfQueryOptions) => Promise<SfRootSelectProjection<OI, N, S> | undefined>;
277
+ retrieve: (id: string, options?: SfQueryOptions) => Promise<SfRootSelectProjection<OI, N, S>>;
261
278
  selection: S[];
262
279
  //S extends SfRootSelect<OI, N>
263
280
  }
@@ -271,6 +288,22 @@ export interface SfObjActions<OI, N extends KeyOf<OI>> {
271
288
  select: <S extends SfRootSelect<OI, N>>(select: S[]) => (SfSelectActions<OI, N, S> & SfWhereActions<OI, N, S> & SfSelectAditionalActions<OI, N, S>);
272
289
  }
273
290
 
291
+ export class SfBasicClientSaveError extends Error {
292
+ constructor(public errors: SfSaveError[]) {
293
+ super('Salesforce error(s): ' + errors.map(e => `[${e.errorCode}] ${e.message}, field(s): ${e.fields?.join(',')}`).join(';\r\n'))
294
+ this.name = 'SfBasicClientSaveError';
295
+ Object.setPrototypeOf(this, new.target.prototype);
296
+ }
297
+ }
298
+
299
+ export class SfBasicClientReadError extends Error {
300
+ constructor(public error: string) {
301
+ super('Salesforce error: ' + error)
302
+ this.name = 'SfBasicClientReadError';
303
+ Object.setPrototypeOf(this, new.target.prototype);
304
+ }
305
+ }
306
+
274
307
  // functions
275
308
 
276
309
  export function isPlainObject(value: unknown): value is Record<string, any> {
@@ -340,8 +373,6 @@ export function constructSoql<OI>(_cfg: SfObjCfgIndex<OI>) {
340
373
  'limit': limit?.toString()
341
374
  }
342
375
 
343
-
344
-
345
376
  return Object.keys(o).filter(k => !!o[k]).reduce((p, k) => ([p, k, o[k]].join(' ')), '');
346
377
  }
347
378
 
@@ -509,7 +540,22 @@ export function constructSoql<OI>(_cfg: SfObjCfgIndex<OI>) {
509
540
  return _constructFullQuery;
510
541
  }
511
542
 
512
- export function getSfObject<OI>(_cfg: SfObjCfgIndex<OI>) {
543
+ function processSaveResult(sr: SfSaveResult[], breakOnError?: boolean): SfSaveResult[] {
544
+
545
+ if (breakOnError) {
546
+
547
+ const _errors: SfSaveError[] = sr.filter(r => (r.success !== true)).map(r => r.errors).flat();
548
+
549
+ if (_errors.length) {
550
+ throw new SfBasicClientSaveError(_errors);
551
+ }
552
+ }
553
+
554
+ return sr;
555
+ }
556
+
557
+ export function getSfObject<OI>(_cfg: SfObjCfgIndex<OI>, o?: SfClientOptions) {
558
+
513
559
 
514
560
  function _query<S extends SfRootSelect<OI, N>, N extends KeyOf<OI>>(
515
561
  conn: ISfConnection,
@@ -524,11 +570,21 @@ export function getSfObject<OI>(_cfg: SfObjCfgIndex<OI>) {
524
570
 
525
571
  return ({
526
572
  soql,
527
- get: async (options?: SfQueryOptions) => await conn.query<SfRootSelectProjection<OI, N, S>>(soql(), options), // to get rid of promiselike,
573
+ get: async (options: SfQueryOptions | undefined = o?.query) => await conn.query<SfRootSelectProjection<OI, N, S>>(soql(), options), // to get rid of promiselike,
528
574
  limit: (limit: number) => _query(conn, from, select, where, orderBy, limit)
529
575
  });
530
576
  }
531
577
 
578
+ function _queryOne<S extends SfRootSelect<OI, N>, N extends KeyOf<OI>>(
579
+ conn: ISfConnection,
580
+ from: N,
581
+ select: S[],
582
+ id: string,
583
+ options: SfQueryOptions | undefined = o?.query
584
+ ) {
585
+ return _query(conn, from, select, `Id = '${id}'`).limit(1).get(options);
586
+ }
587
+
532
588
  return <N extends KeyOf<OI>>(from: N, _conn: ISfConnection): SfObjActions<OI, N> => {
533
589
 
534
590
  return ({
@@ -538,13 +594,13 @@ export function getSfObject<OI>(_cfg: SfObjCfgIndex<OI>) {
538
594
  return _query(_conn, from, select, where, orderBy, limit);
539
595
  },
540
596
 
541
- delete: (ids: string[], options?: SfDmlOptions) => _conn.delete(from, ids, options),
597
+ delete: async (ids: string[], options: SfDmlOptions | undefined = o?.dml) => processSaveResult(await _conn.delete(from, ids, options), o?.breakOnError),
542
598
 
543
- update: (records: SfUpdate<OI[N]>[], options?: SfDmlOptions) => _conn.update(from, records, options),
599
+ update: async (records: SfUpdate<OI[N]>[], options: SfDmlOptions | undefined = o?.dml) => processSaveResult(await _conn.update(from, records, options), o?.breakOnError),
544
600
 
545
- create: (records: SfCreate<OI[N]>[], options?: SfDmlOptions) => _conn.create(from, records, options),
601
+ create: async (records: SfCreate<OI[N]>[], options: SfDmlOptions | undefined = o?.dml) => processSaveResult(await _conn.create(from, records, options), o?.breakOnError),
546
602
 
547
- upsert: <K extends MandatoryCreateProps<OI[N]>>(records: SfUpsert<OI[N], K>[], key: K, options?: SfDmlOptions) => _conn.upsert(from, records, key, options),
603
+ upsert: async <K extends MandatoryCreateProps<OI[N]>>(records: SfUpsert<OI[N], K>[], key: K, options: SfDmlOptions | undefined = o?.dml) => processSaveResult(await _conn.upsert(from, records, key, options), o?.breakOnError),
548
604
 
549
605
  select: <S extends SfRootSelect<OI, N>>(select: S[]) => ({
550
606
 
@@ -560,17 +616,27 @@ export function getSfObject<OI>(_cfg: SfObjCfgIndex<OI>) {
560
616
 
561
617
  }),
562
618
 
563
- find: async (id: string, options?: SfQueryOptions) => {
619
+ find: async (id: string, options: SfQueryOptions | undefined = o?.query) => {
564
620
 
565
- const result = await _query(_conn, from, select, `Id = '${id}'`).limit(1).get(options);
621
+ const result = await _queryOne(_conn, from, select, id, options);
566
622
 
567
623
  if (result.records.length) {
568
624
  return result.records[0];
569
625
  }
570
626
  },
571
627
 
572
- selection: select
628
+ retrieve: async (id: string, options: SfQueryOptions | undefined = o?.query) => {
573
629
 
630
+ const result = await _queryOne(_conn, from, select, id, options);
631
+
632
+ if (!result.records.length) {
633
+ throw new SfBasicClientReadError(`Record with id '${id}' is not found in '${from}'.`);
634
+ }
635
+
636
+ return result.records[0];
637
+ },
638
+
639
+ selection: select
574
640
  })
575
641
  })
576
642
  };
@@ -578,8 +644,8 @@ export function getSfObject<OI>(_cfg: SfObjCfgIndex<OI>) {
578
644
  }
579
645
 
580
646
 
581
- export const getSfObjects = <OI>(cfg: SfObjCfgIndex<OI>) => (conn: ISfConnection) => {
582
- const _func = getSfObject<OI>(cfg);
647
+ export const getSfObjects = <OI>(cfg: SfObjCfgIndex<OI>) => (conn: ISfConnection, options?: SfClientOptions) => {
648
+ const _func = getSfObject<OI>(cfg, options);
583
649
  return (Object.keys(cfg) as KeyOf<OI>[]).reduce((p, n) => ({ ...p, [n]: _func(n, conn) }), {} as { [N in KeyOf<OI>]: SfObjActions<OI, N> });
584
650
  }
585
651