sqlstack 1.0.5 → 1.0.6

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.
@@ -1,6 +1,6 @@
1
1
  type KV = Record<string, any>;
2
2
  export type NodeSpec = {
3
- id: string;
3
+ id?: string;
4
4
  name?: string;
5
5
  [collectionKey: string]: any;
6
6
  };
@@ -1 +1 @@
1
- {"version":3,"file":"dto.d.ts","sourceRoot":"","sources":["../../src/utils/dto.ts"],"names":[],"mappings":"AAAA,KAAK,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAE9B,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,CAAC,aAAa,EAAE,MAAM,GAAG,GAAG,CAAC;CAC9B,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,iGAAiG;IACjG,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AA6CF;;GAEG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAE,UAAe,IA4D7B,MAAM,EAAE,EAAE,sBAerC"}
1
+ {"version":3,"file":"dto.d.ts","sourceRoot":"","sources":["../../src/utils/dto.ts"],"names":[],"mappings":"AAAA,KAAK,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAE9B,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,CAAC,aAAa,EAAE,MAAM,GAAG,GAAG,CAAC;CAC9B,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,iGAAiG;IACjG,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AA6CF;;GAEG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAE,UAAe,IAkE7B,MAAM,EAAE,EAAE,sBAerC"}
package/dist/utils/dto.js CHANGED
@@ -19,7 +19,7 @@ function childCollections(spec) {
19
19
  if (key === 'id' || key === 'name')
20
20
  continue;
21
21
  const val = spec[key];
22
- if (val && typeof val === 'object' && 'id' in val)
22
+ if (val && typeof val === 'object' && !Array.isArray(val))
23
23
  out.push([key, val]);
24
24
  }
25
25
  return out;
@@ -58,50 +58,56 @@ function DTO(spec, opts = {}) {
58
58
  return cached;
59
59
  const out = [];
60
60
  for (const [k, v] of Object.entries(levelSpec)) {
61
- if (k === 'id' || k === 'name')
62
- continue;
63
61
  if (typeof v === 'string')
64
62
  out.push([k, v]);
65
63
  }
64
+ // Ensure stable ordering so identity is independent of spec key order
65
+ out.sort((a, b) => a[0].localeCompare(b[0]));
66
66
  mappingsCache.set(levelSpec, out);
67
67
  return out;
68
68
  }
69
+ function computeKey(levelSpec, row) {
70
+ const mappings = getMappings(levelSpec);
71
+ if (mappings.length === 0)
72
+ return undefined;
73
+ const pairs = mappings.map(([, source]) => row[source]);
74
+ // If all mapping values are null/undefined, skip
75
+ if (pairs.every((v) => v === null || v === undefined))
76
+ return undefined;
77
+ // Stable composite key: include source keys with values
78
+ const composite = mappings.map(([, source], i) => [source, pairs[i]]);
79
+ return JSON.stringify(composite);
80
+ }
69
81
  function upsertAtLevel(rowsIndex, rowsOut, levelSpec, row) {
70
- const nodeId = row[levelSpec.id];
71
- if (nodeId == null)
82
+ const nodeKey = computeKey(levelSpec, row);
83
+ if (nodeKey == null)
72
84
  return null;
73
- let node = rowsIndex.get(nodeId);
85
+ let node = rowsIndex.get(nodeKey);
74
86
  if (!node) {
75
- node = {
76
- id: nodeId,
77
- ...(levelSpec.name ? { name: row[levelSpec.name] } : {}),
78
- };
87
+ node = {};
79
88
  for (const [target, source] of getMappings(levelSpec)) {
80
89
  if (source in row)
81
90
  setDeep(node, target, row[source]);
82
91
  }
83
- rowsIndex.set(nodeId, node);
92
+ rowsIndex.set(nodeKey, node);
84
93
  rowsOut.push(node);
85
94
  }
86
95
  return node;
87
96
  }
