s3db.js 4.1.1 → 4.1.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/README.md +42 -0
- package/dist/s3db.cjs.js +93 -16
- package/dist/s3db.cjs.min.js +8 -8
- package/dist/s3db.es.js +93 -16
- package/dist/s3db.es.min.js +8 -8
- package/dist/s3db.iife.js +93 -16
- package/dist/s3db.iife.min.js +8 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -830,6 +830,48 @@ const resource = await s3db.createResource({
|
|
|
830
830
|
});
|
|
831
831
|
```
|
|
832
832
|
|
|
833
|
+
#### Check Resource Existence
|
|
834
|
+
|
|
835
|
+
```javascript
|
|
836
|
+
// Check if a resource exists by name
|
|
837
|
+
const exists = s3db.resourceExists("users");
|
|
838
|
+
console.log(exists); // true or false
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
#### Create Resource If Not Exists
|
|
842
|
+
|
|
843
|
+
```javascript
|
|
844
|
+
// Create a resource only if it doesn't exist with the same definition hash
|
|
845
|
+
const result = await s3db.createResourceIfNotExists({
|
|
846
|
+
name: "users",
|
|
847
|
+
attributes: {
|
|
848
|
+
name: "string|required",
|
|
849
|
+
email: "email|required"
|
|
850
|
+
},
|
|
851
|
+
options: { timestamps: true },
|
|
852
|
+
behavior: "user-management"
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
console.log(result);
|
|
856
|
+
// {
|
|
857
|
+
// resource: Resource,
|
|
858
|
+
// created: true, // or false if already existed
|
|
859
|
+
// reason: "New resource created" // or "Resource already exists with same definition hash"
|
|
860
|
+
// }
|
|
861
|
+
|
|
862
|
+
// If the resource already exists with the same hash, it returns the existing resource
|
|
863
|
+
const result2 = await s3db.createResourceIfNotExists({
|
|
864
|
+
name: "users",
|
|
865
|
+
attributes: {
|
|
866
|
+
name: "string|required",
|
|
867
|
+
email: "email|required"
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
console.log(result2.created); // false
|
|
872
|
+
console.log(result2.reason); // "Resource already exists with same definition hash"
|
|
873
|
+
```
|
|
874
|
+
|
|
833
875
|
#### Get Resource Reference
|
|
834
876
|
|
|
835
877
|
```javascript
|
package/dist/s3db.cjs.js
CHANGED
|
@@ -9606,20 +9606,13 @@ class Resource extends EventEmitter {
|
|
|
9606
9606
|
* @returns {string} SHA256 hash of the schema definition
|
|
9607
9607
|
*/
|
|
9608
9608
|
getDefinitionHash() {
|
|
9609
|
-
const
|
|
9610
|
-
const
|
|
9611
|
-
...exportedSchema,
|
|
9612
|
-
attributes: { ...exportedSchema.attributes }
|
|
9613
|
-
};
|
|
9609
|
+
const attributes = this.schema.export().attributes;
|
|
9610
|
+
const stableAttributes = { ...attributes };
|
|
9614
9611
|
if (this.options.timestamps) {
|
|
9615
|
-
delete
|
|
9616
|
-
delete
|
|
9617
|
-
if (stableSchema.options && stableSchema.options.partitions) {
|
|
9618
|
-
delete stableSchema.options.partitions.byCreatedDate;
|
|
9619
|
-
delete stableSchema.options.partitions.byUpdatedDate;
|
|
9620
|
-
}
|
|
9612
|
+
delete stableAttributes.createdAt;
|
|
9613
|
+
delete stableAttributes.updatedAt;
|
|
9621
9614
|
}
|
|
9622
|
-
const stableString = jsonStableStringify(
|
|
9615
|
+
const stableString = jsonStableStringify(stableAttributes);
|
|
9623
9616
|
return `sha256:${crypto.createHash("sha256").update(stableString).digest("hex")}`;
|
|
9624
9617
|
}
|
|
9625
9618
|
/**
|
|
@@ -9813,7 +9806,7 @@ class Database extends EventEmitter {
|
|
|
9813
9806
|
this.version = "1";
|
|
9814
9807
|
this.s3dbVersion = (() => {
|
|
9815
9808
|
try {
|
|
9816
|
-
return true ? "4.1.
|
|
9809
|
+
return true ? "4.1.2" : "latest";
|
|
9817
9810
|
} catch (e) {
|
|
9818
9811
|
return "latest";
|
|
9819
9812
|
}
|
|
@@ -9925,10 +9918,21 @@ class Database extends EventEmitter {
|
|
|
9925
9918
|
/**
|
|
9926
9919
|
* Generate a consistent hash for a resource definition
|
|
9927
9920
|
* @param {Object} definition - Resource definition to hash
|
|
9921
|
+
* @param {string} behavior - Resource behavior
|
|
9928
9922
|
* @returns {string} SHA256 hash
|
|
9929
9923
|
*/
|
|
9930
|
-
generateDefinitionHash(definition) {
|
|
9931
|
-
const
|
|
9924
|
+
generateDefinitionHash(definition, behavior = void 0) {
|
|
9925
|
+
const attributes = definition.attributes;
|
|
9926
|
+
const stableAttributes = { ...attributes };
|
|
9927
|
+
if (definition.options?.timestamps) {
|
|
9928
|
+
delete stableAttributes.createdAt;
|
|
9929
|
+
delete stableAttributes.updatedAt;
|
|
9930
|
+
}
|
|
9931
|
+
const hashObj = {
|
|
9932
|
+
attributes: stableAttributes,
|
|
9933
|
+
behavior: behavior || definition.behavior || "user-management"
|
|
9934
|
+
};
|
|
9935
|
+
const stableString = jsonStableStringify(hashObj);
|
|
9932
9936
|
return `sha256:${crypto.createHash("sha256").update(stableString).digest("hex")}`;
|
|
9933
9937
|
}
|
|
9934
9938
|
/**
|
|
@@ -10015,6 +10019,73 @@ class Database extends EventEmitter {
|
|
|
10015
10019
|
resources: {}
|
|
10016
10020
|
};
|
|
10017
10021
|
}
|
|
10022
|
+
/**
|
|
10023
|
+
* Check if a resource exists by name
|
|
10024
|
+
* @param {string} name - Resource name
|
|
10025
|
+
* @returns {boolean} True if resource exists, false otherwise
|
|
10026
|
+
*/
|
|
10027
|
+
resourceExists(name) {
|
|
10028
|
+
return !!this.resources[name];
|
|
10029
|
+
}
|
|
10030
|
+
/**
|
|
10031
|
+
* Check if a resource exists with the same definition hash
|
|
10032
|
+
* @param {string} name - Resource name
|
|
10033
|
+
* @param {Object} attributes - Resource attributes
|
|
10034
|
+
* @param {Object} options - Resource options
|
|
10035
|
+
* @param {string} behavior - Resource behavior
|
|
10036
|
+
* @returns {Object} Object with exists flag and hash information
|
|
10037
|
+
*/
|
|
10038
|
+
resourceExistsWithSameHash({ name, attributes, options = {}, behavior = "user-management" }) {
|
|
10039
|
+
if (!this.resources[name]) {
|
|
10040
|
+
return { exists: false, sameHash: false, hash: null };
|
|
10041
|
+
}
|
|
10042
|
+
const tempResource = new Resource({
|
|
10043
|
+
name,
|
|
10044
|
+
attributes,
|
|
10045
|
+
behavior,
|
|
10046
|
+
observers: [],
|
|
10047
|
+
client: this.client,
|
|
10048
|
+
version: "temp",
|
|
10049
|
+
options: {
|
|
10050
|
+
cache: this.cache,
|
|
10051
|
+
...options
|
|
10052
|
+
}
|
|
10053
|
+
});
|
|
10054
|
+
const newHash = this.generateDefinitionHash(tempResource.export(), behavior);
|
|
10055
|
+
const existingHash = this.generateDefinitionHash(this.resources[name].export(), this.resources[name].behavior);
|
|
10056
|
+
return {
|
|
10057
|
+
exists: true,
|
|
10058
|
+
sameHash: newHash === existingHash,
|
|
10059
|
+
hash: newHash,
|
|
10060
|
+
existingHash
|
|
10061
|
+
};
|
|
10062
|
+
}
|
|
10063
|
+
/**
|
|
10064
|
+
* Create a resource only if it doesn't exist with the same definition hash
|
|
10065
|
+
* @param {Object} params - Resource parameters
|
|
10066
|
+
* @param {string} params.name - Resource name
|
|
10067
|
+
* @param {Object} params.attributes - Resource attributes
|
|
10068
|
+
* @param {Object} params.options - Resource options
|
|
10069
|
+
* @param {string} params.behavior - Resource behavior
|
|
10070
|
+
* @returns {Object} Object with resource and created flag
|
|
10071
|
+
*/
|
|
10072
|
+
async createResourceIfNotExists({ name, attributes, options = {}, behavior = "user-management" }) {
|
|
10073
|
+
const alreadyExists = !!this.resources[name];
|
|
10074
|
+
const hashCheck = this.resourceExistsWithSameHash({ name, attributes, options, behavior });
|
|
10075
|
+
if (hashCheck.exists && hashCheck.sameHash) {
|
|
10076
|
+
return {
|
|
10077
|
+
resource: this.resources[name],
|
|
10078
|
+
created: false,
|
|
10079
|
+
reason: "Resource already exists with same definition hash"
|
|
10080
|
+
};
|
|
10081
|
+
}
|
|
10082
|
+
const resource = await this.createResource({ name, attributes, options, behavior });
|
|
10083
|
+
return {
|
|
10084
|
+
resource,
|
|
10085
|
+
created: !alreadyExists,
|
|
10086
|
+
reason: alreadyExists ? "Resource updated with new definition" : "New resource created"
|
|
10087
|
+
};
|
|
10088
|
+
}
|
|
10018
10089
|
async createResource({ name, attributes, options = {}, behavior = "user-management" }) {
|
|
10019
10090
|
if (this.resources[name]) {
|
|
10020
10091
|
const existingResource = this.resources[name];
|
|
@@ -10026,7 +10097,13 @@ class Database extends EventEmitter {
|
|
|
10026
10097
|
existingResource.behavior = behavior;
|
|
10027
10098
|
}
|
|
10028
10099
|
existingResource.updateAttributes(attributes);
|
|
10029
|
-
|
|
10100
|
+
const newHash = this.generateDefinitionHash(existingResource.export(), existingResource.behavior);
|
|
10101
|
+
const existingMetadata2 = this.savedMetadata?.resources?.[name];
|
|
10102
|
+
const currentVersion = existingMetadata2?.currentVersion || "v0";
|
|
10103
|
+
const existingVersionData = existingMetadata2?.versions?.[currentVersion];
|
|
10104
|
+
if (!existingVersionData || existingVersionData.hash !== newHash) {
|
|
10105
|
+
await this.uploadMetadataFile();
|
|
10106
|
+
}
|
|
10030
10107
|
this.emit("s3db.resourceUpdated", name);
|
|
10031
10108
|
return existingResource;
|
|
10032
10109
|
}
|