Updating pouchdb keys based on an updated version of docuri.
This commit is contained in:
1 parent
12f0a8a10d
commit
00ad6285d0
22 files changed
+344
-181
No files matched your search
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* DocURI: Rich document ids for CouchDB.
|
||||
*
|
||||
* Copyright (c) 2014 null2 GmbH Berlin
|
||||
* Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
// type/id/subtype/index/version
|
||||
|
||||
var docuri = module.exports = exports = {};
|
||||
|
||||
// Cached regular expressions for matching named param parts and splatted parts
|
||||
// of route strings.
|
||||
// http://backbonejs.org/docs/backbone.html#section-158
|
||||
var optionalParam = /\((.*?)\)/g;
|
||||
var namedParam = /(\(\?)?:\w+/g;
|
||||
var splatParam = /\*\w+/g;
|
||||
var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
|
||||
var paramKeys = /[*:]\w+/g;
|
||||
|
||||
// Convert a route string into a regular expression,
|
||||
// with named regular expressions for named arguments.
|
||||
// http://backbonejs.org/docs/backbone.html#section-165
|
||||
function routeToRegExp(src) {
|
||||
var keys = [], match;
|
||||
|
||||
while ( ( match = paramKeys.exec( src ) ) !== null )
|
||||
{
|
||||
keys.push( match[0] );
|
||||
}
|
||||
|
||||
var route = src.replace(escapeRegExp, '\\$&')
|
||||
.replace(optionalParam, '(?:$1)?')
|
||||
.replace(namedParam, function(match, optional) {
|
||||
|
||||
return optional ? match : '([^/?]+)';
|
||||
})
|
||||
.replace(splatParam, '([^?]*?)');
|
||||
|
||||
keys = keys.reduce(function(memo, key) {
|
||||
var value = '\\' + key;
|
||||
|
||||
memo[key] = new RegExp(value + '(\\/|\\)|\\(|$)');
|
||||
|
||||
return memo;
|
||||
}, {});
|
||||
|
||||
return {
|
||||
src: src,
|
||||
exp: new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$'),
|
||||
keys: keys
|
||||
}
|
||||
}
|
||||
|
||||
// Given a route and a DocURI return an object of extracted parameters.
|
||||
// Unmatched DocURIs will be treated as false.
|
||||
// http://backbonejs.org/docs/backbone.html#section-166
|
||||
function extractParameters(route, fragment, coding) {
|
||||
var params = route.exp.exec(fragment);
|
||||
|
||||
if (!params) {
|
||||
return false;
|
||||
}
|
||||
|
||||
params = params.slice(1);
|
||||
|
||||
return Object.keys(route.keys).reduce(function(memo, key, i) {
|
||||
var param = params[i];
|
||||
|
||||
if (param) {
|
||||
|
||||
var k = key.substr(1);
|
||||
var decoder = (coding[k] ?? {decoder:decodeURIComponent}).decoder;
|
||||
|
||||
if (key[0] === '*') {
|
||||
param = param.split('/').map(decoder);
|
||||
} else {
|
||||
param = decoder(param);
|
||||
}
|
||||
|
||||
|
||||
memo[key.substr(1)] = param;
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, {});
|
||||
}
|
||||
|
||||
// Insert named parameters from object.
|
||||
function insertParameters(route, obj, coding) {
|
||||
var str = route.src;
|
||||
|
||||
Object.keys(route.keys).forEach(function(key) {
|
||||
var k = key.substr(1);
|
||||
var value = (obj[k] !== undefined) ? obj[k] : '';
|
||||
|
||||
var encoder = (coding[k] ?? {encoder:encodeURIComponent}).encoder;
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
value = value.map(encoder).join('/');
|
||||
} else {
|
||||
value = encoder(value);
|
||||
}
|
||||
|
||||
str = str.replace(route.keys[key], value + '$1');
|
||||
});
|
||||
|
||||
// massage optional parameter
|
||||
return str
|
||||
.replace(/\(\/\)/g, '')
|
||||
.replace(/[)(]/g, '');
|
||||
}
|
||||
|
||||
|
||||
docuri.route = function(route, coding={}) {
|
||||
route = routeToRegExp(route);
|
||||
|
||||
return function(source, target) {
|
||||
source = source || {};
|
||||
|
||||
if (target) {
|
||||
source = extractParameters(route, source, coding);
|
||||
Object.keys(target).forEach(function(key) {
|
||||
source[key] = target[key];
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof source === 'object') {
|
||||
return insertParameters(route, source, coding);
|
||||
}
|
||||
|
||||
if (typeof source === 'string') {
|
||||
return extractParameters(route, source, coding);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
+39
-35
@@ -1,4 +1,4 @@
|
||||
import { route } from 'docuri';
|
||||
import { route } from './docuri';
|
||||
import uri from './ids';
|
||||
|
||||
describe('Checking some DocURI features', () => {
|
||||
@@ -43,64 +43,68 @@ describe('Checking a multilevel route with optional part', () => {
|
||||
});
|
||||
|
||||
describe('Checking gpx ids', () => {
|
||||
const id = {
|
||||
gpx: 12345678901234567n,
|
||||
};
|
||||
const key = 'gpx/12345678901234567';
|
||||
test(', vice', () => {
|
||||
const gpx = uri('gpx', { gpx: 'id' });
|
||||
expect(gpx).toBe('gpx/id');
|
||||
const gpx = uri('gpx', id);
|
||||
expect(gpx).toBe(key);
|
||||
});
|
||||
test(', and versa', () => {
|
||||
const gpx = uri('gpx', 'gpx/id');
|
||||
expect(gpx).toMatchObject({ gpx: 'id' });
|
||||
const gpx = uri('gpx', key);
|
||||
expect(gpx).toMatchObject(id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Checking trk ids', () => {
|
||||
const id = {
|
||||
gpx: 12345678901234567n,
|
||||
trk: 123456,
|
||||
};
|
||||
const key = 'gpx/12345678901234567/2trk/123456';
|
||||
test(', vice', () => {
|
||||
const rte = uri('trk', { gpx: 'gpxid', trk: 'trkid' });
|
||||
expect(rte).toBe('gpx/gpxid/2trk/trkid');
|
||||
const rte = uri('trk', id);
|
||||
expect(rte).toBe(key);
|
||||
});
|
||||
test(', and versa', () => {
|
||||
const rte = uri('trk', 'gpx/gpxid/2trk/trkid');
|
||||
expect(rte).toMatchObject({ gpx: 'gpxid', trk: 'trkid' });
|
||||
const rte = uri('trk', key);
|
||||
expect(rte).toMatchObject(id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Checking trkseg ids', () => {
|
||||
const id = {
|
||||
gpx: 111n,
|
||||
trk: 0,
|
||||
trkseg: 3,
|
||||
};
|
||||
const key = 'gpx/00000000000000111/2trk/000000/000003';
|
||||
test(', vice', () => {
|
||||
const rte = uri('trkseg', {
|
||||
gpx: 'gpxid',
|
||||
trk: 'trkid',
|
||||
trkseg: 'trksegid',
|
||||
});
|
||||
expect(rte).toBe('gpx/gpxid/2trk/trkid/trksegid');
|
||||
const rte = uri('trkseg', id);
|
||||
expect(rte).toBe(key);
|
||||
});
|
||||
test(', and versa', () => {
|
||||
const rte = uri('trkseg', 'gpx/gpxid/2trk/trkid/trksegid');
|
||||
expect(rte).toMatchObject({
|
||||
gpx: 'gpxid',
|
||||
trk: 'trkid',
|
||||
trkseg: 'trksegid',
|
||||
});
|
||||
const rte = uri('trkseg', key);
|
||||
expect(rte).toMatchObject(id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Checking trkpt ids', () => {
|
||||
const id = {
|
||||
gpx: 25n,
|
||||
trk: 8,
|
||||
trkseg: 0,
|
||||
trkpt: 155,
|
||||
};
|
||||
const key = 'gpx/00000000000000025/2trk/000008/000000/000155';
|
||||
test(', vice', () => {
|
||||
const rte = uri('trkpt', {
|
||||
gpx: 'gpxid',
|
||||
trk: 'trkid',
|
||||
trkseg: 'trksegid',
|
||||
trkpt: 'trkptid',
|
||||
});
|
||||
expect(rte).toBe('gpx/gpxid/2trk/trkid/trksegid/trkptid');
|
||||
const rte = uri('trkpt', id);
|
||||
expect(rte).toBe(key);
|
||||
});
|
||||
test(', and versa', () => {
|
||||
const rte = uri('trkpt', 'gpx/gpxid/2trk/trkid/trksegid/trkptid');
|
||||
expect(rte).toMatchObject({
|
||||
gpx: 'gpxid',
|
||||
trk: 'trkid',
|
||||
trkseg: 'trksegid',
|
||||
trkpt: 'trkptid',
|
||||
});
|
||||
const rte = uri('trkpt', key);
|
||||
expect(rte).toMatchObject(id);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+34
-10
@@ -1,15 +1,39 @@
|
||||
import { route } from 'docuri';
|
||||
import { route } from './docuri';
|
||||
|
||||
const integerType = (n: number) => {
|
||||
return {
|
||||
encoder: (v: number) => v.toString().padStart(n, '0'),
|
||||
decoder: parseInt,
|
||||
};
|
||||
};
|
||||
|
||||
const bigIntType = (n: number) => {
|
||||
return {
|
||||
encoder: (v: number) => v.toString().padStart(n, '0'),
|
||||
decoder: BigInt,
|
||||
};
|
||||
};
|
||||
|
||||
const coding = {
|
||||
gpx: bigIntType(17),
|
||||
wpt: integerType(6),
|
||||
rte: integerType(6),
|
||||
rtept: integerType(6),
|
||||
trk: integerType(6),
|
||||
trkseg: integerType(6),
|
||||
trkpt: integerType(6),
|
||||
};
|
||||
|
||||
const routes = {
|
||||
dbdef: route('dbdef'),
|
||||
settings: route('settings'),
|
||||
gpx: route('gpx/:gpx'),
|
||||
wpt: route('gpx/:gpx/0wpt/:wpt'),
|
||||
rte: route('gpx/:gpx/1rte/:rte'),
|
||||
rtept: route('gpx/:gpx/1rte/:rte/:rtept'),
|
||||
trk: route('gpx/:gpx/2trk/:trk'),
|
||||
trkseg: route('gpx/:gpx/2trk/:trk/:trkseg'),
|
||||
trkpt: route('gpx/:gpx/2trk/:trk/:trkseg/:trkpt'),
|
||||
dbdef: route('dbdef', coding),
|
||||
settings: route('settings', coding),
|
||||
gpx: route('gpx/:gpx', coding),
|
||||
wpt: route('gpx/:gpx/0wpt/:wpt', coding),
|
||||
rte: route('gpx/:gpx/1rte/:rte', coding),
|
||||
rtept: route('gpx/:gpx/1rte/:rte/:rtept', coding),
|
||||
trk: route('gpx/:gpx/2trk/:trk', coding),
|
||||
trkseg: route('gpx/:gpx/2trk/:trk/:trkseg', coding),
|
||||
trkpt: route('gpx/:gpx/2trk/:trk/:trkseg/:trkpt', coding),
|
||||
};
|
||||
|
||||
type RouteKey = keyof typeof routes;
|
||||
|
||||
Vendored
+17
-17
@@ -1,34 +1,34 @@
|
||||
interface IdGpx {
|
||||
gpx: string;
|
||||
gpx: BigInt;
|
||||
}
|
||||
|
||||
interface IdTrk {
|
||||
gpx: string;
|
||||
trk: string;
|
||||
gpx: BigInt;
|
||||
trk: number;
|
||||
}
|
||||
interface IdTrkseg {
|
||||
gpx: string;
|
||||
trk: string;
|
||||
trkseg: string;
|
||||
gpx: BigInt;
|
||||
trk: number;
|
||||
trkseg: number;
|
||||
}
|
||||
interface IdTrkpt {
|
||||
gpx: string;
|
||||
trk: string;
|
||||
trkseg: string;
|
||||
trkpt: string;
|
||||
gpx: BigInt;
|
||||
trk: number;
|
||||
trkseg: number;
|
||||
trkpt: number;
|
||||
}
|
||||
interface IdWpt {
|
||||
gpx: string;
|
||||
wpt: string;
|
||||
gpx: BigInt;
|
||||
wpt: number;
|
||||
}
|
||||
|
||||
interface IdRte {
|
||||
gpx: string;
|
||||
rte: string;
|
||||
gpx: BigInt;
|
||||
rte: number;
|
||||
}
|
||||
|
||||
interface IdRtept {
|
||||
gpx: string;
|
||||
rte: string;
|
||||
rtept: string;
|
||||
gpx: BigInt;
|
||||
rte: number;
|
||||
rtept: number;
|
||||
}
|
||||
Reference in new issue
Block a user