@objectstack/driver-sql 10.2.0 → 10.3.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/dist/index.d.mts +24 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +33 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +33 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -476,6 +476,30 @@ declare class SqlDriver implements IDataDriver {
|
|
|
476
476
|
analyzeQuery(object: string, query: any, options?: DriverOptions): Promise<any>;
|
|
477
477
|
syncSchema(object: string, schema: unknown, _options?: DriverOptions): Promise<void>;
|
|
478
478
|
dropTable(object: string, _options?: DriverOptions): Promise<void>;
|
|
479
|
+
/**
|
|
480
|
+
* Resolve the per-table tenant-isolation column for a schema, honoring an
|
|
481
|
+
* explicit tenancy opt-out. Single source of truth for both {@link initObjects}
|
|
482
|
+
* and {@link registerExternalObject} (they previously inlined this logic and
|
|
483
|
+
* drifted).
|
|
484
|
+
*
|
|
485
|
+
* Precedence:
|
|
486
|
+
* 1. `tenancy.enabled === false` → `null` (NO driver-level org scope), even
|
|
487
|
+
* when the object carries an `organization_id` column. Platform-global
|
|
488
|
+
* objects (e.g. `sys_license`) keep an optional, often-NULL org FK but must
|
|
489
|
+
* NOT be tenant-scoped: otherwise an authenticated caller's active-org
|
|
490
|
+
* `DriverOptions.tenantId` injects `WHERE organization_id = <org>` and every
|
|
491
|
+
* NULL-org / cross-org row silently disappears (the platform admin then
|
|
492
|
+
* reads zero licenses while an unscoped/anonymous read still sees them).
|
|
493
|
+
* The declarative branch below already respected `enabled !== false`; the
|
|
494
|
+
* implicit `organization_id` fallback did not — this closes that gap.
|
|
495
|
+
* 2. Declared `tenancy.tenantField` (when that field exists on the object).
|
|
496
|
+
* 3. Implicit `organization_id` column detection (legacy objects whose
|
|
497
|
+
* multi-tenant column was injected by the kernel without a spec migration).
|
|
498
|
+
*/
|
|
499
|
+
protected computeTenantField(schema: {
|
|
500
|
+
fields?: Record<string, any>;
|
|
501
|
+
tenancy?: any;
|
|
502
|
+
}): string | null;
|
|
479
503
|
/**
|
|
480
504
|
* Batch-initialise tables from an array of object definitions.
|
|
481
505
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -476,6 +476,30 @@ declare class SqlDriver implements IDataDriver {
|
|
|
476
476
|
analyzeQuery(object: string, query: any, options?: DriverOptions): Promise<any>;
|
|
477
477
|
syncSchema(object: string, schema: unknown, _options?: DriverOptions): Promise<void>;
|
|
478
478
|
dropTable(object: string, _options?: DriverOptions): Promise<void>;
|
|
479
|
+
/**
|
|
480
|
+
* Resolve the per-table tenant-isolation column for a schema, honoring an
|
|
481
|
+
* explicit tenancy opt-out. Single source of truth for both {@link initObjects}
|
|
482
|
+
* and {@link registerExternalObject} (they previously inlined this logic and
|
|
483
|
+
* drifted).
|
|
484
|
+
*
|
|
485
|
+
* Precedence:
|
|
486
|
+
* 1. `tenancy.enabled === false` → `null` (NO driver-level org scope), even
|
|
487
|
+
* when the object carries an `organization_id` column. Platform-global
|
|
488
|
+
* objects (e.g. `sys_license`) keep an optional, often-NULL org FK but must
|
|
489
|
+
* NOT be tenant-scoped: otherwise an authenticated caller's active-org
|
|
490
|
+
* `DriverOptions.tenantId` injects `WHERE organization_id = <org>` and every
|
|
491
|
+
* NULL-org / cross-org row silently disappears (the platform admin then
|
|
492
|
+
* reads zero licenses while an unscoped/anonymous read still sees them).
|
|
493
|
+
* The declarative branch below already respected `enabled !== false`; the
|
|
494
|
+
* implicit `organization_id` fallback did not — this closes that gap.
|
|
495
|
+
* 2. Declared `tenancy.tenantField` (when that field exists on the object).
|
|
496
|
+
* 3. Implicit `organization_id` column detection (legacy objects whose
|
|
497
|
+
* multi-tenant column was injected by the kernel without a spec migration).
|
|
498
|
+
*/
|
|
499
|
+
protected computeTenantField(schema: {
|
|
500
|
+
fields?: Record<string, any>;
|
|
501
|
+
tenancy?: any;
|
|
502
|
+
}): string | null;
|
|
479
503
|
/**
|
|
480
504
|
* Batch-initialise tables from an array of object definitions.
|
|
481
505
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1088,6 +1088,37 @@ var SqlDriver = class {
|
|
|
1088
1088
|
this.assertSchemaMutable("dropTable");
|
|
1089
1089
|
await this.knex.schema.dropTableIfExists(object);
|
|
1090
1090
|
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Resolve the per-table tenant-isolation column for a schema, honoring an
|
|
1093
|
+
* explicit tenancy opt-out. Single source of truth for both {@link initObjects}
|
|
1094
|
+
* and {@link registerExternalObject} (they previously inlined this logic and
|
|
1095
|
+
* drifted).
|
|
1096
|
+
*
|
|
1097
|
+
* Precedence:
|
|
1098
|
+
* 1. `tenancy.enabled === false` → `null` (NO driver-level org scope), even
|
|
1099
|
+
* when the object carries an `organization_id` column. Platform-global
|
|
1100
|
+
* objects (e.g. `sys_license`) keep an optional, often-NULL org FK but must
|
|
1101
|
+
* NOT be tenant-scoped: otherwise an authenticated caller's active-org
|
|
1102
|
+
* `DriverOptions.tenantId` injects `WHERE organization_id = <org>` and every
|
|
1103
|
+
* NULL-org / cross-org row silently disappears (the platform admin then
|
|
1104
|
+
* reads zero licenses while an unscoped/anonymous read still sees them).
|
|
1105
|
+
* The declarative branch below already respected `enabled !== false`; the
|
|
1106
|
+
* implicit `organization_id` fallback did not — this closes that gap.
|
|
1107
|
+
* 2. Declared `tenancy.tenantField` (when that field exists on the object).
|
|
1108
|
+
* 3. Implicit `organization_id` column detection (legacy objects whose
|
|
1109
|
+
* multi-tenant column was injected by the kernel without a spec migration).
|
|
1110
|
+
*/
|
|
1111
|
+
computeTenantField(schema) {
|
|
1112
|
+
const tenancyDecl = schema?.tenancy;
|
|
1113
|
+
if (tenancyDecl?.enabled === false) return null;
|
|
1114
|
+
const fields = schema?.fields;
|
|
1115
|
+
if (tenancyDecl?.tenantField) {
|
|
1116
|
+
const declared = String(tenancyDecl.tenantField);
|
|
1117
|
+
if (fields && Object.prototype.hasOwnProperty.call(fields, declared)) return declared;
|
|
1118
|
+
}
|
|
1119
|
+
if (fields && Object.prototype.hasOwnProperty.call(fields, "organization_id")) return "organization_id";
|
|
1120
|
+
return null;
|
|
1121
|
+
}
|
|
1091
1122
|
/**
|
|
1092
1123
|
* Batch-initialise tables from an array of object definitions.
|
|
1093
1124
|
*/
|
|
@@ -1139,18 +1170,7 @@ var SqlDriver = class {
|
|
|
1139
1170
|
const dateCols = [];
|
|
1140
1171
|
const datetimeCols = [];
|
|
1141
1172
|
const autoNumberCols = [];
|
|
1142
|
-
const
|
|
1143
|
-
let tenantField = null;
|
|
1144
|
-
if (tenancyDecl && tenancyDecl.enabled !== false && tenancyDecl.tenantField) {
|
|
1145
|
-
const declared = String(tenancyDecl.tenantField);
|
|
1146
|
-
if (schema.fields && Object.prototype.hasOwnProperty.call(schema.fields, declared)) {
|
|
1147
|
-
tenantField = declared;
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
if (!tenantField) {
|
|
1151
|
-
const hasOrgField = !!(schema.fields && Object.prototype.hasOwnProperty.call(schema.fields, "organization_id"));
|
|
1152
|
-
tenantField = hasOrgField ? "organization_id" : null;
|
|
1153
|
-
}
|
|
1173
|
+
const tenantField = this.computeTenantField(schema);
|
|
1154
1174
|
if (schema.fields) {
|
|
1155
1175
|
for (const [name, field] of Object.entries(schema.fields)) {
|
|
1156
1176
|
const type = field.type || "string";
|
|
@@ -1188,18 +1208,7 @@ var SqlDriver = class {
|
|
|
1188
1208
|
const booleanCols = [];
|
|
1189
1209
|
const numericCols = [];
|
|
1190
1210
|
const autoNumberCols = [];
|
|
1191
|
-
const
|
|
1192
|
-
let tenantField = null;
|
|
1193
|
-
if (tenancyDecl && tenancyDecl.enabled !== false && tenancyDecl.tenantField) {
|
|
1194
|
-
const declared = String(tenancyDecl.tenantField);
|
|
1195
|
-
if (obj.fields && Object.prototype.hasOwnProperty.call(obj.fields, declared)) {
|
|
1196
|
-
tenantField = declared;
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
if (!tenantField) {
|
|
1200
|
-
const hasOrgField = !!(obj.fields && Object.prototype.hasOwnProperty.call(obj.fields, "organization_id"));
|
|
1201
|
-
tenantField = hasOrgField ? "organization_id" : null;
|
|
1202
|
-
}
|
|
1211
|
+
const tenantField = this.computeTenantField(obj);
|
|
1203
1212
|
if (obj.fields) {
|
|
1204
1213
|
for (const [name, field] of Object.entries(obj.fields)) {
|
|
1205
1214
|
const type = field.type || "string";
|