@aurabase/aurabase-js 0.3.0 → 0.4.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 +26 -795
- package/{packages/aurabase/dist/AuraClient-DAtDbfPB.d.ts → dist/AuraClient-BcFE8u1v.d.cts} +1 -1
- package/{packages/aurabase/dist/AuraClient-DAtDbfPB.d.cts → dist/AuraClient-BcFE8u1v.d.ts} +1 -1
- package/{packages/aurabase/dist → dist}/index.d.cts +1 -1
- package/{packages/aurabase/dist → dist}/index.d.ts +1 -1
- package/{packages/aurabase/dist → dist}/ssr.d.cts +1 -1
- package/{packages/aurabase/dist → dist}/ssr.d.ts +1 -1
- package/package.json +72 -82
- package/.changeset/config.json +0 -11
- package/CHANGELOG.md +0 -30
- package/packages/ai/LICENSE +0 -21
- package/packages/ai/README.md +0 -106
- package/packages/ai/dist/index.cjs +0 -229
- package/packages/ai/dist/index.d.cts +0 -139
- package/packages/ai/dist/index.d.ts +0 -139
- package/packages/ai/dist/index.js +0 -226
- package/packages/ai/node_modules/.bin/esbuild +0 -19
- package/packages/ai/node_modules/.bin/tsc +0 -22
- package/packages/ai/node_modules/.bin/tsserver +0 -22
- package/packages/ai/node_modules/.bin/tsup +0 -22
- package/packages/ai/node_modules/.bin/tsup-node +0 -22
- package/packages/ai/node_modules/.bin/vite +0 -22
- package/packages/ai/node_modules/.bin/vitest +0 -22
- package/packages/ai/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/ai/package.json +0 -61
- package/packages/ai/src/AiService.ts +0 -226
- package/packages/ai/src/index.ts +0 -18
- package/packages/ai/src/sse.ts +0 -141
- package/packages/ai/src/types.ts +0 -30
- package/packages/ai/tests/chat-stream.test.ts +0 -151
- package/packages/ai/tests/rag-namespaces.test.ts +0 -54
- package/packages/ai/tests/sse.test.ts +0 -69
- package/packages/ai/tsconfig.json +0 -5
- package/packages/ai/tsup.config.ts +0 -11
- package/packages/aurabase/LICENSE +0 -21
- package/packages/aurabase/README.md +0 -64
- package/packages/aurabase/node_modules/.bin/esbuild +0 -19
- package/packages/aurabase/node_modules/.bin/tsc +0 -22
- package/packages/aurabase/node_modules/.bin/tsserver +0 -22
- package/packages/aurabase/node_modules/.bin/tsup +0 -22
- package/packages/aurabase/node_modules/.bin/tsup-node +0 -22
- package/packages/aurabase/node_modules/.bin/vite +0 -22
- package/packages/aurabase/node_modules/.bin/vitest +0 -22
- package/packages/aurabase/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/aurabase/package.json +0 -80
- package/packages/aurabase/src/AuraClient.ts +0 -237
- package/packages/aurabase/src/index.ts +0 -152
- package/packages/aurabase/src/ssr.ts +0 -156
- package/packages/aurabase/tests/ai-streaming-rag-e2e.test.ts +0 -82
- package/packages/aurabase/tests/ai.test.ts +0 -111
- package/packages/aurabase/tests/auth-admin.test.ts +0 -515
- package/packages/aurabase/tests/auth-e2e.test.ts +0 -135
- package/packages/aurabase/tests/auth-hardening.test.ts +0 -206
- package/packages/aurabase/tests/auth.test.ts +0 -947
- package/packages/aurabase/tests/database.test.ts +0 -230
- package/packages/aurabase/tests/db-types-e2e.test.ts +0 -217
- package/packages/aurabase/tests/dispose.test.ts +0 -23
- package/packages/aurabase/tests/foreign-token.e2e.test.ts +0 -129
- package/packages/aurabase/tests/functions.test.ts +0 -107
- package/packages/aurabase/tests/integration.test.ts +0 -413
- package/packages/aurabase/tests/live-production-validation.js +0 -241
- package/packages/aurabase/tests/live-sdk-production-validation.js +0 -293
- package/packages/aurabase/tests/mocks.ts +0 -139
- package/packages/aurabase/tests/notifications.test.ts +0 -314
- package/packages/aurabase/tests/observability-backup.test.ts +0 -186
- package/packages/aurabase/tests/observability-hook.test.ts +0 -130
- package/packages/aurabase/tests/production-robustness.test.ts +0 -268
- package/packages/aurabase/tests/public-api-surface.test.ts +0 -53
- package/packages/aurabase/tests/query-builder.test.ts +0 -329
- package/packages/aurabase/tests/readme-smoke-e2e.test.ts +0 -231
- package/packages/aurabase/tests/realtime-filter-e2e.test.ts +0 -344
- package/packages/aurabase/tests/refresh-locks.test.ts +0 -210
- package/packages/aurabase/tests/retry-option.test.ts +0 -17
- package/packages/aurabase/tests/rpc-e2e.test.ts +0 -254
- package/packages/aurabase/tests/rs256-local-e2e.test.ts +0 -114
- package/packages/aurabase/tests/rt-alias-public-e2e.test.ts +0 -235
- package/packages/aurabase/tests/rt-http-broadcast-e2e.test.ts +0 -124
- package/packages/aurabase/tests/service-role-guard.test.ts +0 -99
- package/packages/aurabase/tests/ssr.test.ts +0 -91
- package/packages/aurabase/tests/storage-backend-e2e.test.ts +0 -481
- package/packages/aurabase/tests/storage-sdk-parity-e2e.test.ts +0 -104
- package/packages/aurabase/tests/storage-transform-e2e.test.ts +0 -684
- package/packages/aurabase/tests/storage.test.ts +0 -55
- package/packages/aurabase/tests/types/client-generic.test-d.ts +0 -79
- package/packages/aurabase/tests/types/docs-snippets.test-d.ts +0 -571
- package/packages/aurabase/tests/types/error-code.test-d.ts +0 -53
- package/packages/aurabase/tsconfig.json +0 -5
- package/packages/aurabase/tsconfig.test-d.json +0 -5
- package/packages/aurabase/tsup.config.ts +0 -11
- package/packages/aurabase/vitest.config.ts +0 -16
- package/packages/aurabase/vitest.e2e.config.ts +0 -9
- package/packages/auth/LICENSE +0 -21
- package/packages/auth/README.md +0 -215
- package/packages/auth/dist/index.cjs +0 -1175
- package/packages/auth/dist/index.d.cts +0 -397
- package/packages/auth/dist/index.d.ts +0 -397
- package/packages/auth/dist/index.js +0 -1170
- package/packages/auth/node_modules/.bin/esbuild +0 -19
- package/packages/auth/node_modules/.bin/tsc +0 -22
- package/packages/auth/node_modules/.bin/tsserver +0 -22
- package/packages/auth/node_modules/.bin/tsup +0 -22
- package/packages/auth/node_modules/.bin/tsup-node +0 -22
- package/packages/auth/node_modules/.bin/vite +0 -22
- package/packages/auth/node_modules/.bin/vitest +0 -22
- package/packages/auth/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/auth/package.json +0 -61
- package/packages/auth/src/AuthAdminService.ts +0 -149
- package/packages/auth/src/AuthService.ts +0 -1166
- package/packages/auth/src/SessionManager.ts +0 -92
- package/packages/auth/src/index.ts +0 -17
- package/packages/auth/src/jwks.ts +0 -337
- package/packages/auth/src/pkce.ts +0 -27
- package/packages/auth/src/types.ts +0 -89
- package/packages/auth/tests/auth-lifecycle.test.ts +0 -149
- package/packages/auth/tests/detect-session.test.ts +0 -361
- package/packages/auth/tests/getclaims.test.ts +0 -780
- package/packages/auth/tests/is-mfa-challenge.test.ts +0 -27
- package/packages/auth/tests/password-recovery.test.ts +0 -124
- package/packages/auth/tests/pkce.test.ts +0 -192
- package/packages/auth/tests/session-manager.test.ts +0 -103
- package/packages/auth/tests/set-session.test.ts +0 -139
- package/packages/auth/tests/verify-otp.test.ts +0 -153
- package/packages/auth/tsconfig.json +0 -5
- package/packages/auth/tsup.config.ts +0 -11
- package/packages/core/LICENSE +0 -21
- package/packages/core/README.md +0 -132
- package/packages/core/dist/index.cjs +0 -695
- package/packages/core/dist/index.d.cts +0 -1137
- package/packages/core/dist/index.d.ts +0 -1137
- package/packages/core/dist/index.js +0 -673
- package/packages/core/node_modules/.bin/esbuild +0 -22
- package/packages/core/node_modules/.bin/tsc +0 -22
- package/packages/core/node_modules/.bin/tsserver +0 -22
- package/packages/core/node_modules/.bin/tsup +0 -22
- package/packages/core/node_modules/.bin/tsup-node +0 -22
- package/packages/core/node_modules/.bin/vite +0 -22
- package/packages/core/node_modules/.bin/vitest +0 -22
- package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/core/package.json +0 -57
- package/packages/core/src/AuraError.ts +0 -89
- package/packages/core/src/BaseService.ts +0 -44
- package/packages/core/src/client.ts +0 -34
- package/packages/core/src/cookie-utils.ts +0 -42
- package/packages/core/src/fetch.ts +0 -435
- package/packages/core/src/index.ts +0 -22
- package/packages/core/src/retry.ts +0 -63
- package/packages/core/src/serialize.ts +0 -6
- package/packages/core/src/stores/BaseAuthStore.ts +0 -164
- package/packages/core/src/stores/LocalAuthStore.ts +0 -199
- package/packages/core/src/types.ts +0 -1042
- package/packages/core/tests/auth-store.test.ts +0 -300
- package/packages/core/tests/error-code.test.ts +0 -61
- package/packages/core/tests/error.test.ts +0 -24
- package/packages/core/tests/fetch.test.ts +0 -286
- package/packages/core/tests/mocks.ts +0 -139
- package/packages/core/tests/observability.test.ts +0 -86
- package/packages/core/tests/refresh-hardening.test.ts +0 -164
- package/packages/core/tests/refresh-observability.test.ts +0 -111
- package/packages/core/tests/retry.test.ts +0 -106
- package/packages/core/tests/serialize.test.ts +0 -12
- package/packages/core/tests/timeout.test.ts +0 -79
- package/packages/core/tsconfig.json +0 -5
- package/packages/core/tsup.config.ts +0 -11
- package/packages/db/LICENSE +0 -21
- package/packages/db/README.md +0 -152
- package/packages/db/VENDORED.md +0 -93
- package/packages/db/dist/index.cjs +0 -544
- package/packages/db/dist/index.d.cts +0 -1111
- package/packages/db/dist/index.d.ts +0 -1111
- package/packages/db/dist/index.js +0 -541
- package/packages/db/node_modules/.bin/esbuild +0 -19
- package/packages/db/node_modules/.bin/tsc +0 -22
- package/packages/db/node_modules/.bin/tsserver +0 -22
- package/packages/db/node_modules/.bin/tsup +0 -22
- package/packages/db/node_modules/.bin/tsup-node +0 -22
- package/packages/db/node_modules/.bin/vite +0 -22
- package/packages/db/node_modules/.bin/vitest +0 -22
- package/packages/db/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/db/package.json +0 -62
- package/packages/db/src/DatabaseService.ts +0 -170
- package/packages/db/src/QueryBuilder.ts +0 -830
- package/packages/db/src/index.ts +0 -2
- package/packages/db/src/pgrst-types/common/common.ts +0 -86
- package/packages/db/src/pgrst-types/common/rpc.ts +0 -151
- package/packages/db/src/pgrst-types/feature-flags.ts +0 -20
- package/packages/db/src/pgrst-types/types.ts +0 -134
- package/packages/db/src/select-query-parser/parser.ts +0 -479
- package/packages/db/src/select-query-parser/result.ts +0 -553
- package/packages/db/src/select-query-parser/types.ts +0 -132
- package/packages/db/src/select-query-parser/utils.ts +0 -707
- package/packages/db/tests/filters.test.ts +0 -81
- package/packages/db/tests/mutations-filtered.e2e.test.ts +0 -132
- package/packages/db/tests/mutations-filtered.test.ts +0 -188
- package/packages/db/tests/order.test.ts +0 -45
- package/packages/db/tests/rpc.test.ts +0 -41
- package/packages/db/tests/scale/build-large-schema.ts +0 -94
- package/packages/db/tests/scale/scale-compile.test.ts +0 -167
- package/packages/db/tests/schema.test.ts +0 -77
- package/packages/db/tests/single-accept.e2e.test.ts +0 -123
- package/packages/db/tests/single.test.ts +0 -211
- package/packages/db/tests/types/filters.test-d.ts +0 -52
- package/packages/db/tests/types/fixtures.ts +0 -40
- package/packages/db/tests/types/from-views.test-d.ts +0 -18
- package/packages/db/tests/types/mutations.test-d.ts +0 -23
- package/packages/db/tests/types/rpc.test-d.ts +0 -60
- package/packages/db/tests/types/schema-shape.test-d.ts +0 -8
- package/packages/db/tests/types/select-inference.test-d.ts +0 -38
- package/packages/db/tests/vendored/fixtures.ts +0 -83
- package/packages/db/tests/vendored/get-result.test-d.ts +0 -75
- package/packages/db/tsconfig.json +0 -5
- package/packages/db/tsconfig.test-d.json +0 -5
- package/packages/db/tsup.config.ts +0 -11
- package/packages/db/vitest.config.ts +0 -8
- package/packages/functions/LICENSE +0 -21
- package/packages/functions/README.md +0 -96
- package/packages/functions/dist/index.cjs +0 -173
- package/packages/functions/dist/index.d.cts +0 -81
- package/packages/functions/dist/index.d.ts +0 -81
- package/packages/functions/dist/index.js +0 -168
- package/packages/functions/node_modules/.bin/esbuild +0 -19
- package/packages/functions/node_modules/.bin/tsc +0 -22
- package/packages/functions/node_modules/.bin/tsserver +0 -22
- package/packages/functions/node_modules/.bin/tsup +0 -22
- package/packages/functions/node_modules/.bin/tsup-node +0 -22
- package/packages/functions/node_modules/.bin/vite +0 -22
- package/packages/functions/node_modules/.bin/vitest +0 -22
- package/packages/functions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/functions/package.json +0 -60
- package/packages/functions/src/FunctionsService.ts +0 -188
- package/packages/functions/src/errors.ts +0 -70
- package/packages/functions/src/index.ts +0 -6
- package/packages/functions/tests/invoke.test.ts +0 -97
- package/packages/functions/tests/response-type-errors.test.ts +0 -135
- package/packages/functions/tsconfig.json +0 -5
- package/packages/functions/tsup.config.ts +0 -11
- package/packages/gen/LICENSE +0 -21
- package/packages/gen/README.md +0 -84
- package/packages/gen/dist/cli.cjs +0 -334
- package/packages/gen/dist/cli.d.cts +0 -1
- package/packages/gen/dist/cli.d.ts +0 -1
- package/packages/gen/dist/cli.js +0 -332
- package/packages/gen/dist/index.cjs +0 -257
- package/packages/gen/dist/index.d.cts +0 -12
- package/packages/gen/dist/index.d.ts +0 -12
- package/packages/gen/dist/index.js +0 -255
- package/packages/gen/node_modules/.bin/esbuild +0 -19
- package/packages/gen/node_modules/.bin/tsc +0 -22
- package/packages/gen/node_modules/.bin/tsserver +0 -22
- package/packages/gen/node_modules/.bin/tsup +0 -22
- package/packages/gen/node_modules/.bin/tsup-node +0 -22
- package/packages/gen/node_modules/.bin/vite +0 -22
- package/packages/gen/node_modules/.bin/vitest +0 -22
- package/packages/gen/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/gen/package.json +0 -66
- package/packages/gen/src/cli.ts +0 -67
- package/packages/gen/src/generate.ts +0 -0
- package/packages/gen/src/index.ts +0 -2
- package/packages/gen/tests/compile.test.ts +0 -213
- package/packages/gen/tests/e2e.test.ts +0 -130
- package/packages/gen/tests/generate.test.ts +0 -396
- package/packages/gen/tsconfig.json +0 -5
- package/packages/gen/tsup.config.ts +0 -11
- package/packages/notifications/LICENSE +0 -21
- package/packages/notifications/README.md +0 -134
- package/packages/notifications/dist/index.cjs +0 -128
- package/packages/notifications/dist/index.d.cts +0 -81
- package/packages/notifications/dist/index.d.ts +0 -81
- package/packages/notifications/dist/index.js +0 -125
- package/packages/notifications/node_modules/.bin/esbuild +0 -19
- package/packages/notifications/node_modules/.bin/tsc +0 -22
- package/packages/notifications/node_modules/.bin/tsserver +0 -22
- package/packages/notifications/node_modules/.bin/tsup +0 -22
- package/packages/notifications/node_modules/.bin/tsup-node +0 -22
- package/packages/notifications/node_modules/.bin/vite +0 -22
- package/packages/notifications/node_modules/.bin/vitest +0 -22
- package/packages/notifications/package.json +0 -60
- package/packages/notifications/src/NotificationsService.ts +0 -230
- package/packages/notifications/src/index.ts +0 -19
- package/packages/notifications/tsconfig.json +0 -5
- package/packages/notifications/tsup.config.ts +0 -11
- package/packages/realtime/LICENSE +0 -21
- package/packages/realtime/README.md +0 -183
- package/packages/realtime/dist/index.cjs +0 -977
- package/packages/realtime/dist/index.d.cts +0 -259
- package/packages/realtime/dist/index.d.ts +0 -259
- package/packages/realtime/dist/index.js +0 -973
- package/packages/realtime/node_modules/.bin/esbuild +0 -19
- package/packages/realtime/node_modules/.bin/tsc +0 -22
- package/packages/realtime/node_modules/.bin/tsserver +0 -22
- package/packages/realtime/node_modules/.bin/tsup +0 -22
- package/packages/realtime/node_modules/.bin/tsup-node +0 -22
- package/packages/realtime/node_modules/.bin/vite +0 -22
- package/packages/realtime/node_modules/.bin/vitest +0 -22
- package/packages/realtime/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/realtime/package.json +0 -60
- package/packages/realtime/src/AuraChannel.ts +0 -485
- package/packages/realtime/src/HeartbeatManager.ts +0 -73
- package/packages/realtime/src/RealtimeService.ts +0 -505
- package/packages/realtime/src/columnFilter.ts +0 -301
- package/packages/realtime/src/index.ts +0 -4
- package/packages/realtime/tests/ack-routing.test.ts +0 -81
- package/packages/realtime/tests/column-filter.test.ts +0 -144
- package/packages/realtime/tests/dispatch.test.ts +0 -191
- package/packages/realtime/tests/heartbeat.test.ts +0 -67
- package/packages/realtime/tests/http-broadcast.test.ts +0 -68
- package/packages/realtime/tests/realtime-token.test.ts +0 -43
- package/packages/realtime/tests/reconnect-race.test.ts +0 -149
- package/packages/realtime/tests/ref-id.test.ts +0 -34
- package/packages/realtime/tests/set-auth.test.ts +0 -70
- package/packages/realtime/tsconfig.json +0 -5
- package/packages/realtime/tsup.config.ts +0 -11
- package/packages/storage/LICENSE +0 -21
- package/packages/storage/README.md +0 -141
- package/packages/storage/dist/index.cjs +0 -333
- package/packages/storage/dist/index.d.cts +0 -185
- package/packages/storage/dist/index.d.ts +0 -185
- package/packages/storage/dist/index.js +0 -329
- package/packages/storage/node_modules/.bin/esbuild +0 -19
- package/packages/storage/node_modules/.bin/tsc +0 -22
- package/packages/storage/node_modules/.bin/tsserver +0 -22
- package/packages/storage/node_modules/.bin/tsup +0 -22
- package/packages/storage/node_modules/.bin/tsup-node +0 -22
- package/packages/storage/node_modules/.bin/vite +0 -22
- package/packages/storage/node_modules/.bin/vitest +0 -22
- package/packages/storage/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/packages/storage/package.json +0 -60
- package/packages/storage/src/DownloadBuilder.ts +0 -60
- package/packages/storage/src/StorageService.ts +0 -323
- package/packages/storage/src/index.ts +0 -2
- package/packages/storage/src/path.ts +0 -35
- package/packages/storage/src/transform.ts +0 -15
- package/packages/storage/tests/download.test.ts +0 -64
- package/packages/storage/tests/parity.test.ts +0 -154
- package/packages/storage/tests/path.test.ts +0 -87
- package/packages/storage/tests/transform.test.ts +0 -79
- package/packages/storage/tsconfig.json +0 -5
- package/packages/storage/tsup.config.ts +0 -11
- package/pnpm-workspace.yaml +0 -24
- package/tsconfig.base.json +0 -15
- /package/{packages/aurabase/dist → dist}/index.cjs +0 -0
- /package/{packages/aurabase/dist → dist}/index.js +0 -0
- /package/{packages/aurabase/dist → dist}/ssr.cjs +0 -0
- /package/{packages/aurabase/dist → dist}/ssr.js +0 -0
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
// LOT 6 (B5 — TS2589 non testé à l'échelle) : harnais de compile à l'échelle.
|
|
2
|
-
//
|
|
3
|
-
// But : détecter, AVANT la prod, le "mur" TypeScript TS2589 ("Type
|
|
4
|
-
// instantiation is excessively deep and possibly infinite") sur un schéma
|
|
5
|
-
// réaliste (≥50 tables, embeds imbriqués sur plusieurs niveaux, select() large).
|
|
6
|
-
// Ce test est 100% offline (aucune stack requise) : il fabrique un `Database`
|
|
7
|
-
// synthétique via le vrai générateur `@aurabase/gen`, écrit une "sonde" TS qui
|
|
8
|
-
// exerce le query builder dessus, et la compile en sous-processus `tsc` avec
|
|
9
|
-
// `--extendedDiagnostics` pour mesurer le nombre de types instanciés et la
|
|
10
|
-
// durée — puis vérifie que les deux restent sous un budget.
|
|
11
|
-
//
|
|
12
|
-
// Pourquoi un tsconfig autonome plutôt que `-p tsconfig.test-d.json` :
|
|
13
|
-
// le fixture généré et la sonde vivent dans un dossier temporaire (nettoyé en
|
|
14
|
-
// `finally`), hors de l'arborescence du package. Étendre `tsconfig.json` /
|
|
15
|
-
// `tsconfig.test-d.json` tel quel échoue pour ce cas précis, vérifié
|
|
16
|
-
// empiriquement : TS6059 (fichiers hors `rootDir: "src"`) et TS2688
|
|
17
|
-
// (résolution de `types: ["vitest/globals"]" impossible hors de l'arbre du
|
|
18
|
-
// package). Le tsconfig ci-dessous recopie donc 1:1 les `compilerOptions`
|
|
19
|
-
// qui comptent pour l'inférence (strict, target ES2022, moduleResolution
|
|
20
|
-
// bundler, esModuleInterop, skipLibCheck) — c'est le même moteur de type que
|
|
21
|
-
// la vraie compile du package, appliqué à un fichier hors-arbre.
|
|
22
|
-
import { describe, expect, it } from 'vitest'
|
|
23
|
-
import { execFileSync } from 'node:child_process'
|
|
24
|
-
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
|
25
|
-
import { tmpdir } from 'node:os'
|
|
26
|
-
import { dirname, join } from 'node:path'
|
|
27
|
-
import { fileURLToPath } from 'node:url'
|
|
28
|
-
import { generateDatabaseTypes } from '../../../gen/src/generate'
|
|
29
|
-
import { buildLargeSchemaTables } from './build-large-schema'
|
|
30
|
-
|
|
31
|
-
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
32
|
-
const DB_PACKAGE_DIR = join(__dirname, '..', '..') // packages/db
|
|
33
|
-
const DB_SRC_DIR = join(DB_PACKAGE_DIR, 'src')
|
|
34
|
-
|
|
35
|
-
// --- Budget (mesuré empiriquement le 12/07/2026, TypeScript 5.9.3, machine de dev) ---
|
|
36
|
-
// Ce fixture exact (60 tables, chaîne d'embed à 4 niveaux + select nommé de
|
|
37
|
-
// 20 colonnes sur une table "large") compile en ~65 000-75 000 instanciations,
|
|
38
|
-
// ~6-12s (npx inclus). Pour calibrer : un `select()` de 250 colonnes nommées
|
|
39
|
-
// sur une seule table donne ~2,5M instanciations (~8s, toujours OK) ; à 400
|
|
40
|
-
// colonnes, TS2589 apparaît réellement à ~5,3M instanciations (~18-20s) — ce
|
|
41
|
-
// qui confirme que ce harnais détecte bel et bien le mur quand on le franchit
|
|
42
|
-
// (vérifié manuellement pendant le développement de ce test, hors suite
|
|
43
|
-
// committée pour ne pas rendre `npm test` rouge par construction).
|
|
44
|
-
// Budget retenu : ~3,4x l'observé (assez serré pour capter une régression de
|
|
45
|
-
// complexité type-level bien avant TS2589, assez large pour la variance CI).
|
|
46
|
-
const INSTANTIATION_BUDGET = 250_000
|
|
47
|
-
const DURATION_BUDGET_MS = 30_000
|
|
48
|
-
|
|
49
|
-
describe('LOT 6 — garde TS2589 à l\'échelle (schéma ≥50 tables)', () => {
|
|
50
|
-
it(
|
|
51
|
-
'compile un Database à l\'échelle (embed 4 niveaux + select large + eq + insert) sans TS2589, sous budget',
|
|
52
|
-
() => {
|
|
53
|
-
const tables = buildLargeSchemaTables({ tableCount: 60, wideTableColumnCount: 20 })
|
|
54
|
-
expect(tables.length).toBeGreaterThanOrEqual(50)
|
|
55
|
-
|
|
56
|
-
const databaseTypesSource = generateDatabaseTypes(tables)
|
|
57
|
-
|
|
58
|
-
const tempDir = mkdtempSync(join(tmpdir(), 'aura-db-scale-'))
|
|
59
|
-
try {
|
|
60
|
-
const typesFile = join(tempDir, 'database.types.ts')
|
|
61
|
-
writeFileSync(typesFile, databaseTypesSource)
|
|
62
|
-
|
|
63
|
-
// t10 : première table "large" hors de la chaîne d'embed dédiée
|
|
64
|
-
// (t0..t3) — voir build-large-schema.ts (une table sur dix est large).
|
|
65
|
-
const wideTable = tables.find((t) => t.name === 't10')
|
|
66
|
-
if (!wideTable) throw new Error('fixture: table "t10" absente (le générateur de fixture a changé ?)')
|
|
67
|
-
const wideColumns = wideTable.columns
|
|
68
|
-
.slice(0, 20)
|
|
69
|
-
.map((c) => c.name)
|
|
70
|
-
.join(', ')
|
|
71
|
-
|
|
72
|
-
const probeSource = `// Sonde de compile à l'échelle — générée par scale-compile.test.ts (LOT 6).
|
|
73
|
-
// Compilée en sous-processus tsc, jamais exécutée (pas de runtime réel).
|
|
74
|
-
import type { Database } from './database.types'
|
|
75
|
-
import { DatabaseService } from '${DB_SRC_DIR}/DatabaseService'
|
|
76
|
-
|
|
77
|
-
declare const db: DatabaseService<Database>
|
|
78
|
-
|
|
79
|
-
async function probe() {
|
|
80
|
-
// Embed imbriqué sur 4 niveaux, sens many-to-one (t0 -> t1 -> t2 -> t3),
|
|
81
|
-
// même sens que le cas déjà testé unitairement (posts.author_id -> users.id).
|
|
82
|
-
const deep = await db.from('t0').select('*, t1(*, t2(*, t3(name)))')
|
|
83
|
-
|
|
84
|
-
// select() avec une longue liste de colonnes nommées sur une table "large"
|
|
85
|
-
// (chemin qui, empiriquement, fait le plus grossir le nombre d'instanciations).
|
|
86
|
-
const wide = await db.from('${wideTable.name}').select('${wideColumns}')
|
|
87
|
-
|
|
88
|
-
// .eq() typé sur une colonne connue.
|
|
89
|
-
const filtered = db.from('t0').select('id, name').eq('name', 'x')
|
|
90
|
-
|
|
91
|
-
// Mutation typée (insert).
|
|
92
|
-
const inserted = db.from('t0').insert({ name: 'n', t1_id: 'x' })
|
|
93
|
-
|
|
94
|
-
return { deep, wide, filtered, inserted }
|
|
95
|
-
}
|
|
96
|
-
void probe
|
|
97
|
-
`
|
|
98
|
-
const probeFile = join(tempDir, 'probe.ts')
|
|
99
|
-
writeFileSync(probeFile, probeSource)
|
|
100
|
-
|
|
101
|
-
const tsconfig = {
|
|
102
|
-
compilerOptions: {
|
|
103
|
-
target: 'ES2022',
|
|
104
|
-
module: 'ESNext',
|
|
105
|
-
moduleResolution: 'bundler',
|
|
106
|
-
lib: ['ES2022', 'DOM'],
|
|
107
|
-
strict: true,
|
|
108
|
-
esModuleInterop: true,
|
|
109
|
-
skipLibCheck: true,
|
|
110
|
-
noEmit: true,
|
|
111
|
-
declaration: false,
|
|
112
|
-
types: [],
|
|
113
|
-
},
|
|
114
|
-
include: [probeFile],
|
|
115
|
-
}
|
|
116
|
-
const tsconfigFile = join(tempDir, 'tsconfig.json')
|
|
117
|
-
writeFileSync(tsconfigFile, JSON.stringify(tsconfig, null, 2))
|
|
118
|
-
|
|
119
|
-
const startedAt = Date.now()
|
|
120
|
-
let stdout = ''
|
|
121
|
-
let compileError: (Error & { stdout?: string; stderr?: string }) | undefined
|
|
122
|
-
try {
|
|
123
|
-
stdout = execFileSync(
|
|
124
|
-
'npx',
|
|
125
|
-
['tsc', '--noEmit', '-p', tsconfigFile, '--extendedDiagnostics'],
|
|
126
|
-
{ cwd: DB_PACKAGE_DIR, encoding: 'utf8', timeout: 90_000 },
|
|
127
|
-
)
|
|
128
|
-
} catch (e) {
|
|
129
|
-
compileError = e as Error & { stdout?: string; stderr?: string }
|
|
130
|
-
stdout = compileError.stdout ?? ''
|
|
131
|
-
}
|
|
132
|
-
const durationMs = Date.now() - startedAt
|
|
133
|
-
|
|
134
|
-
// Le mur à détecter avant la prod : `error TS2589: Type instantiation
|
|
135
|
-
// is excessively deep and possibly infinite.`
|
|
136
|
-
const hasTS2589 = /TS2589/.test(stdout) || /TS2589/.test(compileError?.stderr ?? '')
|
|
137
|
-
expect(hasTS2589, `TS2589 détecté — mur d'instanciation atteint :\n${stdout}`).toBe(false)
|
|
138
|
-
|
|
139
|
-
// Toute autre erreur de compilation est aussi un échec : la sonde doit
|
|
140
|
-
// être 100% valide vis-à-vis du query builder réel.
|
|
141
|
-
if (compileError) {
|
|
142
|
-
throw new Error(`tsc a échoué (hors TS2589) :\n${stdout}\n${compileError.stderr ?? ''}`)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const instantiationsMatch = /Instantiations:\s*([\d,]+)/.exec(stdout)
|
|
146
|
-
expect(
|
|
147
|
-
instantiationsMatch,
|
|
148
|
-
`--extendedDiagnostics n'a pas produit de ligne "Instantiations:" :\n${stdout}`,
|
|
149
|
-
).not.toBeNull()
|
|
150
|
-
const instantiations = Number(instantiationsMatch![1].replace(/,/g, ''))
|
|
151
|
-
|
|
152
|
-
expect(
|
|
153
|
-
instantiations,
|
|
154
|
-
`${instantiations} instanciations > budget ${INSTANTIATION_BUDGET} — régression de complexité ` +
|
|
155
|
-
'type-level probable (voir marge documentée en tête de fichier)',
|
|
156
|
-
).toBeLessThan(INSTANTIATION_BUDGET)
|
|
157
|
-
|
|
158
|
-
expect(durationMs, `compile à ${durationMs}ms > budget ${DURATION_BUDGET_MS}ms`).toBeLessThan(
|
|
159
|
-
DURATION_BUDGET_MS,
|
|
160
|
-
)
|
|
161
|
-
} finally {
|
|
162
|
-
rmSync(tempDir, { recursive: true, force: true })
|
|
163
|
-
}
|
|
164
|
-
},
|
|
165
|
-
90_000,
|
|
166
|
-
)
|
|
167
|
-
})
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { DatabaseService } from '../src/DatabaseService'
|
|
3
|
-
import { BaseAuthStore } from '@aurabase/core'
|
|
4
|
-
import type { AuraClientLike } from '@aurabase/core'
|
|
5
|
-
|
|
6
|
-
function client(extra?: Record<string, unknown>): AuraClientLike {
|
|
7
|
-
const body = JSON.stringify({
|
|
8
|
-
data: {
|
|
9
|
-
project_id: 'p',
|
|
10
|
-
engine: 'postgres',
|
|
11
|
-
tables: [{ name: 'users', columns: [], indexes: [], rls_enabled: false, realtime_enabled: false }],
|
|
12
|
-
...extra,
|
|
13
|
-
},
|
|
14
|
-
})
|
|
15
|
-
return {
|
|
16
|
-
baseUrl: 'http://x', projectId: 'p', apiKey: 'k',
|
|
17
|
-
fetchFn: (async () =>
|
|
18
|
-
new Response(body, { status: 200, headers: { 'Content-Type': 'application/json' } })) as unknown as typeof globalThis.fetch,
|
|
19
|
-
authStore: new BaseAuthStore(),
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
|
-
auth: { refreshSession: async () => ({ data: null, error: null }) as any },
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
describe('DatabaseService.schema()', () => {
|
|
26
|
-
it('déballe SchemaDefinition.tables ET .functions — le backend renvoie { project_id, engine, tables, functions }', async () => {
|
|
27
|
-
const db = new DatabaseService(
|
|
28
|
-
client({
|
|
29
|
-
functions: [
|
|
30
|
-
{ name: 'add', args: [{ name: 'a', data_type: 'int4', mode: 'IN' }], returns: 'int4', is_set_returning: false },
|
|
31
|
-
],
|
|
32
|
-
}),
|
|
33
|
-
)
|
|
34
|
-
const { data, error } = await db.schema()
|
|
35
|
-
expect(error).toBeNull()
|
|
36
|
-
expect(Array.isArray(data?.tables)).toBe(true)
|
|
37
|
-
expect(data?.tables).toHaveLength(1)
|
|
38
|
-
expect(data?.tables[0].name).toBe('users')
|
|
39
|
-
expect(Array.isArray(data?.functions)).toBe(true)
|
|
40
|
-
expect(data?.functions).toHaveLength(1)
|
|
41
|
-
expect(data?.functions[0]).toEqual({
|
|
42
|
-
name: 'add',
|
|
43
|
-
args: [{ name: 'a', data_type: 'int4', mode: 'IN' }],
|
|
44
|
-
returns: 'int4',
|
|
45
|
-
is_set_returning: false,
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('functions absentes du backend → []', async () => {
|
|
50
|
-
const db = new DatabaseService(client())
|
|
51
|
-
const { data, error } = await db.schema()
|
|
52
|
-
expect(error).toBeNull()
|
|
53
|
-
expect(data?.functions).toEqual([])
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('déballe .enums ET .views (LOT C) — le backend renvoie enums/views', async () => {
|
|
57
|
-
const db = new DatabaseService(
|
|
58
|
-
client({
|
|
59
|
-
enums: [{ name: 'mood', values: ['happy', 'sad'] }],
|
|
60
|
-
views: [{ name: 'v_x', columns: [], indexes: [], rls_enabled: false, realtime_enabled: false }],
|
|
61
|
-
}),
|
|
62
|
-
)
|
|
63
|
-
const { data, error } = await db.schema()
|
|
64
|
-
expect(error).toBeNull()
|
|
65
|
-
expect(data?.enums).toEqual([{ name: 'mood', values: ['happy', 'sad'] }])
|
|
66
|
-
expect(data?.views).toHaveLength(1)
|
|
67
|
-
expect(data?.views[0].name).toBe('v_x')
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('enums/views absents du backend → [] (rétrocompat)', async () => {
|
|
71
|
-
const db = new DatabaseService(client())
|
|
72
|
-
const { data, error } = await db.schema()
|
|
73
|
-
expect(error).toBeNull()
|
|
74
|
-
expect(data?.enums).toEqual([])
|
|
75
|
-
expect(data?.views).toEqual([])
|
|
76
|
-
})
|
|
77
|
-
})
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// E2E réel (stack live) — single()/maybeSingle() via Accept: object+json.
|
|
3
|
-
//
|
|
4
|
-
// Vérifie la parité postgrest-js et le correctif du cas qui cassait :
|
|
5
|
-
// `.eq().update().select().single()` (PostgREST rejette `limit` sans `order` sur
|
|
6
|
-
// une mutation ; le nouvel en-tête Accept n'a pas ce problème).
|
|
7
|
-
//
|
|
8
|
-
// Gaté par RUN_E2E + credentials (AURA_E2E_URL / AURA_E2E_PROJECT / AURA_E2E_KEY ;
|
|
9
|
-
// clé service_role requise pour le SQL brut). Skip PROPRE sinon (describe.runIf).
|
|
10
|
-
//
|
|
11
|
-
// Table de test créée en SQL brut NON qualifié (schéma tenant `project_<pid>`).
|
|
12
|
-
// Retry borné sur 404 (propagation `reload schema` post-DDL) + 503 (reload/indispo).
|
|
13
|
-
//
|
|
14
|
-
// Le run réel n'est PAS lancé ici (pas de creds) — le contrôleur le fera ; ce
|
|
15
|
-
// fichier doit seulement compiler et skip proprement.
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
import { describe, it, expect } from 'vitest'
|
|
19
|
-
import { BaseAuthStore } from '@aurabase/core'
|
|
20
|
-
import type { AuraClientLike, AuraResponse } from '@aurabase/core'
|
|
21
|
-
import { DatabaseService } from '../src/DatabaseService'
|
|
22
|
-
|
|
23
|
-
const URL = process.env.AURA_E2E_URL
|
|
24
|
-
const PROJECT = process.env.AURA_E2E_PROJECT
|
|
25
|
-
const KEY = process.env.AURA_E2E_KEY
|
|
26
|
-
const RUN = Boolean(process.env.RUN_E2E && URL && PROJECT && KEY)
|
|
27
|
-
|
|
28
|
-
/** Monte un `DatabaseService` réel au-dessus d'un `AuraClientLike` minimal. */
|
|
29
|
-
function makeDb(): DatabaseService {
|
|
30
|
-
const client: AuraClientLike = {
|
|
31
|
-
baseUrl: URL!,
|
|
32
|
-
projectId: PROJECT!,
|
|
33
|
-
apiKey: KEY!,
|
|
34
|
-
fetchFn: globalThis.fetch,
|
|
35
|
-
authStore: new BaseAuthStore(),
|
|
36
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
-
auth: { refreshSession: async () => ({ data: null, error: null }) as any },
|
|
38
|
-
}
|
|
39
|
-
return new DatabaseService(client)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Rejoue tant que la réponse est transitoire (404 propagation schéma / 503 reload), borné. */
|
|
43
|
-
async function retry503<T>(fn: () => Promise<AuraResponse<T>>): Promise<AuraResponse<T>> {
|
|
44
|
-
const transient = (s?: number): boolean => s === 404 || s === 503
|
|
45
|
-
let res = await fn()
|
|
46
|
-
for (let i = 0; i < 25 && transient(res.error?.status); i++) {
|
|
47
|
-
await new Promise((r) => setTimeout(r, 1000))
|
|
48
|
-
res = await fn()
|
|
49
|
-
}
|
|
50
|
-
return res
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
describe.runIf(RUN)('single()/maybeSingle() E2E — Accept object+json + mutation filtrée', () => {
|
|
54
|
-
it(
|
|
55
|
-
'select/mutation .single() renvoient l’objet ; 0/>1 → PGRST116 ; maybeSingle 0 → null',
|
|
56
|
-
async () => {
|
|
57
|
-
const db = makeDb()
|
|
58
|
-
const suffix = process.env.AURA_E2E_SUFFIX ?? 'single'
|
|
59
|
-
const table = `e2e_single_${suffix}`
|
|
60
|
-
|
|
61
|
-
// Création via SQL brut (service_role). Noms NON qualifiés → schéma tenant.
|
|
62
|
-
await db.sql(`DROP TABLE IF EXISTS ${table}`)
|
|
63
|
-
await db.sql(
|
|
64
|
-
`CREATE TABLE ${table} (id uuid PRIMARY KEY DEFAULT gen_random_uuid(), name text NOT NULL, n int NOT NULL DEFAULT 0)`,
|
|
65
|
-
)
|
|
66
|
-
await db.sql(`GRANT ALL ON ${table} TO PUBLIC`)
|
|
67
|
-
await db.sql(`SELECT pg_notify('pgrst', 'reload schema')`)
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
// -- Seed : 3 lignes, dont 2 partageant name='dup' (pour le cas >1 ligne) ---
|
|
71
|
-
// TESTS-1.1 : PLUS de graceful-skip silencieux. `retry503` absorbe les 503/404
|
|
72
|
-
// TRANSITOIRES (reload schéma) ; un 503 PERSISTANT après retries doit FAIRE
|
|
73
|
-
// ÉCHOUER le test (`expect(...).toBeNull()`), pas être masqué par un `return`.
|
|
74
|
-
const seeded = await retry503(() =>
|
|
75
|
-
db.from(table).insert([
|
|
76
|
-
{ name: 'uno', n: 1 },
|
|
77
|
-
{ name: 'dup', n: 2 },
|
|
78
|
-
{ name: 'dup', n: 3 },
|
|
79
|
-
]),
|
|
80
|
-
)
|
|
81
|
-
expect(seeded.error).toBeNull()
|
|
82
|
-
|
|
83
|
-
// -- (a) SELECT .eq(pk unique).single() → l'objet --------------------------
|
|
84
|
-
const one = await retry503(() =>
|
|
85
|
-
db.from(table).eq('name', 'uno').select('name,n').single(),
|
|
86
|
-
)
|
|
87
|
-
expect(one.error).toBeNull()
|
|
88
|
-
expect(one.data).toMatchObject({ name: 'uno', n: 1 })
|
|
89
|
-
|
|
90
|
-
// -- (b1) .select().single() sur 0 ligne → PGRST116 -----------------------
|
|
91
|
-
const zero = await retry503(() =>
|
|
92
|
-
db.from(table).eq('name', 'absent').select('name,n').single(),
|
|
93
|
-
)
|
|
94
|
-
expect(zero.data).toBeNull()
|
|
95
|
-
expect(zero.error?.code).toBe('PGRST116')
|
|
96
|
-
|
|
97
|
-
// -- (b2) .select().single() sur >1 ligne → PGRST116 ----------------------
|
|
98
|
-
const many = await retry503(() =>
|
|
99
|
-
db.from(table).eq('name', 'dup').select('name,n').single(),
|
|
100
|
-
)
|
|
101
|
-
expect(many.data).toBeNull()
|
|
102
|
-
expect(many.error?.code).toBe('PGRST116')
|
|
103
|
-
|
|
104
|
-
// -- (c) maybeSingle sur 0 ligne → null SANS erreur -----------------------
|
|
105
|
-
const maybeZero = await retry503(() =>
|
|
106
|
-
db.from(table).eq('name', 'absent').select('name,n').maybeSingle(),
|
|
107
|
-
)
|
|
108
|
-
expect(maybeZero.data).toBeNull()
|
|
109
|
-
expect(maybeZero.error).toBeNull()
|
|
110
|
-
|
|
111
|
-
// -- (d) LE CAS QUI CASSAIT : .eq().update().select().single() ------------
|
|
112
|
-
const updated = await retry503(() =>
|
|
113
|
-
db.from(table).eq('name', 'uno').update({ n: 99 }).select('name,n').single(),
|
|
114
|
-
)
|
|
115
|
-
expect(updated.error).toBeNull()
|
|
116
|
-
expect(updated.data).toMatchObject({ name: 'uno', n: 99 })
|
|
117
|
-
} finally {
|
|
118
|
-
await db.sql(`DROP TABLE IF EXISTS ${table}`)
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
120_000,
|
|
122
|
-
)
|
|
123
|
-
})
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { QueryBuilder } from '../src/QueryBuilder'
|
|
3
|
-
import { BaseAuthStore } from '@aurabase/core'
|
|
4
|
-
import type { AuraClientLike } from '@aurabase/core'
|
|
5
|
-
|
|
6
|
-
interface Captured {
|
|
7
|
-
url: string
|
|
8
|
-
init: RequestInit
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Client mock enregistrant la requête et renvoyant une réponse paramétrable.
|
|
13
|
-
* `respond` reçoit l'URL et renvoie `{ status, body }` (body sérialisé en JSON).
|
|
14
|
-
*/
|
|
15
|
-
function client(
|
|
16
|
-
respond: (url: string) => { status: number; body: unknown },
|
|
17
|
-
captured?: Captured[],
|
|
18
|
-
): AuraClientLike {
|
|
19
|
-
return {
|
|
20
|
-
baseUrl: 'http://x',
|
|
21
|
-
projectId: 'p',
|
|
22
|
-
apiKey: 'k',
|
|
23
|
-
fetchFn: (async (url: string, init: RequestInit) => {
|
|
24
|
-
captured?.push({ url, init })
|
|
25
|
-
const { status, body } = respond(url)
|
|
26
|
-
return new Response(JSON.stringify(body), {
|
|
27
|
-
status,
|
|
28
|
-
headers: { 'Content-Type': 'application/json' },
|
|
29
|
-
})
|
|
30
|
-
}) as unknown as typeof globalThis.fetch,
|
|
31
|
-
authStore: new BaseAuthStore(),
|
|
32
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
33
|
-
auth: { refreshSession: async () => ({ data: null, error: null }) as any },
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** Corps d'erreur 406 tel que réécrit par le gateway (code NOT_SINGULAR + détail PostgREST). */
|
|
38
|
-
function notSingular(rows: number): { status: number; body: unknown } {
|
|
39
|
-
return {
|
|
40
|
-
status: 406,
|
|
41
|
-
body: {
|
|
42
|
-
error: {
|
|
43
|
-
code: 'NOT_SINGULAR',
|
|
44
|
-
message: 'JSON object requested, multiple (or no) rows returned',
|
|
45
|
-
details: `The result contains ${rows} rows`,
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Corps d'erreur 404 tel que réécrit par le gateway sur la route id-based
|
|
53
|
-
* `/{table}/{id}` quand l'id est introuvable (PGRST116 → `RECORD_NOT_FOUND`).
|
|
54
|
-
*/
|
|
55
|
-
function recordNotFound(): { status: number; body: unknown } {
|
|
56
|
-
return {
|
|
57
|
-
status: 404,
|
|
58
|
-
body: { error: { code: 'RECORD_NOT_FOUND', message: 'Record not found' } },
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** Extrait l'en-tête `Accept` (insensible à la casse de la clé) de l'init capturé. */
|
|
63
|
-
function acceptOf(init: RequestInit): string | undefined {
|
|
64
|
-
const h = (init.headers ?? {}) as Record<string, string>
|
|
65
|
-
return h.Accept ?? h.accept
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
describe('single() / maybeSingle() — en-tête Accept object+json (parité postgrest-js)', () => {
|
|
69
|
-
it('single() envoie Accept: application/vnd.pgrst.object+json et PAS limit=2', async () => {
|
|
70
|
-
const cap: Captured[] = []
|
|
71
|
-
await new QueryBuilder(client(() => ({ status: 200, body: { data: { id: 1 } } }), cap), '/t')
|
|
72
|
-
.eq('id', 1)
|
|
73
|
-
.select('*')
|
|
74
|
-
.single()
|
|
75
|
-
expect(cap).toHaveLength(1)
|
|
76
|
-
expect(acceptOf(cap[0]!.init)).toBe('application/vnd.pgrst.object+json')
|
|
77
|
-
expect(cap[0]!.url).not.toMatch(/limit=/)
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
it('single sur objet unique (200) → renvoie l’objet', async () => {
|
|
81
|
-
const { data, error } = await new QueryBuilder(
|
|
82
|
-
client(() => ({ status: 200, body: { data: { id: 1, name: 'a' } } })),
|
|
83
|
-
'/t',
|
|
84
|
-
).single()
|
|
85
|
-
expect(error).toBeNull()
|
|
86
|
-
expect(data).toEqual({ id: 1, name: 'a' })
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('single sur 0 ligne (406) → erreur PGRST116/406', async () => {
|
|
90
|
-
const { data, error } = await new QueryBuilder(client(() => notSingular(0)), '/t').single()
|
|
91
|
-
expect(data).toBeNull()
|
|
92
|
-
expect(error?.status).toBe(406)
|
|
93
|
-
expect(error?.code).toBe('PGRST116')
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('single sur >1 ligne (406) → erreur PGRST116', async () => {
|
|
97
|
-
const { error } = await new QueryBuilder(client(() => notSingular(2)), '/t').single()
|
|
98
|
-
expect(error?.code).toBe('PGRST116')
|
|
99
|
-
expect(error?.message).toMatch(/multiple/)
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
it('maybeSingle sur 0 ligne (406 « 0 rows ») → null sans erreur', async () => {
|
|
103
|
-
const { data, error } = await new QueryBuilder(client(() => notSingular(0)), '/t').maybeSingle()
|
|
104
|
-
expect(data).toBeNull()
|
|
105
|
-
expect(error).toBeNull()
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('maybeSingle sur objet unique (200) → renvoie l’objet', async () => {
|
|
109
|
-
const { data, error } = await new QueryBuilder(
|
|
110
|
-
client(() => ({ status: 200, body: { data: { id: 7 } } })),
|
|
111
|
-
'/t',
|
|
112
|
-
).maybeSingle()
|
|
113
|
-
expect(error).toBeNull()
|
|
114
|
-
expect(data).toEqual({ id: 7 })
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
it('maybeSingle sur >1 ligne (406) → erreur PGRST116', async () => {
|
|
118
|
-
const { error } = await new QueryBuilder(client(() => notSingular(2)), '/t').maybeSingle()
|
|
119
|
-
expect(error?.code).toBe('PGRST116')
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
it('discrimination robuste : « 10 rows » n’est PAS traité comme « 0 rows » (maybeSingle → erreur)', async () => {
|
|
123
|
-
const { data, error } = await new QueryBuilder(client(() => notSingular(10)), '/t').maybeSingle()
|
|
124
|
-
expect(data).toBeNull()
|
|
125
|
-
expect(error?.code).toBe('PGRST116')
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
it('.eq().update().select().single() → en-tête Accept + Prefer, PAS de limit (cas qui cassait)', async () => {
|
|
129
|
-
const cap: Captured[] = []
|
|
130
|
-
const { data, error } = await new QueryBuilder(
|
|
131
|
-
client(() => ({ status: 200, body: { data: { id: 1, n: 99 } } }), cap),
|
|
132
|
-
'/t',
|
|
133
|
-
)
|
|
134
|
-
.eq('id', 1)
|
|
135
|
-
.update({ n: 99 })
|
|
136
|
-
.select('*')
|
|
137
|
-
.single()
|
|
138
|
-
expect(error).toBeNull()
|
|
139
|
-
expect(data).toEqual({ id: 1, n: 99 })
|
|
140
|
-
expect(cap).toHaveLength(1)
|
|
141
|
-
const h = (cap[0]!.init.headers ?? {}) as Record<string, string>
|
|
142
|
-
expect(acceptOf(cap[0]!.init)).toBe('application/vnd.pgrst.object+json')
|
|
143
|
-
expect(h.Prefer).toMatch(/return=representation/)
|
|
144
|
-
expect(cap[0]!.url).not.toMatch(/limit=/)
|
|
145
|
-
expect(cap[0]!.init.method).toBe('PATCH')
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
// -- DB-F1 : route id-based → 404 RECORD_NOT_FOUND traité comme 0-ligne -------
|
|
149
|
-
describe('route id-based (404 RECORD_NOT_FOUND) — parité single/maybeSingle', () => {
|
|
150
|
-
it('update(idInexistant).select().maybeSingle() → { data:null, error:null }', async () => {
|
|
151
|
-
const { data, error } = await new QueryBuilder(client(() => recordNotFound()), '/t')
|
|
152
|
-
.update('missing-id', { n: 1 })
|
|
153
|
-
.select('*')
|
|
154
|
-
.maybeSingle()
|
|
155
|
-
expect(data).toBeNull()
|
|
156
|
-
expect(error).toBeNull()
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
it('update(idInexistant).select().single() → erreur PGRST116 (0 rows)', async () => {
|
|
160
|
-
const { data, error } = await new QueryBuilder(client(() => recordNotFound()), '/t')
|
|
161
|
-
.update('missing-id', { n: 1 })
|
|
162
|
-
.select('*')
|
|
163
|
-
.single()
|
|
164
|
-
expect(data).toBeNull()
|
|
165
|
-
expect(error?.code).toBe('PGRST116')
|
|
166
|
-
expect(error?.message).toMatch(/0 rows/)
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
it('delete(idInexistant).select().single() → erreur PGRST116 (0 rows)', async () => {
|
|
170
|
-
const { error } = await new QueryBuilder(client(() => recordNotFound()), '/t')
|
|
171
|
-
.delete('missing-id')
|
|
172
|
-
.select('*')
|
|
173
|
-
.single()
|
|
174
|
-
expect(error?.code).toBe('PGRST116')
|
|
175
|
-
})
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
// -- Chemin défensif : backend renvoyant un TABLEAU (en-tête ignoré) ---------
|
|
179
|
-
describe('fallback tableau (compat défensive)', () => {
|
|
180
|
-
it('single sur [obj] → objet', async () => {
|
|
181
|
-
const { data, error } = await new QueryBuilder(
|
|
182
|
-
client(() => ({ status: 200, body: { data: [{ id: 1 }] } })),
|
|
183
|
-
'/t',
|
|
184
|
-
).single()
|
|
185
|
-
expect(error).toBeNull()
|
|
186
|
-
expect(data).toEqual({ id: 1 })
|
|
187
|
-
})
|
|
188
|
-
it('single sur [] → erreur PGRST116', async () => {
|
|
189
|
-
const { error } = await new QueryBuilder(
|
|
190
|
-
client(() => ({ status: 200, body: { data: [] } })),
|
|
191
|
-
'/t',
|
|
192
|
-
).single()
|
|
193
|
-
expect(error?.code).toBe('PGRST116')
|
|
194
|
-
})
|
|
195
|
-
it('maybeSingle sur [] → null sans erreur', async () => {
|
|
196
|
-
const { data, error } = await new QueryBuilder(
|
|
197
|
-
client(() => ({ status: 200, body: { data: [] } })),
|
|
198
|
-
'/t',
|
|
199
|
-
).maybeSingle()
|
|
200
|
-
expect(data).toBeNull()
|
|
201
|
-
expect(error).toBeNull()
|
|
202
|
-
})
|
|
203
|
-
it('maybeSingle sur [a,b] → erreur PGRST116', async () => {
|
|
204
|
-
const { error } = await new QueryBuilder(
|
|
205
|
-
client(() => ({ status: 200, body: { data: [{ id: 1 }, { id: 2 }] } })),
|
|
206
|
-
'/t',
|
|
207
|
-
).maybeSingle()
|
|
208
|
-
expect(error?.code).toBe('PGRST116')
|
|
209
|
-
})
|
|
210
|
-
})
|
|
211
|
-
})
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { DatabaseService } from '../../src/DatabaseService'
|
|
2
|
-
import type { Database } from './fixtures'
|
|
3
|
-
|
|
4
|
-
declare const db: DatabaseService<Database>
|
|
5
|
-
|
|
6
|
-
test('eq accepte une colonne connue + type de valeur correct', () => {
|
|
7
|
-
db.from('users').select('id').eq('email', 'a@b.c') // OK
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
test('eq refuse une colonne inconnue', () => {
|
|
11
|
-
// @ts-expect-error colonne inexistante
|
|
12
|
-
db.from('users').select('id').eq('nope', 'x')
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
test('eq refuse un mauvais type de valeur', () => {
|
|
16
|
-
// @ts-expect-error email est string
|
|
17
|
-
db.from('users').select('id').eq('email', 123)
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
test('neq/gt/gte/lt/lte typés sur Row', () => {
|
|
21
|
-
db.from('users').select('id').neq('email', 'a@b.c') // OK
|
|
22
|
-
// @ts-expect-error colonne inexistante
|
|
23
|
-
db.from('users').select('id').neq('nope', 'x')
|
|
24
|
-
// @ts-expect-error mauvais type
|
|
25
|
-
db.from('users').select('id').neq('email', 123)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test('in accepte column + Row[C][]', () => {
|
|
29
|
-
db.from('users').select('id').in('email', ['a@b.c', 'd@e.f']) // OK
|
|
30
|
-
// @ts-expect-error colonne inexistante
|
|
31
|
-
db.from('users').select('id').in('nope', ['x'])
|
|
32
|
-
// @ts-expect-error mauvais type de valeur
|
|
33
|
-
db.from('users').select('id').in('email', [123])
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
test('like/ilike acceptent colonne connue', () => {
|
|
37
|
-
db.from('users').select('id').like('email', '%a%') // OK
|
|
38
|
-
// @ts-expect-error colonne inexistante
|
|
39
|
-
db.from('users').select('id').like('nope', '%a%')
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
test('filter/not/match restent permissifs (colonne string)', () => {
|
|
43
|
-
db.from('users').select('id').filter('anything', 'eq', 'x') // OK, échappatoire
|
|
44
|
-
db.from('users').select('id').not('anything', 'eq', 'x') // OK, échappatoire
|
|
45
|
-
db.from('users').select('id').match({ anything: 'x' }) // OK, échappatoire
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
test('or garde sa signature actuelle (string brute)', () => {
|
|
49
|
-
db.from('users')
|
|
50
|
-
.select('id')
|
|
51
|
-
.or([{ column: 'anything', op: 'eq', value: 'x' }]) // OK, échappatoire
|
|
52
|
-
})
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
// Database fixture partagé par les tests type-level (forme + inférence de select).
|
|
2
|
-
// Forme identique à ce que `@aurabase/gen` (Phase 1) produit : chaque table expose
|
|
3
|
-
// Row/Insert/Update/Relationships, avec au moins deux tables liées par une FK.
|
|
4
|
-
|
|
5
|
-
export interface Database {
|
|
6
|
-
public: {
|
|
7
|
-
Tables: {
|
|
8
|
-
users: {
|
|
9
|
-
Row: { id: string; email: string; bio: string | null }
|
|
10
|
-
Insert: { id?: string; email: string; bio?: string | null }
|
|
11
|
-
Update: { id?: string; email?: string; bio?: string | null }
|
|
12
|
-
Relationships: []
|
|
13
|
-
}
|
|
14
|
-
posts: {
|
|
15
|
-
Row: { id: string; author_id: string; title: string }
|
|
16
|
-
Insert: { id?: string; author_id: string; title: string }
|
|
17
|
-
Update: { id?: string; author_id?: string; title?: string }
|
|
18
|
-
Relationships: [
|
|
19
|
-
{
|
|
20
|
-
foreignKeyName: 'posts_author_id_fkey'
|
|
21
|
-
columns: ['author_id']
|
|
22
|
-
isOneToOne: false
|
|
23
|
-
referencedRelation: 'users'
|
|
24
|
-
referencedColumns: ['id']
|
|
25
|
-
},
|
|
26
|
-
]
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
Views: {
|
|
30
|
-
// Vue non updatable (Row seul, pas d'Insert/Update) — parité générateur LOT C.
|
|
31
|
-
active_users: {
|
|
32
|
-
Row: { id: string; email: string }
|
|
33
|
-
Relationships: []
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
Functions: Record<string, never>
|
|
37
|
-
Enums: Record<string, never>
|
|
38
|
-
CompositeTypes: Record<string, never>
|
|
39
|
-
}
|
|
40
|
-
}
|