declastruct 1.5.2 → 1.6.0

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.
@@ -4,6 +4,8 @@ export { DeclastructChange, DeclastructChangeAction, } from '../../domain.object
4
4
  export { DeclastructDao } from '../../domain.objects/DeclastructDao';
5
5
  export { DeclastructPlan } from '../../domain.objects/DeclastructPlan';
6
6
  export { DeclastructProvider } from '../../domain.objects/DeclastructProvider';
7
+ export type { DeclastructDaoInput, DeclastructDaoWithRef, DeclastructDaoWoutRef, } from '../../domain.objects/genDeclastructDao';
8
+ export { genDeclastructDao } from '../../domain.objects/genDeclastructDao';
7
9
  export type { IsoTimestamp } from '../../domain.objects/IsoTimestamp';
8
10
  export { getRefByPrimary } from '../../domain.operations/ref/getRefByPrimary';
9
11
  export { getRefByUnique } from '../../domain.operations/ref/getRefByUnique';
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // domain objects
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.getRefByUnique = exports.getRefByPrimary = exports.DeclastructProvider = exports.DeclastructPlan = exports.DeclastructDao = exports.DeclastructChangeAction = exports.DeclastructChange = void 0;
4
+ exports.getRefByUnique = exports.getRefByPrimary = exports.genDeclastructDao = exports.DeclastructProvider = exports.DeclastructPlan = exports.DeclastructDao = exports.DeclastructChangeAction = exports.DeclastructChange = void 0;
5
5
  var DeclastructChange_1 = require("../../domain.objects/DeclastructChange");
6
6
  Object.defineProperty(exports, "DeclastructChange", { enumerable: true, get: function () { return DeclastructChange_1.DeclastructChange; } });
7
7
  Object.defineProperty(exports, "DeclastructChangeAction", { enumerable: true, get: function () { return DeclastructChange_1.DeclastructChangeAction; } });
@@ -11,6 +11,9 @@ var DeclastructPlan_1 = require("../../domain.objects/DeclastructPlan");
11
11
  Object.defineProperty(exports, "DeclastructPlan", { enumerable: true, get: function () { return DeclastructPlan_1.DeclastructPlan; } });
12
12
  var DeclastructProvider_1 = require("../../domain.objects/DeclastructProvider");
13
13
  Object.defineProperty(exports, "DeclastructProvider", { enumerable: true, get: function () { return DeclastructProvider_1.DeclastructProvider; } });
14
+ // factories
15
+ var genDeclastructDao_1 = require("../../domain.objects/genDeclastructDao");
16
+ Object.defineProperty(exports, "genDeclastructDao", { enumerable: true, get: function () { return genDeclastructDao_1.genDeclastructDao; } });
14
17
  // domain operations
15
18
  var getRefByPrimary_1 = require("../../domain.operations/ref/getRefByPrimary");
16
19
  Object.defineProperty(exports, "getRefByPrimary", { enumerable: true, get: function () { return getRefByPrimary_1.getRefByPrimary; } });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/contract/sdk/index.ts"],"names":[],"mappings":";AAAA,iBAAiB;;;AAIjB,4EAGgD;AAF9C,sHAAA,iBAAiB,OAAA;AACjB,4HAAA,uBAAuB,OAAA;AAEzB,sEAAqE;AAA5D,gHAAA,cAAc,OAAA;AACvB,wEAAuE;AAA9D,kHAAA,eAAe,OAAA;AACxB,gFAA+E;AAAtE,0HAAA,mBAAmB,OAAA;AAG5B,oBAAoB;AACpB,+EAA8E;AAArE,kHAAA,eAAe,OAAA;AACxB,6EAA4E;AAAnE,gHAAA,cAAc,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/contract/sdk/index.ts"],"names":[],"mappings":";AAAA,iBAAiB;;;AAIjB,4EAGgD;AAF9C,sHAAA,iBAAiB,OAAA;AACjB,4HAAA,uBAAuB,OAAA;AAEzB,sEAAqE;AAA5D,gHAAA,cAAc,OAAA;AACvB,wEAAuE;AAA9D,kHAAA,eAAe,OAAA;AACxB,gFAA+E;AAAtE,0HAAA,mBAAmB,OAAA;AAM5B,YAAY;AACZ,4EAA2E;AAAlE,sHAAA,iBAAiB,OAAA;AAE1B,oBAAoB;AACpB,+EAA8E;AAArE,kHAAA,eAAe,OAAA;AACxB,6EAA4E;AAAnE,gHAAA,cAAc,OAAA"}
@@ -56,14 +56,14 @@ export interface DeclastructDao<TResourceClass extends Refable<any, any, any>, T
56
56
  *
57
57
  * .note = set to null if resource lacks primary keys
58
58
  */
59
- byPrimary: null | ((input: Ref<TResourceClass>, context: TContext) => Promise<RefByPrimary<TResourceClass>>);
59
+ byPrimary: null | ((input: Ref<TResourceClass>, context: TContext) => Promise<RefByPrimary<TResourceClass> | null>);
60
60
  /**
61
61
  * .what = resolve any ref to RefByUnique
62
62
  * .why = enables getting unique key from any ref type
63
63
  *
64
64
  * .note = set to null if resource lacks primary keys
65
65
  */
66
- byUnique: null | ((input: Ref<TResourceClass>, context: TContext) => Promise<RefByUnique<TResourceClass>>);
66
+ byUnique: null | ((input: Ref<TResourceClass>, context: TContext) => Promise<RefByUnique<TResourceClass> | null>);
67
67
  };
68
68
  };
69
69
  /**
@@ -0,0 +1,71 @@
1
+ import { type Ref, type Refable, type RefByPrimary, type RefByUnique } from 'domain-objects';
2
+ import type { DeclastructDao } from './DeclastructDao';
3
+ /**
4
+ * .what = input type for genDeclastructDao without get.ref and get.one.byRef (auto-wired by factory)
5
+ * .why = derives from DeclastructDao to stay in sync, omits auto-wired methods
6
+ */
7
+ export type DeclastructDaoInput<TResourceClass extends Refable<any, any, any>, TContext> = Omit<DeclastructDao<TResourceClass, TContext>, 'get'> & {
8
+ get: {
9
+ one: Omit<DeclastructDao<TResourceClass, TContext>['get']['one'], 'byRef'>;
10
+ };
11
+ };
12
+ /**
13
+ * .what = input type for daos with byPrimary defined
14
+ * .why = enables overload to distinguish daos with primary key support
15
+ */
16
+ export type DeclastructDaoInputWithPrimary<TResourceClass extends Refable<any, any, any>, TContext> = Omit<DeclastructDaoInput<TResourceClass, TContext>, 'get'> & {
17
+ get: {
18
+ one: Omit<DeclastructDao<TResourceClass, TContext>['get']['one'], 'byPrimary' | 'byRef'> & {
19
+ byPrimary: NonNullable<DeclastructDao<TResourceClass, TContext>['get']['one']['byPrimary']>;
20
+ };
21
+ };
22
+ };
23
+ /**
24
+ * .what = input type for daos without byPrimary
25
+ * .why = enables overload to distinguish daos without primary key support
26
+ */
27
+ export type DeclastructDaoInputWoutPrimary<TResourceClass extends Refable<any, any, any>, TContext> = Omit<DeclastructDaoInput<TResourceClass, TContext>, 'get'> & {
28
+ get: {
29
+ one: Omit<DeclastructDao<TResourceClass, TContext>['get']['one'], 'byPrimary' | 'byRef'> & {
30
+ byPrimary: null;
31
+ };
32
+ };
33
+ };
34
+ /**
35
+ * .what = output type for daos with ref methods defined
36
+ * .why = enables type-safe access to ref resolution methods
37
+ */
38
+ export type DeclastructDaoWithRef<TResourceClass extends Refable<any, any, any>, TContext> = Omit<DeclastructDao<TResourceClass, TContext>, 'get'> & {
39
+ get: {
40
+ one: DeclastructDao<TResourceClass, TContext>['get']['one'];
41
+ ref: {
42
+ byPrimary: (input: Ref<TResourceClass>, context: TContext) => Promise<RefByPrimary<TResourceClass> | null>;
43
+ byUnique: (input: Ref<TResourceClass>, context: TContext) => Promise<RefByUnique<TResourceClass> | null>;
44
+ };
45
+ };
46
+ };
47
+ /**
48
+ * .what = output type for daos without ref methods
49
+ * .why = forces explicit null for ref methods when byPrimary is not supported
50
+ */
51
+ export type DeclastructDaoWoutRef<TResourceClass extends Refable<any, any, any>, TContext> = Omit<DeclastructDao<TResourceClass, TContext>, 'get'> & {
52
+ get: {
53
+ one: DeclastructDao<TResourceClass, TContext>['get']['one'];
54
+ ref: {
55
+ byPrimary: null;
56
+ byUnique: null;
57
+ };
58
+ };
59
+ };
60
+ /**
61
+ * .what = factory to create DeclastructDao with auto-wired ref methods
62
+ * .why = enforces that ref methods are defined iff byPrimary is defined
63
+ * .note = TContext must be explicitly provided as a generic parameter to avoid hazardous Record<string, any> inference
64
+ *
65
+ * @overload input with byPrimary defined → output with ref methods defined
66
+ */
67
+ export declare function genDeclastructDao<TResourceClass extends Refable<any, any, any>, TContext extends Record<string, any> = never>(input: DeclastructDaoInputWithPrimary<TResourceClass, TContext>): DeclastructDaoWithRef<TResourceClass, TContext>;
68
+ /**
69
+ * @overload input without byPrimary → output with ref methods null
70
+ */
71
+ export declare function genDeclastructDao<TResourceClass extends Refable<any, any, any>, TContext extends Record<string, any> = never>(input: DeclastructDaoInputWoutPrimary<TResourceClass, TContext>): DeclastructDaoWoutRef<TResourceClass, TContext>;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.genDeclastructDao = void 0;
4
+ const domain_objects_1 = require("domain-objects");
5
+ const helpful_errors_1 = require("helpful-errors");
6
+ const getRefByPrimary_1 = require("../domain.operations/ref/getRefByPrimary");
7
+ const getRefByUnique_1 = require("../domain.operations/ref/getRefByUnique");
8
+ /**
9
+ * .impl = creates dao with byRef and ref methods auto-wired based on byPrimary presence
10
+ */
11
+ function genDeclastructDao(input) {
12
+ const hasPrimary = input.get.one.byPrimary !== null;
13
+ // build byRef from byUnique + byPrimary
14
+ const byRef = async (ref, context) => {
15
+ if ((0, domain_objects_1.isRefByPrimary)({ of: input.dobj })(ref) && input.get.one.byPrimary)
16
+ return input.get.one.byPrimary(ref, context);
17
+ if ((0, domain_objects_1.isRefByUnique)({ of: input.dobj })(ref))
18
+ return input.get.one.byUnique(ref, context);
19
+ throw new helpful_errors_1.BadRequestError('get.one.byRef called with neither a RefByUnique nor RefByPrimary', { ref });
20
+ };
21
+ if (hasPrimary) {
22
+ // auto-wire ref methods using the helper functions
23
+ const dao = {
24
+ ...input,
25
+ get: {
26
+ one: {
27
+ ...input.get.one,
28
+ byRef,
29
+ },
30
+ ref: {
31
+ byPrimary: (ref, context) => (0, getRefByPrimary_1.getRefByPrimary)({ ref }, { dao, ...context }),
32
+ byUnique: (ref, context) => (0, getRefByUnique_1.getRefByUnique)({ ref }, { dao, ...context }),
33
+ },
34
+ },
35
+ };
36
+ return dao;
37
+ }
38
+ // no primary key support - ref methods are null
39
+ return {
40
+ ...input,
41
+ get: {
42
+ one: {
43
+ ...input.get.one,
44
+ byRef,
45
+ },
46
+ ref: {
47
+ byPrimary: null,
48
+ byUnique: null,
49
+ },
50
+ },
51
+ };
52
+ }
53
+ exports.genDeclastructDao = genDeclastructDao;
54
+ //# sourceMappingURL=genDeclastructDao.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"genDeclastructDao.js","sourceRoot":"","sources":["../../src/domain.objects/genDeclastructDao.ts"],"names":[],"mappings":";;;AAAA,mDAOwB;AACxB,mDAAiD;AAEjD,8EAA2E;AAC3E,4EAAyE;AAwHzE;;GAEG;AACH,SAAgB,iBAAiB,CAI/B,KAAoD;IAEpD,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,KAAK,IAAI,CAAC;IAEpD,wCAAwC;IACxC,MAAM,KAAK,GAAG,KAAK,EACjB,GAAwB,EACxB,OAAiB,EAC6B,EAAE;QAChD,IAAI,IAAA,+BAAc,EAAC,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS;YACpE,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC/C,IAAI,IAAA,8BAAa,EAAC,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC;YACxC,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,IAAI,gCAAe,CACvB,kEAAkE,EAClE,EAAE,GAAG,EAAE,CACR,CAAC;IACJ,CAAC,CAAC;IAEF,IAAI,UAAU,EAAE,CAAC;QACf,mDAAmD;QACnD,MAAM,GAAG,GAA6C;YACpD,GAAG,KAAK;YACR,GAAG,EAAE;gBACH,GAAG,EAAE;oBACH,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG;oBAChB,KAAK;iBACN;gBACD,GAAG,EAAE;oBACH,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAC1B,IAAA,iCAAe,EAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;oBAC/C,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CACzB,IAAA,+BAAc,EAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;iBAC/C;aACF;SACF,CAAC;QACF,OAAO,GAAG,CAAC;IACb,CAAC;IAED,gDAAgD;IAChD,OAAO;QACL,GAAG,KAAK;QACR,GAAG,EAAE;YACH,GAAG,EAAE;gBACH,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG;gBAChB,KAAK;aACN;YACD,GAAG,EAAE;gBACH,SAAS,EAAE,IAAI;gBACf,QAAQ,EAAE,IAAI;aACf;SACF;KACF,CAAC;AACJ,CAAC;AAzDD,8CAyDC"}
@@ -9,4 +9,4 @@ export declare const getRefByPrimary: <TResourceClass extends Refable<any, any,
9
9
  ref: Ref<TResourceClass>;
