sqlstack 3.0.0 → 3.1.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.
Files changed (58) hide show
  1. package/dist/cjs/decorators/query.d.ts.map +1 -1
  2. package/dist/cjs/decorators/query.js +258 -240
  3. package/dist/cjs/decorators/query.js.map +1 -1
  4. package/dist/cjs/index.d.ts +1 -0
  5. package/dist/cjs/index.d.ts.map +1 -1
  6. package/dist/cjs/index.js +4 -1
  7. package/dist/cjs/index.js.map +1 -1
  8. package/dist/cjs/run.d.ts +29 -0
  9. package/dist/cjs/run.d.ts.map +1 -0
  10. package/dist/cjs/run.js +38 -0
  11. package/dist/cjs/run.js.map +1 -0
  12. package/dist/cjs/testing/index.d.ts +4 -0
  13. package/dist/cjs/testing/index.d.ts.map +1 -1
  14. package/dist/cjs/testing/index.js +5 -1
  15. package/dist/cjs/testing/index.js.map +1 -1
  16. package/dist/cjs/testing/schema/ddl.d.ts +1 -10
  17. package/dist/cjs/testing/schema/ddl.d.ts.map +1 -1
  18. package/dist/cjs/testing/schema/ddl.js +29 -13
  19. package/dist/cjs/testing/schema/ddl.js.map +1 -1
  20. package/dist/cjs/testing/schema/normalize.js +3 -3
  21. package/dist/cjs/testing/schema/normalize.js.map +1 -1
  22. package/dist/cjs/testing/schema/types.d.ts +1 -20
  23. package/dist/cjs/testing/schema/types.d.ts.map +1 -1
  24. package/dist/cjs/testing/schema/types.js +0 -4
  25. package/dist/cjs/testing/schema/types.js.map +1 -1
  26. package/dist/cjs/testing/sqlite/builder.d.ts +24 -0
  27. package/dist/cjs/testing/sqlite/builder.d.ts.map +1 -0
  28. package/dist/cjs/testing/sqlite/builder.js +134 -0
  29. package/dist/cjs/testing/sqlite/builder.js.map +1 -0
  30. package/dist/cjs/testing/sqlite/database.d.ts +18 -0
  31. package/dist/cjs/testing/sqlite/database.d.ts.map +1 -0
  32. package/dist/cjs/testing/sqlite/database.js +123 -0
  33. package/dist/cjs/testing/sqlite/database.js.map +1 -0
  34. package/dist/cjs/testing/sqlite/loadData.d.ts +7 -0
  35. package/dist/cjs/testing/sqlite/loadData.d.ts.map +1 -0
  36. package/dist/cjs/testing/sqlite/loadData.js +55 -0
  37. package/dist/cjs/testing/sqlite/loadData.js.map +1 -0
  38. package/dist/esm/decorators/query.js +258 -240
  39. package/dist/esm/decorators/query.js.map +1 -1
  40. package/dist/esm/index.js +2 -0
  41. package/dist/esm/index.js.map +1 -1
  42. package/dist/esm/run.js +34 -0
  43. package/dist/esm/run.js.map +1 -0
  44. package/dist/esm/testing/index.js +2 -0
  45. package/dist/esm/testing/index.js.map +1 -1
  46. package/dist/esm/testing/schema/ddl.js +29 -13
  47. package/dist/esm/testing/schema/ddl.js.map +1 -1
  48. package/dist/esm/testing/schema/normalize.js +3 -3
  49. package/dist/esm/testing/schema/normalize.js.map +1 -1
  50. package/dist/esm/testing/schema/types.js +0 -4
  51. package/dist/esm/testing/schema/types.js.map +1 -1
  52. package/dist/esm/testing/sqlite/builder.js +98 -0
  53. package/dist/esm/testing/sqlite/builder.js.map +1 -0
  54. package/dist/esm/testing/sqlite/database.js +85 -0
  55. package/dist/esm/testing/sqlite/database.js.map +1 -0
  56. package/dist/esm/testing/sqlite/loadData.js +48 -0
  57. package/dist/esm/testing/sqlite/loadData.js.map +1 -0
  58. package/package.json +4 -3
@@ -1 +1 @@
1
- {"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/decorators/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/G,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AACrF,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAQrC,MAAM,UAAU,KAAK,CAAC,GAA2B;IAC/C,OAAO,UAAU,OAAY,EAAE,IAAqB,EAAE,IAAwB;QAC5E,MAAM,OAAO,GAA6B,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC;QACpF,MAAM,OAAO,GAAuB,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9E,6CAA6C;QAC7C,IAAI,OAAO,EAAE,EAAE,EAAE,CAAC;YAChB,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,+BAA+B;QAC/B,IAAI,OAAO,EAAE,GAAG,EAAE,CAAC;YACjB,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACnF,CAAC;aAAM,CAAC;YACN,wEAAwE;YACxE,qEAAqE;YACrE,wEAAwE;YACxE,sCAAsC;YACtC,MAAM,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;YAC5C,IAAI,OAAO,EAAE,CAAC;gBACZ,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;YACtE,CAAC;QACH,CAAC;QAED,qEAAqE;QACrE,uEAAuE;QACvE,gDAAgD;QAChD,MAAM,cAAc,GAAG;YACrB,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,IAAI,aAAa;YACtD,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC;YACxB,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG;SACvB,CAAC;QACF,wBAAwB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;QAClD,uBAAuB,CAAC,cAAc,CAAC,CAAC;QAExC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC;QAC5B,IAAI,CAAC,KAAK,GAAG,KAAK,WAAW,GAAG,QAAe;YAC7C,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC3C,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;YAEzC,4EAA4E;YAC5E,IAAI,cAAuB,CAAC;YAC5B,IAAI,CAAC;gBACH,cAAc,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACxD,CAAC;YAAC,MAAM,CAAC;gBACP,uGAAuG;gBACvG,cAAc,GAAG,SAAS,CAAC;YAC7B,CAAC;YACD,IAAI,cAAc,YAAY,WAAW,EAAE,CAAC;gBAC1C,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,KAAK,EAAE,CAAC;gBAEzD,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,IAAI,OAAO,EAAE,EAAE,IAAI,WAAW,EAAE,EAAE,CAAC;gBAC3D,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;gBACjD,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;gBAEpB,IAAI,GAAG,CAAC;gBACR,IAAI,CAAC;oBACH,MAAM,EAAE,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;oBACvC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBACjF,CAAC;gBAAC,OAAO,OAAY,EAAE,CAAC;oBACtB,MAAM,IAAI,aAAa,CACrB,OAAO,EAAE,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,EACnC,QAAQ,EACR,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAC/C,CAAC;gBACJ,CAAC;gBAED,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;oBACvB,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;oBAC7C,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;oBAEzE,IAAI,MAAM,CAAC,cAAc,IAAI,CAAC,oBAAoB,EAAE,EAAE,CAAC;wBACrD,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;4BAC/B,KAAK,MAAM,GAAG,IAAI,WAAW;gCAAE,cAAc,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;wBAC5E,CAAC;6BAAM,IAAI,WAAW,KAAK,IAAI,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;4BAC7D,cAAc,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;wBACrD,CAAC;oBACH,CAAC;oBACD,OAAO,WAAW,CAAC;gBACrB,CAAC;gBACD,OAAO,GAAG,CAAC;YACb,CAAC;YAED,gCAAgC;YAChC,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,6BAA6B;YAE9F,4DAA4D;YAC5D,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,IAAI,OAAO,EAAE,EAAE,IAAI,WAAW,EAAE,EAAE,CAAC;YAC3D,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC3E,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC,OAAO,IAAI,QAAQ,CAAC;YAE3D,oEAAoE;YACpE,4EAA4E;YAC5E,MAAM,GAAG,GAAG,MAAM,EAAE,MAAM,EAAE,IAAI,KAAK,QAAQ;gBAC3C,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG;gBACnB,CAAC,CAAC,cAAc;oBACd,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC;wBACrB,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,IAAI,aAAa;wBACnD,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC;wBACxB,OAAO;wBACP,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;qBAC3E,CAAC;oBACJ,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,KAAK,IAAI;wBAC7B,CAAC,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,GAAG;wBACpE,CAAC,CAAC,yBAAyB,EAAE,EAAE,OAAO,CAAC;4BACnC,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,IAAI,aAAa;4BACnD,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC;4BACxB,OAAO;yBACR,CAAC,CAAC;YACX,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,aAAa,CAAC,qCAAqC,MAAM,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;YACpI,CAAC;YAED,uBAAuB;YACvB,yDAAyD;YACzD,IAAI,UAAU,GAAG,GAAG,CAAC;YACrB,MAAM,aAAa,GAAG,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAEzD,0BAA0B;YAC1B,IAAI,IAAS,CAAC;YACd,IAAI,aAAa,EAAE,CAAC;gBAClB,IAAI,GAAG,QAAQ,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACN,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAChE,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC;YACzD,CAAC;YAED,iFAAiF;YACjF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;YAC5B,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;gBACnC,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE9B,0FAA0F;gBAC1F,MAAM,cAAc,GAAG,CAAC,GAAQ,EAAsB,EAAE;oBACtD,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,OAAQ,GAAW,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;wBACtG,MAAM,CAAC,GAAI,GAAW,CAAC,IAAI,CAAC;wBAC5B,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,QAAQ,CAAC,CAAC,CAAC;4BAAE,OAAO,CAAC,CAAC;oBACrD,CAAC;oBACD,OAAO,SAAS,CAAC;gBACnB,CAAC,CAAC;gBAEF,IAAI,OAA2B,CAAC;gBAChC,IAAI,aAAa,EAAE,CAAC;oBAClB,8DAA8D;oBAC9D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACxB,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;wBAC3C,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;oBACjC,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,wEAAwE;oBACxE,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACxB,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;wBAC3C,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;oBACjC,CAAC;oBACD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;wBAC1B,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;oBACjC,CAAC;gBACH,CAAC;gBAED,MAAM,aAAa,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;gBACnE,MAAM,MAAM,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;gBAC7C,MAAM,KAAK,GAAG,IAAI,CAAC;gBAEnB,IAAI,aAAa,EAAE,CAAC;oBAClB,mFAAmF;oBACnF,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,kCAAkC;oBACrE,IAAI,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC;oBAC9B,MAAM,SAAS,GAAc,EAAE,CAAC;oBAEhC,MAAM,OAAO,GAAG,CAAC,OAAe,EAAE,EAAE;wBAClC,MAAM,GAAG,GAAa,EAAE,CAAC;wBACzB,IAAI,CAAC,GAAG,CAAC,CAAC;wBACV,IAAI,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,CAAC;wBAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;wBAC3B,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;4BACf,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;4BACtB,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;4BAC/C,IAAI,IAAI,EAAE,CAAC;gCAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gCAAC,IAAI,EAAE,KAAK,IAAI;oCAAE,IAAI,GAAG,KAAK,CAAC;gCAAC,CAAC,EAAE,CAAC;gCAAC,SAAS;4BAAC,CAAC;4BACzE,IAAI,IAAI,EAAE,CAAC;gCAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gCAAC,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oCAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oCAAC,CAAC,EAAE,CAAC;oCAAC,IAAI,GAAG,KAAK,CAAC;gCAAC,CAAC;gCAAC,CAAC,EAAE,CAAC;gCAAC,SAAS;4BAAC,CAAC;4BACjH,IAAI,IAAI,EAAE,CAAC;gCACT,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gCACb,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oCAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oCAAC,CAAC,IAAI,CAAC,CAAC;oCAAC,SAAS;gCAAC,CAAC;gCACrE,IAAI,EAAE,KAAK,GAAG;oCAAE,IAAI,GAAG,KAAK,CAAC;gCAC7B,CAAC,EAAE,CAAC;gCACJ,SAAS;4BACX,CAAC;4BACD,IAAI,IAAI,EAAE,CAAC;gCACT,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gCACb,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oCAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oCAAC,CAAC,IAAI,CAAC,CAAC;oCAAC,SAAS;gCAAC,CAAC;gCACrE,IAAI,EAAE,KAAK,GAAG;oCAAE,IAAI,GAAG,KAAK,CAAC;gCAC7B,CAAC,EAAE,CAAC;gCACJ,SAAS;4BACX,CAAC;4BACD,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gCAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;gCAAC,CAAC,IAAI,CAAC,CAAC;gCAAC,IAAI,GAAG,IAAI,CAAC;gCAAC,SAAS;4BAAC,CAAC;4BACtF,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gCAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;gCAAC,CAAC,IAAI,CAAC,CAAC;gCAAC,IAAI,GAAG,IAAI,CAAC;gCAAC,SAAS;4BAAC,CAAC;4BACtF,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;gCAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gCAAC,IAAI,GAAG,IAAI,CAAC;gCAAC,CAAC,EAAE,CAAC;gCAAC,SAAS;4BAAC,CAAC;4BAC7D,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;gCAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gCAAC,IAAI,GAAG,IAAI,CAAC;gCAAC,CAAC,EAAE,CAAC;gCAAC,SAAS;4BAAC,CAAC;4BAC7D,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gCAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gCAAC,CAAC,IAAI,CAAC,CAAC;gCAAC,SAAS;4BAAC,CAAC;4BACrE,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;gCACf,cAAc;gCACd,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gCACd,MAAM,KAAK,GAAG,CAAC,CAAC;gCAChB,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;oCACf,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;oCACrB,IAAI,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG;wCAAE,CAAC,EAAE,CAAC;;wCAAM,MAAM;gCAC/G,CAAC;gCACD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gCACrC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;oCACtB,MAAM,KAAK,GAAG,OAAO,SAAS,EAAE,EAAE,CAAC;oCACnC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oCAChB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oCACvB,CAAC,GAAG,CAAC,CAAC;oCACN,SAAS;gCACX,CAAC;gCACD,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;oCACrB,MAAM,KAAK,GAAG,OAAO,SAAS,EAAE,EAAE,CAAC;oCACnC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oCAChB,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oCACtB,CAAC,GAAG,CAAC,CAAC;oCACN,SAAS;gCACX,CAAC;gCACD,4BAA4B;gCAC5B,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gCACd,CAAC,EAAE,CAAC;gCACJ,SAAS;4BACX,CAAC;4BACD,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;4BACb,CAAC,EAAE,CAAC;wBACN,CAAC;wBACD,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACtB,CAAC,CAAC;oBAEF,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;oBACtC,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;wBAC7B,UAAU,GAAG,SAAS,CAAC;wBACvB,uCAAuC;wBACtC,IAAkB,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;oBACzC,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,6DAA6D;oBAC7D,IAAI,GAAG,EAAE,GAAI,IAAgC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;gBACjE,CAAC;YACH,CAAC;YACD,MAAM,MAAM,GACV,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,oBAAoB,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,kBAAkB,EAAE,CAAC;YACrH,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,IAAW,CAAC,CAAC;YAEvE,mCAAmC;YACnC,IAAI,GAAG,CAAC;YACR,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;gBACvC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACjF,CAAC;YAAC,OAAO,OAAY,EAAE,CAAC;gBACtB,8DAA8D;gBAC9D,MAAM,IAAI,aAAa,CACrB,OAAO,EAAE,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,EACnC,QAAQ,EACR,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAC/C,CAAC;YACJ,CAAC;YAED,sEAAsE;YACtE,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC7C,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;gBAEzE,kDAAkD;gBAClD,IAAI,MAAM,CAAC,cAAc,IAAI,CAAC,oBAAoB,EAAE,EAAE,CAAC;oBACrD,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;wBAC/B,KAAK,MAAM,GAAG,IAAI,WAAW;4BAAE,cAAc,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;oBAC5E,CAAC;yBAAM,IAAI,WAAW,KAAK,IAAI,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;wBAC7D,cAAc,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;oBACrD,CAAC;gBACH,CAAC;gBACD,OAAO,WAAW,CAAC;YACrB,CAAC;YAED,4CAA4C;YAC5C,OAAO,GAAG,CAAC;QACb,CAAC,CAAC;QAEF,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,QAA6C,EAAE,KAAU;IAC9E,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,2CAA2C;IACnF,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;AAC3C,CAAC;AAED,SAAS,UAAU,CAAI,IAAS,EAAE,KAA4C;IAC5E,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,QAAQ;YACX,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1C,KAAK,MAAM;YACT,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAM,IAAI,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,KAAK,OAAO;YACV,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;gBAAE,MAAM,IAAI,WAAW,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,KAAK,MAAM;YACT,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;gBAAE,MAAM,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC3D,OAAO,IAAI,CAAC;QACd;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC","sourcesContent":["import { getClassLabels, getMethodLabels, setMethodLabels } from '../core/metadata';\nimport { SqlStackError, ExactlyOneRowError, NoRowsError, RowsExistError, DatabaseError } from '../core/errors';\nimport { isValidationDisabled, validateOutput } from '../core/validator';\nimport { resolveExecution } from '../runtime';\nimport { createSqliteBinder, createMysqlBinder, createPostgresBinder } from '../binders/sqlBinder';\nimport { coerceRootPath, resolveSqlFromFs } from '../core/fileResolution';\nimport { registerDecoratedMethod, recordQueryMethodOnClass } from '../core/resolver';\nimport { defaultSourceScanResolver } from '../core/sourceScanResolver';\nimport { getActiveTransaction } from '../transactions';\nimport { SqlFragment } from '../sql';\n\ntype QueryOptions = {\n sql?: string; // optional inline SQL for testing; otherwise, future: load from file\n db?: string; // optional override DB name\n dialect?: 'sqlite' | 'mysql' | 'postgres';\n};\n\nexport function Query(arg?: string | QueryOptions) {\n return function (_target: any, prop: string | symbol, desc: PropertyDescriptor) {\n const options: QueryOptions | undefined = typeof arg === 'string' ? undefined : arg;\n const rootArg: string | undefined = typeof arg === 'string' ? arg : undefined;\n // Store method-level db override if provided\n if (options?.db) {\n setMethodLabels(_target, prop, { db: options.db });\n }\n // Store inline SQL if provided\n if (options?.sql) {\n setMethodLabels(_target, prop, { source: { kind: 'inline', sql: options.sql } });\n } else {\n // FS-based resolution: only an EXPLICIT path argument pins a directory.\n // Bare @Query() resolves through the active resolver (or the default\n // SourceScanResolver) — no stack-based directory guessing, which breaks\n // under bundlers and test transforms.\n const { rootDir } = coerceRootPath(rootArg);\n if (rootDir) {\n setMethodLabels(_target, prop, { source: { kind: 'fs', rootDir } });\n }\n }\n\n // Record for resolver coverage checks: immutable class metadata (the\n // canonical, environment-local source) plus the deprecated global list\n // consulted by the legacy global-resolver path.\n const decoratedEntry = {\n className: _target?.constructor?.name ?? '<anonymous>',\n methodName: String(prop),\n inline: !!options?.sql,\n };\n recordQueryMethodOnClass(_target, decoratedEntry);\n registerDecoratedMethod(decoratedEntry);\n\n const original = desc.value;\n desc.value = async function (...callArgs: any[]) {\n const labels = getMethodLabels(this, prop);\n const classLabels = getClassLabels(this);\n\n // 0) Check if the method body returns a SqlFragment (template literal path)\n let fragmentResult: unknown;\n try {\n fragmentResult = await original.apply(this, callArgs);\n } catch {\n // Method body threw (e.g. placeholder `throw new Error('replaced')`) — fall through to file/inline SQL\n fragmentResult = undefined;\n }\n if (fragmentResult instanceof SqlFragment) {\n const { sql: boundSql, params } = fragmentResult.toSQL();\n\n const dbName = labels.db ?? options?.db ?? classLabels?.db;\n const { entry } = await resolveExecution(dbName);\n const db = entry.db;\n\n let out;\n try {\n const tx = getActiveTransaction(entry);\n out = tx ? await tx.query(boundSql, params) : await db.query(boundSql, params);\n } catch (dbError: any) {\n throw new DatabaseError(\n dbError?.message || String(dbError),\n boundSql,\n dbError instanceof Error ? dbError : undefined\n );\n }\n\n if (Array.isArray(out)) {\n const shaped = applyShape(out, labels.shape);\n const transformed = labels.transform ? labels.transform(shaped) : shaped;\n\n if (labels.validateSchema && !isValidationDisabled()) {\n if (Array.isArray(transformed)) {\n for (const row of transformed) validateOutput(labels.validateSchema, row);\n } else if (transformed !== null && transformed !== undefined) {\n validateOutput(labels.validateSchema, transformed);\n }\n }\n return transformed;\n }\n return out;\n }\n\n // 1) prepare args with defaults\n const rawInput = callArgs.length === 1 ? callArgs[0] : callArgs; // object or positional array\n\n // 2) choose database and dialect via the active environment\n const dbName = labels.db ?? options?.db ?? classLabels?.db;\n const { entry, resolver: activeResolver } = await resolveExecution(dbName);\n const db = entry.db;\n const dialect = options?.dialect ?? db.dialect ?? 'sqlite';\n\n // 3) load SQL source (inline, environment resolver, v1 fs fallback,\n // or the zero-config source scan — bare @Query() with nothing installed)\n const sql = labels?.source?.kind === 'inline'\n ? labels.source.sql\n : activeResolver\n ? activeResolver.resolve({\n className: this?.constructor?.name ?? '<anonymous>',\n methodName: String(prop),\n dialect,\n rootDir: labels?.source?.kind === 'fs' ? labels.source.rootDir : undefined,\n })\n : labels?.source?.kind === 'fs'\n ? resolveSqlFromFs(labels.source.rootDir, String(prop), dialect).sql\n : defaultSourceScanResolver()?.resolve({\n className: this?.constructor?.name ?? '<anonymous>',\n methodName: String(prop),\n dialect,\n });\n if (!sql) {\n throw new SqlStackError(`No SQL source provided for method ${String(prop)}. Use @Query() with a file/folder path or inline sql.`);\n }\n\n // 4) bind placeholders\n // Decide argument mode: positional if SQL contains :argN\n let workingSql = sql;\n const hasPositional = /:arg[1-9][0-9]*/.test(workingSql);\n\n // Prepare args for binder\n let args: any;\n if (hasPositional) {\n args = callArgs;\n } else {\n const namedBase = callArgs.length > 0 ? callArgs[0] : undefined;\n args = applyDefaults(labels.defaults, namedBase ?? {});\n }\n\n // Compute paging and inject :offset/:limit (named mode) or rewrite to positional\n const pageCfg = labels.page;\n if (pageCfg) {\n const { size, zeroBase } = pageCfg;\n const base = zeroBase ? 0 : 1;\n\n // Extract page number from input (object) or a trailing options object in positional mode\n const pageFromObject = (val: any): number | undefined => {\n if (val && typeof val === 'object' && !Array.isArray(val) && typeof (val as any).page !== 'undefined') {\n const p = (val as any).page;\n if (typeof p === 'number' && isFinite(p)) return p;\n }\n return undefined;\n };\n\n let pageNum: number | undefined;\n if (hasPositional) {\n // Variadic-style: only the LAST argument may carry `{ page }`\n if (callArgs.length > 0) {\n const last = callArgs[callArgs.length - 1];\n pageNum = pageFromObject(last);\n }\n } else {\n // Prefer last-arg options if provided; otherwise read from named object\n if (callArgs.length > 1) {\n const last = callArgs[callArgs.length - 1];\n pageNum = pageFromObject(last);\n }\n if (pageNum === undefined) {\n pageNum = pageFromObject(args);\n }\n }\n\n const effectivePage = typeof pageNum === 'number' ? pageNum : base;\n const offset = (effectivePage - base) * size;\n const limit = size;\n\n if (hasPositional) {\n // Replace occurrences of :offset and :limit with new :argN tokens appended to args\n const baseIndex = callArgs.length; // start numbering after user args\n let nextIndex = baseIndex + 1;\n const additions: unknown[] = [];\n\n const rewrite = (sqlText: string) => {\n const out: string[] = [];\n let i = 0;\n let inSQ = false, inDQ = false, inLC = false, inBC = false;\n const len = sqlText.length;\n while (i < len) {\n const ch = sqlText[i];\n const next = i + 1 < len ? sqlText[i + 1] : '';\n if (inLC) { out.push(ch); if (ch === '\\n') inLC = false; i++; continue; }\n if (inBC) { out.push(ch); if (ch === '*' && next === '/') { out.push(next); i++; inBC = false; } i++; continue; }\n if (inSQ) {\n out.push(ch);\n if (ch === \"'\" && next === \"'\") { out.push(next); i += 2; continue; }\n if (ch === \"'\") inSQ = false;\n i++;\n continue;\n }\n if (inDQ) {\n out.push(ch);\n if (ch === '\"' && next === '\"') { out.push(next); i += 2; continue; }\n if (ch === '\"') inDQ = false;\n i++;\n continue;\n }\n if (ch === '-' && next === '-') { out.push(ch, next); i += 2; inLC = true; continue; }\n if (ch === '/' && next === '*') { out.push(ch, next); i += 2; inBC = true; continue; }\n if (ch === '\"') { out.push(ch); inDQ = true; i++; continue; }\n if (ch === \"'\") { out.push(ch); inSQ = true; i++; continue; }\n if (ch === ':' && next === ':') { out.push('::'); i += 2; continue; }\n if (ch === ':') {\n // parse token\n let j = i + 1;\n const start = j;\n while (j < len) {\n const c = sqlText[j];\n if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_') j++; else break;\n }\n const name = sqlText.slice(start, j);\n if (name === 'offset') {\n const token = `:arg${nextIndex++}`;\n out.push(token);\n additions.push(offset);\n i = j;\n continue;\n }\n if (name === 'limit') {\n const token = `:arg${nextIndex++}`;\n out.push(token);\n additions.push(limit);\n i = j;\n continue;\n }\n // otherwise leave untouched\n out.push(':');\n i++;\n continue;\n }\n out.push(ch);\n i++;\n }\n return out.join('');\n };\n\n const rewritten = rewrite(workingSql);\n if (rewritten !== workingSql) {\n workingSql = rewritten;\n // append values so :argK map correctly\n (args as unknown[]).push(...additions);\n }\n } else {\n // Named-mode: attach computed values (override any provided)\n args = { ...(args as Record<string, unknown>), offset, limit };\n }\n }\n const binder =\n dialect === 'postgres' ? createPostgresBinder() : dialect === 'mysql' ? createMysqlBinder() : createSqliteBinder();\n const { sql: boundSql, params } = binder.bind(workingSql, args as any);\n\n // 5) execute query via registry DB\n let out;\n try {\n const tx = getActiveTransaction(entry);\n out = tx ? await tx.query(boundSql, params) : await db.query(boundSql, params);\n } catch (dbError: any) {\n // Attach SQL query (with placeholders) to error for debugging\n throw new DatabaseError(\n dbError?.message || String(dbError),\n boundSql,\n dbError instanceof Error ? dbError : undefined\n );\n }\n\n // 6) If rows were returned (SELECT/CTE), shape + transform + validate\n if (Array.isArray(out)) {\n const shaped = applyShape(out, labels.shape);\n const transformed = labels.transform ? labels.transform(shaped) : shaped;\n\n // 7) validate result via JSON Schema, if provided\n if (labels.validateSchema && !isValidationDisabled()) {\n if (Array.isArray(transformed)) {\n for (const row of transformed) validateOutput(labels.validateSchema, row);\n } else if (transformed !== null && transformed !== undefined) {\n validateOutput(labels.validateSchema, transformed);\n }\n }\n return transformed;\n }\n\n // Non-SELECT: return the write result as-is\n return out;\n };\n\n return desc;\n };\n}\n\nfunction applyDefaults(defaults: Record<string, unknown> | undefined, input: any) {\n if (!defaults) return input;\n if (Array.isArray(input)) return input; // defaults only apply to named-object args\n return { ...defaults, ...(input || {}) };\n}\n\nfunction applyShape<T>(rows: T[], shape?: 'single' | 'only' | 'exist' | 'none'): any {\n switch (shape) {\n case 'single':\n return rows.length > 0 ? rows[0] : null;\n case 'only':\n if (rows.length !== 1) throw new ExactlyOneRowError(rows.length);\n return rows[0];\n case 'exist':\n if (rows.length < 1) throw new NoRowsError();\n return rows[0];\n case 'none':\n if (rows.length > 0) throw new RowsExistError(rows.length);\n return null;\n default:\n return rows;\n }\n}\n"]}
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/decorators/query.ts"],"names":[],"mappings":"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","sourcesContent":["import { getClassLabels, getMethodLabels, setMethodLabels } from '../core/metadata';\nimport { SqlStackError, ExactlyOneRowError, NoRowsError, RowsExistError, DatabaseError } from '../core/errors';\nimport { isValidationDisabled, validateOutput } from '../core/validator';\nimport { resolveExecution } from '../runtime';\nimport { createSqliteBinder, createMysqlBinder, createPostgresBinder } from '../binders/sqlBinder';\nimport { coerceRootPath, resolveSqlFromFs } from '../core/fileResolution';\nimport { registerDecoratedMethod, recordQueryMethodOnClass } from '../core/resolver';\nimport { defaultSourceScanResolver } from '../core/sourceScanResolver';\nimport { getActiveTransaction } from '../transactions';\nimport { SqlFragment } from '../sql';\nimport { runStorage, type RunContext } from '../run';\n\ntype QueryOptions = {\n sql?: string; // optional inline SQL for testing; otherwise, future: load from file\n db?: string; // optional override DB name\n dialect?: 'sqlite' | 'mysql' | 'postgres';\n};\n\nexport function Query(arg?: string | QueryOptions) {\n return function (_target: any, prop: string | symbol, desc: PropertyDescriptor) {\n const options: QueryOptions | undefined = typeof arg === 'string' ? undefined : arg;\n const rootArg: string | undefined = typeof arg === 'string' ? arg : undefined;\n // Store method-level db override if provided\n if (options?.db) {\n setMethodLabels(_target, prop, { db: options.db });\n }\n // Store inline SQL if provided\n if (options?.sql) {\n setMethodLabels(_target, prop, { source: { kind: 'inline', sql: options.sql } });\n } else {\n // FS-based resolution: only an EXPLICIT path argument pins a directory.\n // Bare @Query() resolves through the active resolver (or the default\n // SourceScanResolver) — no stack-based directory guessing, which breaks\n // under bundlers and test transforms.\n const { rootDir } = coerceRootPath(rootArg);\n if (rootDir) {\n setMethodLabels(_target, prop, { source: { kind: 'fs', rootDir } });\n }\n }\n\n // Record for resolver coverage checks: immutable class metadata (the\n // canonical, environment-local source) plus the deprecated global list\n // consulted by the legacy global-resolver path.\n const decoratedEntry = {\n className: _target?.constructor?.name ?? '<anonymous>',\n methodName: String(prop),\n inline: !!options?.sql,\n };\n recordQueryMethodOnClass(_target, decoratedEntry);\n registerDecoratedMethod(decoratedEntry);\n\n const original = desc.value;\n desc.value = async function (...callArgs: any[]) {\n const labels = getMethodLabels(this, prop);\n const classLabels = getClassLabels(this);\n\n // The full file/inline pipeline (resolve source, bind, execute,\n // shape/transform/validate). Invoked either by run() from inside the\n // method body, or directly as the legacy fallback when the body throws.\n const pipeline = async () => {\n // 1) prepare args with defaults\n const rawInput = callArgs.length === 1 ? callArgs[0] : callArgs; // object or positional array\n\n // 2) choose database and dialect via the active environment\n const dbName = labels.db ?? options?.db ?? classLabels?.db;\n const { entry, resolver: activeResolver } = await resolveExecution(dbName);\n const db = entry.db;\n const dialect = options?.dialect ?? db.dialect ?? 'sqlite';\n\n // 3) load SQL source (inline, environment resolver, v1 fs fallback,\n // or the zero-config source scan — bare @Query() with nothing installed)\n const sql = labels?.source?.kind === 'inline'\n ? labels.source.sql\n : activeResolver\n ? activeResolver.resolve({\n className: this?.constructor?.name ?? '<anonymous>',\n methodName: String(prop),\n dialect,\n rootDir: labels?.source?.kind === 'fs' ? labels.source.rootDir : undefined,\n })\n : labels?.source?.kind === 'fs'\n ? resolveSqlFromFs(labels.source.rootDir, String(prop), dialect).sql\n : defaultSourceScanResolver()?.resolve({\n className: this?.constructor?.name ?? '<anonymous>',\n methodName: String(prop),\n dialect,\n });\n if (!sql) {\n throw new SqlStackError(`No SQL source provided for method ${String(prop)}. Use @Query() with a file/folder path or inline sql.`);\n }\n\n // 4) bind placeholders\n // Decide argument mode: positional if SQL contains :argN\n let workingSql = sql;\n const hasPositional = /:arg[1-9][0-9]*/.test(workingSql);\n\n // Prepare args for binder\n let args: any;\n if (hasPositional) {\n args = callArgs;\n } else {\n const namedBase = callArgs.length > 0 ? callArgs[0] : undefined;\n args = applyDefaults(labels.defaults, namedBase ?? {});\n }\n\n // Compute paging and inject :offset/:limit (named mode) or rewrite to positional\n const pageCfg = labels.page;\n if (pageCfg) {\n const { size, zeroBase } = pageCfg;\n const base = zeroBase ? 0 : 1;\n\n // Extract page number from input (object) or a trailing options object in positional mode\n const pageFromObject = (val: any): number | undefined => {\n if (val && typeof val === 'object' && !Array.isArray(val) && typeof (val as any).page !== 'undefined') {\n const p = (val as any).page;\n if (typeof p === 'number' && isFinite(p)) return p;\n }\n return undefined;\n };\n\n let pageNum: number | undefined;\n if (hasPositional) {\n // Variadic-style: only the LAST argument may carry `{ page }`\n if (callArgs.length > 0) {\n const last = callArgs[callArgs.length - 1];\n pageNum = pageFromObject(last);\n }\n } else {\n // Prefer last-arg options if provided; otherwise read from named object\n if (callArgs.length > 1) {\n const last = callArgs[callArgs.length - 1];\n pageNum = pageFromObject(last);\n }\n if (pageNum === undefined) {\n pageNum = pageFromObject(args);\n }\n }\n\n const effectivePage = typeof pageNum === 'number' ? pageNum : base;\n const offset = (effectivePage - base) * size;\n const limit = size;\n\n if (hasPositional) {\n // Replace occurrences of :offset and :limit with new :argN tokens appended to args\n const baseIndex = callArgs.length; // start numbering after user args\n let nextIndex = baseIndex + 1;\n const additions: unknown[] = [];\n\n const rewrite = (sqlText: string) => {\n const out: string[] = [];\n let i = 0;\n let inSQ = false, inDQ = false, inLC = false, inBC = false;\n const len = sqlText.length;\n while (i < len) {\n const ch = sqlText[i];\n const next = i + 1 < len ? sqlText[i + 1] : '';\n if (inLC) { out.push(ch); if (ch === '\\n') inLC = false; i++; continue; }\n if (inBC) { out.push(ch); if (ch === '*' && next === '/') { out.push(next); i++; inBC = false; } i++; continue; }\n if (inSQ) {\n out.push(ch);\n if (ch === \"'\" && next === \"'\") { out.push(next); i += 2; continue; }\n if (ch === \"'\") inSQ = false;\n i++;\n continue;\n }\n if (inDQ) {\n out.push(ch);\n if (ch === '\"' && next === '\"') { out.push(next); i += 2; continue; }\n if (ch === '\"') inDQ = false;\n i++;\n continue;\n }\n if (ch === '-' && next === '-') { out.push(ch, next); i += 2; inLC = true; continue; }\n if (ch === '/' && next === '*') { out.push(ch, next); i += 2; inBC = true; continue; }\n if (ch === '\"') { out.push(ch); inDQ = true; i++; continue; }\n if (ch === \"'\") { out.push(ch); inSQ = true; i++; continue; }\n if (ch === ':' && next === ':') { out.push('::'); i += 2; continue; }\n if (ch === ':') {\n // parse token\n let j = i + 1;\n const start = j;\n while (j < len) {\n const c = sqlText[j];\n if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_') j++; else break;\n }\n const name = sqlText.slice(start, j);\n if (name === 'offset') {\n const token = `:arg${nextIndex++}`;\n out.push(token);\n additions.push(offset);\n i = j;\n continue;\n }\n if (name === 'limit') {\n const token = `:arg${nextIndex++}`;\n out.push(token);\n additions.push(limit);\n i = j;\n continue;\n }\n // otherwise leave untouched\n out.push(':');\n i++;\n continue;\n }\n out.push(ch);\n i++;\n }\n return out.join('');\n };\n\n const rewritten = rewrite(workingSql);\n if (rewritten !== workingSql) {\n workingSql = rewritten;\n // append values so :argK map correctly\n (args as unknown[]).push(...additions);\n }\n } else {\n // Named-mode: attach computed values (override any provided)\n args = { ...(args as Record<string, unknown>), offset, limit };\n }\n }\n const binder =\n dialect === 'postgres' ? createPostgresBinder() : dialect === 'mysql' ? createMysqlBinder() : createSqliteBinder();\n const { sql: boundSql, params } = binder.bind(workingSql, args as any);\n\n // 5) execute query via registry DB\n let out;\n try {\n const tx = getActiveTransaction(entry);\n out = tx ? await tx.query(boundSql, params) : await db.query(boundSql, params);\n } catch (dbError: any) {\n // Attach SQL query (with placeholders) to error for debugging\n throw new DatabaseError(\n dbError?.message || String(dbError),\n boundSql,\n dbError instanceof Error ? dbError : undefined\n );\n }\n\n // 6) If rows were returned (SELECT/CTE), shape + transform + validate\n if (Array.isArray(out)) {\n const shaped = applyShape(out, labels.shape);\n const transformed = labels.transform ? labels.transform(shaped) : shaped;\n\n // 7) validate result via JSON Schema, if provided\n if (labels.validateSchema && !isValidationDisabled()) {\n if (Array.isArray(transformed)) {\n for (const row of transformed) validateOutput(labels.validateSchema, row);\n } else if (transformed !== null && transformed !== undefined) {\n validateOutput(labels.validateSchema, transformed);\n }\n }\n return transformed;\n }\n\n // Non-SELECT: return the write result as-is\n return out;\n };\n\n // 0) Invoke the method body inside a run() context. Three outcomes:\n // - body calls run(): the pipeline executed inside the body; return\n // the body's result verbatim (it may have caught/transformed it).\n // - body returns a SqlFragment (template literal path): execute it.\n // - body throws without calling run() (legacy placeholder throw):\n // fall through to the pipeline.\n const runCtx: RunContext = { ran: false, execute: pipeline };\n let fragmentResult: unknown;\n try {\n fragmentResult = await runStorage.run(runCtx, () => original.apply(this, callArgs));\n } catch (bodyError) {\n // A body that invoked run() is real logic — its errors propagate.\n if (runCtx.ran) throw bodyError;\n // Method body threw (e.g. placeholder `throw new Error('replaced')`) — fall through to file/inline SQL\n fragmentResult = undefined;\n }\n if (runCtx.ran) return fragmentResult;\n\n if (fragmentResult instanceof SqlFragment) {\n const { sql: boundSql, params } = fragmentResult.toSQL();\n\n const dbName = labels.db ?? options?.db ?? classLabels?.db;\n const { entry } = await resolveExecution(dbName);\n const db = entry.db;\n\n let out;\n try {\n const tx = getActiveTransaction(entry);\n out = tx ? await tx.query(boundSql, params) : await db.query(boundSql, params);\n } catch (dbError: any) {\n throw new DatabaseError(\n dbError?.message || String(dbError),\n boundSql,\n dbError instanceof Error ? dbError : undefined\n );\n }\n\n if (Array.isArray(out)) {\n const shaped = applyShape(out, labels.shape);\n const transformed = labels.transform ? labels.transform(shaped) : shaped;\n\n if (labels.validateSchema && !isValidationDisabled()) {\n if (Array.isArray(transformed)) {\n for (const row of transformed) validateOutput(labels.validateSchema, row);\n } else if (transformed !== null && transformed !== undefined) {\n validateOutput(labels.validateSchema, transformed);\n }\n }\n return transformed;\n }\n return out;\n }\n\n return pipeline();\n };\n\n return desc;\n };\n}\n\nfunction applyDefaults(defaults: Record<string, unknown> | undefined, input: any) {\n if (!defaults) return input;\n if (Array.isArray(input)) return input; // defaults only apply to named-object args\n return { ...defaults, ...(input || {}) };\n}\n\nfunction applyShape<T>(rows: T[], shape?: 'single' | 'only' | 'exist' | 'none'): any {\n switch (shape) {\n case 'single':\n return rows.length > 0 ? rows[0] : null;\n case 'only':\n if (rows.length !== 1) throw new ExactlyOneRowError(rows.length);\n return rows[0];\n case 'exist':\n if (rows.length < 1) throw new NoRowsError();\n return rows[0];\n case 'none':\n if (rows.length > 0) throw new RowsExistError(rows.length);\n return null;\n default:\n return rows;\n }\n}\n"]}
package/dist/esm/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  // SQL Template Strings
2
2
  export { sql, SqlFragment } from './sql.js';
3
+ // Query body execution — `return run<T>()` inside a @Query method body
4
+ export { run } from './run.js';
3
5
  // Decorators
4
6
  export * from './decorators/queryBinder.js';
5
7
  export * from './decorators/query.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEzC,aAAa;AACb,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAElC,eAAe;AACf,cAAc,gBAAgB,CAAC;AAE/B,WAAW;AACX,cAAc,YAAY,CAAC;AAE3B,wBAAwB;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AAEjC,aAAa;AACb,cAAc,aAAa,CAAC;AAI5B,OAAO,EAAE,UAAU,EAAY,MAAM,YAAY,CAAC;AAElD,gFAAgF;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7D,sCAAsC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAQzC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAKvD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,mDAAmD;AACnD,cAAc,qBAAqB,CAAC","sourcesContent":["// SQL Template Strings\nexport { sql, SqlFragment } from './sql';\n\n// Decorators\nexport * from './decorators/queryBinder';\nexport * from './decorators/query';\nexport * from './decorators/defaults';\nexport * from './decorators/resultShape';\nexport * from './decorators/validateResult';\nexport * from './decorators/transform';\nexport * from './decorators/page';\n\n// Transactions\nexport * from './transactions';\n\n// Adapters\nexport * from './adapters';\n\n// Errors and Validation\nexport * from './core/errors';\nexport * from './core/validator';\n\n// DTO Helper\nexport * from './utils/dto';\n\n// Database Registry and Types\nexport type { Dialect, WriteResult, PostgresWriteResult, QueryResult, Database } from './registry';\nexport { SqlStackDB, IStackDB } from './registry';\n\n// Environment-owned runtime (v3): per-root SqlStack + active-context resolution\nexport { SqlStack } from './stack';\nexport type { DatabaseEntry, DatabaseRegistration, SqlStackConfig } from './stack';\nexport { activeSqlStack, resolveExecution } from './runtime';\n\n// Dynamic database families (spec 17)\nexport { FamilyRuntime } from './family';\nexport type {\n DatabaseFamilyProvider,\n FamilyConfig,\n FamilyMemberEntry,\n DatabaseLease,\n DatabaseInspection,\n} from './family';\nexport { sqliteFamily } from './families/sqliteFamily';\nexport type { SqliteFamilyOptions } from './families/sqliteFamily';\n\n// SQL Resolvers (v2): pluggable SQL source resolution\nexport type { SqlResolver, SqlManifest, SqlResolutionRequest, ManifestResolverOptions } from './core/resolver';\nexport { FsResolver, ManifestResolver, MANIFEST_DIALECT_EXT } from './core/resolver';\nexport { SourceScanResolver } from './core/sourceScanResolver';\n\n// Legacy exports (kept for backward compatibility)\nexport * from './binders/sqlBinder';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEzC,uEAAuE;AACvE,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAE5B,aAAa;AACb,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAElC,eAAe;AACf,cAAc,gBAAgB,CAAC;AAE/B,WAAW;AACX,cAAc,YAAY,CAAC;AAE3B,wBAAwB;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AAEjC,aAAa;AACb,cAAc,aAAa,CAAC;AAI5B,OAAO,EAAE,UAAU,EAAY,MAAM,YAAY,CAAC;AAElD,gFAAgF;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7D,sCAAsC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAQzC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAKvD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,mDAAmD;AACnD,cAAc,qBAAqB,CAAC","sourcesContent":["// SQL Template Strings\nexport { sql, SqlFragment } from './sql';\n\n// Query body execution — `return run<T>()` inside a @Query method body\nexport { run } from './run';\n\n// Decorators\nexport * from './decorators/queryBinder';\nexport * from './decorators/query';\nexport * from './decorators/defaults';\nexport * from './decorators/resultShape';\nexport * from './decorators/validateResult';\nexport * from './decorators/transform';\nexport * from './decorators/page';\n\n// Transactions\nexport * from './transactions';\n\n// Adapters\nexport * from './adapters';\n\n// Errors and Validation\nexport * from './core/errors';\nexport * from './core/validator';\n\n// DTO Helper\nexport * from './utils/dto';\n\n// Database Registry and Types\nexport type { Dialect, WriteResult, PostgresWriteResult, QueryResult, Database } from './registry';\nexport { SqlStackDB, IStackDB } from './registry';\n\n// Environment-owned runtime (v3): per-root SqlStack + active-context resolution\nexport { SqlStack } from './stack';\nexport type { DatabaseEntry, DatabaseRegistration, SqlStackConfig } from './stack';\nexport { activeSqlStack, resolveExecution } from './runtime';\n\n// Dynamic database families (spec 17)\nexport { FamilyRuntime } from './family';\nexport type {\n DatabaseFamilyProvider,\n FamilyConfig,\n FamilyMemberEntry,\n DatabaseLease,\n DatabaseInspection,\n} from './family';\nexport { sqliteFamily } from './families/sqliteFamily';\nexport type { SqliteFamilyOptions } from './families/sqliteFamily';\n\n// SQL Resolvers (v2): pluggable SQL source resolution\nexport type { SqlResolver, SqlManifest, SqlResolutionRequest, ManifestResolverOptions } from './core/resolver';\nexport { FsResolver, ManifestResolver, MANIFEST_DIALECT_EXT } from './core/resolver';\nexport { SourceScanResolver } from './core/sourceScanResolver';\n\n// Legacy exports (kept for backward compatibility)\nexport * from './binders/sqlBinder';\n"]}
@@ -0,0 +1,34 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import { SqlStackError } from './core/errors.js';
3
+ // Anchored on globalThis via Symbol.for so duplicated module instances
4
+ // (npm link, dual ESM/CJS loads) share one channel between the decorator
5
+ // and the run() the application imports.
6
+ const RUN_CHANNEL = Symbol.for('noego.sqlstack.runContext');
7
+ const anchor = globalThis;
8
+ if (!anchor[RUN_CHANNEL]) {
9
+ anchor[RUN_CHANNEL] = new AsyncLocalStorage();
10
+ }
11
+ export const runStorage = anchor[RUN_CHANNEL];
12
+ /**
13
+ * Execute the current @Query method's SQL and return the finished result.
14
+ * Call it as the body of a @Query-decorated method in place of the legacy
15
+ * placeholder throw:
16
+ *
17
+ * @Query()
18
+ * async getUsers(active: boolean): Promise<User[]> {
19
+ * return run<User[]>();
20
+ * }
21
+ *
22
+ * Takes no arguments — the method's own arguments, database, SQL source,
23
+ * transaction, shaping, transform, and validation all come from the
24
+ * decorator context. The generic is a typing convenience only.
25
+ */
26
+ export async function run() {
27
+ const ctx = runStorage.getStore();
28
+ if (!ctx) {
29
+ throw new SqlStackError('run() called outside a @Query method. It may only be invoked from the body of a @Query-decorated method.');
30
+ }
31
+ ctx.ran = true;
32
+ return ctx.execute();
33
+ }
34
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAc9C,uEAAuE;AACvE,yEAAyE;AACzE,yCAAyC;AACzC,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;AAC5D,MAAM,MAAM,GAAG,UAA0C,CAAC;AAC1D,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;IACzB,MAAM,CAAC,WAAW,CAAC,GAAG,IAAI,iBAAiB,EAAc,CAAC;AAC5D,CAAC;AACD,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,CAAkC,CAAC;AAE/E;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC;IAClC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,aAAa,CACrB,0GAA0G,CAC3G,CAAC;IACJ,CAAC;IACD,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC;IACf,OAAO,GAAG,CAAC,OAAO,EAAgB,CAAC;AACrC,CAAC","sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport { SqlStackError } from './core/errors';\n\n/**\n * Per-invocation context established by the @Query wrapper before the method\n * body executes. `execute` performs the full query pipeline (resolve SQL,\n * bind, execute, shape/transform/validate); `ran` records that the body\n * invoked run(), so the wrapper returns the body's result verbatim instead\n * of falling through to the legacy pipeline.\n */\nexport type RunContext = {\n execute: () => Promise<unknown>;\n ran: boolean;\n};\n\n// Anchored on globalThis via Symbol.for so duplicated module instances\n// (npm link, dual ESM/CJS loads) share one channel between the decorator\n// and the run() the application imports.\nconst RUN_CHANNEL = Symbol.for('noego.sqlstack.runContext');\nconst anchor = globalThis as Record<PropertyKey, unknown>;\nif (!anchor[RUN_CHANNEL]) {\n anchor[RUN_CHANNEL] = new AsyncLocalStorage<RunContext>();\n}\nexport const runStorage = anchor[RUN_CHANNEL] as AsyncLocalStorage<RunContext>;\n\n/**\n * Execute the current @Query method's SQL and return the finished result.\n * Call it as the body of a @Query-decorated method in place of the legacy\n * placeholder throw:\n *\n * @Query()\n * async getUsers(active: boolean): Promise<User[]> {\n * return run<User[]>();\n * }\n *\n * Takes no arguments — the method's own arguments, database, SQL source,\n * transaction, shaping, transform, and validation all come from the\n * decorator context. The generic is a typing convenience only.\n */\nexport async function run<T = any>(): Promise<T> {\n const ctx = runStorage.getStore();\n if (!ctx) {\n throw new SqlStackError(\n 'run() called outside a @Query method. It may only be invoked from the body of a @Query-decorated method.'\n );\n }\n ctx.ran = true;\n return ctx.execute() as Promise<T>;\n}\n"]}
@@ -1,4 +1,6 @@
1
1
  export { testPostgres } from './builder.js';
2
+ export { testSqlite } from './sqlite/builder.js';
3
+ export { TestSqliteError } from './sqlite/database.js';
2
4
  export { parseTestSchema } from './schema/parser.js';
3
5
  export { normalizeTestSchema, TestSchemaError } from './schema/normalize.js';
4
6
  export { generateDdl } from './schema/ddl.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAGzC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["export { testPostgres } from './builder';\nexport type { TestPostgresBuilder, TestPostgresOptions } from './builder';\nexport type { TestPostgresDatabase } from './postgres/database';\nexport { parseTestSchema } from './schema/parser';\nexport { normalizeTestSchema, TestSchemaError } from './schema/normalize';\nexport { generateDdl } from './schema/ddl';\nexport { TestDataError } from './postgres/loadData';\nexport { TestPostgresServerError, DEFAULT_ADMIN_URL } from './postgres/server';\nexport type {\n NormalizedTestSchema,\n NormalizedTable,\n NormalizedColumn,\n RawSqlEntry,\n ParseTestSchemaOptions,\n} from './schema/types';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAGzC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["export { testPostgres } from './builder';\nexport type { TestPostgresBuilder, TestPostgresOptions } from './builder';\nexport type { TestPostgresDatabase } from './postgres/database';\nexport { testSqlite } from './sqlite/builder';\nexport type { TestSqliteBuilder, TestSqliteOptions } from './sqlite/builder';\nexport { TestSqliteError } from './sqlite/database';\nexport type { TestSqliteDatabase } from './sqlite/database';\nexport { parseTestSchema } from './schema/parser';\nexport { normalizeTestSchema, TestSchemaError } from './schema/normalize';\nexport { generateDdl } from './schema/ddl';\nexport { TestDataError } from './postgres/loadData';\nexport { TestPostgresServerError, DEFAULT_ADMIN_URL } from './postgres/server';\nexport type {\n NormalizedTestSchema,\n NormalizedTable,\n NormalizedColumn,\n RawSqlEntry,\n ParseTestSchemaOptions,\n} from './schema/types';\n"]}
@@ -1,25 +1,47 @@
1
- /** Quote a (pre-validated) identifier for PostgreSQL. */
2
1
  export function quoteIdent(name) {
3
2
  return `"${name.replace(/"/g, '""')}"`;
4
3
  }
5
4
  function renderDefault(value) {
6
- // String defaults are raw SQL expressions (e.g. now(), 'active', gen_random_uuid()).
7
5
  if (typeof value === 'string')
8
6
  return value;
9
7
  if (typeof value === 'boolean')
10
8
  return value ? 'TRUE' : 'FALSE';
11
9
  return String(value);
12
10
  }
13
- export function generateTableDdl(table) {
11
+ function sqliteType(type) {
12
+ const normalized = type.trim().toLowerCase();
13
+ if (normalized === 'uuid')
14
+ return 'TEXT';
15
+ if (/^(timestamp|timestamptz)(\s+with(out)?\s+time\s+zone)?$/.test(normalized))
16
+ return 'TEXT';
17
+ if (normalized === 'json' || normalized === 'jsonb')
18
+ return 'TEXT';
19
+ if (normalized === 'boolean' || normalized === 'bool')
20
+ return 'INTEGER';
21
+ if (normalized === 'citext')
22
+ return 'TEXT COLLATE NOCASE';
23
+ if (/^(serial|bigserial|smallserial)$/.test(normalized))
24
+ return 'INTEGER';
25
+ if (/^(bytea)$/.test(normalized))
26
+ return 'BLOB';
27
+ if (/^(double precision|real|float[48]?)$/.test(normalized))
28
+ return 'REAL';
29
+ return type;
30
+ }
31
+ export function generateTableDdl(table, dialect = 'postgres') {
14
32
  const lines = [];
15
33
  for (const col of table.columns) {
16
- let line = ` ${quoteIdent(col.name)} ${col.type}`;
34
+ const type = dialect === 'sqlite' ? sqliteType(col.type) : col.type;
35
+ let line = ` ${quoteIdent(col.name)} ${type}`;
17
36
  if (!col.nullable && !col.primary)
18
37
  line += ' NOT NULL';
19
38
  if (col.unique && !col.primary)
20
39
  line += ' UNIQUE';
21
40
  if (col.hasDefault)
22
41
  line += ` DEFAULT ${renderDefault(col.default)}`;
42
+ if (dialect === 'sqlite' && col.references) {
43
+ line += ` REFERENCES ${quoteIdent(col.references.table)} (${quoteIdent(col.references.column)})`;
44
+ }
23
45
  lines.push(line);
24
46
  }
25
47
  if (table.primaryKey.length > 0) {
@@ -27,16 +49,10 @@ export function generateTableDdl(table) {
27
49
  }
28
50
  return `CREATE TABLE ${quoteIdent(table.name)} (\n${lines.join(',\n')}\n)`;
29
51
  }
30
- /**
31
- * Deterministic DDL for the structured tables.
32
- *
33
- * Tables are created in authored order without inline foreign keys; declared
34
- * references are then added as ALTER TABLE statements so authored table
35
- * order never has to match dependency order. Raw SQL entries are applied by
36
- * the builder after these statements, in authored order.
37
- */
38
52
  export function generateDdl(schema) {
39
- const statements = schema.tables.map(generateTableDdl);
53
+ const statements = schema.tables.map((table) => generateTableDdl(table, schema.dialect));
54
+ if (schema.dialect === 'sqlite')
55
+ return statements;
40
56
  for (const table of schema.tables) {
41
57
  for (const col of table.columns) {
42
58
  if (col.references) {
@@ -1 +1 @@
1
- {"version":3,"file":"ddl.js","sourceRoot":"","sources":["../../../../src/testing/schema/ddl.ts"],"names":[],"mappings":"AAEA,yDAAyD;AACzD,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;AACzC,CAAC;AAED,SAAS,aAAa,CAAC,KAAgC;IACrD,qFAAqF;IACrF,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAChE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAsB;IACrD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAChC,IAAI,IAAI,GAAG,KAAK,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QACnD,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,OAAO;YAAE,IAAI,IAAI,WAAW,CAAC;QACvD,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO;YAAE,IAAI,IAAI,SAAS,CAAC;QAClD,IAAI,GAAG,CAAC,UAAU;YAAE,IAAI,IAAI,YAAY,aAAa,CAAC,GAAG,CAAC,OAAQ,CAAC,EAAE,CAAC;QACtE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,kBAAkB,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,gBAAgB,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AAC7E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,MAA4B;IACtD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACvD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YAChC,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;gBACnB,UAAU,CAAC,IAAI,CACb,eAAe,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,UAAU,CAChE,MAAM,KAAK,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAC/B,iBAAiB,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,UAAU,CAC9D,GAAG,CAAC,UAAU,CAAC,KAAK,CACrB,KAAK,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAC3C,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC","sourcesContent":["import type { NormalizedTable, NormalizedTestSchema } from './types';\n\n/** Quote a (pre-validated) identifier for PostgreSQL. */\nexport function quoteIdent(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction renderDefault(value: string | number | boolean): string {\n // String defaults are raw SQL expressions (e.g. now(), 'active', gen_random_uuid()).\n if (typeof value === 'string') return value;\n if (typeof value === 'boolean') return value ? 'TRUE' : 'FALSE';\n return String(value);\n}\n\nexport function generateTableDdl(table: NormalizedTable): string {\n const lines: string[] = [];\n for (const col of table.columns) {\n let line = ` ${quoteIdent(col.name)} ${col.type}`;\n if (!col.nullable && !col.primary) line += ' NOT NULL';\n if (col.unique && !col.primary) line += ' UNIQUE';\n if (col.hasDefault) line += ` DEFAULT ${renderDefault(col.default!)}`;\n lines.push(line);\n }\n if (table.primaryKey.length > 0) {\n lines.push(` PRIMARY KEY (${table.primaryKey.map(quoteIdent).join(', ')})`);\n }\n return `CREATE TABLE ${quoteIdent(table.name)} (\\n${lines.join(',\\n')}\\n)`;\n}\n\n/**\n * Deterministic DDL for the structured tables.\n *\n * Tables are created in authored order without inline foreign keys; declared\n * references are then added as ALTER TABLE statements so authored table\n * order never has to match dependency order. Raw SQL entries are applied by\n * the builder after these statements, in authored order.\n */\nexport function generateDdl(schema: NormalizedTestSchema): string[] {\n const statements = schema.tables.map(generateTableDdl);\n for (const table of schema.tables) {\n for (const col of table.columns) {\n if (col.references) {\n statements.push(\n `ALTER TABLE ${quoteIdent(table.name)} ADD CONSTRAINT ${quoteIdent(\n `fk_${table.name}_${col.name}`\n )} FOREIGN KEY (${quoteIdent(col.name)}) REFERENCES ${quoteIdent(\n col.references.table\n )} (${quoteIdent(col.references.column)})`\n );\n }\n }\n }\n return statements;\n}\n"]}
1
+ {"version":3,"file":"ddl.js","sourceRoot":"","sources":["../../../../src/testing/schema/ddl.ts"],"names":[],"mappings":"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","sourcesContent":["import type { NormalizedTable, NormalizedTestSchema } from './types';\n\nexport function quoteIdent(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction renderDefault(value: string | number | boolean): string {\n if (typeof value === 'string') return value;\n if (typeof value === 'boolean') return value ? 'TRUE' : 'FALSE';\n return String(value);\n}\n\nfunction sqliteType(type: string): string {\n const normalized = type.trim().toLowerCase();\n if (normalized === 'uuid') return 'TEXT';\n if (/^(timestamp|timestamptz)(\\s+with(out)?\\s+time\\s+zone)?$/.test(normalized)) return 'TEXT';\n if (normalized === 'json' || normalized === 'jsonb') return 'TEXT';\n if (normalized === 'boolean' || normalized === 'bool') return 'INTEGER';\n if (normalized === 'citext') return 'TEXT COLLATE NOCASE';\n if (/^(serial|bigserial|smallserial)$/.test(normalized)) return 'INTEGER';\n if (/^(bytea)$/.test(normalized)) return 'BLOB';\n if (/^(double precision|real|float[48]?)$/.test(normalized)) return 'REAL';\n return type;\n}\n\nexport function generateTableDdl(\n table: NormalizedTable,\n dialect: 'postgres' | 'sqlite' = 'postgres'\n): string {\n const lines: string[] = [];\n for (const col of table.columns) {\n const type = dialect === 'sqlite' ? sqliteType(col.type) : col.type;\n let line = ` ${quoteIdent(col.name)} ${type}`;\n if (!col.nullable && !col.primary) line += ' NOT NULL';\n if (col.unique && !col.primary) line += ' UNIQUE';\n if (col.hasDefault) line += ` DEFAULT ${renderDefault(col.default!)}`;\n if (dialect === 'sqlite' && col.references) {\n line += ` REFERENCES ${quoteIdent(col.references.table)} (${quoteIdent(col.references.column)})`;\n }\n lines.push(line);\n }\n if (table.primaryKey.length > 0) {\n lines.push(` PRIMARY KEY (${table.primaryKey.map(quoteIdent).join(', ')})`);\n }\n return `CREATE TABLE ${quoteIdent(table.name)} (\\n${lines.join(',\\n')}\\n)`;\n}\n\nexport function generateDdl(schema: NormalizedTestSchema): string[] {\n const statements = schema.tables.map((table) => generateTableDdl(table, schema.dialect));\n if (schema.dialect === 'sqlite') return statements;\n for (const table of schema.tables) {\n for (const col of table.columns) {\n if (col.references) {\n statements.push(\n `ALTER TABLE ${quoteIdent(table.name)} ADD CONSTRAINT ${quoteIdent(\n `fk_${table.name}_${col.name}`\n )} FOREIGN KEY (${quoteIdent(col.name)}) REFERENCES ${quoteIdent(\n col.references.table\n )} (${quoteIdent(col.references.column)})`\n );\n }\n }\n }\n return statements;\n}\n"]}
@@ -115,8 +115,8 @@ export function normalizeTestSchema(doc, options = {}) {
115
115
  if (root.version !== 1) {
116
116
  throw new TestSchemaError(`Unsupported test schema version: ${JSON.stringify(root.version)} (expected: version: 1)`, source);
117
117
  }
118
- if (root.dialect !== 'postgres') {
119
- throw new TestSchemaError(`Unsupported test schema dialect: ${JSON.stringify(root.dialect)} (expected: dialect: postgres)`, source);
118
+ if (root.dialect !== 'postgres' && root.dialect !== 'sqlite') {
119
+ throw new TestSchemaError(`Unsupported test schema dialect: ${JSON.stringify(root.dialect)} (expected: dialect: postgres or sqlite)`, source);
120
120
  }
121
121
  for (const key of Object.keys(root)) {
122
122
  if (!['version', 'dialect', 'tables', 'sql'].includes(key)) {
@@ -155,7 +155,7 @@ export function normalizeTestSchema(doc, options = {}) {
155
155
  }
156
156
  return Object.freeze({
157
157
  version: 1,
158
- dialect: 'postgres',
158
+ dialect: root.dialect,
159
159
  tables: Object.freeze(tables),
160
160
  sql: Object.freeze(sql),
161
161
  source,
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../../../src/testing/schema/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAUlD,MAAM,OAAO,eAAgB,SAAQ,aAAa;IAChD,YAAY,OAAe,EAAE,MAAe;QAC1C,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,oBAAoB,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAClE,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED,MAAM,KAAK,GAAG,0BAA0B,CAAC;AAEzC,SAAS,gBAAgB,CAAC,IAAY,EAAE,IAAY,EAAE,MAAc;IAClE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,eAAe,CACvB,WAAW,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,+CAA+C,EAC3F,MAAM,CACP,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,GAAY,EAAE,KAAa,EAAE,MAAc;IACjE,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,eAAe,CAAC,2BAA2B,KAAK,yCAAyC,EAAE,MAAM,CAAC,CAAC;IAC/G,CAAC;IACD,4CAA4C;IAC5C,IAAI,CAAC,GAAG,sDAAsD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzE,IAAI,CAAC,CAAC;QAAE,CAAC,GAAG,wDAAwD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/E,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,eAAe,CACvB,+BAA+B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,KAAK,yCAAyC,EACvG,MAAM,CACP,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;AAEhG,SAAS,eAAe,CAAC,SAAiB,EAAE,IAAY,EAAE,IAAa,EAAE,MAAc;IACrF,MAAM,KAAK,GAAG,GAAG,SAAS,IAAI,IAAI,EAAE,CAAC;IACrC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACzC,IAAI,GAA4B,CAAC;IACjC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,GAAG,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACvB,CAAC;SAAM,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACpE,GAAG,GAAG,IAA+B,CAAC;IACxC,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,eAAe,CACvB,mCAAmC,KAAK,uCAAuC,EAC/E,MAAM,CACP,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,eAAe,CACvB,2BAA2B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,KAAK,8BAA8B,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EACrH,MAAM,CACP,CAAC;QACJ,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IACtB,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACnD,MAAM,IAAI,eAAe,CAAC,gCAAgC,KAAK,kCAAkC,EAAE,MAAM,CAAC,CAAC;IAC7G,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAU,EAAE,CAAC;QAC9D,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YAC9D,MAAM,IAAI,eAAe,CAAC,YAAY,IAAI,QAAQ,KAAK,sBAAsB,EAAE,MAAM,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;IACD,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC;IACxB,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;QAC/E,MAAM,IAAI,eAAe,CAAC,wBAAwB,KAAK,yCAAyC,EAAE,MAAM,CAAC,CAAC;IAC5G,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACrC,OAAO;QACL,IAAI;QACJ,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;QACjB,QAAQ,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAE,GAAG,CAAC,QAAoB;QAC3E,OAAO;QACP,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,IAAI;QAC3B,UAAU,EAAE,GAAG,KAAK,SAAS;QAC7B,OAAO,EAAE,GAA4C;QACrD,UAAU,EAAE,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC;KACrG,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,IAAY,EAAE,IAAa,EAAE,MAAc;IACjE,gBAAgB,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,eAAe,CAAC,gCAAgC,IAAI,sCAAsC,EAAE,MAAM,CAAC,CAAC;IAChH,CAAC;IACD,MAAM,WAAW,GAAI,IAAgC,CAAC,OAAO,CAAC;IAC9D,IAAI,CAAC,WAAW,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAClF,MAAM,IAAI,eAAe,CAAC,UAAU,IAAI,8BAA8B,EAAE,MAAM,CAAC,CAAC;IAClF,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,WAAsC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,CAChG,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAChD,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,eAAe,CAAC,UAAU,IAAI,uBAAuB,EAAE,MAAM,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACvE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;AAC1F,CAAC;AAED,SAAS,iBAAiB,CACxB,GAAY,EACZ,KAAa,EACb,OAA+B,EAC/B,MAAc;IAEd,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACjD,MAAM,IAAI,eAAe,CAAC,sBAAsB,KAAK,+BAA+B,EAAE,MAAM,CAAC,CAAC;IAChG,CAAC;IACD,MAAM,aAAa,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACxE,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAC7C,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QACvB,MAAM,IAAI,eAAe,CACvB,cAAc,KAAK,qBAAqB,QAAQ,mCAAmC;YACjF,kGAAkG;YAClG,8DAA8D,EAChE,MAAM,CACP,CAAC;IACJ,CAAC;IACD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC/D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,eAAe,CACvB,cAAc,KAAK,qBAAqB,QAAQ,iBAAiB,YAAY,GAAG,EAChF,MAAM,CACP,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,GAAY,EACZ,UAAkC,EAAE;IAEpC,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,IAAI,iBAAiB,CAAC;IACxD,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,eAAe,CAAC,6CAA6C,EAAE,MAAM,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,IAAI,GAAG,GAA8B,CAAC;IAC5C,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,eAAe,CACvB,oCAAoC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,yBAAyB,EACzF,MAAM,CACP,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,eAAe,CACvB,oCAAoC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,gCAAgC,EAChG,MAAM,CACP,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,eAAe,CAAC,yBAAyB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;QACnG,CAAC;IACH,CAAC;IAED,IAAI,MAAM,GAAsB,EAAE,CAAC;IACnC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAClF,MAAM,IAAI,eAAe,CAAC,yDAAyD,EAAE,MAAM,CAAC,CAAC;QAC/F,CAAC;QACD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAiC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CACnF,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CACnC,CAAC;IACJ,CAAC;IAED,uDAAuD;IACvD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,CAAC,CAAC,UAAU,CAAC;YACzB,IAAI,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC;gBACtC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;oBACzD,MAAM,IAAI,eAAe,CACvB,UAAU,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,eAAe,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAK,yBAAyB,GAAG,CAAC,MAAM,GAAG,EAC/H,MAAM,CACP,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,GAAG,GAAkB,EAAE,CAAC;IAC5B,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,eAAe,CAAC,+DAA+D,EAAE,MAAM,CAAC,CAAC;QACrG,CAAC;QACD,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,eAAe,CAAC,mDAAmD,EAAE,MAAM,CAAC,CAAC;IACzF,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,OAAO,EAAE,CAAU;QACnB,OAAO,EAAE,UAAmB;QAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QAC7B,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC;QACvB,MAAM;KACP,CAAC,CAAC;AACL,CAAC","sourcesContent":["import * as path from 'path';\nimport * as fs from 'fs';\nimport { SqlStackError } from '../../core/errors';\nimport type {\n NormalizedColumn,\n NormalizedReference,\n NormalizedTable,\n NormalizedTestSchema,\n ParseTestSchemaOptions,\n RawSqlEntry,\n} from './types';\n\nexport class TestSchemaError extends SqlStackError {\n constructor(message: string, source?: string) {\n super(source ? `${message} (schema source: ${source})` : message);\n this.name = 'TestSchemaError';\n }\n}\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nfunction assertIdentifier(kind: string, name: string, source: string): void {\n if (!IDENT.test(name)) {\n throw new TestSchemaError(\n `Invalid ${kind} name ${JSON.stringify(name)}: names must match /^[A-Za-z_][A-Za-z0-9_]*$/`,\n source\n );\n }\n}\n\nfunction parseReference(raw: unknown, where: string, source: string): NormalizedReference {\n if (typeof raw !== 'string') {\n throw new TestSchemaError(`Invalid \"references\" at ${where}: expected a string like \"table.column\"`, source);\n }\n // Accept \"table.column\" or \"table(column)\".\n let m = /^([A-Za-z_][A-Za-z0-9_]*)\\.([A-Za-z_][A-Za-z0-9_]*)$/.exec(raw);\n if (!m) m = /^([A-Za-z_][A-Za-z0-9_]*)\\(([A-Za-z_][A-Za-z0-9_]*)\\)$/.exec(raw);\n if (!m) {\n throw new TestSchemaError(\n `Invalid \"references\" syntax ${JSON.stringify(raw)} at ${where}: use \"table.column\" or \"table(column)\"`,\n source\n );\n }\n return { table: m[1]!, column: m[2]! };\n}\n\nconst COLUMN_KEYS = new Set(['type', 'nullable', 'primary', 'unique', 'default', 'references']);\n\nfunction normalizeColumn(tableName: string, name: string, decl: unknown, source: string): NormalizedColumn {\n const where = `${tableName}.${name}`;\n assertIdentifier('column', name, source);\n let obj: Record<string, unknown>;\n if (typeof decl === 'string') {\n obj = { type: decl };\n } else if (decl && typeof decl === 'object' && !Array.isArray(decl)) {\n obj = decl as Record<string, unknown>;\n } else {\n throw new TestSchemaError(\n `Malformed column declaration at ${where}: expected a type string or an object`,\n source\n );\n }\n for (const key of Object.keys(obj)) {\n if (!COLUMN_KEYS.has(key)) {\n throw new TestSchemaError(\n `Unknown column property ${JSON.stringify(key)} at ${where}: supported properties are ${[...COLUMN_KEYS].join(', ')}`,\n source\n );\n }\n }\n const type = obj.type;\n if (typeof type !== 'string' || type.trim() === '') {\n throw new TestSchemaError(`Missing or invalid \"type\" at ${where}: a non-empty string is required`, source);\n }\n for (const flag of ['nullable', 'primary', 'unique'] as const) {\n if (obj[flag] !== undefined && typeof obj[flag] !== 'boolean') {\n throw new TestSchemaError(`Invalid \"${flag}\" at ${where}: expected a boolean`, source);\n }\n }\n const def = obj.default;\n if (def !== undefined && !['string', 'number', 'boolean'].includes(typeof def)) {\n throw new TestSchemaError(`Invalid \"default\" at ${where}: expected a string, number, or boolean`, source);\n }\n const primary = obj.primary === true;\n return {\n name,\n type: type.trim(),\n nullable: obj.nullable === undefined ? !primary : (obj.nullable as boolean),\n primary,\n unique: obj.unique === true,\n hasDefault: def !== undefined,\n default: def as string | number | boolean | undefined,\n references: obj.references === undefined ? undefined : parseReference(obj.references, where, source),\n };\n}\n\nfunction normalizeTable(name: string, decl: unknown, source: string): NormalizedTable {\n assertIdentifier('table', name, source);\n if (!decl || typeof decl !== 'object' || Array.isArray(decl)) {\n throw new TestSchemaError(`Malformed table declaration \"${name}\": expected an object with \"columns\"`, source);\n }\n const columnsDecl = (decl as Record<string, unknown>).columns;\n if (!columnsDecl || typeof columnsDecl !== 'object' || Array.isArray(columnsDecl)) {\n throw new TestSchemaError(`Table \"${name}\" is missing a \"columns\" map`, source);\n }\n const columns = Object.entries(columnsDecl as Record<string, unknown>).map(([colName, colDecl]) =>\n normalizeColumn(name, colName, colDecl, source)\n );\n if (columns.length === 0) {\n throw new TestSchemaError(`Table \"${name}\" declares no columns`, source);\n }\n const primaryKey = columns.filter((c) => c.primary).map((c) => c.name);\n return { name, columns: Object.freeze(columns), primaryKey: Object.freeze(primaryKey) };\n}\n\nfunction normalizeSqlEntry(\n raw: unknown,\n index: number,\n options: ParseTestSchemaOptions,\n source: string\n): RawSqlEntry {\n if (typeof raw !== 'string' || raw.trim() === '') {\n throw new TestSchemaError(`Invalid sql entry #${index}: expected a non-empty string`, source);\n }\n const looksLikeFile = !raw.includes('\\n') && /\\.sql$/i.test(raw.trim());\n if (!looksLikeFile) {\n return { kind: 'inline', index, sql: raw };\n }\n const authored = raw.trim();\n if (!options.sourceDir) {\n throw new TestSchemaError(\n `sql entry #${index} references file \"${authored}\" but no sourceDir is available. ` +\n `Pass the schema as a file path, or provide { sourceDir } so relative .sql paths can be resolved ` +\n `(paths are never resolved against process.cwd() implicitly).`,\n source\n );\n }\n const resolvedPath = path.resolve(options.sourceDir, authored);\n if (!fs.existsSync(resolvedPath)) {\n throw new TestSchemaError(\n `sql entry #${index}: file not found: ${authored} (resolved to ${resolvedPath})`,\n source\n );\n }\n return { kind: 'file', index, sourcePath: authored, resolvedPath };\n}\n\nexport function normalizeTestSchema(\n doc: unknown,\n options: ParseTestSchemaOptions = {}\n): NormalizedTestSchema {\n const source = options.sourceLabel ?? '<inline schema>';\n if (!doc || typeof doc !== 'object' || Array.isArray(doc)) {\n throw new TestSchemaError('Test schema must be a YAML mapping / object', source);\n }\n const root = doc as Record<string, unknown>;\n if (root.version !== 1) {\n throw new TestSchemaError(\n `Unsupported test schema version: ${JSON.stringify(root.version)} (expected: version: 1)`,\n source\n );\n }\n if (root.dialect !== 'postgres') {\n throw new TestSchemaError(\n `Unsupported test schema dialect: ${JSON.stringify(root.dialect)} (expected: dialect: postgres)`,\n source\n );\n }\n for (const key of Object.keys(root)) {\n if (!['version', 'dialect', 'tables', 'sql'].includes(key)) {\n throw new TestSchemaError(`Unknown top-level key ${JSON.stringify(key)} in test schema`, source);\n }\n }\n\n let tables: NormalizedTable[] = [];\n if (root.tables !== undefined) {\n if (!root.tables || typeof root.tables !== 'object' || Array.isArray(root.tables)) {\n throw new TestSchemaError('\"tables\" must be a mapping of table name to declaration', source);\n }\n tables = Object.entries(root.tables as Record<string, unknown>).map(([name, decl]) =>\n normalizeTable(name, decl, source)\n );\n }\n\n // Validate references that point at structured tables.\n const byName = new Map(tables.map((t) => [t.name, t]));\n for (const t of tables) {\n for (const c of t.columns) {\n const ref = c.references;\n if (ref && byName.has(ref.table)) {\n const target = byName.get(ref.table)!;\n if (!target.columns.some((tc) => tc.name === ref.column)) {\n throw new TestSchemaError(\n `Column ${t.name}.${c.name} references ${ref.table}.${ref.column}, but table \"${ref.table}\" declares no column \"${ref.column}\"`,\n source\n );\n }\n }\n }\n }\n\n let sql: RawSqlEntry[] = [];\n if (root.sql !== undefined) {\n if (!Array.isArray(root.sql)) {\n throw new TestSchemaError('\"sql\" must be a list of inline SQL strings or .sql file paths', source);\n }\n sql = root.sql.map((entry, i) => normalizeSqlEntry(entry, i, options, source));\n }\n\n if (tables.length === 0 && sql.length === 0) {\n throw new TestSchemaError('Test schema declares no tables and no sql entries', source);\n }\n\n return Object.freeze({\n version: 1 as const,\n dialect: 'postgres' as const,\n tables: Object.freeze(tables),\n sql: Object.freeze(sql),\n source,\n });\n}\n"]}
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../../../src/testing/schema/normalize.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport * as fs from 'fs';\nimport { SqlStackError } from '../../core/errors';\nimport type {\n NormalizedColumn,\n NormalizedReference,\n NormalizedTable,\n NormalizedTestSchema,\n ParseTestSchemaOptions,\n RawSqlEntry,\n} from './types';\n\nexport class TestSchemaError extends SqlStackError {\n constructor(message: string, source?: string) {\n super(source ? `${message} (schema source: ${source})` : message);\n this.name = 'TestSchemaError';\n }\n}\n\nconst IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nfunction assertIdentifier(kind: string, name: string, source: string): void {\n if (!IDENT.test(name)) {\n throw new TestSchemaError(\n `Invalid ${kind} name ${JSON.stringify(name)}: names must match /^[A-Za-z_][A-Za-z0-9_]*$/`,\n source\n );\n }\n}\n\nfunction parseReference(raw: unknown, where: string, source: string): NormalizedReference {\n if (typeof raw !== 'string') {\n throw new TestSchemaError(`Invalid \"references\" at ${where}: expected a string like \"table.column\"`, source);\n }\n // Accept \"table.column\" or \"table(column)\".\n let m = /^([A-Za-z_][A-Za-z0-9_]*)\\.([A-Za-z_][A-Za-z0-9_]*)$/.exec(raw);\n if (!m) m = /^([A-Za-z_][A-Za-z0-9_]*)\\(([A-Za-z_][A-Za-z0-9_]*)\\)$/.exec(raw);\n if (!m) {\n throw new TestSchemaError(\n `Invalid \"references\" syntax ${JSON.stringify(raw)} at ${where}: use \"table.column\" or \"table(column)\"`,\n source\n );\n }\n return { table: m[1]!, column: m[2]! };\n}\n\nconst COLUMN_KEYS = new Set(['type', 'nullable', 'primary', 'unique', 'default', 'references']);\n\nfunction normalizeColumn(tableName: string, name: string, decl: unknown, source: string): NormalizedColumn {\n const where = `${tableName}.${name}`;\n assertIdentifier('column', name, source);\n let obj: Record<string, unknown>;\n if (typeof decl === 'string') {\n obj = { type: decl };\n } else if (decl && typeof decl === 'object' && !Array.isArray(decl)) {\n obj = decl as Record<string, unknown>;\n } else {\n throw new TestSchemaError(\n `Malformed column declaration at ${where}: expected a type string or an object`,\n source\n );\n }\n for (const key of Object.keys(obj)) {\n if (!COLUMN_KEYS.has(key)) {\n throw new TestSchemaError(\n `Unknown column property ${JSON.stringify(key)} at ${where}: supported properties are ${[...COLUMN_KEYS].join(', ')}`,\n source\n );\n }\n }\n const type = obj.type;\n if (typeof type !== 'string' || type.trim() === '') {\n throw new TestSchemaError(`Missing or invalid \"type\" at ${where}: a non-empty string is required`, source);\n }\n for (const flag of ['nullable', 'primary', 'unique'] as const) {\n if (obj[flag] !== undefined && typeof obj[flag] !== 'boolean') {\n throw new TestSchemaError(`Invalid \"${flag}\" at ${where}: expected a boolean`, source);\n }\n }\n const def = obj.default;\n if (def !== undefined && !['string', 'number', 'boolean'].includes(typeof def)) {\n throw new TestSchemaError(`Invalid \"default\" at ${where}: expected a string, number, or boolean`, source);\n }\n const primary = obj.primary === true;\n return {\n name,\n type: type.trim(),\n nullable: obj.nullable === undefined ? !primary : (obj.nullable as boolean),\n primary,\n unique: obj.unique === true,\n hasDefault: def !== undefined,\n default: def as string | number | boolean | undefined,\n references: obj.references === undefined ? undefined : parseReference(obj.references, where, source),\n };\n}\n\nfunction normalizeTable(name: string, decl: unknown, source: string): NormalizedTable {\n assertIdentifier('table', name, source);\n if (!decl || typeof decl !== 'object' || Array.isArray(decl)) {\n throw new TestSchemaError(`Malformed table declaration \"${name}\": expected an object with \"columns\"`, source);\n }\n const columnsDecl = (decl as Record<string, unknown>).columns;\n if (!columnsDecl || typeof columnsDecl !== 'object' || Array.isArray(columnsDecl)) {\n throw new TestSchemaError(`Table \"${name}\" is missing a \"columns\" map`, source);\n }\n const columns = Object.entries(columnsDecl as Record<string, unknown>).map(([colName, colDecl]) =>\n normalizeColumn(name, colName, colDecl, source)\n );\n if (columns.length === 0) {\n throw new TestSchemaError(`Table \"${name}\" declares no columns`, source);\n }\n const primaryKey = columns.filter((c) => c.primary).map((c) => c.name);\n return { name, columns: Object.freeze(columns), primaryKey: Object.freeze(primaryKey) };\n}\n\nfunction normalizeSqlEntry(\n raw: unknown,\n index: number,\n options: ParseTestSchemaOptions,\n source: string\n): RawSqlEntry {\n if (typeof raw !== 'string' || raw.trim() === '') {\n throw new TestSchemaError(`Invalid sql entry #${index}: expected a non-empty string`, source);\n }\n const looksLikeFile = !raw.includes('\\n') && /\\.sql$/i.test(raw.trim());\n if (!looksLikeFile) {\n return { kind: 'inline', index, sql: raw };\n }\n const authored = raw.trim();\n if (!options.sourceDir) {\n throw new TestSchemaError(\n `sql entry #${index} references file \"${authored}\" but no sourceDir is available. ` +\n `Pass the schema as a file path, or provide { sourceDir } so relative .sql paths can be resolved ` +\n `(paths are never resolved against process.cwd() implicitly).`,\n source\n );\n }\n const resolvedPath = path.resolve(options.sourceDir, authored);\n if (!fs.existsSync(resolvedPath)) {\n throw new TestSchemaError(\n `sql entry #${index}: file not found: ${authored} (resolved to ${resolvedPath})`,\n source\n );\n }\n return { kind: 'file', index, sourcePath: authored, resolvedPath };\n}\n\nexport function normalizeTestSchema(\n doc: unknown,\n options: ParseTestSchemaOptions = {}\n): NormalizedTestSchema {\n const source = options.sourceLabel ?? '<inline schema>';\n if (!doc || typeof doc !== 'object' || Array.isArray(doc)) {\n throw new TestSchemaError('Test schema must be a YAML mapping / object', source);\n }\n const root = doc as Record<string, unknown>;\n if (root.version !== 1) {\n throw new TestSchemaError(\n `Unsupported test schema version: ${JSON.stringify(root.version)} (expected: version: 1)`,\n source\n );\n }\n if (root.dialect !== 'postgres' && root.dialect !== 'sqlite') {\n throw new TestSchemaError(\n `Unsupported test schema dialect: ${JSON.stringify(root.dialect)} (expected: dialect: postgres or sqlite)`,\n source\n );\n }\n for (const key of Object.keys(root)) {\n if (!['version', 'dialect', 'tables', 'sql'].includes(key)) {\n throw new TestSchemaError(`Unknown top-level key ${JSON.stringify(key)} in test schema`, source);\n }\n }\n\n let tables: NormalizedTable[] = [];\n if (root.tables !== undefined) {\n if (!root.tables || typeof root.tables !== 'object' || Array.isArray(root.tables)) {\n throw new TestSchemaError('\"tables\" must be a mapping of table name to declaration', source);\n }\n tables = Object.entries(root.tables as Record<string, unknown>).map(([name, decl]) =>\n normalizeTable(name, decl, source)\n );\n }\n\n // Validate references that point at structured tables.\n const byName = new Map(tables.map((t) => [t.name, t]));\n for (const t of tables) {\n for (const c of t.columns) {\n const ref = c.references;\n if (ref && byName.has(ref.table)) {\n const target = byName.get(ref.table)!;\n if (!target.columns.some((tc) => tc.name === ref.column)) {\n throw new TestSchemaError(\n `Column ${t.name}.${c.name} references ${ref.table}.${ref.column}, but table \"${ref.table}\" declares no column \"${ref.column}\"`,\n source\n );\n }\n }\n }\n }\n\n let sql: RawSqlEntry[] = [];\n if (root.sql !== undefined) {\n if (!Array.isArray(root.sql)) {\n throw new TestSchemaError('\"sql\" must be a list of inline SQL strings or .sql file paths', source);\n }\n sql = root.sql.map((entry, i) => normalizeSqlEntry(entry, i, options, source));\n }\n\n if (tables.length === 0 && sql.length === 0) {\n throw new TestSchemaError('Test schema declares no tables and no sql entries', source);\n }\n\n return Object.freeze({\n version: 1 as const,\n dialect: root.dialect as 'postgres' | 'sqlite',\n tables: Object.freeze(tables),\n sql: Object.freeze(sql),\n source,\n });\n}\n"]}
@@ -1,9 +1,5 @@
1
1
  /**
2
2
  * Types for the sqlstack/testing versioned YAML test-schema.
3
- *
4
- * The structured vocabulary is intentionally small (type / nullable /
5
- * primary / unique / default / references). PostgreSQL type strings pass
6
- * through; raw SQL covers everything the vocabulary cannot express.
7
3
  */
8
4
  export {};
9
5
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/testing/schema/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * Types for the sqlstack/testing versioned YAML test-schema.\n *\n * The structured vocabulary is intentionally small (type / nullable /\n * primary / unique / default / references). PostgreSQL type strings pass\n * through; raw SQL covers everything the vocabulary cannot express.\n */\n\n/** A column declaration after shorthand expansion (scalar string => { type }). */\nexport interface TestColumnInput {\n type: string;\n nullable?: boolean;\n primary?: boolean;\n unique?: boolean;\n /** Raw SQL default expression (emitted verbatim into DDL). */\n default?: string | number | boolean;\n /** Reference target: \"table.column\" or \"table(column)\". */\n references?: string;\n}\n\nexport interface TestTableInput {\n columns: Record<string, string | TestColumnInput>;\n}\n\n/** Root YAML document shape. */\nexport interface TestSchemaInput {\n version: number;\n dialect: string;\n tables?: Record<string, TestTableInput>;\n sql?: string[];\n}\n\n/** Normalized (immutable) representations ------------------------------- */\n\nexport interface NormalizedReference {\n readonly table: string;\n readonly column: string;\n}\n\nexport interface NormalizedColumn {\n readonly name: string;\n readonly type: string;\n readonly nullable: boolean;\n readonly primary: boolean;\n readonly unique: boolean;\n readonly hasDefault: boolean;\n readonly default?: string | number | boolean;\n readonly references?: NormalizedReference;\n}\n\nexport interface NormalizedTable {\n readonly name: string;\n /** Authored column order preserved. */\n readonly columns: readonly NormalizedColumn[];\n /** Ordered declared primary-key column names. */\n readonly primaryKey: readonly string[];\n}\n\nexport type RawSqlEntry =\n | {\n readonly kind: 'inline';\n readonly index: number;\n readonly sql: string;\n }\n | {\n readonly kind: 'file';\n readonly index: number;\n /** Path as authored in the YAML. */\n readonly sourcePath: string;\n /** Absolute resolved path. */\n readonly resolvedPath: string;\n };\n\nexport interface NormalizedTestSchema {\n readonly version: 1;\n readonly dialect: 'postgres';\n /** Authored table order preserved. */\n readonly tables: readonly NormalizedTable[];\n readonly sql: readonly RawSqlEntry[];\n /** Where the schema came from, for diagnostics. */\n readonly source: string;\n}\n\nexport interface ParseTestSchemaOptions {\n /**\n * Directory used to resolve relative .sql file entries. Required when the\n * schema contains file entries and no source file path is known. Never\n * defaults to process.cwd() implicitly.\n */\n sourceDir?: string;\n /** Label used in diagnostics (e.g. the YAML file path). */\n sourceLabel?: string;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/testing/schema/types.ts"],"names":[],"mappings":"AAAA;;GAEG","sourcesContent":["/**\n * Types for the sqlstack/testing versioned YAML test-schema.\n */\n\nexport interface TestColumnInput {\n type: string;\n nullable?: boolean;\n primary?: boolean;\n unique?: boolean;\n /** Raw SQL default expression (emitted verbatim into DDL). */\n default?: string | number | boolean;\n /** Reference target: \"table.column\" or \"table(column)\". */\n references?: string;\n}\n\nexport interface TestTableInput {\n columns: Record<string, string | TestColumnInput>;\n}\n\nexport interface TestSchemaInput {\n version: number;\n dialect: string;\n tables?: Record<string, TestTableInput>;\n sql?: string[];\n}\n\nexport interface NormalizedReference {\n readonly table: string;\n readonly column: string;\n}\n\nexport interface NormalizedColumn {\n readonly name: string;\n readonly type: string;\n readonly nullable: boolean;\n readonly primary: boolean;\n readonly unique: boolean;\n readonly hasDefault: boolean;\n readonly default?: string | number | boolean;\n readonly references?: NormalizedReference;\n}\n\nexport interface NormalizedTable {\n readonly name: string;\n readonly columns: readonly NormalizedColumn[];\n readonly primaryKey: readonly string[];\n}\n\nexport type RawSqlEntry =\n | { readonly kind: 'inline'; readonly index: number; readonly sql: string }\n | {\n readonly kind: 'file';\n readonly index: number;\n readonly sourcePath: string;\n readonly resolvedPath: string;\n };\n\nexport interface NormalizedTestSchema {\n readonly version: 1;\n readonly dialect: 'postgres' | 'sqlite';\n readonly tables: readonly NormalizedTable[];\n readonly sql: readonly RawSqlEntry[];\n readonly source: string;\n}\n\nexport interface ParseTestSchemaOptions {\n sourceDir?: string;\n sourceLabel?: string;\n}\n"]}
@@ -0,0 +1,98 @@
1
+ import * as fs from 'node:fs';
2
+ import { generateDdl } from '../schema/ddl.js';
3
+ import { parseTestSchema } from '../schema/parser.js';
4
+ import { createDatabaseHandle, TestSqliteError } from './database.js';
5
+ import { composeRows, insertRows, toOperations } from './loadData.js';
6
+ function readRawSql(schema) {
7
+ return schema.sql.map((entry) => {
8
+ if (entry.kind === 'inline') {
9
+ return { label: `sql entry #${entry.index} (inline)`, sql: entry.sql };
10
+ }
11
+ try {
12
+ return {
13
+ label: `sql entry #${entry.index} (${entry.sourcePath})`,
14
+ sql: fs.readFileSync(entry.resolvedPath, 'utf8'),
15
+ };
16
+ }
17
+ catch (err) {
18
+ throw new TestSqliteError(`Cannot read raw SQL file for sql entry #${entry.index}: ${entry.resolvedPath} ` +
19
+ `(authored as "${entry.sourcePath}" in ${schema.source}): ${err.message}`);
20
+ }
21
+ });
22
+ }
23
+ async function executeRaw(handle, sql) {
24
+ const conn = handle.conn;
25
+ if (typeof conn?.exec === 'function') {
26
+ await conn.exec(sql);
27
+ }
28
+ else {
29
+ await handle.db.query(sql, []);
30
+ }
31
+ }
32
+ function makeBuilder(state) {
33
+ return {
34
+ schema: state.schema,
35
+ ops: state.ops,
36
+ data(rows) {
37
+ return makeBuilder({
38
+ ...state,
39
+ ops: [...state.ops, ...toOperations(state.schema, rows)],
40
+ });
41
+ },
42
+ async build() {
43
+ const rawSql = readRawSql(state.schema);
44
+ const ddl = generateDdl(state.schema);
45
+ const effective = composeRows(state.schema, state.ops);
46
+ const fileBacked = state.options.mode
47
+ ? state.options.mode === 'file'
48
+ : state.options.fileBacked !== false && state.options.tempFile !== false;
49
+ const handle = await createDatabaseHandle(fileBacked);
50
+ try {
51
+ for (const statement of ddl) {
52
+ try {
53
+ await handle.db.query(statement, []);
54
+ }
55
+ catch (err) {
56
+ throw new TestSqliteError(`Failed to apply structured DDL from ${state.schema.source}: ${err.message}\n` +
57
+ `Statement:\n${statement}`);
58
+ }
59
+ }
60
+ for (const entry of rawSql) {
61
+ try {
62
+ await executeRaw(handle, entry.sql);
63
+ }
64
+ catch (err) {
65
+ throw new TestSqliteError(`Failed to apply raw ${entry.label} from ${state.schema.source}: ${err.message}`);
66
+ }
67
+ }
68
+ await insertRows((sql, params) => handle.db.query(sql, params), state.schema, effective);
69
+ return handle;
70
+ }
71
+ catch (err) {
72
+ await handle.dispose();
73
+ throw err;
74
+ }
75
+ },
76
+ };
77
+ }
78
+ export function testSqlite(schema, options = {}) {
79
+ const normalized = isNormalizedSchema(schema)
80
+ ? schema
81
+ : parseTestSchema(schema, options);
82
+ if (normalized.dialect !== 'sqlite') {
83
+ throw new TestSqliteError(`testSqlite requires a schema with dialect: sqlite (received: ${normalized.dialect})`);
84
+ }
85
+ return makeBuilder({
86
+ schema: normalized,
87
+ ops: [],
88
+ options: Object.freeze({ ...options }),
89
+ });
90
+ }
91
+ function isNormalizedSchema(input) {
92
+ return (!!input &&
93
+ typeof input === 'object' &&
94
+ Array.isArray(input.tables) &&
95
+ Array.isArray(input.sql) &&
96
+ typeof input.source === 'string');
97
+ }
98
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../../../../src/testing/sqlite/builder.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport { generateDdl } from '../schema/ddl';\nimport { parseTestSchema } from '../schema/parser';\nimport type { NormalizedTestSchema, ParseTestSchemaOptions } from '../schema/types';\nimport { createDatabaseHandle, TestSqliteDatabase, TestSqliteError } from './database';\nimport { composeRows, DataOperation, insertRows, Row, toOperations } from './loadData';\n\nexport interface TestSqliteOptions extends ParseTestSchemaOptions {\n /**\n * Storage for the test database. Defaults to `'file'`: an owned temporary\n * file, removed on `dispose()`. Pass `'memory'` to opt back into an isolated\n * `:memory:` database — only worth it for a test that opens many databases\n * and never touches restart behavior.\n */\n mode?: 'memory' | 'file';\n /** Legacy alias for `mode`. `false` selects `:memory:`. */\n fileBacked?: boolean;\n /** Legacy alias for `mode`. `false` selects `:memory:`. */\n tempFile?: boolean;\n}\n\nexport interface TestSqliteBuilder {\n readonly schema: NormalizedTestSchema;\n readonly ops: readonly DataOperation[];\n data(rows: Record<string, Row[]>): TestSqliteBuilder;\n build(): Promise<TestSqliteDatabase>;\n}\n\ninterface BuilderState {\n readonly schema: NormalizedTestSchema;\n readonly ops: readonly DataOperation[];\n readonly options: Readonly<TestSqliteOptions>;\n}\n\nfunction readRawSql(schema: NormalizedTestSchema): { label: string; sql: string }[] {\n return schema.sql.map((entry) => {\n if (entry.kind === 'inline') {\n return { label: `sql entry #${entry.index} (inline)`, sql: entry.sql };\n }\n try {\n return {\n label: `sql entry #${entry.index} (${entry.sourcePath})`,\n sql: fs.readFileSync(entry.resolvedPath, 'utf8'),\n };\n } catch (err) {\n throw new TestSqliteError(\n `Cannot read raw SQL file for sql entry #${entry.index}: ${entry.resolvedPath} ` +\n `(authored as \"${entry.sourcePath}\" in ${schema.source}): ${(err as Error).message}`\n );\n }\n });\n}\n\nasync function executeRaw(handle: TestSqliteDatabase, sql: string): Promise<void> {\n const conn = handle.conn as { exec?: (sql: string) => unknown };\n if (typeof conn?.exec === 'function') {\n await conn.exec(sql);\n } else {\n await handle.db.query(sql, []);\n }\n}\n\nfunction makeBuilder(state: BuilderState): TestSqliteBuilder {\n return {\n schema: state.schema,\n ops: state.ops,\n data(rows: Record<string, Row[]>): TestSqliteBuilder {\n return makeBuilder({\n ...state,\n ops: [...state.ops, ...toOperations(state.schema, rows)],\n });\n },\n async build(): Promise<TestSqliteDatabase> {\n const rawSql = readRawSql(state.schema);\n const ddl = generateDdl(state.schema);\n const effective = composeRows(state.schema, state.ops);\n const fileBacked = state.options.mode\n ? state.options.mode === 'file'\n : state.options.fileBacked !== false && state.options.tempFile !== false;\n const handle = await createDatabaseHandle(fileBacked);\n try {\n for (const statement of ddl) {\n try {\n await handle.db.query(statement, []);\n } catch (err) {\n throw new TestSqliteError(\n `Failed to apply structured DDL from ${state.schema.source}: ${(err as Error).message}\\n` +\n `Statement:\\n${statement}`\n );\n }\n }\n for (const entry of rawSql) {\n try {\n await executeRaw(handle, entry.sql);\n } catch (err) {\n throw new TestSqliteError(\n `Failed to apply raw ${entry.label} from ${state.schema.source}: ${(err as Error).message}`\n );\n }\n }\n await insertRows((sql, params) => handle.db.query(sql, params), state.schema, effective);\n return handle;\n } catch (err) {\n await handle.dispose();\n throw err;\n }\n },\n };\n}\n\nexport function testSqlite(\n schema: string | object,\n options: TestSqliteOptions = {}\n): TestSqliteBuilder {\n const normalized = isNormalizedSchema(schema)\n ? schema\n : parseTestSchema(schema as string | object, options);\n if (normalized.dialect !== 'sqlite') {\n throw new TestSqliteError(\n `testSqlite requires a schema with dialect: sqlite (received: ${normalized.dialect})`\n );\n }\n return makeBuilder({\n schema: normalized,\n ops: [],\n options: Object.freeze({ ...options }),\n });\n}\n\nfunction isNormalizedSchema(input: unknown): input is NormalizedTestSchema {\n return (\n !!input &&\n typeof input === 'object' &&\n Array.isArray((input as NormalizedTestSchema).tables) &&\n Array.isArray((input as NormalizedTestSchema).sql) &&\n typeof (input as NormalizedTestSchema).source === 'string'\n );\n}\n"]}