88
97
  function descend(parent, levelSpec, row) {
89
98
  for (const [collectionKey, childSpec] of childCollections(levelSpec)) {
90
- const childId = row[childSpec.id];
91
- if (childId == null)
99
+ const childKey = computeKey(childSpec, row);
100
+ if (childKey == null)
92
101
  continue; // skip this branch for this row
93
102
  const { arr, index } = ensureChildInfra(parent, collectionKey);
94
- let child = index.get(childId);
103
+ let child = index.get(childKey);
95
104
  if (!child) {
96
- child = {
97
- id: childId,
98
- ...(childSpec.name ? { name: row[childSpec.name] } : {}),
99
- };
105
+ child = {};
100
106
  for (const [target, source] of getMappings(childSpec)) {
101
107
  if (source in row)
102
108
  setDeep(child, target, row[source]);
103
109
  }
104
- index.set(childId, child);
110
+ index.set(childKey, child);
105
111
  arr.push(child);
106
112
  }
107
113
  // Recurse further for this child (it may host its own collections)
@@ -1 +1 @@
1
- {"version":3,"file":"dto.js","sourceRoot":"","sources":["../../src/utils/dto.ts"],"names":[],"mappings":"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","sourcesContent":["type KV = Record<string, any>;\n\nexport type NodeSpec = {\n id: string;\n name?: string;\n // nested collections: { [collectionKey]: NodeSpec }\n [collectionKey: string]: any;\n};\n\ntype DTOOptions = {\n /** If true, return a single root (or null). If false, return an array of roots. Default: true */\n single?: boolean;\n};\n\nconst CHILD_INDEX = Symbol('childIndex');\n\nfunction setDeep(obj: KV, path: string, value: any) {\n const parts = path.split('.');\n let cur: any = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const k = parts[i]!;\n if (cur[k] == null || typeof cur[k] !== 'object') cur[k] = {};\n cur = cur[k];\n }\n cur[parts[parts.length - 1]!] = value;\n}\n\nfunction childCollections(spec: NodeSpec): Array<[string, NodeSpec]> {\n const out: Array<[string, NodeSpec]> = [];\n for (const key of Object.keys(spec)) {\n if (key === 'id' || key === 'name') continue;\n const val = (spec as any)[key];\n if (val && typeof val === 'object' && 'id' in val) out.push([key, val as NodeSpec]);\n }\n return out;\n}\n\nfunction ensureChildInfra(node: KV, collectionKey: string) {\n if (!node[collectionKey]) node[collectionKey] = [];\n if (!(node as any)[CHILD_INDEX]) (node as any)[CHILD_INDEX] = {} as Record<string, Map<any, KV>>;\n const idxBag = (node as any)[CHILD_INDEX] as Record<string, Map<any, KV>>;\n if (!idxBag[collectionKey]) idxBag[collectionKey] = new Map<any, KV>();\n return { arr: node[collectionKey] as KV[], index: idxBag[collectionKey] as Map<any, KV> };\n}\n\nfunction stripMeta(node: KV) {\n if (node && typeof node === 'object') {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete (node as any)[CHILD_INDEX];\n for (const k of Object.keys(node)) {\n const v = node[k];\n if (Array.isArray(v)) v.forEach(stripMeta);\n }\n }\n return node;\n}\n\n/**\n * Build a rows→tree transformer from a nested spec.\n */\nexport function DTO(spec: NodeSpec, opts: DTOOptions = {}) {\n const single = opts.single ?? false;\n type IndexMap = Map<any, KV>;\n const mappingsCache = new WeakMap<NodeSpec, Array<[string, string]>>();\n\n function getMappings(levelSpec: NodeSpec): Array<[string, string]> {\n const cached = mappingsCache.get(levelSpec);\n if (cached) return cached;\n const out: Array<[string, string]> = [];\n for (const [k, v] of Object.entries(levelSpec)) {\n if (k === 'id' || k === 'name') continue;\n if (typeof v === 'string') out.push([k, v]);\n }\n mappingsCache.set(levelSpec, out);\n return out;\n }\n\n function upsertAtLevel(rowsIndex: IndexMap, rowsOut: KV[], levelSpec: NodeSpec, row: KV) {\n const nodeId = row[levelSpec.id];\n if (nodeId == null) return null;\n\n let node = rowsIndex.get(nodeId);\n if (!node) {\n node = {\n id: nodeId,\n ...(levelSpec.name ? { name: row[levelSpec.name] } : {}),\n };\n for (const [target, source] of getMappings(levelSpec)) {\n if (source in row) setDeep(node, target, (row as any)[source]);\n }\n rowsIndex.set(nodeId, node);\n rowsOut.push(node);\n }\n return node;\n }\n\n function descend(parent: KV, levelSpec: NodeSpec, row: KV) {\n for (const [collectionKey, childSpec] of childCollections(levelSpec)) {\n const childId = row[childSpec.id];\n if (childId == null) continue; // skip this branch for this row\n\n const { arr, index } = ensureChildInfra(parent, collectionKey);\n let child = index.get(childId);\n if (!child) {\n child = {\n id: childId,\n ...(childSpec.name ? { name: row[childSpec.name] } : {}),\n };\n for (const [target, source] of getMappings(childSpec)) {\n if (source in row) setDeep(child, target, (row as any)[source]);\n }\n index.set(childId, child);\n arr.push(child);\n }\n\n // Recurse further for this child (it may host its own collections)\n descend(child, childSpec, row);\n }\n }\n\n return function transform(rows: KV[]) {\n if (!rows || rows.length === 0) return single ? null : [];\n\n const roots: KV[] = [];\n const rootIndex: IndexMap = new Map();\n\n for (const row of rows) {\n const root = upsertAtLevel(rootIndex, roots, spec, row);\n if (!root) continue;\n descend(root, spec, row);\n }\n\n roots.forEach(stripMeta);\n return single ? roots[0] ?? null : roots;\n };\n}\n"]}
1
+ {"version":3,"file":"dto.js","sourceRoot":"","sources":["../../src/utils/dto.ts"],"names":[],"mappings":"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","sourcesContent":["type KV = Record<string, any>;\n\nexport type NodeSpec = {\n id?: string;\n name?: string;\n // nested collections: { [collectionKey]: NodeSpec }\n [collectionKey: string]: any;\n};\n\ntype DTOOptions = {\n /** If true, return a single root (or null). If false, return an array of roots. Default: true */\n single?: boolean;\n};\n\nconst CHILD_INDEX = Symbol('childIndex');\n\nfunction setDeep(obj: KV, path: string, value: any) {\n const parts = path.split('.');\n let cur: any = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const k = parts[i]!;\n if (cur[k] == null || typeof cur[k] !== 'object') cur[k] = {};\n cur = cur[k];\n }\n cur[parts[parts.length - 1]!] = value;\n}\n\nfunction childCollections(spec: NodeSpec): Array<[string, NodeSpec]> {\n const out: Array<[string, NodeSpec]> = [];\n for (const key of Object.keys(spec)) {\n if (key === 'id' || key === 'name') continue;\n const val = (spec as any)[key];\n if (val && typeof val === 'object' && !Array.isArray(val)) out.push([key, val as NodeSpec]);\n }\n return out;\n}\n\nfunction ensureChildInfra(node: KV, collectionKey: string) {\n if (!node[collectionKey]) node[collectionKey] = [];\n if (!(node as any)[CHILD_INDEX]) (node as any)[CHILD_INDEX] = {} as Record<string, Map<any, KV>>;\n const idxBag = (node as any)[CHILD_INDEX] as Record<string, Map<any, KV>>;\n if (!idxBag[collectionKey]) idxBag[collectionKey] = new Map<any, KV>();\n return { arr: node[collectionKey] as KV[], index: idxBag[collectionKey] as Map<any, KV> };\n}\n\nfunction stripMeta(node: KV) {\n if (node && typeof node === 'object') {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete (node as any)[CHILD_INDEX];\n for (const k of Object.keys(node)) {\n const v = node[k];\n if (Array.isArray(v)) v.forEach(stripMeta);\n }\n }\n return node;\n}\n\n/**\n * Build a rows→tree transformer from a nested spec.\n */\nexport function DTO(spec: NodeSpec, opts: DTOOptions = {}) {\n const single = opts.single ?? false;\n type IndexMap = Map<any, KV>;\n const mappingsCache = new WeakMap<NodeSpec, Array<[string, string]>>();\n\n function getMappings(levelSpec: NodeSpec): Array<[string, string]> {\n const cached = mappingsCache.get(levelSpec);\n if (cached) return cached;\n const out: Array<[string, string]> = [];\n for (const [k, v] of Object.entries(levelSpec)) {\n if (typeof v === 'string') out.push([k, v]);\n }\n // Ensure stable ordering so identity is independent of spec key order\n out.sort((a, b) => (a[0] as string).localeCompare(b[0] as string));\n mappingsCache.set(levelSpec, out);\n return out;\n }\n\n function computeKey(levelSpec: NodeSpec, row: KV): any {\n const mappings = getMappings(levelSpec);\n if (mappings.length === 0) return undefined;\n const pairs = mappings.map(([, source]) => row[source]);\n // If all mapping values are null/undefined, skip\n if (pairs.every((v) => v === null || v === undefined)) return undefined;\n // Stable composite key: include source keys with values\n const composite = mappings.map(([, source], i) => [source, pairs[i]] as [string, any]);\n return JSON.stringify(composite);\n }\n\n function upsertAtLevel(rowsIndex: IndexMap, rowsOut: KV[], levelSpec: NodeSpec, row: KV) {\n const nodeKey = computeKey(levelSpec, row);\n if (nodeKey == null) return null;\n\n let node = rowsIndex.get(nodeKey);\n if (!node) {\n node = {};\n for (const [target, source] of getMappings(levelSpec)) {\n if (source in row) setDeep(node, target, (row as any)[source]);\n }\n rowsIndex.set(nodeKey, node);\n rowsOut.push(node);\n }\n return node;\n }\n\n function descend(parent: KV, levelSpec: NodeSpec, row: KV) {\n for (const [collectionKey, childSpec] of childCollections(levelSpec)) {\n const childKey = computeKey(childSpec, row);\n if (childKey == null) continue; // skip this branch for this row\n\n const { arr, index } = ensureChildInfra(parent, collectionKey);\n let child = index.get(childKey);\n if (!child) {\n child = {};\n for (const [target, source] of getMappings(childSpec)) {\n if (source in row) setDeep(child, target, (row as any)[source]);\n }\n index.set(childKey, child);\n arr.push(child);\n }\n\n // Recurse further for this child (it may host its own collections)\n descend(child, childSpec, row);\n }\n }\n\n return function transform(rows: KV[]) {\n if (!rows || rows.length === 0) return single ? null : [];\n\n const roots: KV[] = [];\n const rootIndex: IndexMap = new Map();\n\n for (const row of rows) {\n const root = upsertAtLevel(rootIndex, roots, spec, row);\n if (!root) continue;\n descend(root, spec, row);\n }\n\n roots.forEach(stripMeta);\n return single ? roots[0] ?? null : roots;\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sqlstack",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "",