@creative-introvert/tons-of-tests 0.9.0 → 1.0.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 (103) hide show
  1. package/README.md +78 -12
  2. package/dist/cjs/Classify.js +33 -2
  3. package/dist/cjs/Classify.js.map +1 -1
  4. package/dist/cjs/RepositoryError.js +45 -0
  5. package/dist/cjs/RepositoryError.js.map +1 -0
  6. package/dist/cjs/Test.js +2 -1
  7. package/dist/cjs/Test.js.map +1 -1
  8. package/dist/cjs/Test.repository.js +32 -6
  9. package/dist/cjs/Test.repository.js.map +1 -1
  10. package/dist/cjs/Test.repository.types.js +14 -0
  11. package/dist/cjs/Test.repository.types.js.map +1 -0
  12. package/dist/cjs/index.js +1 -1
  13. package/dist/cjs/internal/Classify.js +4 -32
  14. package/dist/cjs/internal/Classify.js.map +1 -1
  15. package/dist/cjs/internal/Classify.spec.js +223 -0
  16. package/dist/cjs/internal/Classify.spec.js.map +1 -0
  17. package/dist/cjs/internal/Test.js +61 -29
  18. package/dist/cjs/internal/Test.js.map +1 -1
  19. package/dist/cjs/internal/Test.repository.sqlite.js +172 -121
  20. package/dist/cjs/internal/Test.repository.sqlite.js.map +1 -1
  21. package/dist/cjs/internal/Test.repository.sqlite.spec.js +263 -170
  22. package/dist/cjs/internal/Test.repository.sqlite.spec.js.map +1 -1
  23. package/dist/cjs/internal/Test.spec.js +205 -0
  24. package/dist/cjs/internal/Test.spec.js.map +1 -0
  25. package/dist/cjs/internal/format-diff.spec.js +22 -16
  26. package/dist/cjs/internal/format-diff.spec.js.map +1 -1
  27. package/dist/cjs/internal/summarize.js.map +1 -1
  28. package/dist/cjs/pack.js.map +1 -1
  29. package/dist/dts/Classify.d.ts +58 -24
  30. package/dist/dts/Classify.d.ts.map +1 -1
  31. package/dist/dts/Error.d.ts +1 -1
  32. package/dist/dts/RepositoryError.d.ts +40 -0
  33. package/dist/dts/RepositoryError.d.ts.map +1 -0
  34. package/dist/dts/Test.d.ts +8 -1
  35. package/dist/dts/Test.d.ts.map +1 -1
  36. package/dist/dts/Test.repository.d.ts +11 -55
  37. package/dist/dts/Test.repository.d.ts.map +1 -1
  38. package/dist/dts/Test.repository.types.d.ts +66 -0
  39. package/dist/dts/Test.repository.types.d.ts.map +1 -0
  40. package/dist/dts/index.d.ts +1 -1
  41. package/dist/dts/index.d.ts.map +1 -1
  42. package/dist/dts/internal/Classify.d.ts +14 -23
  43. package/dist/dts/internal/Classify.d.ts.map +1 -1
  44. package/dist/dts/internal/Classify.spec.d.ts +2 -0
  45. package/dist/dts/internal/Classify.spec.d.ts.map +1 -0
  46. package/dist/dts/internal/Test.d.ts +3 -3
  47. package/dist/dts/internal/Test.d.ts.map +1 -1
  48. package/dist/dts/internal/Test.repository.sqlite.d.ts +9 -12
  49. package/dist/dts/internal/Test.repository.sqlite.d.ts.map +1 -1
  50. package/dist/dts/internal/Test.spec.d.ts +2 -0
  51. package/dist/dts/internal/Test.spec.d.ts.map +1 -0
  52. package/dist/dts/internal/common.d.ts +1 -1
  53. package/dist/dts/internal/common.d.ts.map +1 -1
  54. package/dist/dts/internal/diff.d.ts.map +1 -1
  55. package/dist/dts/internal/format-diff.d.ts.map +1 -1
  56. package/dist/dts/internal/lib/Schema.d.ts.map +1 -1
  57. package/dist/dts/internal/lib/jsondiffpatch/contexts/context.d.ts.map +1 -1
  58. package/dist/dts/internal/lib/jsondiffpatch/contexts/diff.d.ts.map +1 -1
  59. package/dist/dts/internal/lib/jsondiffpatch/contexts/patch.d.ts.map +1 -1
  60. package/dist/dts/internal/lib/jsondiffpatch/contexts/reverse.d.ts.map +1 -1
  61. package/dist/dts/internal/lib/jsondiffpatch/diffpatcher.d.ts.map +1 -1
  62. package/dist/dts/internal/lib/jsondiffpatch/filters/lcs.d.ts.map +1 -1
  63. package/dist/dts/internal/lib/jsondiffpatch/formatters/annotated.d.ts.map +1 -1
  64. package/dist/dts/internal/lib/jsondiffpatch/formatters/base.d.ts +1 -1
  65. package/dist/dts/internal/lib/jsondiffpatch/formatters/base.d.ts.map +1 -1
  66. package/dist/dts/internal/lib/jsondiffpatch/formatters/html.d.ts.map +1 -1
  67. package/dist/dts/internal/lib/jsondiffpatch/formatters/jsonpatch.d.ts.map +1 -1
  68. package/dist/dts/internal/lib/jsondiffpatch/pipe.d.ts.map +1 -1
  69. package/dist/dts/internal/lib/jsondiffpatch/processor.d.ts +1 -1
  70. package/dist/dts/internal/lib/jsondiffpatch/processor.d.ts.map +1 -1
  71. package/dist/dts/internal/pack.d.ts.map +1 -1
  72. package/dist/dts/internal/stats.d.ts +1 -1
  73. package/dist/dts/internal/stats.d.ts.map +1 -1
  74. package/dist/dts/internal/summarize.d.ts +2 -2
  75. package/dist/dts/internal/summarize.d.ts.map +1 -1
  76. package/dist/esm/Classify.js +33 -2
  77. package/dist/esm/Classify.js.map +1 -1
  78. package/dist/esm/RepositoryError.js +45 -0
  79. package/dist/esm/RepositoryError.js.map +1 -0
  80. package/dist/esm/Test.js +2 -1
  81. package/dist/esm/Test.js.map +1 -1
  82. package/dist/esm/Test.repository.js +32 -6
  83. package/dist/esm/Test.repository.js.map +1 -1
  84. package/dist/esm/Test.repository.types.js +14 -0
  85. package/dist/esm/Test.repository.types.js.map +1 -0
  86. package/dist/esm/index.js +1 -1
  87. package/dist/esm/internal/Classify.js +4 -32
  88. package/dist/esm/internal/Classify.js.map +1 -1
  89. package/dist/esm/internal/Classify.spec.js +204 -0
  90. package/dist/esm/internal/Classify.spec.js.map +1 -0
  91. package/dist/esm/internal/Test.js +61 -29
  92. package/dist/esm/internal/Test.js.map +1 -1
  93. package/dist/esm/internal/Test.repository.sqlite.js +172 -121
  94. package/dist/esm/internal/Test.repository.sqlite.js.map +1 -1
  95. package/dist/esm/internal/Test.repository.sqlite.spec.js +263 -170
  96. package/dist/esm/internal/Test.repository.sqlite.spec.js.map +1 -1
  97. package/dist/esm/internal/Test.spec.js +186 -0
  98. package/dist/esm/internal/Test.spec.js.map +1 -0
  99. package/dist/esm/internal/format-diff.spec.js +22 -16
  100. package/dist/esm/internal/format-diff.spec.js.map +1 -1
  101. package/dist/esm/internal/summarize.js.map +1 -1
  102. package/dist/esm/pack.js.map +1 -1
  103. package/package.json +7 -7
@@ -7,7 +7,8 @@ exports.test = exports.runCollectRecord = exports.makeSha256 = exports.diff = ex
7
7
  var _nodeCrypto = /*#__PURE__*/require("node:crypto");
8
8
  var _nodePerf_hooks = /*#__PURE__*/require("node:perf_hooks");
9
9
  var _effect = /*#__PURE__*/require("effect");
10
- var _Classify = /*#__PURE__*/require("./Classify.js");
10
+ var _Classify = /*#__PURE__*/require("../Classify.js");
11
+ var _Classify2 = /*#__PURE__*/require("./Classify.js");
11
12
  const makeSha256 = input => {
12
13
  return (0, _nodeCrypto.createHash)('sha256').update(JSON.stringify(input)).digest('hex');
13
14
  };
@@ -47,7 +48,7 @@ const TestResultSchema = exports.TestResultSchema = /*#__PURE__*/_effect.Schema.
47
48
  input: _effect.Schema.Unknown,
48
49
  result: _effect.Schema.Unknown,
49
50
  expected: _effect.Schema.Unknown,
50
- label: _Classify.LabelSchema,
51
+ label: _Classify2.LabelSchema,
51
52
  tags: /*#__PURE__*/_effect.Schema.Array(_effect.Schema.String),
52
53
  timeMillis: _effect.Schema.Number
53
54
  });
@@ -87,8 +88,8 @@ exports.test = test;
87
88
  const all = ({
88
89
  testCases,
89
90
  program,
90
- classify = (0, _Classify.makeClassify)({
91
- isEqual: _Classify.defaultIsEqual
91
+ classify = (0, _Classify2.makeClassify)({
92
+ isEqual: _Classify2.defaultIsEqual
92
93
  })
93
94
  }, {
94
95
  concurrency
@@ -111,33 +112,64 @@ _effect.Array.map(testCases, ({
111
112
  }), _effect.Stream.tap(testResult => {
112
113
  const i = testResult.ordering + 1;
113
114
  const total = testCases.length;
114
- const n = Math.floor(i % Math.max(total * 0.05, 10));
115
- if (i === 1 || n === 0 || i === total) {
116
- const s = `PROGRESS: ${i}/${total}\r`;
117
- if (process.env.NODE_ENV === 'development') {
118
- process.stdout.write(s);
119
- } else {
120
- return _effect.Console.log(s);
121
- }
122
- }
123
- return _effect.Effect.void;
115
+ const stride = Math.max(Math.floor(total * 0.05), 10);
116
+ const isMilestone = i === 1 || i === total || i % stride === 0;
117
+ return isMilestone ? _effect.Effect.logInfo(`progress ${i}/${total}`) : _effect.Effect.void;
124
118
  }));
125
119
  exports.all = all;
126
- const runCollectRecord = testRun => testResults$ => testResults$.pipe(_effect.Stream.runFold(TestRunResults.emptyFromTestRun(testRun), (run, result) => {
127
- run.testResultsByTestCaseHash[result.hashTestCase] = result;
128
- run.testCaseHashes.push(result.hashTestCase);
129
- run.stats[result.label]++;
130
- return run;
131
- }), _effect.Effect.map(run => {
132
- run.stats.precision = (0, _Classify.precision)(run.stats);
133
- run.stats.recall = (0, _Classify.recall)(run.stats);
134
- const times = run.testCaseHashes.map(hash => run.testResultsByTestCaseHash[hash].timeMillis);
135
- run.stats.timeMean = _effect.Option.some(times.reduce((mean, n) => mean + n, 0) / times.length);
136
- run.stats.timeMax = _effect.Option.some(times.reduce((max, n) => Math.max(max, n), 0));
137
- run.stats.timeMin = _effect.Option.some(times.reduce((min, n) => Math.min(min, n), Number.POSITIVE_INFINITY));
138
- run.stats.timeMedian = (0, _Classify.median)(times);
139
- run.stats.total = run.testCaseHashes.length;
140
- return run;
120
+ const emptyAcc = () => ({
121
+ testResultsByTestCaseHash: {},
122
+ testCaseHashes: [],
123
+ times: [],
124
+ TP: 0,
125
+ TN: 0,
126
+ FP: 0,
127
+ FN: 0,
128
+ timeSum: 0,
129
+ timeMin: Number.POSITIVE_INFINITY,
130
+ timeMax: Number.NEGATIVE_INFINITY
131
+ });
132
+ const runCollectRecord = testRun => testResults$ => testResults$.pipe(_effect.Stream.run(
133
+ // Sink.foldLeft threads the accumulator by reference within a
134
+ // single fiber, so mutating in place is safe and avoids
135
+ // rebuilding the object per element.
136
+ _effect.Sink.foldLeft(emptyAcc(), (acc, r) => {
137
+ acc.testResultsByTestCaseHash[r.hashTestCase] = r;
138
+ acc.testCaseHashes.push(r.hashTestCase);
139
+ acc.times.push(r.timeMillis);
140
+ acc.timeSum += r.timeMillis;
141
+ if (r.timeMillis < acc.timeMin) acc.timeMin = r.timeMillis;
142
+ if (r.timeMillis > acc.timeMax) acc.timeMax = r.timeMillis;
143
+ if (r.label === 'TP') acc.TP++;else if (r.label === 'TN') acc.TN++;else if (r.label === 'FP') acc.FP++;else acc.FN++;
144
+ return acc;
145
+ })), _effect.Effect.map(acc => {
146
+ const total = acc.testCaseHashes.length;
147
+ const hasTimes = acc.times.length > 0;
148
+ const stats = new _Classify.Stats({
149
+ TP: acc.TP,
150
+ TN: acc.TN,
151
+ FP: acc.FP,
152
+ FN: acc.FN,
153
+ total,
154
+ precision: (0, _Classify2.precision)({
155
+ TP: acc.TP,
156
+ FP: acc.FP
157
+ }),
158
+ recall: (0, _Classify2.recall)({
159
+ TP: acc.TP,
160
+ FN: acc.FN
161
+ }),
162
+ timeMean: hasTimes ? _effect.Option.some(acc.timeSum / acc.times.length) : _effect.Option.none(),
163
+ timeMin: hasTimes ? _effect.Option.some(acc.timeMin) : _effect.Option.none(),
164
+ timeMax: hasTimes ? _effect.Option.some(acc.timeMax) : _effect.Option.none(),
165
+ timeMedian: (0, _Classify2.median)(acc.times)
166
+ });
167
+ return {
168
+ ...testRun,
169
+ testResultsByTestCaseHash: acc.testResultsByTestCaseHash,
170
+ testCaseHashes: acc.testCaseHashes,
171
+ stats
172
+ };
141
173
  }));
142
174
  exports.runCollectRecord = runCollectRecord;
143
175
  const diff = ({
@@ -1 +1 @@
1
- {"version":3,"file":"Test.js","names":["_nodeCrypto","require","_nodePerf_hooks","_effect","_Classify","makeSha256","input","createHash","update","JSON","stringify","digest","exports","TestResult","make","args","label","result","expected","id","hashTestCase","TestResultSchema","Schema","Struct","String","ordering","Int","Unknown","LabelSchema","tags","Array","timeMillis","Number","TestRunResults","emptyFromTestRun","testResultsByTestCaseHash","testCaseHashes","stats","Stats","empty","test","testCase","program","classify","t0","performance","now","pipe","Effect","map","t1","all","testCases","makeClassify","isEqual","defaultIsEqual","concurrency","A","_","Stream","fromIterable","mapEffect","unordered","tap","testResult","i","total","length","n","Math","floor","max","s","process","env","NODE_ENV","stdout","write","Console","log","void","runCollectRecord","testRun","testResults$","runFold","run","push","precision","recall","times","hash","timeMean","Option","some","reduce","mean","timeMax","timeMin","min","POSITIVE_INFINITY","timeMedian","median","diff","previousTestRun","match","onNone","onSome","previousStats","TP","TN","FP","FN"],"sources":["../../../src/internal/Test.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"Test.js","names":["_nodeCrypto","require","_nodePerf_hooks","_effect","_Classify","_Classify2","makeSha256","input","createHash","update","JSON","stringify","digest","exports","TestResult","make","args","label","result","expected","id","hashTestCase","TestResultSchema","Schema","Struct","String","ordering","Int","Unknown","LabelSchema","tags","Array","timeMillis","Number","TestRunResults","emptyFromTestRun","testResultsByTestCaseHash","testCaseHashes","stats","Stats","empty","test","testCase","program","classify","t0","performance","now","pipe","Effect","map","t1","all","testCases","makeClassify","isEqual","defaultIsEqual","concurrency","A","_","Stream","fromIterable","mapEffect","unordered","tap","testResult","i","total","length","stride","Math","max","floor","isMilestone","logInfo","void","emptyAcc","times","TP","TN","FP","FN","timeSum","timeMin","POSITIVE_INFINITY","timeMax","NEGATIVE_INFINITY","runCollectRecord","testRun","testResults$","run","Sink","foldLeft","acc","r","push","hasTimes","precision","recall","timeMean","Option","some","none","timeMedian","median","diff","previousTestRun","match","onNone","onSome","previousStats"],"sources":["../../../src/internal/Test.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -3,10 +3,18 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.tables = exports.makeSqliteLiveLayer = exports.TestRepository = exports.SqliteTestLayer = exports.LiveLayer = void 0;
7
- var Sql = /*#__PURE__*/_interopRequireWildcard(/*#__PURE__*/require("@effect/sql"));
8
- var Sqlite = /*#__PURE__*/_interopRequireWildcard(/*#__PURE__*/require("@effect/sql-sqlite-node"));
6
+ Object.defineProperty(exports, "TestRepository", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _TestRepository.TestRepository;
10
+ }
11
+ });
12
+ exports.tables = exports.makeTestRepository = void 0;
13
+ var SqlClient = /*#__PURE__*/_interopRequireWildcard(/*#__PURE__*/require("@effect/sql/SqlClient"));
9
14
  var _effect = /*#__PURE__*/require("effect");
15
+ var _TestRepository = /*#__PURE__*/require("../Test.repository.js");
16
+ var _TestRepositoryTypes = /*#__PURE__*/require("../Test.repository.types.js");
17
+ var _RepositoryError = /*#__PURE__*/require("../RepositoryError.js");
10
18
  var _Classify = /*#__PURE__*/require("./Classify.js");
11
19
  var _Schema = /*#__PURE__*/require("./lib/Schema.js");
12
20
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
@@ -26,13 +34,7 @@ const TestResultWriteSchema = /*#__PURE__*/_effect.Schema.Struct({
26
34
  tags: /*#__PURE__*/(0, _Schema.split)(','),
27
35
  timeMillis: _effect.Schema.Number
28
36
  });
29
- const TestResultsSchema = /*#__PURE__*/TestResultWriteSchema.pipe(_effect.Schema.Array);
30
- const TestRunReadSchema = /*#__PURE__*/_effect.Schema.Struct({
31
- id: _effect.Schema.Int,
32
- name: _effect.Schema.String,
33
- // TODO: Is this a hash, or uuid?
34
- hash: /*#__PURE__*/_effect.Schema.String.pipe(_effect.Schema.NullOr)
35
- });
37
+ const TestResultsSchema = /*#__PURE__*/_effect.Schema.Array(TestResultWriteSchema);
36
38
  const CountSchema = /*#__PURE__*/_effect.Schema.Tuple(_effect.Schema.Struct({
37
39
  count: _effect.Schema.Int
38
40
  })).pipe(/*#__PURE__*/_effect.Schema.transform(_effect.Schema.Int, {
@@ -43,29 +45,29 @@ const CountSchema = /*#__PURE__*/_effect.Schema.Tuple(_effect.Schema.Struct({
43
45
  count
44
46
  }]
45
47
  }));
46
- const TestRunsReadSchema = /*#__PURE__*/TestRunReadSchema.pipe(_effect.Schema.Array);
47
- const CurrentTestRunSchema = /*#__PURE__*/_effect.Schema.Tuple(TestRunReadSchema).pipe(/*#__PURE__*/_effect.Schema.transform(TestRunReadSchema, {
48
- encode: _ => [_],
49
- decode: ([_]) => _
50
- }));
51
- const TestRunResultsSchema = /*#__PURE__*/_effect.Schema.Struct({
48
+ const TestRunsReadSchema = /*#__PURE__*/_effect.Schema.Array(_TestRepositoryTypes.TestRun);
49
+ const TestRunResultsSchema = /*#__PURE__*/_effect.Schema.Array(/*#__PURE__*/_effect.Schema.Struct({
52
50
  testRun: _effect.Schema.Int,
53
51
  testResult: _effect.Schema.String
54
- }).pipe(_effect.Schema.Array);
55
- // FIXME: Effect.tag
56
- const TestRepository = exports.TestRepository = /*#__PURE__*/_effect.Context.GenericTag('TestRunRepository');
57
- const makeTestRepository = /*#__PURE__*/_effect.Effect.gen(function* () {
58
- const sql = yield* Sql.SqlClient.SqlClient;
52
+ }));
53
+ const makeTestRepository = exports.makeTestRepository = /*#__PURE__*/_effect.Effect.gen(function* () {
54
+ const sql = yield* SqlClient.SqlClient;
59
55
  yield* sql`PRAGMA auto_vacuum = FULL;`;
60
56
  yield* sql`
61
57
  CREATE TABLE IF NOT EXISTS ${sql(tables.testRuns)}(
62
58
  id INTEGER PRIMARY KEY AUTOINCREMENT,
63
59
  name TEXT NOT NULL,
64
- hash TEXT,
65
- UNIQUE (id, name, hash)
60
+ hash TEXT
66
61
  );
67
62
  `;
68
63
  yield* sql`CREATE INDEX IF NOT EXISTS idx_name_hash ON ${sql(tables.testRuns)}(name, hash)`;
64
+ // At most one "current" (hash IS NULL) row per suite name. Partial index
65
+ // so committed rows are unaffected.
66
+ yield* sql`
67
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_current_per_name
68
+ ON ${sql(tables.testRuns)}(name)
69
+ WHERE hash IS NULL;
70
+ `;
69
71
  yield* sql`
70
72
  CREATE TABLE IF NOT EXISTS ${sql(tables.testResults)}(
71
73
  id TEXT PRIMARY KEY,
@@ -88,42 +90,82 @@ const makeTestRepository = /*#__PURE__*/_effect.Effect.gen(function* () {
88
90
  UNIQUE (testRun, testResult)
89
91
  );
90
92
  `;
91
- /** Assumes that a `TestRun` with hash=null exists. */
92
- const insertTestResult = (testResult, name) => sql.withTransaction(_effect.Effect.gen(function* () {
93
- const encoded = yield* _effect.Schema.encode(TestResultWriteSchema)(testResult);
94
- yield* sql`
95
- INSERT INTO ${sql(tables.testResults)}
96
- ${sql.insert(encoded)}
97
- ON CONFLICT(id) DO NOTHING;
98
- `;
99
- yield* sql`
100
- INSERT INTO ${sql(tables.testRunResults)}
101
- VALUES (
102
- (
103
- SELECT id FROM ${sql(tables.testRuns)}
104
- WHERE hash IS NULL AND name = ${name}
105
- ),
106
- ${encoded.id}
107
- )
108
- ON CONFLICT(testRun, testResult) DO NOTHING;
109
- `;
110
- }));
111
- const getTestResultsStream = testRun => _effect.Effect.gen(function* () {
112
- const raw = yield* sql`
113
- SELECT res.* FROM ${sql(tables.testResults)} res
114
- JOIN ${sql(tables.testRunResults)} runres ON res.id = runres.testResult
115
- JOIN ${sql(tables.testRuns)} runs ON runs.id = runres.testRun
116
- WHERE runs.id = ${testRun.id}
117
- ORDER BY ordering ASC;
118
- `;
119
- return yield* _effect.Schema.decode(TestResultsSchema)(raw);
120
- }).pipe(_effect.Stream.fromIterableEffect);
93
+ // Lookup by the junction's `testResult` column: the existing
94
+ // UNIQUE(testRun, testResult) index is keyed on testRun first, so orphan
95
+ // cleanup (`... NOT IN (SELECT testResult ...)`) and stream joins
96
+ // (`res.id = runres.testResult`) would otherwise full-scan the junction.
97
+ yield* sql`CREATE INDEX IF NOT EXISTS idx_trr_testresult ON ${sql(tables.testRunResults)}(testResult)`;
98
+ yield* sql`CREATE INDEX IF NOT EXISTS idx_tr_hashtestcase ON ${sql(tables.testResults)}(hashTestCase)`;
99
+ // SQLite's default SQLITE_MAX_VARIABLE_NUMBER is 999; testResults has 9
100
+ // columns and junction rows 2, so 50 rows stays well under the limit.
101
+ const INSERT_BATCH_SIZE = 50;
102
+ const insertTestResults = (testResults, testRun) => sql.withTransaction(_effect.Effect.gen(function* () {
103
+ if (testResults.length === 0) return;
104
+ const encoded = yield* _effect.Effect.forEach(testResults, _ => _effect.Schema.encode(TestResultWriteSchema)(_).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('insertTestResults'))));
105
+ for (let i = 0; i < encoded.length; i += INSERT_BATCH_SIZE) {
106
+ const chunk = encoded.slice(i, i + INSERT_BATCH_SIZE);
107
+ yield* sql`
108
+ INSERT INTO ${sql(tables.testResults)}
109
+ ${sql.insert(chunk)}
110
+ ON CONFLICT(id) DO NOTHING;
111
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryWriteError.from('insertTestResults')));
112
+ }
113
+ // Junction rows reference the resolved testRun.id directly,
114
+ // so no correlated subquery.
115
+ const junction = encoded.map(_ => ({
116
+ testRun: testRun.id,
117
+ testResult: _.id
118
+ }));
119
+ for (let i = 0; i < junction.length; i += INSERT_BATCH_SIZE) {
120
+ const chunk = junction.slice(i, i + INSERT_BATCH_SIZE);
121
+ yield* sql`
122
+ INSERT INTO ${sql(tables.testRunResults)}
123
+ ${sql.insert(chunk)}
124
+ ON CONFLICT(testRun, testResult) DO NOTHING;
125
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryWriteError.from('insertTestResults')));
126
+ }
127
+ })).pipe(_effect.Effect.catchTag('SqlError', e => _effect.Effect.fail(_RepositoryError.RepositoryWriteError.from('insertTestResults')(e))));
128
+ const insertTestResult = (testResult, testRun) => insertTestResults([testResult], testRun);
129
+ const makeTestResultSchema = schemas => {
130
+ const input = schemas?.input ?? _effect.Schema.Unknown;
131
+ const result = schemas?.result ?? _effect.Schema.Unknown;
132
+ const expected = schemas?.expected ?? _effect.Schema.Unknown;
133
+ return _effect.Schema.Struct({
134
+ id: _effect.Schema.String,
135
+ hashTestCase: _effect.Schema.String,
136
+ ordering: _effect.Schema.Int,
137
+ input: _effect.Schema.parseJson(input),
138
+ result: _effect.Schema.parseJson(result),
139
+ expected: _effect.Schema.parseJson(expected),
140
+ label: _Classify.LabelSchema,
141
+ tags: (0, _Schema.split)(','),
142
+ timeMillis: _effect.Schema.Number
143
+ });
144
+ };
145
+ const getTestResultsStream = (testRun, schemas) => {
146
+ const RowSchema = makeTestResultSchema(schemas);
147
+ const RowsSchema = _effect.Schema.Array(RowSchema);
148
+ // better-sqlite3 is synchronous and doesn't expose a cursor, so the
149
+ // full result set is materialised before emission. Decoding once in
150
+ // bulk avoids fiber-per-row overhead from `Stream.mapEffect`.
151
+ return _effect.Stream.unwrap(_effect.Effect.gen(function* () {
152
+ const rows = yield* sql`
153
+ SELECT res.* FROM ${sql(tables.testResults)} res
154
+ JOIN ${sql(tables.testRunResults)} runres ON res.id = runres.testResult
155
+ JOIN ${sql(tables.testRuns)} runs ON runs.id = runres.testRun
156
+ WHERE runs.id = ${testRun.id}
157
+ ORDER BY ordering ASC;
158
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('getTestResultsStream')));
159
+ const decoded = yield* _effect.Schema.decodeUnknown(RowsSchema)(rows).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getTestResultsStream')));
160
+ return _effect.Stream.fromIterable(decoded);
161
+ }));
162
+ };
121
163
  const hasResults = testRun => _effect.Effect.gen(function* () {
122
164
  const b = yield* sql`
123
165
  SELECT COUNT(*) count FROM ${sql(tables.testRunResults)}
124
166
  WHERE testRun = ${testRun.id};
125
- `;
126
- const r = yield* _effect.Schema.decodeUnknown(CountSchema)(b);
167
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('hasResults')));
168
+ const r = yield* _effect.Schema.decodeUnknown(CountSchema)(b).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('hasResults')));
127
169
  return r > 0;
128
170
  });
129
171
  const getPreviousTestRun = name => _effect.Effect.gen(function* () {
@@ -132,66 +174,75 @@ const makeTestRepository = /*#__PURE__*/_effect.Effect.gen(function* () {
132
174
  WHERE hash IS NOT NULL AND name = ${name}
133
175
  ORDER BY id DESC
134
176
  LIMIT 1;
135
- `;
136
- const p = yield* _effect.Schema.decode(TestRunsReadSchema)(r);
177
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('getPreviousTestRun')));
178
+ const p = yield* _effect.Schema.decodeUnknown(TestRunsReadSchema)(r).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getPreviousTestRun')));
137
179
  return _effect.Array.head(p);
138
180
  });
139
181
  const getAllTestRuns = _effect.Effect.gen(function* () {
140
182
  const results = yield* sql`
141
- SELECT * from ${sql(tables.testRuns)};
142
- `;
143
- return yield* _effect.Schema.decode(TestRunsReadSchema)(results);
183
+ SELECT * from ${sql(tables.testRuns)};
184
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('getAllTestRuns')));
185
+ return yield* _effect.Schema.decodeUnknown(TestRunsReadSchema)(results).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getAllTestRuns')));
144
186
  });
145
187
  const getAllTestRunResults = _effect.Effect.gen(function* () {
146
188
  const results = yield* sql`
147
- SELECT * from ${sql(tables.testRunResults)};
148
- `;
149
- return yield* _effect.Schema.decode(TestRunResultsSchema)(results);
189
+ SELECT * from ${sql(tables.testRunResults)};
190
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('getAllTestRunResults')));
191
+ return yield* _effect.Schema.decodeUnknown(TestRunResultsSchema)(results).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getAllTestRunResults')));
150
192
  });
151
193
  const getAllTestResults = _effect.Effect.gen(function* () {
152
194
  const results = yield* sql`
153
- SELECT * from ${sql(tables.testResults)};
154
- `;
155
- return yield* _effect.Schema.decode(TestResultsSchema)(results);
195
+ SELECT * from ${sql(tables.testResults)};
196
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('getAllTestResults')));
197
+ return yield* _effect.Schema.decodeUnknown(TestResultsSchema)(results).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getAllTestResults')));
156
198
  });
157
- const getLastTestRunHash = name => _effect.Effect.gen(function* () {
158
- const current = yield* sql`
159
- SELECT *
160
- FROM ${sql(tables.testRuns)}
161
- WHERE hash IS NOT NULL AND name = ${name}
162
- ORDER BY id DESC
163
- LIMIT 1;
164
- `;
165
- return current;
166
- }).pipe(_effect.Effect.map((0, _effect.flow)(_effect.Array.get(0), _effect.Option.flatMap(_ => _effect.Option.fromNullable(_.hash)))));
167
- const getOrCreateCurrentTestRun = name => _effect.Effect.gen(function* () {
168
- const current = yield* sql`
169
- SELECT *
170
- FROM ${sql(tables.testRuns)}
171
- WHERE hash IS NULL AND name = ${name};
172
- `;
173
- if (current.length === 0) {
174
- return yield* sql`
199
+ const getLastTestRunHash = name => sql`
200
+ SELECT *
201
+ FROM ${sql(tables.testRuns)}
202
+ WHERE hash IS NOT NULL AND name = ${name}
203
+ ORDER BY id DESC
204
+ LIMIT 1;
205
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('getLastTestRunHash')), _effect.Effect.map((0, _effect.flow)(_effect.Array.get(0), _effect.Option.flatMap(_ => _effect.Option.fromNullable(_.hash)))));
206
+ const getOrCreateCurrentTestRun = name => sql.withTransaction(_effect.Effect.gen(function* () {
207
+ const currentRaw = yield* sql`
208
+ SELECT *
209
+ FROM ${sql(tables.testRuns)}
210
+ WHERE hash IS NULL AND name = ${name}
211
+ ORDER BY id DESC
212
+ LIMIT 1;
213
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('getOrCreateCurrentTestRun')));
214
+ const current = yield* _effect.Schema.decodeUnknown(TestRunsReadSchema)(currentRaw).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getOrCreateCurrentTestRun')));
215
+ const existing = _effect.Array.head(current);
216
+ if (_effect.Option.isSome(existing)) {
217
+ return existing.value;
218
+ }
219
+ const insertedRaw = yield* sql`
175
220
  INSERT INTO ${sql(tables.testRuns)}
176
221
  ${sql.insert({
177
- name
178
- })}
222
+ name
223
+ })}
179
224
  RETURNING *;
180
- `;
181
- }
182
- return current;
183
- }).pipe(_effect.Effect.map((0, _effect.flow)(_effect.Array.head, _effect.Option.getOrThrow)));
225
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryWriteError.from('getOrCreateCurrentTestRun')));
226
+ const inserted = yield* _effect.Schema.decodeUnknown(TestRunsReadSchema)(insertedRaw).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('getOrCreateCurrentTestRun')));
227
+ return yield* _effect.Array.head(inserted).pipe(_effect.Option.match({
228
+ onNone: () => _effect.Effect.fail(new _RepositoryError.TestRunNotCreated({
229
+ name
230
+ })),
231
+ onSome: _effect.Effect.succeed
232
+ }));
233
+ })).pipe(_effect.Effect.catchTag('SqlError', e => _effect.Effect.fail(_RepositoryError.RepositoryQueryError.fromSql('getOrCreateCurrentTestRun')(e))));
184
234
  const clearStale = ({
185
235
  name,
186
236
  keep = 1
187
237
  }) => sql.withTransaction(_effect.Effect.gen(function* () {
188
- const staleTestRuns = yield* _effect.Schema.decode(TestRunsReadSchema)(yield* sql`
189
- SELECT *
190
- FROM ${sql(tables.testRuns)}
191
- WHERE hash IS NOT NULL AND name = ${name}
192
- ORDER BY id DESC
193
- LIMIT -1 OFFSET ${keep};
194
- `);
238
+ const raw = yield* sql`
239
+ SELECT *
240
+ FROM ${sql(tables.testRuns)}
241
+ WHERE hash IS NOT NULL AND name = ${name}
242
+ ORDER BY id DESC
243
+ LIMIT -1 OFFSET ${keep};
244
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('clearStale')));
245
+ const staleTestRuns = yield* _effect.Schema.decodeUnknown(TestRunsReadSchema)(raw).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('clearStale')));
195
246
  if (staleTestRuns.length === 0) {
196
247
  return;
197
248
  }
@@ -199,38 +250,45 @@ const makeTestRepository = /*#__PURE__*/_effect.Effect.gen(function* () {
199
250
  yield* sql`
200
251
  DELETE FROM ${sql(tables.testRunResults)}
201
252
  WHERE testRun IN ${sql.in(ids)};
202
- `;
253
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryWriteError.from('clearStale')));
203
254
  yield* sql`
204
255
  DELETE FROM ${sql(tables.testRuns)}
205
256
  WHERE id IN ${sql.in(ids)};
206
- `;
257
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryWriteError.from('clearStale')));
207
258
  yield* sql`
208
259
  DELETE FROM ${sql(tables.testResults)}
209
260
  WHERE id NOT IN (
210
261
  SELECT DISTINCT testResult FROM ${sql(tables.testRunResults)}
211
262
  );
212
- `;
263
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryWriteError.from('clearStale')));
213
264
  yield* _effect.Console.log('Cleared stale test runs.');
214
- }));
265
+ })).pipe(_effect.Effect.catchTag('SqlError', e => _effect.Effect.fail(_RepositoryError.RepositoryWriteError.from('clearStale')(e))));
215
266
  const clearUncommitedTestResults = ({
216
267
  name
217
268
  }) => sql.withTransaction(_effect.Effect.gen(function* () {
218
- const currentTestRun = yield* _effect.Schema.decodeUnknown(CurrentTestRunSchema)(yield* sql`
219
- SELECT *
220
- FROM ${sql(tables.testRuns)}
221
- WHERE hash IS NULL AND name = ${name};
222
- `);
269
+ const currentRaw = yield* sql`
270
+ SELECT *
271
+ FROM ${sql(tables.testRuns)}
272
+ WHERE hash IS NULL AND name = ${name}
273
+ ORDER BY id DESC
274
+ LIMIT 1;
275
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('clearUncommitedTestResults')));
276
+ const current = yield* _effect.Schema.decodeUnknown(TestRunsReadSchema)(currentRaw).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('clearUncommitedTestResults')));
277
+ const currentTestRun = _effect.Array.head(current);
278
+ if (_effect.Option.isNone(currentTestRun)) {
279
+ return;
280
+ }
223
281
  yield* sql`
224
282
  DELETE FROM ${sql(tables.testRunResults)}
225
- WHERE testRun = ${currentTestRun.id};
226
- `;
283
+ WHERE testRun = ${currentTestRun.value.id};
284
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryWriteError.from('clearUncommitedTestResults')));
227
285
  yield* sql`
228
286
  DELETE FROM ${sql(tables.testResults)}
229
287
  WHERE id NOT IN (
230
288
  SELECT DISTINCT testResult FROM ${sql(tables.testRunResults)}
231
289
  );
232
- `;
233
- }));
290
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryWriteError.from('clearUncommitedTestResults')));
291
+ })).pipe(_effect.Effect.catchTag('SqlError', e => _effect.Effect.fail(_RepositoryError.RepositoryWriteError.from('clearUncommitedTestResults')(e))));
234
292
  const commitCurrentTestRun = ({
235
293
  name,
236
294
  hash
@@ -242,7 +300,7 @@ const makeTestRepository = /*#__PURE__*/_effect.Effect.gen(function* () {
242
300
  FROM ${sql(tables.testRuns)}
243
301
  WHERE hash IS NULL AND name = ${name}
244
302
  );
245
- `);
303
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryQueryError.fromSql('commitCurrentTestRun')))).pipe(_effect.Effect.mapError(_RepositoryError.RepositoryDecodeError.from('commitCurrentTestRun')));
246
304
  if (currentTestRunResults === 0) {
247
305
  yield* _effect.Console.log('Current run has no test results, not commiting.');
248
306
  return;
@@ -255,13 +313,13 @@ const makeTestRepository = /*#__PURE__*/_effect.Effect.gen(function* () {
255
313
  FROM ${sql(tables.testRuns)}
256
314
  WHERE hash IS NULL AND name = ${name}
257
315
  );
258
- `;
316
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryWriteError.from('commitCurrentTestRun')));
259
317
  yield* sql`
260
318
  INSERT INTO ${sql(tables.testRuns)}
261
319
  ${sql.insert({
262
320
  name
263
321
  })};
264
- `;
322
+ `.pipe(_effect.Effect.mapError(_RepositoryError.RepositoryWriteError.from('commitCurrentTestRun')));
265
323
  yield* _effect.Console.log('Commited test run.');
266
324
  });
267
325
  const service = {
@@ -276,16 +334,9 @@ const makeTestRepository = /*#__PURE__*/_effect.Effect.gen(function* () {
276
334
  getTestResultsStream,
277
335
  hasResults,
278
336
  insertTestResult,
337
+ insertTestResults,
279
338
  getAllTestRunResults
280
339
  };
281
340
  return service;
282
341
  });
283
- const LiveLayer = exports.LiveLayer = /*#__PURE__*/_effect.Layer.effect(TestRepository, makeTestRepository);
284
- const makeSqliteLiveLayer = dbPath => Sqlite.SqliteClient.layer({
285
- filename: dbPath
286
- });
287
- exports.makeSqliteLiveLayer = makeSqliteLiveLayer;
288
- const SqliteTestLayer = exports.SqliteTestLayer = /*#__PURE__*/Sqlite.SqliteClient.layer({
289
- filename: ':memory:'
290
- });
291
342
  //# sourceMappingURL=Test.repository.sqlite.js.map