10
10
  }, context: {
11
11
  dao: DeclastructDao<TResourceClass, TContext>;
12
- } & TContext) => Promise<RefByPrimary<TResourceClass>>;
12
+ } & TContext) => Promise<RefByPrimary<TResourceClass> | null>;
@@ -16,11 +16,9 @@ const getRefByPrimary = async (input, context) => {
16
16
  if ((0, domain_objects_1.isRefByUnique)({ of: context.dao.dobj })(input.ref)) {
17
17
  // fetch the resource by unique key
18
18
  const resource = await context.dao.get.one.byUnique(input.ref, context);
19
- // throw if resource not found
19
+ // return null if resource not found (resource may not exist yet)
20
20
  if (!resource)
21
- throw new helpful_errors_1.BadRequestError('resource not found by unique ref', {
22
- ref: input.ref,
23
- });
21
+ return null;
24
22
  // extract primary key from the resource
25
23
  return (0, domain_objects_1.refByPrimary)(resource);
26
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"getRefByPrimary.js","sourceRoot":"","sources":["../../../src/domain.operations/ref/getRefByPrimary.ts"],"names":[],"mappings":";;;AAAA,mDAOwB;AACxB,mDAA0E;AAI1E;;;;GAIG;AACI,MAAM,eAAe,GAAG,KAAK,EAIlC,KAEC,EACD,OAEY,EAC2B,EAAE;IACzC,wDAAwD;IACxD,IAAI,IAAA,+BAAc,EAAC,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC;IAE1E,yDAAyD;IACzD,IAAI,IAAA,8BAAa,EAAC,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACvD,mCAAmC;QACnC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAExE,8BAA8B;QAC9B,IAAI,CAAC,QAAQ;YACX,MAAM,IAAI,gCAAe,CAAC,kCAAkC,EAAE;gBAC5D,GAAG,EAAE,KAAK,CAAC,GAAG;aACf,CAAC,CAAC;QAEL,wCAAwC;QACxC,OAAO,IAAA,6BAAY,EAAiB,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED,iCAAiC;IACjC,MAAM,IAAI,wCAAuB,CAAC,kBAAkB,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;AAC5E,CAAC,CAAC;AA/BW,QAAA,eAAe,mBA+B1B"}
1
+ {"version":3,"file":"getRefByPrimary.js","sourceRoot":"","sources":["../../../src/domain.operations/ref/getRefByPrimary.ts"],"names":[],"mappings":";;;AAAA,mDAOwB;AACxB,mDAAyD;AAIzD;;;;GAIG;AACI,MAAM,eAAe,GAAG,KAAK,EAIlC,KAEC,EACD,OAEY,EACkC,EAAE;IAChD,wDAAwD;IACxD,IAAI,IAAA,+BAAc,EAAC,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC;IAE1E,yDAAyD;IACzD,IAAI,IAAA,8BAAa,EAAC,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACvD,mCAAmC;QACnC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAExE,iEAAiE;QACjE,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAE3B,wCAAwC;QACxC,OAAO,IAAA,6BAAY,EAAiB,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED,iCAAiC;IACjC,MAAM,IAAI,wCAAuB,CAAC,kBAAkB,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;AAC5E,CAAC,CAAC;AA5BW,QAAA,eAAe,mBA4B1B"}
@@ -9,4 +9,4 @@ export declare const getRefByUnique: <TResourceClass extends Refable<any, any, a
9
9
  ref: Ref<TResourceClass>;
10
10
  }, context: {
11
11
  dao: DeclastructDao<TResourceClass, TContext>;
12
- } & TContext) => Promise<RefByUnique<TResourceClass>>;
12
+ } & TContext) => Promise<RefByUnique<TResourceClass> | null>;
@@ -19,11 +19,9 @@ const getRefByUnique = async (input, context) => {
19
19
  throw new helpful_errors_1.UnexpectedCodePathError('dao does not support byPrimary lookup', { ref: input.ref });
20
20
  // fetch the resource by primary key
21
21
  const resource = await context.dao.get.one.byPrimary(input.ref, context);
22
- // throw if resource not found
22
+ // return null if resource not found (resource may not exist yet)
23
23
  if (!resource)
24
- throw new helpful_errors_1.BadRequestError('resource not found by primary ref', {
25
- ref: input.ref,
26
- });
24
+ return null;
27
25
  // extract unique key from the resource
28
26
  return (0, domain_objects_1.refByUnique)(resource);
29
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"getRefByUnique.js","sourceRoot":"","sources":["../../../src/domain.operations/ref/getRefByUnique.ts"],"names":[],"mappings":";;;AAAA,mDAOwB;AACxB,mDAA0E;AAI1E;;;;GAIG;AACI,MAAM,cAAc,GAAG,KAAK,EAIjC,KAEC,EACD,OAEY,EAC0B,EAAE;IACxC,uDAAuD;IACvD,IAAI,IAAA,8BAAa,EAAC,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC;IAEzE,yDAAyD;IACzD,IAAI,IAAA,+BAAc,EAAC,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACxD,gCAAgC;QAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS;YAChC,MAAM,IAAI,wCAAuB,CAC/B,uCAAuC,EACvC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CACnB,CAAC;QAEJ,oCAAoC;QACpC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAEzE,8BAA8B;QAC9B,IAAI,CAAC,QAAQ;YACX,MAAM,IAAI,gCAAe,CAAC,mCAAmC,EAAE;gBAC7D,GAAG,EAAE,KAAK,CAAC,GAAG;aACf,CAAC,CAAC;QAEL,uCAAuC;QACvC,OAAO,IAAA,4BAAW,EAAiB,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,iCAAiC;IACjC,MAAM,IAAI,wCAAuB,CAAC,kBAAkB,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;AAC5E,CAAC,CAAC;AAtCW,QAAA,cAAc,kBAsCzB"}
1
+ {"version":3,"file":"getRefByUnique.js","sourceRoot":"","sources":["../../../src/domain.operations/ref/getRefByUnique.ts"],"names":[],"mappings":";;;AAAA,mDAOwB;AACxB,mDAAyD;AAIzD;;;;GAIG;AACI,MAAM,cAAc,GAAG,KAAK,EAIjC,KAEC,EACD,OAEY,EACiC,EAAE;IAC/C,uDAAuD;IACvD,IAAI,IAAA,8BAAa,EAAC,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC;IAEzE,yDAAyD;IACzD,IAAI,IAAA,+BAAc,EAAC,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACxD,gCAAgC;QAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS;YAChC,MAAM,IAAI,wCAAuB,CAC/B,uCAAuC,EACvC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CACnB,CAAC;QAEJ,oCAAoC;QACpC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAEzE,iEAAiE;QACjE,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAE3B,uCAAuC;QACvC,OAAO,IAAA,4BAAW,EAAiB,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,iCAAiC;IACjC,MAAM,IAAI,wCAAuB,CAAC,kBAAkB,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;AAC5E,CAAC,CAAC;AAnCW,QAAA,cAAc,kBAmCzB"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "declastruct",
3
3
  "author": "ehmpathy",
4
4
  "description": "Add declarative control to any resource constructs. Declare, plan, and apply within an observable pit-of-success.",
5
- "version": "1.5.2",
5
+ "version": "1.6.0",
6
6
  "repository": "ehmpathy/declastruct",
7
7
  "homepage": "https://github.com/ehmpathy/declastruct",
8
8
  "keywords": [
package/readme.md CHANGED
@@ -270,3 +270,145 @@ each `DeclastructChange` includes:
270
270
  ## inspiration
271
271
 
272
272
  inspired by Terraform's declarative approach, but designed to eliminate state file overhead, work with any resource construct, be reusable across both prod codepaths and cicd control, and leverage TypeScript's type system for safer declarative instructions.
273
+
274
+
275
+ # plugin
276
+
277
+ build your own provider to control any resource construct via declastruct.
278
+
279
+ ## 1. declare your resource
280
+
281
+ define your resource as a [`domain-object`](https://github.com/ehmpathy/domain-objects) with key attributes:
282
+
283
+ ```ts
284
+ import { DomainEntity } from 'domain-objects';
285
+
286
+ interface DeclaredStripeCustomer {
287
+ id?: string;
288
+ email: string;
289
+ name: string;
290
+ status?: string;
291
+ }
292
+ class DeclaredStripeCustomer
293
+ extends DomainEntity<DeclaredStripeCustomer>
294
+ implements DeclaredStripeCustomer
295
+ {
296
+ // primary key: the surrogate key identifier for this resource
297
+ public static primary = ['id'] as const;
298
+
299
+ // unique key: the natural key identifier for this resource (i.e., the non-primary unique key)
300
+ public static unique = ['email'] as const;
301
+
302
+ // metadata keys: readonly persistance-specific fields - excluded from change detection
303
+ // if unspecified, the defaults of 'id', 'uuid', 'createdAt', 'updatedAt', 'effectiveAt' will be assumed
304
+ public static metadata = ['id'] as const;
305
+
306
+ // readonly keys: readonly domain-intrinsic fields - excluded from change detection
307
+ // note: all metadata is implicitly readonly, so you only need to specify non-metadata readonly keys here
308
+ public static readonly = ['status'] as const;
309
+ }
310
+ ```
311
+
312
+ key attributes to consider:
313
+ - **primary key** (`static primary`): surrogate identifier for efficient lookups after creation
314
+ - **unique key** (`static unique`): natural key that uniquely identifies the resource, used for idempotent operations
315
+ - **metadata keys** (`static metadata`): readonly persistence-layer fields that describe *how* the object is stored (e.g., `uuid`, `createdAt`). note, metadata is a specific subset of readonly
316
+ - **readonly keys** (`static readonly`): readonly domain-layer fields that describe *what* the object is (e.g., `status`). note, you only need to declare the readonly attributes that are not already flagged as metadata here
317
+
318
+ ## 2. generate your dao
319
+
320
+ use `genDeclastructDao` to create a type-safe DAO with auto-wired ref resolution:
321
+
322
+ ```ts
323
+ import { genDeclastructDao } from 'declastruct';
324
+ import Stripe from 'stripe';
325
+
326
+ // define the context type for your provider
327
+ interface StripeContext {
328
+ stripe: Stripe;
329
+ }
330
+
331
+ const daoStripeCustomer = genDeclastructDao<
332
+ typeof DeclaredStripeCustomer,
333
+ StripeContext
334
+ >({
335
+ dobj: DeclaredStripeCustomer,
336
+ get: {
337
+ one: {
338
+ byUnique: async ({ email }, context) => {
339
+ // lookup by natural key (email)
340
+ const customer = await context.stripe.customers.list({ email });
341
+ return customer.data[0] ? toResource(customer.data[0]) : null;
342
+ },
343
+ byPrimary: async ({ id }, context) => {
344
+ // lookup by stripe-assigned id
345
+ const customer = await context.stripe.customers.retrieve(id);
346
+ return customer ? toResource(customer) : null;
347
+ },
348
+ },
349
+ },
350
+ set: {
351
+ finsert: async (resource, context) => {
352
+ // find-or-insert: idempotent create
353
+ const foundBefore = await daoStripeCustomer.get.one.byUnique(
354
+ { email: resource.email },
355
+ context,
356
+ );
357
+ if (foundBefore) return foundBefore;
358
+
359
+ const created = await context.stripe.customers.create({
360
+ email: resource.email,
361
+ name: resource.name,
362
+ });
363
+ return toResource(created);
364
+ },
365
+ upsert: async (resource, context) => {
366
+ // update-or-insert: idempotent update
367
+ const foundBefore = await daoStripeCustomer.get.one.byUnique(
368
+ { email: resource.email },
369
+ context,
370
+ );
371
+ if (foundBefore) {
372
+ const updated = await context.stripe.customers.update(foundBefore.id, {
373
+ name: resource.name,
374
+ });
375
+ return toResource(updated);
376
+ }
377
+ return daoStripeCustomer.set.finsert(resource, context);
378
+ },
379
+ delete: async (ref, context) => {
380
+ const foundBefore = await daoStripeCustomer.get.one.byRef(ref, context);
381
+ if (foundBefore) await context.stripe.customers.del(foundBefore.id);
382
+ },
383
+ },
384
+ });
385
+ ```
386
+
387
+ the factory automatically:
388
+ - **builds get.one.byRef**: `get.one.byRef` is built for you, based on `get.one.byUnique` and `get.one.byPrimary`
389
+ - **builds get.ref.byPrimary,.byUnique**: if `byPrimary` is defined, `get.ref.byPrimary` and `get.ref.byUnique` are built for you, based on `get.one.byUnique` and `get.one.byPrimary`
390
+ - **enforces type safety**: if `byPrimary` is null, `get.ref.*` are typed as null (prevents accidental calls)
391
+
392
+ ## 3. create your provider
393
+
394
+ bundle your DAOs into a provider:
395
+
396
+ ```ts
397
+ import { DeclastructProvider } from 'declastruct';
398
+
399
+ export const stripeProvider = new DeclastructProvider({
400
+ name: 'stripe',
401
+ daos: {
402
+ DeclaredStripeCustomer: daoStripeCustomer,
403
+ },
404
+ context: {
405
+ stripe, // stripe client instance
406
+ },
407
+ hooks: {
408
+ beforeAll: async () => { /* setup */ },
409
+ afterAll: async () => { /* cleanup */ },
410
+ },
411
+ });
412
+ ```
413
+
414
+ now users can declare stripe customers and use `plan` + `apply` to control them declaratively.