Skip to content

Commit

Permalink
- Some adjustments to README.md to start brining documentation in li…
Browse files Browse the repository at this point in the history
…ne with TypeScript.

  - Modified index.ts to export `Denodata` as well as an alias `Denobase` to preserve backward compatibility.
  • Loading branch information
anywhichway committed Jul 27, 2023
1 parent 9d0b4ad commit 690ba6e
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 34 deletions.
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,20 +135,16 @@ await (async () => {

# Installation

Not yet available on `deno.land/x`. For now, use:

```javascript
import {denodata} from "https://unpkg.com/denodata";`
import {operators} from "https://unpkg.com/denodata/operators";
import Denodata from "https://deno.land/x/denodata";
import {operators} from "https://deno.land/x/denodata/operators";
```

Run Deno with the `--allow-net` and `--unstable` flags.

# API

`db denodata(options={})`

- Returns an enhanced `Deno KV`.
`Denodata(options={}):Proxy<Deno.Kv>`

- `options` has the surface `{idProperty:string="#",metadataProperty:string="^",maxTransactionSize:number=10,indexValueMutator:function}`. At the moment, 10 is the max transaction size supported by `Deno KV` itself. `indexValueMutator` is documented below.
- `indexValueMutator` is a function that takes `key` and `cname`. It should either return the key, a modified form of the key, `undefined` or throw an error. The value being indexed is the last item in the `key`. If `undefined` is returned, the property holding the value is not indexed. If an error is thrown the indexing operation is aborted. This is useful for indexing objects that contain properties that contain string values too large for `Deno KV` to handle. The current limit for `Deno KV` is 2048 bytes for an entire key. The denodata index structure includes property names, so the practical limit for a string is slightly less and depends on the length of property names. If you expect large string values, you must provide an implementation for this function. In advanced cases, it can be used to support vector transformations on values.
Expand All @@ -163,7 +159,7 @@ Notes:

- For the v0.x.x releases only the top level database functions have been modified to support enhanced capabilities. Methods on transactions, e.g. `db.atomic().set()`, are native and do not support automatic key conversion, metadata, etc.

`void db.delete(keyOrPattern:primitive|UInt8Array|array|object,{?cname:string,?indexOnly:bool,?find:boolean})`
`db.delete(keyOrPattern:primitive|UInt8Array|array|object,{?cname:string,?indexOnly:bool,?find:boolean}):void`

- Deletes a record using key or pattern. Updates indexes.

Expand All @@ -179,7 +175,7 @@ Notes:

- If `indexOnly` is `true` and `keyOrPattern` is an object, only the index entries are deleted.

`Entry *db.find(pattern:array|object,{?cname:string,?ctor:function,?valueMatch:function|object,?minScore:number,?select:function|object,?offset:number,?limit:number})`
`*db.find(pattern:array|object,{?cname:string,?ctor:function,?valueMatch:function|object,?minScore:number,?select:function|object,?offset:number,?limit:number}):Entry`

- `Entry` is an object, but not a formal class, with the following properties:

Expand Down Expand Up @@ -223,11 +219,11 @@ Notes:

- `offset` indicates how many entries to skip before returning results.

`Entry db.get(key:primitive|UInt8Array|array)`
`db.get(key:primitive|UInt8Array|array):Entry`

- Works like `Deno KV.get` except that if the entry value is a class instance saved using `db.put`, it is automatically deserialized and instantiated.

`Entry db.patch(value:object|function,{?cname:string,?metadata:object,?pattern:array|object})`
`db.patch(value:object|function,{?cname:string,?metadata:object,?pattern:array|object}):Entry`

- If value is an object and `pattern` is not provided, `db.patch` finds the object in the database based on its id, applies the changes, updates indexes, and saves the object.
- If `pattern` is provided, it is used as an argument to `db.find` and all matching entries are updated using `value`. If `value` is a primitive, it is used as the new value. If it is an object, it is merged with the existing value. If it is a function, it is called with the existing value and the return value is used as the new value. If the function returns `undefined`, the value is not changed.
Expand All @@ -236,15 +232,15 @@ Notes:
- If `cname` is provided, the object is treated as an instance of `cname`.
- If `metadata` is provided, it is merged with the existing metadata.

`void db.put(object,{?cname:string,?metadata:object,?autoIndex:boolean})`
`db.put(object,{?cname:string,?metadata:object,?autoIndex:boolean}):void`

- Takes an object, assigns an id if necessary, populates/updates indexes, and serializes then saves the object using the id as the key.
- If `cname` is provided, the object is treated as an instance of `cname`.
- If `autoIndex` is `true`, the object is indexed using all of its keys.

- `denodata` serializes `bigints`, `symbols`, `Dates`, and `RegExp` so that they can be restored.

`void db.set(key:primitive|Deno KV Key,value:any,?metadata:object)`
`db.set(key:primitive|Deno KV Key,value:any,?metadata:object):void`

- Works like `Deno KV.set`. Does not manage indexes or do specialized serialization.
- See notes at start of API section regarding `key` and `value` types.
Expand Down Expand Up @@ -447,6 +443,11 @@ The following operators are supported in patterns.
- Beta commenced when unit test coverage first exceeded 90%
- The exposed API is stable. Additional features may be exposed.


2023-07-27 v0.0.24 (Beta)
- Some adjustments to README.md to start brining documentation in line with TypeScript.
- Modified index.ts to export `Denodata` as well as an alias `Denobase` to preserve backward compatibility.

2023-07-27 v0.0.23 (Beta)
- Renamed to `denodata` because `denobase` was already taken on `deno.land/x`.
- Tagged as v0.0.23 to force `deno.land/x` to update.
Expand Down
40 changes: 20 additions & 20 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,10 @@ const uuidv4 = (): string => crypto.randomUUID();

const db:{[key:string|symbol]:any} = (await Deno.openKv() as {[key:string|symbol]:any});

type DenobaseOptions = {maxTransactionSize?:number,idProperty?:string,metadataProperty?:string,indexValueMutator?:(value:any)=>any};
type DenodataOptions = {maxTransactionSize?:number,idProperty?:string,metadataProperty?:string,indexValueMutator?:(value:any)=>any};

function Denobase(options:DenobaseOptions) {
const me = (Object.create(Denobase.prototype) as {[key:string|symbol]:any});
function Denodata(options:DenodataOptions) {
const me = (Object.create(Denodata.prototype) as {[key:string|symbol]:any});
Object.assign(me.options,options);
me.options.maxTransactionSize ||= 10;
me.options.idProperty ||= "#";
Expand All @@ -268,13 +268,13 @@ function Denobase(options:DenobaseOptions) {
});
}

Denobase.prototype = db;
Denodata.prototype = db;
const options:{[key:string]:any} = {};
Denobase.prototype.options = options;
Denobase.prototype.schema = {};
Denobase.prototype.indexes = {};
Denodata.prototype.options = options;
Denodata.prototype.schema = {};
Denodata.prototype.indexes = {};

Denobase.prototype.createSchema = function ({
Denodata.prototype.createSchema = function ({
cname,
ctor,
primaryKey,
Expand All @@ -295,7 +295,7 @@ Denobase.prototype.createSchema = function ({
this.schema[(cname as string)] = {cname, ctor, primaryKey, indexes, $schema, $id, title, description, properties, required};
}

Denobase.prototype.createIndex = async function ({name, indexType="object", ctor,cname,keys}:{name?:string,indexType?:string,ctor?:Function,cname?:string,keys?:string[]} = {}) {
Denodata.prototype.createIndex = async function ({name, indexType="object", ctor,cname,keys}:{name?:string,indexType?:string,ctor?:Function,cname?:string,keys?:string[]} = {}) {
if (!keys || !Array.isArray(keys) || !keys.length) throw new Error("Index must have at least one key");
name ||= keys.join("_");
if(!cname && !ctor) throw new Error("Either cname or ctor must be provided when creating an index");
Expand All @@ -320,14 +320,14 @@ Denobase.prototype.createIndex = async function ({name, indexType="object", ctor
return result;
}*/

Denobase.prototype.clear = async function () {
Denodata.prototype.clear = async function () {
for await(const {key} of this.list({start: [new Uint8Array([])], end: [true]})) {
await this.delete(key);
}
}

const _delete = db.delete.bind(db);
Denobase.prototype.delete = async function (value:any, {cname, indexOnly,find}:{cname?:string,indexOnly?:boolean,find?:boolean} = {}) {
Denodata.prototype.delete = async function (value:any, {cname, indexOnly,find}:{cname?:string,indexOnly?:boolean,find?:boolean} = {}) {
const type = typeof (value);
if (Array.isArray( value)) {
const key = toPattern(toKey(value));
Expand Down Expand Up @@ -418,7 +418,7 @@ Denobase.prototype.delete = async function (value:any, {cname, indexOnly,find}:{
}

//valueMatch,select,{cname,fulltext,scan,sort,sortable,minScore,limit=Infinity,offset=0}={}
Denobase.prototype.find = async function* (pattern:({[key:string]:any}|any)=null, {
Denodata.prototype.find = async function* (pattern:({[key:string]:any}|any)=null, {
indexName,
cname,
ctor,
Expand Down Expand Up @@ -573,7 +573,7 @@ Denobase.prototype.find = async function* (pattern:({[key:string]:any}|any)=null
}
}

Denobase.prototype.findAll = async function(...args:any[]) {
Denodata.prototype.findAll = async function(...args:any[]) {
const results = [];
for await (const result of this.find(...args)) {
results.push(result);
Expand All @@ -582,7 +582,7 @@ Denobase.prototype.findAll = async function(...args:any[]) {
}

const _get = db.get.bind(db);
Denobase.prototype.get = async function (key:any) {
Denodata.prototype.get = async function (key:any) {
const entry = deserializeSpecial(null,await _get(toKey(key)));
if(entry.value?.data!==undefined) {
entry.metadata = entry.value.metadata;
Expand All @@ -600,7 +600,7 @@ Denobase.prototype.get = async function (key:any) {
return entry;
}

Denobase.prototype.getKeys = function(target:object, value:any, schemaKeys:string[][], {indexType, cname, noTokens}:{[key:string]:any} = {}, {hasRegExp, keys = []}:{hasRegExp?:boolean,keys?:any[]} = {}) {
Denodata.prototype.getKeys = function(target:object, value:any, schemaKeys:string[][], {indexType, cname, noTokens}:{[key:string]:any} = {}, {hasRegExp, keys = []}:{hasRegExp?:boolean,keys?:any[]} = {}) {
noTokens ||= this.options.index?.fulltext || this.options.index?.trigram;
if (target && typeof (target) === "object" && !Array.isArray(target)) {
return this.getKeys([], target, value, schemaKeys);
Expand Down Expand Up @@ -655,7 +655,7 @@ Denobase.prototype.getKeys = function(target:object, value:any, schemaKeys:strin
return keys;
}

Denobase.prototype.matchValue = function(pattern:object, target:object) {
Denodata.prototype.matchValue = function(pattern:object, target:object) {
const targetKeys = this.getKeys(target);
this.matchValue.score = 1;
if (this.getKeys(pattern).every((key:any[]) => {
Expand All @@ -667,7 +667,7 @@ Denobase.prototype.matchValue = function(pattern:object, target:object) {
}
}

Denobase.prototype.patch = async function (value:any, {cname,pattern,metadata}:{cname?:string|undefined,pattern?:object|undefined,metadata?:object|undefined} = {}) {
Denodata.prototype.patch = async function (value:any, {cname,pattern,metadata}:{cname?:string|undefined,pattern?:object|undefined,metadata?:object|undefined} = {}) {
const type = typeof (value);
if (value && type==="object" && !(value[this.options.idProperty] || pattern)) {
throw new TypeError(`Can't patch non-object or object without id key if there is no pattern.`);
Expand Down Expand Up @@ -745,7 +745,7 @@ Denobase.prototype.patch = async function (value:any, {cname,pattern,metadata}:{
return await this.put(patched, {cname,patch:true}); // should put inside a transaction
}

Denobase.prototype.put = async function (object: { [key:string]:any }, {cname, metadata,indexType, autoIndex,indexKeys,patch} :{cname?:string,metadata?:object,indexType?:string,autoIndex?:boolean,indexKeys?:string[],patch?:boolean}={}) : Promise<string> {
Denodata.prototype.put = async function (object: { [key:string]:any }, {cname, metadata,indexType, autoIndex,indexKeys,patch} :{cname?:string,metadata?:object,indexType?:string,autoIndex?:boolean,indexKeys?:string[],patch?:boolean}={}) : Promise<string> {
cname ||= getCname(object[this.options.idProperty]) || object.constructor.name;
const id = object[this.options.idProperty] ||= createId(cname),
indexes = [];
Expand Down Expand Up @@ -794,7 +794,7 @@ Denobase.prototype.put = async function (object: { [key:string]:any }, {cname, m
}

const _set = db.set.bind(db);
Denobase.prototype.set = async function (key:any, value:any,metadata:object|undefined) {
Denodata.prototype.set = async function (key:any, value:any,metadata:object|undefined) {
value = {data:value,metadata:metadata||value[this.options.metadataProperty]};
//delete value.data[this.options.metadataProperty];
const type = typeof(value.metadata?.expires);
Expand All @@ -809,4 +809,4 @@ Denobase.prototype.set = async function (key:any, value:any,metadata:object|unde
}


export {Denobase as default,Denobase};
export {Denodata as default,Denodata,Denodata as Denobase};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "denodata",
"version": "0.0.23",
"version": "0.0.24",
"description": "Generalized indexing and search for Deno KV",
"type": "module",
"main": "index.ts",
Expand Down

0 comments on commit 690ba6e

Please sign in to comment.