s3db.js 4.0.2 → 4.1.1
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 +463 -7
- package/dist/s3db.cjs.js +127 -15
- package/dist/s3db.cjs.min.js +7 -7
- package/dist/s3db.es.js +128 -16
- package/dist/s3db.es.min.js +7 -7
- package/dist/s3db.iife.js +127 -15
- package/dist/s3db.iife.min.js +10 -10
- package/package.json +1 -1
package/dist/s3db.cjs.js
CHANGED
|
@@ -938,7 +938,7 @@ class Client extends EventEmitter {
|
|
|
938
938
|
Key: this.config.keyPrefix ? path.join(this.config.keyPrefix, key) : key
|
|
939
939
|
};
|
|
940
940
|
try {
|
|
941
|
-
const response = await this.
|
|
941
|
+
const response = await this.sendCommand(new clientS3.HeadObjectCommand(options2));
|
|
942
942
|
this.emit("headObject", response, options2);
|
|
943
943
|
return response;
|
|
944
944
|
} catch (error) {
|
|
@@ -3482,9 +3482,10 @@ class Schema {
|
|
|
3482
3482
|
this.attributes = attributes || {};
|
|
3483
3483
|
this.passphrase = passphrase ?? "secret";
|
|
3484
3484
|
this.options = lodashEs.merge({}, this.defaultOptions(), options);
|
|
3485
|
+
const processedAttributes = this.preprocessAttributesForValidation(this.attributes);
|
|
3485
3486
|
this.validator = new ValidatorManager({ autoEncrypt: false }).compile(lodashEs.merge(
|
|
3486
3487
|
{ $$async: true },
|
|
3487
|
-
|
|
3488
|
+
processedAttributes
|
|
3488
3489
|
));
|
|
3489
3490
|
if (this.options.generateAutoHooks) this.generateAutoHooks();
|
|
3490
3491
|
if (!lodashEs.isEmpty(map)) {
|
|
@@ -3565,6 +3566,7 @@ class Schema {
|
|
|
3565
3566
|
version,
|
|
3566
3567
|
attributes
|
|
3567
3568
|
} = lodashEs.isString(data) ? JSON.parse(data) : data;
|
|
3569
|
+
attributes = Schema._importAttributes(attributes);
|
|
3568
3570
|
const schema = new Schema({
|
|
3569
3571
|
map,
|
|
3570
3572
|
name,
|
|
@@ -3574,22 +3576,60 @@ class Schema {
|
|
|
3574
3576
|
});
|
|
3575
3577
|
return schema;
|
|
3576
3578
|
}
|
|
3579
|
+
/**
|
|
3580
|
+
* Recursively import attributes, parsing only stringified objects (legacy)
|
|
3581
|
+
*/
|
|
3582
|
+
static _importAttributes(attrs) {
|
|
3583
|
+
if (typeof attrs === "string") {
|
|
3584
|
+
try {
|
|
3585
|
+
const parsed = JSON.parse(attrs);
|
|
3586
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
3587
|
+
return Schema._importAttributes(parsed);
|
|
3588
|
+
}
|
|
3589
|
+
} catch (e) {
|
|
3590
|
+
}
|
|
3591
|
+
return attrs;
|
|
3592
|
+
}
|
|
3593
|
+
if (Array.isArray(attrs)) {
|
|
3594
|
+
return attrs.map((a) => Schema._importAttributes(a));
|
|
3595
|
+
}
|
|
3596
|
+
if (typeof attrs === "object" && attrs !== null) {
|
|
3597
|
+
const out = {};
|
|
3598
|
+
for (const [k, v] of Object.entries(attrs)) {
|
|
3599
|
+
out[k] = Schema._importAttributes(v);
|
|
3600
|
+
}
|
|
3601
|
+
return out;
|
|
3602
|
+
}
|
|
3603
|
+
return attrs;
|
|
3604
|
+
}
|
|
3577
3605
|
export() {
|
|
3578
3606
|
const data = {
|
|
3579
3607
|
version: this.version,
|
|
3580
3608
|
name: this.name,
|
|
3581
3609
|
options: this.options,
|
|
3582
|
-
attributes:
|
|
3610
|
+
attributes: this._exportAttributes(this.attributes),
|
|
3583
3611
|
map: this.map
|
|
3584
3612
|
};
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3613
|
+
return data;
|
|
3614
|
+
}
|
|
3615
|
+
/**
|
|
3616
|
+
* Recursively export attributes, keeping objects as objects and only serializing leaves as string
|
|
3617
|
+
*/
|
|
3618
|
+
_exportAttributes(attrs) {
|
|
3619
|
+
if (typeof attrs === "string") {
|
|
3620
|
+
return attrs;
|
|
3621
|
+
}
|
|
3622
|
+
if (Array.isArray(attrs)) {
|
|
3623
|
+
return attrs.map((a) => this._exportAttributes(a));
|
|
3624
|
+
}
|
|
3625
|
+
if (typeof attrs === "object" && attrs !== null) {
|
|
3626
|
+
const out = {};
|
|
3627
|
+
for (const [k, v] of Object.entries(attrs)) {
|
|
3628
|
+
out[k] = this._exportAttributes(v);
|
|
3590
3629
|
}
|
|
3630
|
+
return out;
|
|
3591
3631
|
}
|
|
3592
|
-
return
|
|
3632
|
+
return attrs;
|
|
3593
3633
|
}
|
|
3594
3634
|
async applyHooksActions(resourceItem, hook) {
|
|
3595
3635
|
for (const [attribute, actions] of Object.entries(this.options.hooks[hook])) {
|
|
@@ -3630,6 +3670,26 @@ class Schema {
|
|
|
3630
3670
|
await this.applyHooksActions(rest, "afterUnmap");
|
|
3631
3671
|
return flat.unflatten(rest);
|
|
3632
3672
|
}
|
|
3673
|
+
/**
|
|
3674
|
+
* Preprocess attributes to convert nested objects into validator-compatible format
|
|
3675
|
+
* @param {Object} attributes - Original attributes
|
|
3676
|
+
* @returns {Object} Processed attributes for validator
|
|
3677
|
+
*/
|
|
3678
|
+
preprocessAttributesForValidation(attributes) {
|
|
3679
|
+
const processed = {};
|
|
3680
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
3681
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
3682
|
+
processed[key] = {
|
|
3683
|
+
type: "object",
|
|
3684
|
+
properties: this.preprocessAttributesForValidation(value),
|
|
3685
|
+
strict: false
|
|
3686
|
+
};
|
|
3687
|
+
} else {
|
|
3688
|
+
processed[key] = value;
|
|
3689
|
+
}
|
|
3690
|
+
}
|
|
3691
|
+
return processed;
|
|
3692
|
+
}
|
|
3633
3693
|
}
|
|
3634
3694
|
|
|
3635
3695
|
var global$1 = (typeof global !== "undefined" ? global :
|
|
@@ -8945,7 +9005,7 @@ class Resource extends EventEmitter {
|
|
|
8945
9005
|
continue;
|
|
8946
9006
|
}
|
|
8947
9007
|
for (const fieldName of Object.keys(partitionDef.fields)) {
|
|
8948
|
-
if (!
|
|
9008
|
+
if (!this.fieldExistsInAttributes(fieldName)) {
|
|
8949
9009
|
throw new Error(
|
|
8950
9010
|
`Partition '${partitionName}' uses field '${fieldName}' which does not exist in resource version '${this.version}'. Available fields: ${currentAttributes.join(", ")}. This version of resource does not have support for this partition.`
|
|
8951
9011
|
);
|
|
@@ -8953,6 +9013,25 @@ class Resource extends EventEmitter {
|
|
|
8953
9013
|
}
|
|
8954
9014
|
}
|
|
8955
9015
|
}
|
|
9016
|
+
/**
|
|
9017
|
+
* Check if a field (including nested fields) exists in the current attributes
|
|
9018
|
+
* @param {string} fieldName - Field name (can be nested like 'utm.source')
|
|
9019
|
+
* @returns {boolean} True if field exists
|
|
9020
|
+
*/
|
|
9021
|
+
fieldExistsInAttributes(fieldName) {
|
|
9022
|
+
if (!fieldName.includes(".")) {
|
|
9023
|
+
return Object.keys(this.attributes || {}).includes(fieldName);
|
|
9024
|
+
}
|
|
9025
|
+
const keys = fieldName.split(".");
|
|
9026
|
+
let currentLevel = this.attributes || {};
|
|
9027
|
+
for (const key of keys) {
|
|
9028
|
+
if (!currentLevel || typeof currentLevel !== "object" || !(key in currentLevel)) {
|
|
9029
|
+
return false;
|
|
9030
|
+
}
|
|
9031
|
+
currentLevel = currentLevel[key];
|
|
9032
|
+
}
|
|
9033
|
+
return true;
|
|
9034
|
+
}
|
|
8956
9035
|
/**
|
|
8957
9036
|
* Apply a single partition rule to a field value
|
|
8958
9037
|
* @param {*} value - The field value
|
|
@@ -9015,17 +9094,38 @@ class Resource extends EventEmitter {
|
|
|
9015
9094
|
const partitionSegments = [];
|
|
9016
9095
|
const sortedFields = Object.entries(partition.fields).sort(([a], [b]) => a.localeCompare(b));
|
|
9017
9096
|
for (const [fieldName, rule] of sortedFields) {
|
|
9018
|
-
const fieldValue = this.
|
|
9019
|
-
|
|
9097
|
+
const fieldValue = this.getNestedFieldValue(data, fieldName);
|
|
9098
|
+
const transformedValue = this.applyPartitionRule(fieldValue, rule);
|
|
9099
|
+
if (transformedValue === void 0 || transformedValue === null) {
|
|
9020
9100
|
return null;
|
|
9021
9101
|
}
|
|
9022
|
-
partitionSegments.push(`${fieldName}=${
|
|
9102
|
+
partitionSegments.push(`${fieldName}=${transformedValue}`);
|
|
9023
9103
|
}
|
|
9024
9104
|
if (partitionSegments.length === 0) {
|
|
9025
9105
|
return null;
|
|
9026
9106
|
}
|
|
9027
9107
|
return join(`resource=${this.name}`, `partition=${partitionName}`, ...partitionSegments, `id=${id}`);
|
|
9028
9108
|
}
|
|
9109
|
+
/**
|
|
9110
|
+
* Get nested field value from data object using dot notation
|
|
9111
|
+
* @param {Object} data - Data object
|
|
9112
|
+
* @param {string} fieldPath - Field path (e.g., "utm.source", "address.city")
|
|
9113
|
+
* @returns {*} Field value
|
|
9114
|
+
*/
|
|
9115
|
+
getNestedFieldValue(data, fieldPath) {
|
|
9116
|
+
if (!fieldPath.includes(".")) {
|
|
9117
|
+
return data[fieldPath];
|
|
9118
|
+
}
|
|
9119
|
+
const keys = fieldPath.split(".");
|
|
9120
|
+
let value = data;
|
|
9121
|
+
for (const key of keys) {
|
|
9122
|
+
if (value === null || value === void 0 || typeof value !== "object") {
|
|
9123
|
+
return void 0;
|
|
9124
|
+
}
|
|
9125
|
+
value = value[key];
|
|
9126
|
+
}
|
|
9127
|
+
return value;
|
|
9128
|
+
}
|
|
9029
9129
|
async insert({ id, ...attributes }) {
|
|
9030
9130
|
if (this.options.timestamps) {
|
|
9031
9131
|
attributes.createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -9507,7 +9607,19 @@ class Resource extends EventEmitter {
|
|
|
9507
9607
|
*/
|
|
9508
9608
|
getDefinitionHash() {
|
|
9509
9609
|
const exportedSchema = this.schema.export();
|
|
9510
|
-
const
|
|
9610
|
+
const stableSchema = {
|
|
9611
|
+
...exportedSchema,
|
|
9612
|
+
attributes: { ...exportedSchema.attributes }
|
|
9613
|
+
};
|
|
9614
|
+
if (this.options.timestamps) {
|
|
9615
|
+
delete stableSchema.attributes.createdAt;
|
|
9616
|
+
delete stableSchema.attributes.updatedAt;
|
|
9617
|
+
if (stableSchema.options && stableSchema.options.partitions) {
|
|
9618
|
+
delete stableSchema.options.partitions.byCreatedDate;
|
|
9619
|
+
delete stableSchema.options.partitions.byUpdatedDate;
|
|
9620
|
+
}
|
|
9621
|
+
}
|
|
9622
|
+
const stableString = jsonStableStringify(stableSchema);
|
|
9511
9623
|
return `sha256:${crypto.createHash("sha256").update(stableString).digest("hex")}`;
|
|
9512
9624
|
}
|
|
9513
9625
|
/**
|
|
@@ -9701,7 +9813,7 @@ class Database extends EventEmitter {
|
|
|
9701
9813
|
this.version = "1";
|
|
9702
9814
|
this.s3dbVersion = (() => {
|
|
9703
9815
|
try {
|
|
9704
|
-
return true ? "4.0
|
|
9816
|
+
return true ? "4.1.0" : "latest";
|
|
9705
9817
|
} catch (e) {
|
|
9706
9818
|
return "latest";
|
|
9707
9819
|
}
|