@byline/db-mysql 4.8.0 → 4.9.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.
- package/README.md +23 -50
- package/dist/database/schema/auth.js +1 -1
- package/dist/database/schema/common.js +1 -1
- package/dist/database/schema/index.js +5 -5
- package/dist/index.d.ts +1 -1
- package/dist/modules/audit/audit-commands.d.ts +1 -1
- package/dist/modules/audit/audit-queries.d.ts +1 -1
- package/dist/modules/storage/storage-commands.d.ts +2 -2
- package/dist/modules/storage/storage-commands.js +4 -4
- package/dist/modules/storage/storage-queries.d.ts +1 -1
- package/dist/modules/storage/storage-queries.js +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -4,14 +4,12 @@
|
|
|
4
4
|
> exercised, not because MySQL is a fully supported Byline backend yet. The
|
|
5
5
|
> storage layer is complete and proven — it passes the entire shared
|
|
6
6
|
> `@byline/db-conformance` behavioural suite, the same suite `@byline/db-postgres`
|
|
7
|
-
> passes, with identical results.
|
|
7
|
+
> passes, with identical results. Search is also implemented; the remaining
|
|
8
|
+
> limitations are in tooling and breadth of environment coverage:
|
|
8
9
|
>
|
|
9
|
-
> - **
|
|
10
|
-
>
|
|
11
|
-
>
|
|
12
|
-
> [Search on MySQL](#search-on-mysql) below for the one-step workaround you will
|
|
13
|
-
> need. Tracked in
|
|
14
|
-
> [#52](https://github.com/Byline-CMS/bylinecms.dev/issues/52).
|
|
10
|
+
> - **Search is available.** `@byline/search-mysql` implements the same
|
|
11
|
+
> provider contract and conformance suite as the built-in PostgreSQL search
|
|
12
|
+
> driver. It owns an independent, disposable migration stream.
|
|
15
13
|
> - **No CLI support.** `byline init` scaffolds a Postgres installation; wiring
|
|
16
14
|
> MySQL is a manual edit to your `server.config.ts`.
|
|
17
15
|
> - **Narrower CI coverage than Postgres.** Continuous integration pins MySQL 8.0
|
|
@@ -19,8 +17,8 @@
|
|
|
19
17
|
> runs under a non-UTC timezone. Tracked in
|
|
20
18
|
> [#55](https://github.com/Byline-CMS/bylinecms.dev/issues/55).
|
|
21
19
|
>
|
|
22
|
-
> Treat it as suitable for evaluation, prototypes, and installations
|
|
23
|
-
>
|
|
20
|
+
> Treat it as suitable for evaluation, prototypes, and controlled installations.
|
|
21
|
+
> The criteria for general availability are tracked in
|
|
24
22
|
> [#58](https://github.com/Byline-CMS/bylinecms.dev/issues/58).
|
|
25
23
|
|
|
26
24
|
MySQL adapter for Byline CMS — Drizzle schema, migrations, and the storage /
|
|
@@ -198,12 +196,10 @@ databases, and a few divergences are real rather than papered over.
|
|
|
198
196
|
are meaning-bearing in some scripts (a Thai tone mark, a Devanagari
|
|
199
197
|
anusvara, Hebrew niqqud) are never silently folded together the way
|
|
200
198
|
`ai_ci` would fold them.
|
|
201
|
-
- **
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
[the `@byline/search-mysql` follow-up issue](https://github.com/Byline-CMS/bylinecms.dev/issues/52)
|
|
206
|
-
for status.
|
|
199
|
+
- **Search uses a dialect-specific provider.** Register
|
|
200
|
+
`@byline/search-mysql` with this adapter. It implements the same portable
|
|
201
|
+
lexical and weighting contract as `@byline/search-postgres`, while owning its
|
|
202
|
+
own MySQL `FULLTEXT` schema and migrations.
|
|
207
203
|
- **The connection string is the only connection input.** See "Usage"
|
|
208
204
|
above — this is called out here too because it is the most common way
|
|
209
205
|
this adapter is misconfigured by a reader coming from the Postgres
|
|
@@ -218,56 +214,33 @@ databases, and a few divergences are real rather than papered over.
|
|
|
218
214
|
|
|
219
215
|
## Search on MySQL
|
|
220
216
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
**throws** when any collection declares a `search` block but no provider is
|
|
224
|
-
registered. Byline's own reference application opts five collections into
|
|
225
|
-
search, so a MySQL installation that copies it fails at boot with an error that
|
|
226
|
-
does not mention MySQL at all.
|
|
227
|
-
|
|
228
|
-
Until `@byline/search-mysql` exists, register a no-op provider. It satisfies
|
|
229
|
-
validation, and indexing and querying become silent no-ops rather than errors —
|
|
230
|
-
the admin Reindex action and any search page return nothing, which is the honest
|
|
231
|
-
answer on this adapter today:
|
|
217
|
+
Register `@byline/search-mysql` with the adapter's existing promise pool. Apply
|
|
218
|
+
the provider's independent migration stream before serving traffic:
|
|
232
219
|
|
|
233
220
|
```ts
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
typoTolerance: false,
|
|
238
|
-
semantic: false,
|
|
239
|
-
bm25: false,
|
|
240
|
-
weighting: false,
|
|
241
|
-
highlights: false,
|
|
242
|
-
},
|
|
243
|
-
async upsert() {},
|
|
244
|
-
async remove() {},
|
|
245
|
-
async search() {
|
|
246
|
-
return { hits: [], total: 0 }
|
|
247
|
-
},
|
|
248
|
-
}
|
|
221
|
+
import { migrate, mysqlSearch } from '@byline/search-mysql'
|
|
222
|
+
|
|
223
|
+
await migrate(db.pool)
|
|
249
224
|
|
|
250
225
|
await initBylineCore({
|
|
251
226
|
// …
|
|
252
227
|
db,
|
|
253
|
-
search:
|
|
228
|
+
search: mysqlSearch({ pool: db.pool, defaultLocale }),
|
|
254
229
|
})
|
|
255
230
|
```
|
|
256
231
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
232
|
+
Search rows are a disposable projection of published versions. The provider
|
|
233
|
+
uses parser-safe portable terms, weighted MySQL `FULLTEXT` indexes, and analyzer
|
|
234
|
+
fingerprints. Its package README documents migrations, capabilities, and the
|
|
235
|
+
clear-and-rebuild procedure.
|
|
261
236
|
|
|
262
237
|
## Not yet shipped
|
|
263
238
|
|
|
264
|
-
- **`@byline/search-mysql`** — see [Search on MySQL](#search-on-mysql) above.
|
|
265
|
-
Tracked in [issue #52](https://github.com/Byline-CMS/bylinecms.dev/issues/52).
|
|
266
239
|
- **CLI support.** `byline init` scaffolds a Postgres installation. Adding MySQL
|
|
267
240
|
to an existing project is a manual edit to `byline/server.config.ts` — swap
|
|
268
241
|
`pgAdapter` for `mysqlAdapter`, swap the `@byline/db-postgres/admin` import for
|
|
269
|
-
`@byline/db-mysql/admin`,
|
|
270
|
-
|
|
242
|
+
`@byline/db-mysql/admin`, and swap `postgresSearch` for `mysqlSearch`. Both
|
|
243
|
+
search packages expose the same `migrate(pool)` shape.
|
|
271
244
|
- **A MySQL storage-benchmark target.** The design spec flags view
|
|
272
245
|
materialisation (the `ROW_NUMBER()` window inside a derived table, used
|
|
273
246
|
by both current-version views) as a question to answer before this
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* to 1; bumped by write paths when needed).
|
|
21
21
|
* - snake_case column names matching the rest of the Byline schema.
|
|
22
22
|
*
|
|
23
|
-
* See docs/
|
|
23
|
+
* See docs/07-auth-and-security/01-authn-authz.md for the full data model and present-state
|
|
24
24
|
* reference.
|
|
25
25
|
*/
|
|
26
26
|
import { relations, sql } from 'drizzle-orm';
|
|
@@ -86,7 +86,7 @@ export const varcharCaseSensitive = customType({
|
|
|
86
86
|
* same tick and receive an *identical* `CURRENT_TIMESTAMP(3)` value, which
|
|
87
87
|
* is a real correctness gap for anything that orders or windows by these
|
|
88
88
|
* columns (found via `packages/db-conformance`'s audit activity-feed
|
|
89
|
-
* fixture — see docs/
|
|
89
|
+
* fixture — see docs/10-testing.md and the Task 11 report for the
|
|
90
90
|
* live-server evidence: four rapid statements produced 2 distinct values at
|
|
91
91
|
* fsp 3 versus 4 distinct values at fsp 6). Matching pg's precision closes
|
|
92
92
|
* that gap at the source instead of asking every fixture/consumer to work
|
|
@@ -168,7 +168,7 @@ export const documentPaths = mysqlTable('byline_document_paths', {
|
|
|
168
168
|
// carries forward across edits and survives restore. Surfaced on reads as
|
|
169
169
|
// `availableLocales`; the public advertised set is the intersection with the
|
|
170
170
|
// ledger's `_availableVersionLocales`. Replaced wholesale on write (the lifecycle
|
|
171
|
-
// deletes then re-inserts the set), never appended. See docs/
|
|
171
|
+
// deletes then re-inserts the set), never appended. See docs/08-internationalization/index.md.
|
|
172
172
|
export const documentAvailableLocales = mysqlTable('byline_document_available_locales', {
|
|
173
173
|
document_id: uuidChar('document_id').notNull(),
|
|
174
174
|
locale: varchar('locale', { length: 10 }).notNull(),
|
|
@@ -198,7 +198,7 @@ export const documentAvailableLocales = mysqlTable('byline_document_available_lo
|
|
|
198
198
|
// identically in any locale). Computed status-blind at write time and frozen
|
|
199
199
|
// on the immutable version, so restore / point-in-time reads stay consistent.
|
|
200
200
|
// Drives `localeFallback: 'strict'` reads via an indexed EXISTS gate without
|
|
201
|
-
// scanning the store_* tables. See docs/
|
|
201
|
+
// scanning the store_* tables. See docs/08-internationalization/index.md.
|
|
202
202
|
export const documentVersionLocales = mysqlTable('byline_document_version_locales', {
|
|
203
203
|
document_version_id: uuidChar('document_version_id').notNull(),
|
|
204
204
|
locale: varchar('locale', { length: 10 }).notNull(),
|
|
@@ -300,7 +300,7 @@ export const currentDocumentsView = mysqlView('byline_current_documents').as((qb
|
|
|
300
300
|
// read paths (`buildLocaleChain` / `pathProjection` / field-fallback)
|
|
301
301
|
// re-base onto the per-document source rather than the mutable global
|
|
302
302
|
// default — a primary-key join, already present for `order_key`.
|
|
303
|
-
// See docs/
|
|
303
|
+
// See docs/08-internationalization/index.md.
|
|
304
304
|
source_locale: documents.source_locale,
|
|
305
305
|
})
|
|
306
306
|
.from(sq)
|
|
@@ -407,7 +407,7 @@ export const textStore = mysqlTable('byline_store_text', {
|
|
|
407
407
|
// no query code references this index name — and Byline's actual
|
|
408
408
|
// full-text search is a separate, pluggable `SearchProvider` seam
|
|
409
409
|
// (`@byline/core`), not built on this table's indexes. See
|
|
410
|
-
// docs/
|
|
410
|
+
// docs/06-search/index.md.
|
|
411
411
|
index('idx_text_locale_value').on(table.locale, sql `${table.value}(191)`),
|
|
412
412
|
index('idx_text_path_value').on(table.field_path, sql `${table.value}(191)`),
|
|
413
413
|
// Unique constraints for unique fields
|
|
@@ -860,7 +860,7 @@ export const jsonStoreRelations = relations(jsonStore, ({ one }) => ({
|
|
|
860
860
|
// fit without a second migration. Append-only and deliberately **FK-free**: an
|
|
861
861
|
// audit row is an immutable historical fact that must outlive the document,
|
|
862
862
|
// collection, or actor it references — a `document.deleted` row cannot be
|
|
863
|
-
// allowed to cascade-delete itself. See docs/
|
|
863
|
+
// allowed to cascade-delete itself. See docs/07-auth-and-security/02-auditability.md — Workstream 2.
|
|
864
864
|
export const auditLog = mysqlTable('byline_audit_log', {
|
|
865
865
|
id: uuidChar('id').primaryKey(), // UUIDv7 — time-ordered, so id ordering ≈ time ordering
|
|
866
866
|
document_id: uuidChar('document_id'), // NULL for admin-realm (non-document) events; no FK
|
package/dist/index.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export declare const mysqlAdapter: ({ connectionString, collections, defaultCont
|
|
|
36
36
|
* for documents whose `source_locale` is not yet backfilled. Per-document
|
|
37
37
|
* reads and writes otherwise re-base onto each document's own `source_locale`
|
|
38
38
|
* (carried on the current-documents views), so changing this value does not
|
|
39
|
-
* re-interpret existing data. See docs/
|
|
39
|
+
* re-interpret existing data. See docs/08-internationalization/index.md.
|
|
40
40
|
*/
|
|
41
41
|
defaultContentLocale: string;
|
|
42
42
|
/**
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
|
-
* Append-only audit-log writes (docs/
|
|
9
|
+
* Append-only audit-log writes (docs/07-auth-and-security/02-auditability.md — Workstream 2). A deliberately
|
|
10
10
|
* dumb command: it inserts one row and knows nothing about *which* changes
|
|
11
11
|
* warrant an audit entry — that policy lives in the lifecycle services, which
|
|
12
12
|
* wrap the mutation + this append in `withTransaction` so they commit
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
|
-
* Audit-log reads (docs/
|
|
9
|
+
* Audit-log reads (docs/07-auth-and-security/02-auditability.md — Workstreams 3 & 4). Reads run on the pool
|
|
10
10
|
* directly — they never need to join an audit write's transaction — so this
|
|
11
11
|
* takes the raw `db` (drizzle over the pool) rather than the `DBManager`.
|
|
12
12
|
* Access scoping is the caller's responsibility (the document's own read
|
|
@@ -205,7 +205,7 @@ export declare class DocumentCommands implements IDocumentCommands {
|
|
|
205
205
|
* clause *after* `INSERT INTO <table>` and immediately before the `SELECT`
|
|
206
206
|
* it modifies (confirmed against a live MySQL 9.7.1 server) — so the two
|
|
207
207
|
* clauses are transposed relative to the pg original. See
|
|
208
|
-
* docs/
|
|
208
|
+
* docs/08-internationalization/index.md.
|
|
209
209
|
*/
|
|
210
210
|
private writeVersionLocaleLedger;
|
|
211
211
|
/**
|
|
@@ -268,7 +268,7 @@ export declare class DocumentCommands implements IDocumentCommands {
|
|
|
268
268
|
* **without** minting a new document version or touching workflow status. The
|
|
269
269
|
* change is immediate and applies across every version of the document; the
|
|
270
270
|
* public advertised set remains the intersection with the resolved version's
|
|
271
|
-
* completeness ledger. See docs/
|
|
271
|
+
* completeness ledger. See docs/08-internationalization/index.md.
|
|
272
272
|
*/
|
|
273
273
|
setDocumentAvailableLocales(params: {
|
|
274
274
|
documentId: string;
|
|
@@ -192,7 +192,7 @@ export class DocumentCommands {
|
|
|
192
192
|
// source locale rather than the mutable global default. NULL (a row not
|
|
193
193
|
// yet touched by `backfillSourceLocales`) falls back to the configured
|
|
194
194
|
// default — the value it was implicitly authored against.
|
|
195
|
-
// See docs/
|
|
195
|
+
// See docs/08-internationalization/index.md.
|
|
196
196
|
let sourceLocale;
|
|
197
197
|
if (documentId == null) {
|
|
198
198
|
documentId = uuidv7();
|
|
@@ -345,7 +345,7 @@ export class DocumentCommands {
|
|
|
345
345
|
// accounts for the per-locale carry-forward in step 5 — not just the
|
|
346
346
|
// freshly-flattened locale. A version with no localized content at all
|
|
347
347
|
// records a single `'all'` sentinel (it renders identically in any
|
|
348
|
-
// locale). Status-blind by design — see docs/
|
|
348
|
+
// locale). Status-blind by design — see docs/08-internationalization/index.md.
|
|
349
349
|
await this.writeVersionLocaleLedger(tx, documentVersion.id, sourceLocale);
|
|
350
350
|
return {
|
|
351
351
|
document: documentVersion,
|
|
@@ -446,7 +446,7 @@ export class DocumentCommands {
|
|
|
446
446
|
* clause *after* `INSERT INTO <table>` and immediately before the `SELECT`
|
|
447
447
|
* it modifies (confirmed against a live MySQL 9.7.1 server) — so the two
|
|
448
448
|
* clauses are transposed relative to the pg original. See
|
|
449
|
-
* docs/
|
|
449
|
+
* docs/08-internationalization/index.md.
|
|
450
450
|
*/
|
|
451
451
|
async writeVersionLocaleLedger(tx, versionId, sourceLocale) {
|
|
452
452
|
await tx.execute(sql `
|
|
@@ -558,7 +558,7 @@ export class DocumentCommands {
|
|
|
558
558
|
* **without** minting a new document version or touching workflow status. The
|
|
559
559
|
* change is immediate and applies across every version of the document; the
|
|
560
560
|
* public advertised set remains the intersection with the resolved version's
|
|
561
|
-
* completeness ledger. See docs/
|
|
561
|
+
* completeness ledger. See docs/08-internationalization/index.md.
|
|
562
562
|
*/
|
|
563
563
|
async setDocumentAvailableLocales(params) {
|
|
564
564
|
await this.db.transaction(async (tx) => {
|
|
@@ -128,7 +128,7 @@ export declare class DocumentQueries implements IDocumentQueries {
|
|
|
128
128
|
* document, or any document read after the global default is switched, falls
|
|
129
129
|
* back to the locale it was actually authored in) — otherwise the configured
|
|
130
130
|
* global default, which is correct for not-yet-anchored rows and for
|
|
131
|
-
* row-less lookups (findByPath). See docs/
|
|
131
|
+
* row-less lookups (findByPath). See docs/08-internationalization/index.md.
|
|
132
132
|
*/
|
|
133
133
|
private buildLocaleChain;
|
|
134
134
|
/**
|
|
@@ -161,7 +161,7 @@ export class DocumentQueries {
|
|
|
161
161
|
* document, or any document read after the global default is switched, falls
|
|
162
162
|
* back to the locale it was actually authored in) — otherwise the configured
|
|
163
163
|
* global default, which is correct for not-yet-anchored rows and for
|
|
164
|
-
* row-less lookups (findByPath). See docs/
|
|
164
|
+
* row-less lookups (findByPath). See docs/08-internationalization/index.md.
|
|
165
165
|
*/
|
|
166
166
|
buildLocaleChain(requestedLocale, sourceLocale) {
|
|
167
167
|
const floor = sourceLocale ?? this.defaultContentLocale;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@byline/db-mysql",
|
|
3
3
|
"private": false,
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.9.0",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=20.9.0"
|
|
8
8
|
},
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"drizzle-orm": "^0.45.2",
|
|
51
51
|
"mysql2": "^3.23.1",
|
|
52
52
|
"uuid": "^14.0.1",
|
|
53
|
-
"@byline/admin": "4.
|
|
54
|
-
"@byline/core": "4.
|
|
53
|
+
"@byline/admin": "4.9.0",
|
|
54
|
+
"@byline/core": "4.9.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@biomejs/biome": "2.5.4",
|
|
@@ -65,9 +65,9 @@
|
|
|
65
65
|
"tsx": "^4.23.1",
|
|
66
66
|
"typescript": "^7.0.2",
|
|
67
67
|
"vitest": "^4.1.10",
|
|
68
|
-
"@byline/
|
|
69
|
-
"@byline/
|
|
70
|
-
"@byline/
|
|
68
|
+
"@byline/db-conformance": "0.0.3",
|
|
69
|
+
"@byline/client": "4.9.0",
|
|
70
|
+
"@byline/auth": "4.9.0"
|
|
71
71
|
},
|
|
72
72
|
"publishConfig": {
|
|
73
73
|
"access": "public",
|