Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

electrodb

Package Overview
Dependencies
Maintainers
1
Versions
163
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

electrodb - npm Package Compare versions

Comparing version 0.8.18 to 0.8.19

2

package.json
{
"name": "electrodb",
"version": "0.8.18",
"version": "0.8.19",
"description": "A library to more easily create and interact with multiple entities and heretical relationships in dynamodb",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -369,9 +369,16 @@ # ElectroDB

### Facet Templates
In a Facet Template, you provide a formatted template for ElectroDB to use when making keys.
In a Facet Template, you provide a formatted template for ElectroDB to use when making keys. Facet Templates allow for potential ElectroDB adoption on already established tables and records.
The syntax to a Facet Template is simple using the following rules:
1. Only alphanumeric, underscore, colons, and hash symbols are valid. the following regex is used to determine validity: `/^[A-Z1-9:#_]+$/gi`
2. Attributes are identified by a prefixed colon and the attributes name. For example, the syntax `:storeId` will matches `storeId` attribute in the `model`
3. Convention for a composing a key use the `#` symbol to separate attributes, and for labels to attach with underscore. For example, when composing both the `mallId` and `buildingId` would be expressed as `mid_:mallId#bid_:buildingId`.
Attributes are identified by a prefixed colon and the attributes name. For example, the syntax `:storeId` will matches `storeId` attribute in the `model`.
Convention for a composing a key use the `#` symbol to separate attributes, and for labels to attach with underscore. For example, when composing both the `mallId` and `buildingId` would be expressed as `mid_:mallId#bid_:buildingId`.
> ElectroDB will not prefix templated keys with the Entity, Project, Version, or Collection. This will give you greater control of your keys but will limit ElectroDBs ability to prevent leaking entities with some queries.
Facet Templates have some "gotchas" to consider:
1. Keys only allow for one instance of an attribute, the template `:prop1#:prop1` will be interpreted the same as `:prop1#`.
2. ElectoDB will continue to always add a trailing delimiter to facets with keys are partially supplied. (More documentation coming on this soon)
```javascript

@@ -416,4 +423,4 @@ attributes: {

{
pk: '$mallstoredirectory_1#sid_storevalue',
sk: '$mallstores#mid_mallvalue#bid_buildingvalue#uid_unitvalue'
pk: 'sid_storevalue',
sk: 'mid_mallvalue#bid_buildingvalue#uid_unitvalue'
}

@@ -420,0 +427,0 @@ ```

@@ -1022,10 +1022,52 @@ "use strict";

_getPrefixes({collection = "", customFacets = {}} = {}) {
/*
Collections will prefix the sort key so they can be queried with
a "begins_with" operator when crossing entities. It is also possible
that the user defined a custom key on either the PK or SK. In the case
of a customKey AND a collection, the collection is ignored to favor
the custom key.
*/
let keys = {
pk: {
prefix: "",
isCustom: false
},
sk: {
prefix: "",
isCustom: false
}
};
if (collection) {
keys.pk.prefix = this.model.prefixes.pk
keys.sk.prefix = `$${collection}#${this.model.entity}`
} else {
keys.pk.prefix = this.model.prefixes.pk;
keys.sk.prefix = this.model.prefixes.sk;
}
if (customFacets.pk) {
keys.pk.prefix = "";
keys.pk.isCustom = customFacets.pk;
}
if (customFacets.sk) {
keys.sk.prefix = "";
keys.sk.isCustom = customFacets.sk;
}
return keys;
}
_makeIndexKeys(index = "", pkFacets = {}, ...skFacets) {
this._validateIndex(index);
let facets = this.model.facets.byIndex[index];
let pk = this._makeKey(this.model.prefixes.pk, facets.pk, pkFacets);
let prefixes = this._getPrefixes(facets);
let pk = this._makeKey(prefixes.pk.prefix, facets.pk, pkFacets, prefixes.pk);
let sk = [];
if (this.model.lookup.indexHasSortKeys[index]) {
for (let skFacet of skFacets) {
sk.push(this._makeKey(this.model.prefixes.sk, facets.sk, skFacet));
sk.push(this._makeKey(prefixes.sk.prefix, facets.sk, skFacet, prefixes.sk));
}

@@ -1036,8 +1078,12 @@ }

_makeKey(prefix = "", facets = [], supplied = {}) {
_makeKey(prefix = "", facets = [], supplied = {}, {isCustom} = {}) {
let key = prefix;
for (let i = 0; i < facets.length; i++) {
let facet = facets[i];
let facet = facets[i];
let { label, name } = this.model.schema.attributes[facet];
key = `${key}#${label || name}_`;
if (isCustom) {
key = `${key}${label}`;
} else {
key = `${key}#${label || name}_`;
}
if (supplied[name] !== undefined) {

@@ -1104,7 +1150,2 @@ key = `${key}${supplied[name]}`;

_parseComposedKey(key = "") {
if (!key.match(/^[A-Z1-9:#_]+$/gi)) {
throw new Error(
`Invalid key facet template. Allowed characters include only "A-Z", "a-z", "1-9", ":", "_", "#". Received: ${key}`,
);
}
let facets = {};

@@ -1122,3 +1163,3 @@ let names = key.match(/:[A-Z1-9]+/gi);

if (name !== "") {
facets[name] = label.replace(/#|_/gi, "");
facets[name] = label;
}

@@ -1130,13 +1171,16 @@ }

_parseFacets(facets) {
if (Array.isArray(facets)) {
return {
facetLabels: {},
facetArray: facets,
};
} else {
let isCustom = !Array.isArray(facets);
if (isCustom) {
let facetLabels = this._parseComposedKey(facets);
return {
isCustom,
facetLabels,
facetArray: Object.keys(facetLabels),
};
} else {
return {
isCustom,
facetLabels: {},
facetArray: facets,
};
}

@@ -1153,3 +1197,3 @@ }

};
let collections = {};
let facets = {

@@ -1173,4 +1217,11 @@ byIndex: {},

let hasSk = !!index.sk;
let inCollection = !!index.collection;
let customFacets = {
pk: false,
sk: false
}
indexHasSortKeys[indexName] = hasSk;
let { facetArray, facetLabels } = this._parseFacets(index.pk.facets);
let parsedPKFacets = this._parseFacets(index.pk.facets);
let { facetArray, facetLabels } = parsedPKFacets;
customFacets.pk = parsedPKFacets.isCustom;
facets.labels = Object.assign({}, facets.labels, facetLabels);

@@ -1188,3 +1239,5 @@ let pk = {

if (hasSk) {
let { facetArray, facetLabels } = this._parseFacets(index.sk.facets);
let parseSKFacets = this._parseFacets(index.sk.facets);
let { facetArray, facetLabels } = parseSKFacets;
customFacets.sk = parseSKFacets.isCustom;
facets.labels = Object.assign({}, facets.labels, facetLabels);

@@ -1202,6 +1255,12 @@ sk = {

if (inCollection) {
collections[index.collection] = index.collection;
}
let definition = {
pk,
sk,
customFacets,
index: indexName,
collection: index.collection
};

@@ -1241,5 +1300,7 @@

facets.byIndex[indexName] = {
customFacets,
pk: pk.facets,
sk: sk.facets,
all: attributes,
collection: index.collection,
};

@@ -1258,2 +1319,3 @@

indexAccessPattern: indexAccessPatternTransaction,
collections: Object.keys(collections)
};

@@ -1286,2 +1348,3 @@ }

indexField,
collections,
indexHasSortKeys,

@@ -1302,2 +1365,3 @@ indexAccessPattern,

prefixes,
collections,
lookup: {

@@ -1316,12 +1380,2 @@ indexHasSortKeys,

// class AccessPattern {
// constructor(name = "", definition = {}) {
// this._validateIndex(definition);
// this.name = name;
// this.index = definition.index;
// }
// _validateIndex() {}
// }
module.exports = {

@@ -1328,0 +1382,0 @@ Entity,

@@ -9,3 +9,3 @@ const { KeyTypes } = require("./types");

this.field = definition.field || definition.name;
this.label = definition.label || definition.name;
this.label = definition.label || "";
this.readOnly = !!definition.readOnly;

@@ -12,0 +12,0 @@ this.required = !!definition.required;

@@ -1,230 +0,67 @@

// const { Entity, clauses } = require("../src/entity");
// const { expect } = require("chai");
// const moment = require("moment");
// const uuidV4 = require("uuid").v4;
// const DynamoDB = require("aws-sdk/clients/dynamodb");
// const client = new DynamoDB.DocumentClient({
// region: "us-east-1",
// });
const { Entity, clauses } = require("../src/entity");
const { expect } = require("chai");
const moment = require("moment");
const uuidV4 = require("uuid").v4;
const DynamoDB = require("aws-sdk/clients/dynamodb");
const client = new DynamoDB.DocumentClient({
region: "us-east-1",
});
// describe("General", async () => {
// let FilterTests = new Entity({
// service: "tests",
// entity: "filters",
// table: "electro",
// version: "1",
// attributes: {
// pen: {
// type: "string",
// default: () => uuidV4(),
// field: "storeLocationId",
// },
// row: {
// type: "string",
// required: true,
// field: "mall",
// },
// animal: {
// type: "string",
// required: true
// },
// dangerous: {
// type: "boolean"
// }
// },
// filters: {},
// indexes: {
// farm: {
// pk: {
// field: "pk",
// facets: ["pen"],
// },
// sk: {
// field: "sk",
// facets: ["row"]
// }
// },
// },
// }, {client});
// let pen = uuidV4();
// let animals = [
// "Chicken",
// "Chick",
// "Cow",
// "Dog",
// "Pig",
// "Rooster",
// "Shark",
// "Sheep",
// ];
// before(async () => {
// let results = await Promise.all(animals.map(animal => {
// let row = uuidV4();
// if (animal === "Shark") {
// return FilterTests.put({pen, row, animal, dangerous: true}).go()
// } else {
// return FilterTests.put({pen, row, animal}).go()
// }
// }));
// })
// it("Should filter 'eq'", async () => {
// let animals = await FilterTests.query
// .farm({pen})
// .filter(({animal}) => animal.eq("Cow"))
// .go()
// expect(animals)
// .to.be.an("array")
// .and.have.length(1)
// expect(animals.map(pen => pen.animal)).to.have.members(["Cow"]);
// })
// it("Should filter 'gt'", async () => {
// let animals = await FilterTests.query
// .farm({pen})
// .filter(({animal}) => animal.gt("Dog"))
// .go()
// expect(animals)
// .to.be.an("array")
// .and.have.length(4);
// expect(animals.map(pen => pen.animal)).to.have.members([
// "Pig",
// "Rooster",
// "Shark",
// "Sheep"
// ]);
// })
// it("Should filter 'lt'", async () => {
// let animals = await FilterTests.query
// .farm({pen})
// .filter(({animal}) => animal.lt("Pig"))
// .go()
// expect(animals)
// .to.be.an("array")
// .and.have.length(4);
// expect(animals.map(pen => pen.animal)).to.have.members([
// "Chicken",
// "Chick",
// "Cow",
// "Dog",
// ]);
// })
// it("Should filter 'gte'", async () => {
// let animals = await FilterTests.query
// .farm({pen})
// .filter(({animal}) => animal.gte("Dog"))
// .go()
// expect(animals)
// .to.be.an("array")
// .and.have.length(5);
// expect(animals.map(pen => pen.animal)).to.have.members([
// "Dog",
// "Pig",
// "Rooster",
// "Shark",
// "Sheep",
// ]);
// })
// it("Should filter 'lte'", async () => {
// let animals = await FilterTests.query
// .farm({pen})
// .filter(({animal}) => animal.lte("Pig"))
// .go()
// expect(animals)
// .to.be.an("array")
// .and.have.length(5);
// expect(animals.map(pen => pen.animal)).to.have.members([
// "Chicken",
// "Chick",
// "Cow",
// "Dog",
// "Pig",
// ]);
// })
// it("Should filter 'between'", async () => {
// let animals = await FilterTests.query
// .farm({pen})
// .filter(({animal}) => animal.between("Dog", "Rooster"))
// .go()
// expect(animals)
// .to.be.an("array")
// .and.have.length(3);
// expect(animals.map(pen => pen.animal)).to.have.members([
// "Dog",
// "Pig",
// "Rooster"
// ]);
// })
// it("Should filter 'begins'", async () => {
// let animals = await FilterTests.query
// .farm({pen})
// .filter(({animal}) => animal.begins("Sh"))
// .go()
// expect(animals)
// .to.be.an("array")
// .and.have.length(2);
// expect(animals.map(pen => pen.animal)).to.have.members([
// "Shark",
// "Sheep",
// ]);
// })
// it("Should filter 'exists'", async () => {
// let animals = await FilterTests.query
// .farm({pen})
// .filter(({dangerous}) => dangerous.exists())
// .go()
// expect(animals)
// .to.be.an("array")
// .and.have.length(1);
// expect(animals.map(pen => pen.animal)).to.have.members([
// "Shark"
// ]);
// })
// it("Should filter 'notExists'", async () => {
// let animals = await FilterTests.query
// .farm({pen})
// .filter(({dangerous}) => dangerous.notExists())
// .go()
// expect(animals)
// .to.be.an("array")
// .and.have.length(7);
// expect(animals.map(pen => pen.animal)).to.have.members([
// "Chicken",
// "Chick",
// "Cow",
// "Dog",
// "Pig",
// "Rooster",
// "Sheep",
// ]);
// })
// it("Should filter 'contains'", async () => {
// let animals = await FilterTests.query
// .farm({pen})
// .filter(({animal}) => animal.contains("Chick"))
// .go()
// expect(animals)
// .to.be.an("array")
// .and.have.length(2);
// expect(animals.map(pen => pen.animal)).to.have.members([
// "Chicken",
// "Chick"
// ]);
// })
// it("Should filter 'notContains'", async () => {
// let animals = await FilterTests.query
// .farm({pen})
// .filter(({animal}) => animal.notContains("o"))
// .go()
// expect(animals)
// .to.be.an("array")
// .and.have.length(5);
// expect(animals.map(pen => pen.animal)).to.have.members([
// "Chicken",
// "Chick",
// "Pig",
// "Shark",
// "Sheep",
// ]);
// })
// })
describe("Custom keys", () => {
it("Should default labels to facet attribute names in facet template (string)", () => {
const schema = {
service: "MallStoreDirectory",
entity: "MallStores",
table: "StoreDirectory",
version: "1",
attributes: {
id: {
type: "string",
field: "storeLocationId",
},
date: {
type: "string",
field: "dateTime",
},
prop1: {
type: "string",
},
prop2: {
type: "string",
},
},
indexes: {
record: {
pk: {
field: "pk",
facets: `id_:id:prop1`,
},
sk: {
field: "sk",
facets: `:date:prop2:id:prop2`,
},
},
},
};
let mallStore = new Entity(schema);
let putParams = mallStore
.put({
id: "IDENTIFIER",
date: "DATE",
prop1: "PROPERTY1",
prop2: "PROPERTY2",
})
.params();
expect(putParams).to.deep.equal({
Item: {
storeLocationId: "IDENTIFIER",
dateTime: "DATE",
prop1: "PROPERTY1",
prop2: "PROPERTY2",
pk: "$mallstoredirectory_1#id_identifier#prop1_property1",
sk: "$mallstores#date_date#p2_property2",
},
TableName: "StoreDirectory",
});
});
})

@@ -732,4 +732,4 @@ const { Entity, clauses } = require("../src/entity");

prop2: "PROPERTY2",
pk: "$mallstoredirectory_1#id_identifier#p1_property1",
sk: "$mallstores#d_date#p2_property2",
pk: "id_identifier#p1_property1",
sk: "d_date#p2_property2",
},

@@ -739,3 +739,46 @@ TableName: "StoreDirectory",

});
it("Should throw on invalid characters in facet template (string)", () => {
/* This test was removed because facet templates was refactored to remove all electrodb opinions. */
//
// it("Should throw on invalid characters in facet template (string)", () => {
// const schema = {
// service: "MallStoreDirectory",
// entity: "MallStores",
// table: "StoreDirectory",
// version: "1",
// attributes: {
// id: {
// type: "string",
// field: "storeLocationId",
// },
// date: {
// type: "string",
// field: "dateTime",
// },
// prop1: {
// type: "string",
// },
// prop2: {
// type: "string",
// },
// },
// indexes: {
// record: {
// pk: {
// field: "pk",
// facets: `id_:id#p1_:prop1`,
// },
// sk: {
// field: "sk",
// facets: `d_:date|p2_:prop2`,
// },
// },
// },
// };
// expect(() => new Entity(schema)).to.throw(
// `Invalid key facet template. Allowed characters include only "A-Z", "a-z", "1-9", ":", "_", "#". Received: d_:date|p2_:prop2`,
// );
// });
it("Should default labels to facet attribute names in facet template (string)", () => {
const schema = {

@@ -766,7 +809,7 @@ service: "MallStoreDirectory",

field: "pk",
facets: `id_:id#p1_:prop1`,
facets: `id_:id#:prop1`,
},
sk: {
field: "sk",
facets: `d_:date|p2_:prop2`,
facets: `:date#p2_:prop2`,
},

@@ -776,7 +819,24 @@ },

};
expect(() => new Entity(schema)).to.throw(
`Invalid key facet template. Allowed characters include only "A-Z", "a-z", "1-9", ":", "_", "#". Received: d_:date|p2_:prop2`,
);
let mallStore = new Entity(schema);
let putParams = mallStore
.put({
id: "IDENTIFIER",
date: "DATE",
prop1: "PROPERTY1",
prop2: "PROPERTY2",
})
.params();
expect(putParams).to.deep.equal({
Item: {
storeLocationId: "IDENTIFIER",
dateTime: "DATE",
prop1: "PROPERTY1",
prop2: "PROPERTY2",
pk: "id_identifier#property1",
sk: "date#p2_property2",
},
TableName: "StoreDirectory",
});
});
it("Should default labels to facet attribute names in facet template (string)", () => {
it("Should allow for mixed custom/composed facets, and adding collection prefixes when defined", () => {
const schema = {

@@ -802,2 +862,5 @@ service: "MallStoreDirectory",

},
prop3: {
type: "string",
}
},

@@ -808,8 +871,9 @@ indexes: {

field: "pk",
facets: `id_:id#:prop1`,
facets: `id_:id#:prop1#wubba_:prop3`,
},
sk: {
field: "sk",
facets: `:date#p2_:prop2`,
facets: ["date", "prop2"],
},
collection: "testing"
},

@@ -825,2 +889,3 @@ },

prop2: "PROPERTY2",
prop3: "PROPERTY3"
})

@@ -834,4 +899,5 @@ .params();

prop2: "PROPERTY2",
pk: "$mallstoredirectory_1#id_identifier#prop1_property1",
sk: "$mallstores#date_date#p2_property2",
prop3: "PROPERTY3",
pk: "id_identifier#property1#wubba_property3",
sk: "$testing#mallstores#date_date#prop2_property2",
},

@@ -838,0 +904,0 @@ TableName: "StoreDirectory",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc