@reventlessdev/reventless-seed 1.0.0-alpha.2 → 1.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/lib/bs/.compiler.log +2 -2
- package/lib/bs/compiler-info.json +1 -1
- package/lib/bs/src/Seed-ReventlessSeed.cmi +0 -0
- package/lib/bs/src/Seed-ReventlessSeed.cmt +0 -0
- package/lib/bs/src/Seed.ast +0 -0
- package/lib/bs/src/Seed.res +1 -0
- package/lib/bs/src/Seed_Runner-ReventlessSeed.cmi +0 -0
- package/lib/bs/src/Seed_Runner-ReventlessSeed.cmj +0 -0
- package/lib/bs/src/Seed_Runner-ReventlessSeed.cmt +0 -0
- package/lib/bs/src/Seed_Runner.ast +0 -0
- package/lib/bs/src/Seed_Runner.res +33 -0
- package/lib/bs/src/Seed_Runner.res.mjs +18 -0
- package/lib/ocaml/.compiler.log +2 -2
- package/lib/ocaml/Seed-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed.ast +0 -0
- package/lib/ocaml/Seed.res +1 -0
- package/lib/ocaml/Seed_Runner-ReventlessSeed.cmi +0 -0
- package/lib/ocaml/Seed_Runner-ReventlessSeed.cmj +0 -0
- package/lib/ocaml/Seed_Runner-ReventlessSeed.cmt +0 -0
- package/lib/ocaml/Seed_Runner.ast +0 -0
- package/lib/ocaml/Seed_Runner.res +33 -0
- package/package.json +1 -1
- package/src/Seed.res +1 -0
- package/src/Seed_Runner.res +33 -0
- package/src/Seed_Runner.res.mjs +18 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 1.0.0-alpha.3 (2026-07-27)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **seed:** refuse to seed onto a non-empty store (fresh-store guard) ([987613f](https://github.com/ReventlessDev/reventless-core/commit/987613f0767fc4391297dfeed3a6b19cd76d8157))
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
# 1.0.0-alpha.2 (2026-07-26)
|
|
7
14
|
|
|
8
15
|
### Features
|
package/lib/bs/.compiler.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
#Start(
|
|
2
|
-
#Done(
|
|
1
|
+
#Start(1785139469133)
|
|
2
|
+
#Done(1785139473598)
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
"bsc_hash": "75e3a59c95cc953608fd3dd6ea6ed68141bba4414a20a52f114261b8a48385fa",
|
|
5
5
|
"rescript_config_hash": "ad3a9d479584c1d6e4fe10cd993d9e290f74732e9b0cb3dd5d7429e88b4bba38",
|
|
6
6
|
"runtime_path": "/home/runner/work/reventless-core/reventless-core/node_modules/@rescript/runtime",
|
|
7
|
-
"generated_at": "
|
|
7
|
+
"generated_at": "1785139473607"
|
|
8
8
|
}
|
|
Binary file
|
|
Binary file
|
package/lib/bs/src/Seed.ast
CHANGED
|
Binary file
|
package/lib/bs/src/Seed.res
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -90,6 +90,33 @@ let warn = (warnings: array<string>): unit =>
|
|
|
90
90
|
warnings->Array.forEach(w => Console.log(` - ${w}`))
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Pre-flight: refuse to seed onto a store that already holds data.
|
|
95
|
+
*
|
|
96
|
+
* The harness is a one-shot against a fresh store — a re-run would hit the
|
|
97
|
+
* domain's own duplicate rejections (`CategoryAlreadyExists`, …) and abort
|
|
98
|
+
* mid-phase. Catching it here, before any command is sent, turns that into an
|
|
99
|
+
* honest "nothing was written" startup abort instead of a misleading
|
|
100
|
+
* half-seeded one. It is the inverse of `verifyViews`: seeding refuses to start
|
|
101
|
+
* unless the store reads empty. Stops at the first non-empty probe view, so a
|
|
102
|
+
* populated store aborts after a single query.
|
|
103
|
+
*/
|
|
104
|
+
let assertStoreEmpty = async (client: Seed_Client.t, ~probeViews: array<string>): unit =>
|
|
105
|
+
for i in 0 to probeViews->Array.length - 1 {
|
|
106
|
+
switch probeViews->Array.get(i) {
|
|
107
|
+
| Some(name) =>
|
|
108
|
+
let count = await Seed_Client.countNodes(client, ~field=name)
|
|
109
|
+
if count > 0 {
|
|
110
|
+
throw(
|
|
111
|
+
Failed(
|
|
112
|
+
`the target store is not empty — "${name}" already holds ${count->Int.toString} row(s). Seeding is a one-shot against a fresh store; reset the store before re-running.`,
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
| None => ()
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
93
120
|
/**
|
|
94
121
|
* Wraps a seed run. On failure it prints the cause and exits non-zero, saying
|
|
95
122
|
* plainly that the store is now half-seeded — recovery is a reset, not a re-run.
|
|
@@ -128,6 +155,9 @@ type dataSet = {
|
|
|
128
155
|
name: string,
|
|
129
156
|
label: string,
|
|
130
157
|
seed: Seed_Connect.connection => promise<unit>,
|
|
158
|
+
// View names probed by the fresh-store guard before any command is sent; a
|
|
159
|
+
// non-empty one aborts the run at startup. Omit to skip the guard.
|
|
160
|
+
probeViews?: array<string>,
|
|
131
161
|
}
|
|
132
162
|
|
|
133
163
|
/**
|
|
@@ -179,6 +209,9 @@ let seed = (~sets: array<dataSet>, ~connect: unit => promise<Seed_Connect.connec
|
|
|
179
209
|
}
|
|
180
210
|
let connection = await connect()
|
|
181
211
|
Seed_Prompt.close()
|
|
212
|
+
// Runs inside this pre-seed `try`, so refusing a non-empty store (or a
|
|
213
|
+
// failed probe query) is reported as "did not start", not "half-seeded".
|
|
214
|
+
await assertStoreEmpty(connection.client, ~probeViews=chosen.probeViews->Option.getOr([]))
|
|
182
215
|
Some((chosen, connection))
|
|
183
216
|
} catch {
|
|
184
217
|
| Failed(message) =>
|
|
@@ -83,6 +83,22 @@ function warn(warnings) {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
async function assertStoreEmpty(client, probeViews) {
|
|
87
|
+
for (let i = 0, i_finish = probeViews.length; i < i_finish; ++i) {
|
|
88
|
+
let name = probeViews[i];
|
|
89
|
+
if (name !== undefined) {
|
|
90
|
+
let count = await Seed_Client$ReventlessSeed.countNodes(client, name);
|
|
91
|
+
if (count > 0) {
|
|
92
|
+
throw {
|
|
93
|
+
RE_EXN_ID: Seed_Types$ReventlessSeed.Failed,
|
|
94
|
+
_1: `the target store is not empty — "` + name + `" already holds ` + count.toString() + ` row(s). Seeding is a one-shot against a fresh store; reset the store before re-running.`,
|
|
95
|
+
Error: new Error()
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
86
102
|
async function run(main) {
|
|
87
103
|
try {
|
|
88
104
|
await main();
|
|
@@ -146,6 +162,7 @@ function seed(sets, connect) {
|
|
|
146
162
|
}
|
|
147
163
|
let connection = await connect();
|
|
148
164
|
Seed_Prompt$ReventlessSeed.close();
|
|
165
|
+
await assertStoreEmpty(connection.client, Stdlib_Option.getOr(chosen.probeViews, []));
|
|
149
166
|
started = [
|
|
150
167
|
chosen,
|
|
151
168
|
connection
|
|
@@ -179,6 +196,7 @@ export {
|
|
|
179
196
|
verifyViews,
|
|
180
197
|
unfillableWarnings,
|
|
181
198
|
warn,
|
|
199
|
+
assertStoreEmpty,
|
|
182
200
|
run,
|
|
183
201
|
abortStartup,
|
|
184
202
|
seed,
|
package/lib/ocaml/.compiler.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
#Start(
|
|
2
|
-
#Done(
|
|
1
|
+
#Start(1785139469133)
|
|
2
|
+
#Done(1785139473598)
|
|
Binary file
|
|
Binary file
|
package/lib/ocaml/Seed.ast
CHANGED
|
Binary file
|
package/lib/ocaml/Seed.res
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -90,6 +90,33 @@ let warn = (warnings: array<string>): unit =>
|
|
|
90
90
|
warnings->Array.forEach(w => Console.log(` - ${w}`))
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Pre-flight: refuse to seed onto a store that already holds data.
|
|
95
|
+
*
|
|
96
|
+
* The harness is a one-shot against a fresh store — a re-run would hit the
|
|
97
|
+
* domain's own duplicate rejections (`CategoryAlreadyExists`, …) and abort
|
|
98
|
+
* mid-phase. Catching it here, before any command is sent, turns that into an
|
|
99
|
+
* honest "nothing was written" startup abort instead of a misleading
|
|
100
|
+
* half-seeded one. It is the inverse of `verifyViews`: seeding refuses to start
|
|
101
|
+
* unless the store reads empty. Stops at the first non-empty probe view, so a
|
|
102
|
+
* populated store aborts after a single query.
|
|
103
|
+
*/
|
|
104
|
+
let assertStoreEmpty = async (client: Seed_Client.t, ~probeViews: array<string>): unit =>
|
|
105
|
+
for i in 0 to probeViews->Array.length - 1 {
|
|
106
|
+
switch probeViews->Array.get(i) {
|
|
107
|
+
| Some(name) =>
|
|
108
|
+
let count = await Seed_Client.countNodes(client, ~field=name)
|
|
109
|
+
if count > 0 {
|
|
110
|
+
throw(
|
|
111
|
+
Failed(
|
|
112
|
+
`the target store is not empty — "${name}" already holds ${count->Int.toString} row(s). Seeding is a one-shot against a fresh store; reset the store before re-running.`,
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
| None => ()
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
93
120
|
/**
|
|
94
121
|
* Wraps a seed run. On failure it prints the cause and exits non-zero, saying
|
|
95
122
|
* plainly that the store is now half-seeded — recovery is a reset, not a re-run.
|
|
@@ -128,6 +155,9 @@ type dataSet = {
|
|
|
128
155
|
name: string,
|
|
129
156
|
label: string,
|
|
130
157
|
seed: Seed_Connect.connection => promise<unit>,
|
|
158
|
+
// View names probed by the fresh-store guard before any command is sent; a
|
|
159
|
+
// non-empty one aborts the run at startup. Omit to skip the guard.
|
|
160
|
+
probeViews?: array<string>,
|
|
131
161
|
}
|
|
132
162
|
|
|
133
163
|
/**
|
|
@@ -179,6 +209,9 @@ let seed = (~sets: array<dataSet>, ~connect: unit => promise<Seed_Connect.connec
|
|
|
179
209
|
}
|
|
180
210
|
let connection = await connect()
|
|
181
211
|
Seed_Prompt.close()
|
|
212
|
+
// Runs inside this pre-seed `try`, so refusing a non-empty store (or a
|
|
213
|
+
// failed probe query) is reported as "did not start", not "half-seeded".
|
|
214
|
+
await assertStoreEmpty(connection.client, ~probeViews=chosen.probeViews->Option.getOr([]))
|
|
182
215
|
Some((chosen, connection))
|
|
183
216
|
} catch {
|
|
184
217
|
| Failed(message) =>
|
package/package.json
CHANGED
package/src/Seed.res
CHANGED
package/src/Seed_Runner.res
CHANGED
|
@@ -90,6 +90,33 @@ let warn = (warnings: array<string>): unit =>
|
|
|
90
90
|
warnings->Array.forEach(w => Console.log(` - ${w}`))
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Pre-flight: refuse to seed onto a store that already holds data.
|
|
95
|
+
*
|
|
96
|
+
* The harness is a one-shot against a fresh store — a re-run would hit the
|
|
97
|
+
* domain's own duplicate rejections (`CategoryAlreadyExists`, …) and abort
|
|
98
|
+
* mid-phase. Catching it here, before any command is sent, turns that into an
|
|
99
|
+
* honest "nothing was written" startup abort instead of a misleading
|
|
100
|
+
* half-seeded one. It is the inverse of `verifyViews`: seeding refuses to start
|
|
101
|
+
* unless the store reads empty. Stops at the first non-empty probe view, so a
|
|
102
|
+
* populated store aborts after a single query.
|
|
103
|
+
*/
|
|
104
|
+
let assertStoreEmpty = async (client: Seed_Client.t, ~probeViews: array<string>): unit =>
|
|
105
|
+
for i in 0 to probeViews->Array.length - 1 {
|
|
106
|
+
switch probeViews->Array.get(i) {
|
|
107
|
+
| Some(name) =>
|
|
108
|
+
let count = await Seed_Client.countNodes(client, ~field=name)
|
|
109
|
+
if count > 0 {
|
|
110
|
+
throw(
|
|
111
|
+
Failed(
|
|
112
|
+
`the target store is not empty — "${name}" already holds ${count->Int.toString} row(s). Seeding is a one-shot against a fresh store; reset the store before re-running.`,
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
| None => ()
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
93
120
|
/**
|
|
94
121
|
* Wraps a seed run. On failure it prints the cause and exits non-zero, saying
|
|
95
122
|
* plainly that the store is now half-seeded — recovery is a reset, not a re-run.
|
|
@@ -128,6 +155,9 @@ type dataSet = {
|
|
|
128
155
|
name: string,
|
|
129
156
|
label: string,
|
|
130
157
|
seed: Seed_Connect.connection => promise<unit>,
|
|
158
|
+
// View names probed by the fresh-store guard before any command is sent; a
|
|
159
|
+
// non-empty one aborts the run at startup. Omit to skip the guard.
|
|
160
|
+
probeViews?: array<string>,
|
|
131
161
|
}
|
|
132
162
|
|
|
133
163
|
/**
|
|
@@ -179,6 +209,9 @@ let seed = (~sets: array<dataSet>, ~connect: unit => promise<Seed_Connect.connec
|
|
|
179
209
|
}
|
|
180
210
|
let connection = await connect()
|
|
181
211
|
Seed_Prompt.close()
|
|
212
|
+
// Runs inside this pre-seed `try`, so refusing a non-empty store (or a
|
|
213
|
+
// failed probe query) is reported as "did not start", not "half-seeded".
|
|
214
|
+
await assertStoreEmpty(connection.client, ~probeViews=chosen.probeViews->Option.getOr([]))
|
|
182
215
|
Some((chosen, connection))
|
|
183
216
|
} catch {
|
|
184
217
|
| Failed(message) =>
|
package/src/Seed_Runner.res.mjs
CHANGED
|
@@ -83,6 +83,22 @@ function warn(warnings) {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
async function assertStoreEmpty(client, probeViews) {
|
|
87
|
+
for (let i = 0, i_finish = probeViews.length; i < i_finish; ++i) {
|
|
88
|
+
let name = probeViews[i];
|
|
89
|
+
if (name !== undefined) {
|
|
90
|
+
let count = await Seed_Client$ReventlessSeed.countNodes(client, name);
|
|
91
|
+
if (count > 0) {
|
|
92
|
+
throw {
|
|
93
|
+
RE_EXN_ID: Seed_Types$ReventlessSeed.Failed,
|
|
94
|
+
_1: `the target store is not empty — "` + name + `" already holds ` + count.toString() + ` row(s). Seeding is a one-shot against a fresh store; reset the store before re-running.`,
|
|
95
|
+
Error: new Error()
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
86
102
|
async function run(main) {
|
|
87
103
|
try {
|
|
88
104
|
await main();
|
|
@@ -146,6 +162,7 @@ function seed(sets, connect) {
|
|
|
146
162
|
}
|
|
147
163
|
let connection = await connect();
|
|
148
164
|
Seed_Prompt$ReventlessSeed.close();
|
|
165
|
+
await assertStoreEmpty(connection.client, Stdlib_Option.getOr(chosen.probeViews, []));
|
|
149
166
|
started = [
|
|
150
167
|
chosen,
|
|
151
168
|
connection
|
|
@@ -179,6 +196,7 @@ export {
|
|
|
179
196
|
verifyViews,
|
|
180
197
|
unfillableWarnings,
|
|
181
198
|
warn,
|
|
199
|
+
assertStoreEmpty,
|
|
182
200
|
run,
|
|
183
201
|
abortStartup,
|
|
184
202
|
seed,
|