mirror of
https://github.com/dolthub/dolt.git
synced 2026-01-29 03:08:47 -06:00
Merge pull request #792 from rafael-atticlabs/betterCollections
JS Collection refactor, splore, crunchbase ui, & pitchmap update
This commit is contained in:
@@ -34,7 +34,7 @@
|
||||
"watchify": "^3.6"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "cp node_modules/nvd3/build/nv.d3.css nv.d3.css; NOMS_SERVER=http://localhost:8000 NOMS_DATASET_ID=crunchbase/index watchify -o out.js -v -d src/main.js",
|
||||
"start": "cp node_modules/nvd3/build/nv.d3.css nv.d3.css; NOMS_SERVER=http://localhost:8000 NOMS_DATASET_ID=crunchbase/index watchify -o out.js -v -d node_modules/babel-regenerator-runtime/runtime.js src/main.js",
|
||||
"build": "./.npm_build_helper.sh",
|
||||
"test": "rm -f out.js && eslint src/ && flow src/"
|
||||
},
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
// @flow
|
||||
|
||||
export function invariant(exp: any, message: string = 'Invariant violated') {
|
||||
if (!exp) {
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
// @flow
|
||||
|
||||
import {readValue, Struct, makeType, Ref, registerPackage} from 'noms';
|
||||
import {invariant} from './assert.js';
|
||||
import type {ChunkStore, Package} from 'noms';
|
||||
import {invariant, Kind, NomsMap, NomsSet, SetLeafSequence, makeCompoundType, makePrimitiveType} from 'noms';
|
||||
|
||||
type RoundTypeEnum = 0 | 1 | 2;
|
||||
const Seed = 0;
|
||||
@@ -34,15 +34,14 @@ export default class DataManager {
|
||||
_datasetId: string;
|
||||
_keyClass: any;
|
||||
_quarterClass: any;
|
||||
_index: Map<string, Ref>;
|
||||
_datasetP: ?Promise<Map<Ref, Ref>>;
|
||||
_datasetP: ?Promise<NomsMap<Ref, Ref>>;
|
||||
_packageP: ?Promise<Package>;
|
||||
|
||||
_categorySetP: ?Promise<Set<Struct>>;
|
||||
_timeSetP: ?Promise<Set<Struct>>;
|
||||
_seedSetP: ?Promise<Set<Struct>>;
|
||||
_seriesASetP: ?Promise<Set<Struct>>;
|
||||
_seriesBSetP: ?Promise<Set<Struct>>;
|
||||
_categorySetP: ?Promise<NomsSet<Struct>>;
|
||||
_timeSetP: ?Promise<NomsSet<Struct>>;
|
||||
_seedSetP: ?Promise<NomsSet<Struct>>;
|
||||
_seriesASetP: ?Promise<NomsSet<Struct>>;
|
||||
_seriesBSetP: ?Promise<NomsSet<Struct>>;
|
||||
|
||||
_data: ?DataArray;
|
||||
_time: ?TimeOption;
|
||||
@@ -55,7 +54,6 @@ export default class DataManager {
|
||||
this._quarterClass = null;
|
||||
this._datasetP = null;
|
||||
this._packageP = null;
|
||||
this._index = new Map();
|
||||
|
||||
this._timeSetP = null;
|
||||
this._categorySetP = null;
|
||||
@@ -68,7 +66,7 @@ export default class DataManager {
|
||||
this._category = '';
|
||||
}
|
||||
|
||||
async _getDataset(): Promise<Map<Ref, Ref>> {
|
||||
async _getDataset(): Promise<NomsMap<Ref, Ref>> {
|
||||
if (this._datasetP) {
|
||||
return this._datasetP;
|
||||
}
|
||||
@@ -82,8 +80,6 @@ export default class DataManager {
|
||||
|
||||
let ds = await this._getDataset();
|
||||
this._packageP = getKeyPackage(ds, this._store);
|
||||
this._index = convertMap(ds);
|
||||
invariant(this._packageP);
|
||||
return this._packageP;
|
||||
}
|
||||
|
||||
@@ -137,19 +133,23 @@ export default class DataManager {
|
||||
await Promise.all([this._seedSetP, this._seriesASetP, this._seriesBSetP,
|
||||
this._timeSetP, this._categorySetP]);
|
||||
|
||||
let baseSet = intersectRounds(timeSet, categorySet);
|
||||
let baseSet = await timeSet.intersect(categorySet);
|
||||
let sets = await Promise.all([baseSet.intersect(seedSet),
|
||||
baseSet.intersect(seriesASet), baseSet.intersect(seriesBSet)]);
|
||||
let ptiles = await Promise.all([percentiles(sets[0]), percentiles(sets[1]),
|
||||
percentiles(sets[2])]);
|
||||
|
||||
return this._data = [
|
||||
{
|
||||
values: percentiles(intersectRounds(baseSet, seedSet)),
|
||||
values: ptiles[0],
|
||||
key: 'Seed'
|
||||
},
|
||||
{
|
||||
values: percentiles(intersectRounds(baseSet, seriesASet)),
|
||||
values: ptiles[1],
|
||||
key: 'A'
|
||||
},
|
||||
{
|
||||
values: percentiles(intersectRounds(baseSet, seriesBSet)),
|
||||
values: ptiles[2],
|
||||
key: 'B'
|
||||
}
|
||||
];
|
||||
@@ -167,31 +167,35 @@ export default class DataManager {
|
||||
return k.ref;
|
||||
}
|
||||
|
||||
async _getSetOfRounds(p: KeyParam): Promise<Set<Struct>> {
|
||||
let s = (await this._getKeyRef(p)).toString();
|
||||
let v = this._index.get(s);
|
||||
if (v === undefined) {
|
||||
return new Set();
|
||||
async _getSetOfRounds(p: KeyParam): Promise<NomsSet<Struct>> {
|
||||
let r = await this._getKeyRef(p);
|
||||
invariant(this._datasetP);
|
||||
let map = await this._datasetP;
|
||||
let setRef = await map.get(r);
|
||||
if (setRef === undefined) {
|
||||
// TODO: Cleanup the NomsSet api (it shouldn't be this hard to create an emptySet)
|
||||
return new NomsSet(this._store, setTr, new SetLeafSequence(setTr, []));
|
||||
}
|
||||
let set = readValue(v, this._store);
|
||||
return set || new Set();
|
||||
}
|
||||
|
||||
return readValue(setRef, this._store);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This is actually the wrong type. Fix when we have JS codegen.
|
||||
const setTr = makeCompoundType(Kind.Set, makeCompoundType(Kind.Ref, makePrimitiveType(Kind.Value)));
|
||||
|
||||
/**
|
||||
* Loads the first key in the index and gets the package from the type.
|
||||
*/
|
||||
async function getKeyPackage(index: Map<Ref, Ref>, store: ChunkStore):
|
||||
async function getKeyPackage(index: NomsMap<Ref, Ref>, store: ChunkStore):
|
||||
Promise<Package> {
|
||||
let ref;
|
||||
for (let v of index.keys()) {
|
||||
ref = v;
|
||||
break;
|
||||
}
|
||||
invariant(ref instanceof Ref);
|
||||
let key = await readValue(ref, store);
|
||||
let pkg = await readValue(key.type.packageRef, store);
|
||||
let kv = await index.first();
|
||||
invariant(kv);
|
||||
let ref = kv[0];
|
||||
let key: Struct = await readValue(ref, store);
|
||||
invariant(key);
|
||||
let pkg: Package = await readValue(key.type.packageRef, store);
|
||||
invariant(pkg);
|
||||
registerPackage(pkg);
|
||||
return pkg;
|
||||
}
|
||||
@@ -208,46 +212,27 @@ function getStructClass(pkg, name) {
|
||||
};
|
||||
}
|
||||
|
||||
async function getDataset(id: string, httpStore: ChunkStore): any {
|
||||
async function getDataset(id: string, httpStore: ChunkStore): Promise<NomsMap<Ref, Ref>> {
|
||||
let rootRef = await httpStore.getRoot();
|
||||
let datasets = await readValue(rootRef, httpStore);
|
||||
let commitRef = datasets.get(id);
|
||||
let commit = await readValue(commitRef, httpStore);
|
||||
let datasets: Map<string, Ref> = await readValue(rootRef, httpStore);
|
||||
let commitRef = await datasets.get(id);
|
||||
invariant(commitRef);
|
||||
let commit: Struct = await readValue(commitRef, httpStore);
|
||||
invariant(commit);
|
||||
return commit.get('value');
|
||||
}
|
||||
|
||||
function convertMap<T>(map: Map<Ref, T>): Map<string, T> {
|
||||
let m = new Map();
|
||||
map.forEach((v, k) => {
|
||||
m.set(k.toString(), v);
|
||||
});
|
||||
return m;
|
||||
}
|
||||
|
||||
function intersectRounds(a: Set<Struct>, b: Set<Struct>): Set<Struct> {
|
||||
let sa = new Set();
|
||||
a.forEach(v => {
|
||||
sa.add(v.ref.toString());
|
||||
});
|
||||
let s = new Set();
|
||||
b.forEach(v => {
|
||||
if (sa.has(v.ref.toString())) {
|
||||
s.add(v);
|
||||
}
|
||||
});
|
||||
return s;
|
||||
}
|
||||
|
||||
function percentiles(s: Set<Struct>): Array<{x: number, y: number}> {
|
||||
async function percentiles(s: NomsSet<Struct>): Promise<Array<{x: number, y: number}>> {
|
||||
let arr: Array<number> = [];
|
||||
for (let round of s) {
|
||||
await s.forEach(round => {
|
||||
let v = round.get('Raised');
|
||||
|
||||
if (v > 0) {
|
||||
arr.push(v);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
arr.sort((a, b) => a - b);
|
||||
let len = arr.length;
|
||||
if (len === 0) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import {readValue, HttpStore, Ref, Struct} from 'noms';
|
||||
import {HttpStore, NomsList, notNull, readValue, Ref} from 'noms';
|
||||
|
||||
const IMAGE_WIDTH_PX = 286;
|
||||
const IMAGE_HEIGHT_PX = 324;
|
||||
@@ -17,13 +17,18 @@ function feetToPixels(f: number): number {
|
||||
}
|
||||
|
||||
type Props = {
|
||||
pitchListRef: Ref,
|
||||
pitchListRefP: Promise<?Ref>,
|
||||
httpStore: HttpStore
|
||||
};
|
||||
|
||||
type Point = {
|
||||
x: number,
|
||||
y: number
|
||||
};
|
||||
|
||||
type State = {
|
||||
loaded: boolean,
|
||||
pitchList: ?Array<Struct>
|
||||
pointList: Array<Point>
|
||||
};
|
||||
|
||||
export default class HeatMap extends React.Component<void, Props, State> {
|
||||
@@ -32,7 +37,7 @@ export default class HeatMap extends React.Component<void, Props, State> {
|
||||
|
||||
this.state = {
|
||||
loaded: false,
|
||||
pitchList: null
|
||||
pointList: []
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,11 +46,20 @@ export default class HeatMap extends React.Component<void, Props, State> {
|
||||
return;
|
||||
}
|
||||
|
||||
let pitchList = await readValue(this.props.pitchListRef, this.props.httpStore);
|
||||
if (Array.isArray(pitchList)) {
|
||||
let pitchListRef = notNull(await this.props.pitchListRefP);
|
||||
let pitchList = await readValue(pitchListRef, this.props.httpStore);
|
||||
|
||||
if (pitchList instanceof NomsList) {
|
||||
let pointList = [];
|
||||
await pitchList.forEach(p => {
|
||||
pointList.push({
|
||||
x: -1 + ORIGIN_X_PIXELS + feetToPixels(p.get('X')),
|
||||
y: -1 + ORIGIN_Z_PIXELS - feetToPixels(p.get('Z'))
|
||||
});
|
||||
});
|
||||
this.setState({
|
||||
loaded: true,
|
||||
pitchList: pitchList
|
||||
pointList: pointList
|
||||
});
|
||||
} else {
|
||||
throw new Error('Unexpected type of pitchList');
|
||||
@@ -77,27 +91,15 @@ export default class HeatMap extends React.Component<void, Props, State> {
|
||||
}
|
||||
|
||||
getPoints(): Array<any> {
|
||||
if (!this.state.loaded) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!this.state.pitchList) {
|
||||
throw new Error('pitchList not loaded');
|
||||
}
|
||||
|
||||
return this.state.pitchList.map(p => {
|
||||
let w = 2;
|
||||
let h = 2;
|
||||
let x = - w / 2 + ORIGIN_X_PIXELS + feetToPixels(p.get('X'));
|
||||
let y = - h / 2 + ORIGIN_Z_PIXELS - feetToPixels(p.get('Z'));
|
||||
return this.state.pointList.map(p => {
|
||||
return <div style={
|
||||
{
|
||||
position: 'absolute',
|
||||
left: x,
|
||||
top: y,
|
||||
left: p.x,
|
||||
top: p.y,
|
||||
background: 'rgba(0,255,0,0.4)',
|
||||
width: w,
|
||||
height: h,
|
||||
width: '2px',
|
||||
height: '2px',
|
||||
boxShadow: '0px 0px 16px 16px rgba(0,255,0,0.4)',
|
||||
borderRadius: '50%'
|
||||
}
|
||||
|
||||
@@ -3,68 +3,67 @@
|
||||
import HeatMap from './heat_map.js';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {readValue, HttpStore, Ref} from 'noms';
|
||||
import {HttpStore, invariant, NomsMap, readValue, Ref, Struct} from 'noms';
|
||||
|
||||
let httpStore: HttpStore;
|
||||
|
||||
window.addEventListener('load', async () => {
|
||||
httpStore = new HttpStore('http://localhost:8000');
|
||||
let rootRef = await httpStore.getRoot();
|
||||
let datasets = await readValue(rootRef, httpStore);
|
||||
let commitRef = datasets.get('mlb/heatmap');
|
||||
let commit = await readValue(commitRef, httpStore);
|
||||
let datasets:NomsMap<string, Ref> = await readValue(rootRef, httpStore);
|
||||
let commitRef = await datasets.get('mlb/heatmap');
|
||||
invariant(commitRef);
|
||||
let commit:Struct = await readValue(commitRef, httpStore);
|
||||
let pitchersMap = commit.get('value');
|
||||
renderPitchersMap(pitchersMap);
|
||||
let pitchers = [];
|
||||
await pitchersMap.forEach((ref, pitcher) => {
|
||||
pitchers.push(pitcher);
|
||||
});
|
||||
|
||||
pitchers.sort();
|
||||
renderPitchersMap(pitchersMap, pitchers);
|
||||
});
|
||||
|
||||
type Props = {
|
||||
pitchersMap: Map<string, Ref>
|
||||
pitchersMap: NomsMap<string, Ref>,
|
||||
pitchers: Array<string>
|
||||
};
|
||||
|
||||
type State = {
|
||||
currentPitcher: string,
|
||||
pitchers: Array<string>
|
||||
currentPitcher: string
|
||||
};
|
||||
|
||||
class PitcherList extends React.Component<void, Props, State> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
let pitchers = [];
|
||||
this.props.pitchersMap.forEach((ref, pitcher) => {
|
||||
pitchers.push(pitcher);
|
||||
});
|
||||
pitchers.sort();
|
||||
|
||||
this.state = {
|
||||
currentPitcher: pitchers[0],
|
||||
pitchers: pitchers
|
||||
currentPitcher: props.pitchers[0]
|
||||
};
|
||||
}
|
||||
|
||||
render() : React.Element {
|
||||
let currentPitcher = this.state.currentPitcher;
|
||||
let pitchListRef = this.props.pitchersMap.get(currentPitcher);
|
||||
let pitchListRefP = this.props.pitchersMap.get(currentPitcher);
|
||||
|
||||
let onChangePitcher = e => {
|
||||
this.setState({
|
||||
currentPitcher: e.target.value,
|
||||
pitchers: this.state.pitchers
|
||||
currentPitcher: e.target.value
|
||||
});
|
||||
};
|
||||
|
||||
return <div>
|
||||
<select onChange={onChangePitcher} defaultValue={currentPitcher}>{
|
||||
this.state.pitchers.map(pitcher => {
|
||||
this.props.pitchers.map(pitcher => {
|
||||
return <option key={pitcher} value={pitcher}>{pitcher}</option>;
|
||||
})
|
||||
}</select>
|
||||
<HeatMap key={currentPitcher} pitchListRef={pitchListRef} httpStore={httpStore}/>
|
||||
<HeatMap key={currentPitcher} pitchListRefP={pitchListRefP} httpStore={httpStore}/>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
function renderPitchersMap(map: Map) {
|
||||
function renderPitchersMap(map: NomsMap<string, Ref>, pitchers: Array<string>) {
|
||||
let renderNode = document.getElementById('heatmap');
|
||||
ReactDOM.render(<PitcherList pitchersMap={map}/>, renderNode);
|
||||
ReactDOM.render(<PitcherList pitchersMap={map} pitchers={pitchers}/>, renderNode);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// @flow
|
||||
|
||||
import {layout, NodeGraph, TreeNode} from './buchheim.js';
|
||||
import Layout from './layout.js';
|
||||
import React from 'react'; // eslint-disable-line no-unused-vars
|
||||
import ReactDOM from 'react-dom';
|
||||
import {CompoundList, CompoundMap, CompoundSet, ListLeaf, MapLeaf, readValue, SetLeaf, HttpStore, Ref, Struct} from 'noms';
|
||||
import {HttpStore, invariant, IndexedMetaSequence, ListLeafSequence, MapLeafSequence, OrderedMetaSequence, NomsList, NomsMap, NomsSet, readValue, Ref, SetLeafSequence, Struct} from 'noms';
|
||||
import {layout, NodeGraph, TreeNode} from './buchheim.js';
|
||||
|
||||
let data: NodeGraph = {nodes: {}, links: {}};
|
||||
let rootRef: Ref;
|
||||
@@ -39,6 +39,20 @@ function formatKeyString(v: any): string {
|
||||
function handleChunkLoad(ref: Ref, val: any, fromRef: ?string) {
|
||||
let counter = 0;
|
||||
|
||||
function processMetaSequence(id, sequence: IndexedMetaSequence | OrderedMetaSequence, name: string) {
|
||||
data.nodes[id] = {name: name};
|
||||
sequence.items.forEach(tuple => {
|
||||
let kid = process(ref, formatKeyString(tuple.value), id);
|
||||
if (kid) {
|
||||
data.nodes[kid].isOpen = true;
|
||||
|
||||
process(ref, tuple.ref, kid);
|
||||
} else {
|
||||
throw new Error('No kid id.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function process(ref, val, fromId): ?string {
|
||||
if (typeof val === 'undefined') {
|
||||
return null;
|
||||
@@ -68,28 +82,45 @@ function handleChunkLoad(ref: Ref, val: any, fromRef: ?string) {
|
||||
|
||||
if (val instanceof Blob) {
|
||||
data.nodes[id] = {name: `Blob (${val.size})`};
|
||||
} else if (val instanceof ListLeaf) {
|
||||
data.nodes[id] = {name: `List (${val.length})`};
|
||||
val.items.forEach(c => process(ref, c, id));
|
||||
} else if (val instanceof SetLeaf) {
|
||||
data.nodes[id] = {name: `Set (${val.size})`};
|
||||
val.items.forEach(c => process(ref, c, id));
|
||||
} else if (val instanceof MapLeaf) {
|
||||
data.nodes[id] = {name: `Map (${val.size})`};
|
||||
val.items.forEach(entry => {
|
||||
let k = entry.key;
|
||||
let v = entry.value;
|
||||
// TODO: handle non-string keys
|
||||
let kid = process(ref, k, id);
|
||||
if (kid) {
|
||||
// Start map keys open, just makes it easier to use.
|
||||
data.nodes[kid].isOpen = true;
|
||||
} else if (val instanceof NomsList) {
|
||||
let sequence = val.sequence;
|
||||
if (sequence instanceof ListLeafSequence) {
|
||||
data.nodes[id] = {name: `List (${val.length})`};
|
||||
sequence.items.forEach(c => process(ref, c, id));
|
||||
} else {
|
||||
invariant(sequence instanceof IndexedMetaSequence);
|
||||
processMetaSequence(id, sequence, 'ListNode');
|
||||
}
|
||||
} else if (val instanceof NomsSet) {
|
||||
let sequence = val.sequence;
|
||||
if (sequence instanceof SetLeafSequence) {
|
||||
data.nodes[id] = {name: `Set (${val.size})`};
|
||||
sequence.items.forEach(c => process(ref, c, id));
|
||||
} else {
|
||||
invariant(sequence instanceof OrderedMetaSequence);
|
||||
processMetaSequence(id, sequence, 'SetNode');
|
||||
}
|
||||
} else if (val instanceof NomsMap) {
|
||||
let sequence = val.sequence;
|
||||
if (sequence instanceof MapLeafSequence) {
|
||||
data.nodes[id] = {name: `Map (${val.size})`};
|
||||
sequence.items.forEach(entry => {
|
||||
let k = entry.key;
|
||||
let v = entry.value;
|
||||
// TODO: handle non-string keys
|
||||
let kid = process(ref, k, id);
|
||||
if (kid) {
|
||||
data.nodes[kid].isOpen = true;
|
||||
|
||||
process(ref, v, kid);
|
||||
} else {
|
||||
throw new Error('No kid id.');
|
||||
}
|
||||
});
|
||||
process(ref, v, kid);
|
||||
} else {
|
||||
throw new Error('No kid id.');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
invariant(sequence instanceof OrderedMetaSequence);
|
||||
processMetaSequence(id, sequence, 'MapNode');
|
||||
}
|
||||
} else if (val instanceof Ref) {
|
||||
let refStr = val.toString();
|
||||
data.nodes[id] = {
|
||||
@@ -114,45 +145,6 @@ function handleChunkLoad(ref: Ref, val: any, fromRef: ?string) {
|
||||
throw new Error('No kid id.');
|
||||
}
|
||||
});
|
||||
} else if (val instanceof CompoundList) {
|
||||
data.nodes[id] = {name: 'ListNode'};
|
||||
val.items.forEach(tuple => {
|
||||
let kid = process(ref, formatKeyString(tuple.value), id);
|
||||
if (kid) {
|
||||
// Start map keys open, just makes it easier to use.
|
||||
data.nodes[kid].isOpen = true;
|
||||
|
||||
process(ref, tuple.ref, kid);
|
||||
} else {
|
||||
throw new Error('No kid id.');
|
||||
}
|
||||
});
|
||||
} else if (val instanceof CompoundMap) {
|
||||
data.nodes[id] = {name: 'MapNode'};
|
||||
val.items.forEach(tuple => {
|
||||
let kid = process(ref, formatKeyString(tuple.value), id);
|
||||
if (kid) {
|
||||
// Start map keys open, just makes it easier to use.
|
||||
data.nodes[kid].isOpen = true;
|
||||
|
||||
process(ref, tuple.ref, kid);
|
||||
} else {
|
||||
throw new Error('No kid id.');
|
||||
}
|
||||
});
|
||||
} else if (val instanceof CompoundSet) {
|
||||
data.nodes[id] = {name: 'SetNode'};
|
||||
val.items.forEach(tuple => {
|
||||
let kid = process(ref, formatKeyString(tuple.value), id);
|
||||
if (kid) {
|
||||
// Start map keys open, just makes it easier to use.
|
||||
data.nodes[kid].isOpen = true;
|
||||
|
||||
process(ref, tuple.ref, kid);
|
||||
} else {
|
||||
throw new Error('No kid id.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return id;
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
// @flow
|
||||
|
||||
export function invariant(exp: boolean, message: string = 'Invariant violated') {
|
||||
if (!exp) {
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import {invariant} from './assert.js';
|
||||
import {readValue} from 'noms';
|
||||
import {invariant, readValue} from 'noms';
|
||||
import eq from './eq.js';
|
||||
import React from 'react';
|
||||
import type {ChunkStore} from 'noms';
|
||||
|
||||
@@ -46,7 +46,7 @@ export function deserialize(buffer: ArrayBuffer): Array<Chunk> {
|
||||
invariant(buffer.byteLength - offset >= chunkHeaderSize, 'Invalid chunk buffer');
|
||||
|
||||
let refArray = new Uint8Array(buffer, offset, sha1Size);
|
||||
let ref = new Ref(new Uint8Array(refArray));
|
||||
let ref = Ref.fromDigest(new Uint8Array(refArray));
|
||||
offset += sha1Size;
|
||||
|
||||
let sizeReadArray = new Uint8Array(buffer, offset, chunkLengthSize);
|
||||
|
||||
17
js/src/collection.js
Normal file
17
js/src/collection.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// @flow
|
||||
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import {Type} from './type.js';
|
||||
import {ValueBase} from './value.js';
|
||||
import type {Sequence} from './sequence.js'; // eslint-disable-line no-unused-vars
|
||||
|
||||
export class Collection<S:Sequence> extends ValueBase {
|
||||
sequence: S;
|
||||
cs: ChunkStore;
|
||||
|
||||
constructor(cs: ChunkStore, type: Type, sequence: S) {
|
||||
super(type);
|
||||
this.cs = cs;
|
||||
this.sequence = sequence;
|
||||
}
|
||||
}
|
||||
@@ -10,11 +10,11 @@ import {Field, makeCompoundType, makeEnumType, makePrimitiveType, makeStructType
|
||||
import {indexTypeForMetaSequence, MetaTuple, newMetaSequenceFromData} from './meta_sequence.js';
|
||||
import {invariant, notNull} from './assert.js';
|
||||
import {isPrimitiveKind, Kind} from './noms_kind.js';
|
||||
import {ListLeaf} from './list.js';
|
||||
import {ListLeafSequence, NomsList} from './list.js';
|
||||
import {lookupPackage, Package, readPackage} from './package.js';
|
||||
import {MapLeaf} from './map.js';
|
||||
import {NomsMap, MapLeafSequence} from './map.js';
|
||||
import {setDecodeNomsValue} from './read_value.js';
|
||||
import {SetLeaf} from './set.js';
|
||||
import {NomsSet, SetLeafSequence} from './set.js';
|
||||
|
||||
const typedTag = 't ';
|
||||
const blobTag = 'b ';
|
||||
@@ -135,17 +135,17 @@ class JsonArrayReader {
|
||||
return list;
|
||||
}
|
||||
|
||||
async readListLeaf(t: Type, pkg: ?Package): Promise<ListLeaf> {
|
||||
async readListLeafSequence(t: Type, pkg: ?Package): Promise<ListLeafSequence> {
|
||||
let seq = await this.readSequence(t, pkg);
|
||||
return new ListLeaf(this._cs, t, seq);
|
||||
return new ListLeafSequence(t, seq);
|
||||
}
|
||||
|
||||
async readSetLeaf(t: Type, pkg: ?Package): Promise<SetLeaf> {
|
||||
async readSetLeafSequence(t: Type, pkg: ?Package): Promise<SetLeafSequence> {
|
||||
let seq = await this.readSequence(t, pkg);
|
||||
return new SetLeaf(this._cs, t, seq);
|
||||
return new SetLeafSequence(t, seq);
|
||||
}
|
||||
|
||||
async readMapLeaf(t: Type, pkg: ?Package): Promise<MapLeaf> {
|
||||
async readMapLeafSequence(t: Type, pkg: ?Package): Promise<MapLeafSequence> {
|
||||
let keyType = t.elemTypes[0];
|
||||
let valueType = t.elemTypes[1];
|
||||
let entries = [];
|
||||
@@ -155,24 +155,19 @@ class JsonArrayReader {
|
||||
entries.push({key: k, value: v});
|
||||
}
|
||||
|
||||
return new MapLeaf(this._cs, t, entries);
|
||||
return new MapLeafSequence(t, entries);
|
||||
}
|
||||
|
||||
readEnum(): number {
|
||||
return this.readUint();
|
||||
}
|
||||
|
||||
async maybeReadMetaSequence(t: Type, pkg: ?Package): Promise<any> {
|
||||
if (!this.readBool()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let r2 = new JsonArrayReader(this.readArray(), this._cs);
|
||||
async readMetaSequence(t: Type, pkg: ?Package): Promise<any> {
|
||||
let data: Array<MetaTuple> = [];
|
||||
let indexType = indexTypeForMetaSequence(t);
|
||||
while (!r2.atEnd()) {
|
||||
let ref = r2.readRef();
|
||||
let v = await r2.readValueWithoutTag(indexType, pkg);
|
||||
while (!this.atEnd()) {
|
||||
let ref = this.readRef();
|
||||
let v = await this.readValueWithoutTag(indexType, pkg);
|
||||
data.push(new MetaTuple(ref, v));
|
||||
}
|
||||
|
||||
@@ -204,11 +199,9 @@ class JsonArrayReader {
|
||||
// TODO: Verify read values match tagged kinds.
|
||||
switch (t.kind) {
|
||||
case Kind.Blob:
|
||||
let ms = await this.maybeReadMetaSequence(t, pkg);
|
||||
if (ms) {
|
||||
return ms;
|
||||
}
|
||||
|
||||
let isMeta = this.readBool();
|
||||
// https://github.com/attic-labs/noms/issues/798
|
||||
invariant(!isMeta, 'CompoundBlob not supported');
|
||||
return this.readBlob();
|
||||
|
||||
case Kind.Bool:
|
||||
@@ -233,22 +226,20 @@ class JsonArrayReader {
|
||||
return this.readValueWithoutTag(t2, pkg);
|
||||
}
|
||||
case Kind.List: {
|
||||
let ms = await this.maybeReadMetaSequence(t, pkg);
|
||||
if (ms) {
|
||||
return ms;
|
||||
}
|
||||
|
||||
let isMeta = this.readBool();
|
||||
let r2 = new JsonArrayReader(this.readArray(), this._cs);
|
||||
return r2.readListLeaf(t, pkg);
|
||||
let sequence = isMeta ?
|
||||
await r2.readMetaSequence(t, pkg) :
|
||||
await r2.readListLeafSequence(t, pkg);
|
||||
return new NomsList(this._cs, t, sequence);
|
||||
}
|
||||
case Kind.Map: {
|
||||
let ms = await this.maybeReadMetaSequence(t, pkg);
|
||||
if (ms) {
|
||||
return ms;
|
||||
}
|
||||
|
||||
let isMeta = this.readBool();
|
||||
let r2 = new JsonArrayReader(this.readArray(), this._cs);
|
||||
return r2.readMapLeaf(t, pkg);
|
||||
let sequence = isMeta ?
|
||||
await r2.readMetaSequence(t, pkg) :
|
||||
await r2.readMapLeafSequence(t, pkg);
|
||||
return new NomsMap(this._cs, t, sequence);
|
||||
}
|
||||
case Kind.Package:
|
||||
return Promise.resolve(this.readPackage(t, pkg));
|
||||
@@ -257,13 +248,12 @@ class JsonArrayReader {
|
||||
// for refs.
|
||||
return Promise.resolve(this.readRef());
|
||||
case Kind.Set: {
|
||||
let ms = await this.maybeReadMetaSequence(t, pkg);
|
||||
if (ms) {
|
||||
return ms;
|
||||
}
|
||||
|
||||
let isMeta = this.readBool();
|
||||
let r2 = new JsonArrayReader(this.readArray(), this._cs);
|
||||
return r2.readSetLeaf(t, pkg);
|
||||
let sequence = isMeta ?
|
||||
await r2.readMetaSequence(t, pkg) :
|
||||
await r2.readSetLeafSequence(t, pkg);
|
||||
return new NomsSet(this._cs, t, sequence);
|
||||
}
|
||||
case Kind.Enum:
|
||||
case Kind.Struct:
|
||||
|
||||
@@ -5,19 +5,21 @@ import MemoryStore from './memory_store.js';
|
||||
import Ref from './ref.js';
|
||||
import Struct from './struct.js';
|
||||
import test from './async_test.js';
|
||||
import type {float64, int32, int64, uint8, uint16, uint32, uint64} from './primitives.js';
|
||||
import type {TypeDesc} from './type.js';
|
||||
import {assert} from 'chai';
|
||||
import {decodeNomsValue, JsonArrayReader} from './decode.js';
|
||||
import {Field, makeCompoundType, makeEnumType, makePrimitiveType, makeStructType, makeType, Type} from './type.js';
|
||||
import {invariant} from './assert.js';
|
||||
import {IndexedMetaSequence, MetaTuple} from './meta_sequence.js';
|
||||
import {invariant, notNull} from './assert.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {ListLeaf, CompoundList} from './list.js';
|
||||
import {MapLeaf} from './map.js';
|
||||
import {MetaTuple} from './meta_sequence.js';
|
||||
import {ListLeafSequence, NomsList} from './list.js';
|
||||
import {MapLeafSequence, NomsMap} from './map.js';
|
||||
import {NomsSet, SetLeafSequence} from './set.js';
|
||||
import {readValue} from './read_value.js';
|
||||
import {registerPackage, Package} from './package.js';
|
||||
import {SetLeaf} from './set.js';
|
||||
import {suite} from 'mocha';
|
||||
import {Value} from './value.js';
|
||||
import {writeValue} from './encode.js';
|
||||
|
||||
suite('Decode', () => {
|
||||
@@ -92,11 +94,11 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.List, Kind.Int32, false, ['0', '1', '2', '3']];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = await r.readTopLevelValue();
|
||||
invariant(v instanceof ListLeaf);
|
||||
let v:NomsList<int32> = await r.readTopLevelValue();
|
||||
invariant(v instanceof NomsList);
|
||||
|
||||
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int32));
|
||||
let l = new ListLeaf(ms, tr, [0, 1, 2, 3]);
|
||||
let l = new NomsList(ms, tr, new ListLeafSequence(tr, [0, 1, 2, 3]));
|
||||
assert.isTrue(l.equals(v));
|
||||
});
|
||||
|
||||
@@ -105,8 +107,9 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.List, Kind.Value, false, [Kind.Int32, '1', Kind.String, 'hi', Kind.Bool, true]];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = await r.readTopLevelValue();
|
||||
invariant(v instanceof ListLeaf);
|
||||
let v:NomsList<Value> = await r.readTopLevelValue();
|
||||
invariant(v instanceof NomsList);
|
||||
|
||||
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Value));
|
||||
assert.isTrue(v.type.equals(tr));
|
||||
assert.strictEqual(1, await v.get(0));
|
||||
@@ -119,10 +122,10 @@ suite('Decode', () => {
|
||||
let a = [Kind.Value, Kind.List, Kind.Int8, false, ['0', '1', '2']];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = await r.readTopLevelValue();
|
||||
invariant(v instanceof ListLeaf);
|
||||
invariant(v instanceof NomsList);
|
||||
|
||||
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int8));
|
||||
let l = new ListLeaf(ms, tr, [0, 1, 2]);
|
||||
let l = new NomsList(ms, tr, new ListLeafSequence(tr, [0, 1, 2]));
|
||||
assert.isTrue(l.equals(v));
|
||||
});
|
||||
|
||||
@@ -130,20 +133,21 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
|
||||
let ltr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int32));
|
||||
let r1 = writeValue(new ListLeaf(ms, ltr, [0, 1]), ltr, ms);
|
||||
let r2 = writeValue(new ListLeaf(ms, ltr, [2, 3]), ltr, ms);
|
||||
let r3 = writeValue(new ListLeaf(ms, ltr, [4, 5]), ltr, ms);
|
||||
let r1 = writeValue(new NomsList(ms, ltr, new ListLeafSequence(ltr, [0, 1])), ltr, ms);
|
||||
let r2 = writeValue(new NomsList(ms, ltr, new ListLeafSequence(ltr, [2, 3])), ltr, ms);
|
||||
let r3 = writeValue(new NomsList(ms, ltr, new ListLeafSequence(ltr, [4, 5])), ltr, ms);
|
||||
let tuples = [
|
||||
new MetaTuple(r1, 2),
|
||||
new MetaTuple(r2, 4),
|
||||
new MetaTuple(r3, 6)
|
||||
];
|
||||
let l = new CompoundList(ms, ltr, tuples);
|
||||
let l:NomsList<int32> = new NomsList(ms, ltr, new IndexedMetaSequence(ltr, tuples));
|
||||
invariant(l instanceof NomsList);
|
||||
|
||||
let a = [Kind.List, Kind.Int32, true, [r1.toString(), '2', r2.toString(), '4', r3.toString(), '6']];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = await r.readTopLevelValue();
|
||||
invariant(v instanceof CompoundList);
|
||||
invariant(v instanceof NomsList);
|
||||
assert.isTrue(v.ref.equals(l.ref));
|
||||
});
|
||||
|
||||
@@ -151,11 +155,23 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.Map, Kind.Int64, Kind.Float64, false, ['0', '1', '2', '3']];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = await r.readTopLevelValue();
|
||||
invariant(v instanceof MapLeaf);
|
||||
let v:NomsMap<int64, float64> = await r.readTopLevelValue();
|
||||
invariant(v instanceof NomsMap);
|
||||
|
||||
let t = makeCompoundType(Kind.Map, makePrimitiveType(Kind.Int64), makePrimitiveType(Kind.Float64));
|
||||
let m = new MapLeaf(ms, t, [{key: 0, value: 1}, {key: 2, value: 3}]);
|
||||
let m = new NomsMap(ms, t, new MapLeafSequence(t, [{key: 0, value: 1}, {key: 2, value: 3}]));
|
||||
assert.isTrue(v.equals(m));
|
||||
});
|
||||
|
||||
test('read map of ref to uint64', async () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.Map, Kind.Ref, Kind.Value, Kind.Uint64, false, ['sha1-0000000000000000000000000000000000000001', '2', 'sha1-0000000000000000000000000000000000000002', '4']];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v:NomsMap<Ref, uint64> = await r.readTopLevelValue();
|
||||
invariant(v instanceof NomsMap);
|
||||
|
||||
let t = makeCompoundType(Kind.Map, makeCompoundType(Kind.Ref, makePrimitiveType(Kind.Value)), makePrimitiveType(Kind.Uint64));
|
||||
let m = new NomsMap(ms, t, new MapLeafSequence(t, [{key: new Ref('sha1-0000000000000000000000000000000000000001'), value: 2}, {key: new Ref('sha1-0000000000000000000000000000000000000002'), value: 4}]));
|
||||
assert.isTrue(v.equals(m));
|
||||
});
|
||||
|
||||
@@ -163,11 +179,11 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.Value, Kind.Map, Kind.Uint64, Kind.Uint32, false, ['0', '1', '2', '3']];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = await r.readTopLevelValue();
|
||||
invariant(v instanceof MapLeaf);
|
||||
let v:NomsMap<uint64, uint32> = await r.readTopLevelValue();
|
||||
invariant(v instanceof NomsMap);
|
||||
|
||||
let t = makeCompoundType(Kind.Map, makePrimitiveType(Kind.Uint64), makePrimitiveType(Kind.Uint32));
|
||||
let m = new MapLeaf(ms, t, [{key: 0, value: 1}, {key: 2, value: 3}]);
|
||||
let m = new NomsMap(ms, t, new MapLeafSequence(t, [{key: 0, value: 1}, {key: 2, value: 3}]));
|
||||
assert.isTrue(v.equals(m));
|
||||
});
|
||||
|
||||
@@ -175,11 +191,11 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.Set, Kind.Uint8, false, ['0', '1', '2', '3']];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = await r.readTopLevelValue();
|
||||
invariant(v instanceof SetLeaf);
|
||||
let v:NomsSet<uint8> = await r.readTopLevelValue();
|
||||
invariant(v instanceof NomsSet);
|
||||
|
||||
let t = makeCompoundType(Kind.Set, makePrimitiveType(Kind.Uint8));
|
||||
let s = new SetLeaf(ms, t, [0, 1, 2, 3]);
|
||||
let s = new NomsSet(ms, t, new SetLeafSequence(t, [0, 1, 2, 3]));
|
||||
assert.isTrue(v.equals(s));
|
||||
});
|
||||
|
||||
@@ -187,14 +203,16 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.Value, Kind.Set, Kind.Uint16, false, ['0', '1', '2', '3']];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = await r.readTopLevelValue();
|
||||
let v:NomsSet<uint16> = await r.readTopLevelValue();
|
||||
invariant(v instanceof NomsSet);
|
||||
|
||||
let t = makeCompoundType(Kind.Set, makePrimitiveType(Kind.Uint16));
|
||||
let s = new SetLeaf(ms, t, [0, 1, 2, 3]);
|
||||
let s = new NomsSet(ms, t, new SetLeafSequence(t, [0, 1, 2, 3]));
|
||||
assert.isTrue(v.equals(s));
|
||||
});
|
||||
|
||||
function assertStruct(s: Struct, desc: TypeDesc, data: {[key: string]: any}) {
|
||||
function assertStruct(s: ?Struct, desc: TypeDesc, data: {[key: string]: any}) {
|
||||
notNull(s);
|
||||
invariant(s instanceof Struct, 'expected instanceof struct');
|
||||
assert.deepEqual(desc, s.desc);
|
||||
|
||||
@@ -287,7 +305,7 @@ suite('Decode', () => {
|
||||
|
||||
assertStruct(v, tr.desc, {
|
||||
b: true,
|
||||
l: new ListLeaf(ms, ltr, [0, 1, 2]),
|
||||
l: new NomsList(ms, ltr, new ListLeafSequence(ltr, [0, 1, 2])),
|
||||
s: 'hi'
|
||||
});
|
||||
});
|
||||
@@ -399,11 +417,10 @@ suite('Decode', () => {
|
||||
let a = [Kind.Value, Kind.Map, Kind.String, Kind.Unresolved, pkg.ref.toString(), '0', false, ['bar', false, '2', 'baz', false, '1', 'foo', true, '3']];
|
||||
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = await r.readTopLevelValue();
|
||||
let v:NomsMap<string, Struct> = await r.readTopLevelValue();
|
||||
invariant(v instanceof NomsMap);
|
||||
|
||||
invariant(v instanceof MapLeaf);
|
||||
assert.strictEqual(3, v.size);
|
||||
|
||||
assertStruct(await v.get('foo'), tr.desc, {b: true, i: 3});
|
||||
assertStruct(await v.get('bar'), tr.desc, {b: false, i: 2});
|
||||
assertStruct(await v.get('baz'), tr.desc, {b: false, i: 1});
|
||||
@@ -412,10 +429,10 @@ suite('Decode', () => {
|
||||
test('decodeNomsValue', async () => {
|
||||
let ms = new MemoryStore();
|
||||
let chunk = Chunk.fromString(`t [${Kind.Value}, ${Kind.Set}, ${Kind.Uint16}, false, ["0", "1", "2", "3"]]`);
|
||||
let v = await decodeNomsValue(chunk, new MemoryStore());
|
||||
let v:NomsSet<uint16> = await decodeNomsValue(chunk, new MemoryStore());
|
||||
|
||||
let t = makeCompoundType(Kind.Set, makePrimitiveType(Kind.Uint16));
|
||||
let s = new SetLeaf(ms, t, [0, 1, 2, 3]);
|
||||
let s:NomsSet<uint16> = new NomsSet(ms, t, new SetLeafSequence(t, [0, 1, 2, 3]));
|
||||
assert.isTrue(v.equals(s));
|
||||
});
|
||||
|
||||
|
||||
@@ -6,16 +6,16 @@ import Struct from './struct.js';
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import type {NomsKind} from './noms_kind.js';
|
||||
import {encode as encodeBase64} from './base64.js';
|
||||
import {EnumDesc, makePrimitiveType, StructDesc, Type} from './type.js';
|
||||
import {indexTypeForMetaSequence} from './meta_sequence.js';
|
||||
import {invariant, notNull} from './assert.js';
|
||||
import {isPrimitiveKind, Kind} from './noms_kind.js';
|
||||
import {ListLeaf} from './list.js';
|
||||
import {ListLeafSequence, NomsList} from './list.js';
|
||||
import {lookupPackage, Package} from './package.js';
|
||||
import {makePrimitiveType, EnumDesc, StructDesc, Type} from './type.js';
|
||||
import {MapLeaf} from './map.js';
|
||||
import {MapLeafSequence, NomsMap} from './map.js';
|
||||
import {NomsSet, SetLeafSequence} from './set.js';
|
||||
import {Sequence} from './sequence.js';
|
||||
import {setEncodeNomsValue} from './get_ref.js';
|
||||
import {SetLeaf} from './set.js';
|
||||
|
||||
const typedTag = 't ';
|
||||
|
||||
@@ -139,29 +139,31 @@ class JsonArrayWriter {
|
||||
this.writeInt(v); // TODO: Verify value fits in type
|
||||
break;
|
||||
case Kind.List: {
|
||||
invariant(v instanceof Sequence);
|
||||
if (this.maybeWriteMetaSequence(v, t, pkg)) {
|
||||
invariant(v instanceof NomsList);
|
||||
let sequence = v.sequence;
|
||||
if (this.maybeWriteMetaSequence(sequence, t, pkg)) {
|
||||
break;
|
||||
}
|
||||
|
||||
invariant(v instanceof ListLeaf);
|
||||
invariant(sequence instanceof ListLeafSequence);
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
let elemType = t.elemTypes[0];
|
||||
v.items.forEach(sv => w2.writeValue(sv, elemType));
|
||||
sequence.items.forEach(sv => w2.writeValue(sv, elemType));
|
||||
this.write(w2.array);
|
||||
break;
|
||||
}
|
||||
case Kind.Map: {
|
||||
invariant(v instanceof Sequence);
|
||||
if (this.maybeWriteMetaSequence(v, t, pkg)) {
|
||||
invariant(v instanceof NomsMap);
|
||||
let sequence = v.sequence;
|
||||
if (this.maybeWriteMetaSequence(sequence, t, pkg)) {
|
||||
break;
|
||||
}
|
||||
|
||||
invariant(v instanceof MapLeaf);
|
||||
invariant(sequence instanceof MapLeafSequence);
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
let keyType = t.elemTypes[0];
|
||||
let valueType = t.elemTypes[1];
|
||||
v.items.forEach(entry => {
|
||||
sequence.items.forEach(entry => {
|
||||
w2.writeValue(entry.key, keyType);
|
||||
w2.writeValue(entry.value, valueType);
|
||||
});
|
||||
@@ -187,16 +189,17 @@ class JsonArrayWriter {
|
||||
break;
|
||||
}
|
||||
case Kind.Set: {
|
||||
invariant(v instanceof Sequence);
|
||||
if (this.maybeWriteMetaSequence(v, t, pkg)) {
|
||||
invariant(v instanceof NomsSet);
|
||||
let sequence = v.sequence;
|
||||
if (this.maybeWriteMetaSequence(sequence, t, pkg)) {
|
||||
break;
|
||||
}
|
||||
|
||||
invariant(v instanceof SetLeaf);
|
||||
invariant(sequence instanceof SetLeafSequence);
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
let elemType = t.elemTypes[0];
|
||||
let elems = [];
|
||||
v.items.forEach(v => {
|
||||
sequence.items.forEach(v => {
|
||||
elems.push(v);
|
||||
});
|
||||
elems.forEach(elem => w2.writeValue(elem, elemType));
|
||||
|
||||
@@ -8,14 +8,14 @@ import Ref from './ref.js';
|
||||
import Struct from './struct.js';
|
||||
import test from './async_test.js';
|
||||
import type {NomsKind} from './noms_kind.js';
|
||||
import {encodeNomsValue, JsonArrayWriter} from './encode.js';
|
||||
import {Field, makeCompoundType, makeEnumType, makePrimitiveType, makeStructType, makeType, Type} from './type.js';
|
||||
import {JsonArrayWriter, encodeNomsValue} from './encode.js';
|
||||
import {IndexedMetaSequence, MetaTuple} from './meta_sequence.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {ListLeaf, CompoundList} from './list.js';
|
||||
import {MapLeaf} from './map.js';
|
||||
import {MetaTuple} from './meta_sequence.js';
|
||||
import {ListLeafSequence, NomsList} from './list.js';
|
||||
import {MapLeafSequence, NomsMap} from './map.js';
|
||||
import {NomsSet, SetLeafSequence} from './set.js';
|
||||
import {Package, registerPackage} from './package.js';
|
||||
import {SetLeaf} from './set.js';
|
||||
import {writeValue} from './encode.js';
|
||||
|
||||
suite('Encode', () => {
|
||||
@@ -61,7 +61,7 @@ suite('Encode', () => {
|
||||
let w = new JsonArrayWriter(ms);
|
||||
|
||||
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int32));
|
||||
let l = new ListLeaf(ms, tr, [0, 1, 2, 3]);
|
||||
let l = new NomsList(ms, tr, new ListLeafSequence(tr, [0, 1, 2, 3]));
|
||||
w.writeTopLevel(tr, l);
|
||||
assert.deepEqual([Kind.List, Kind.Int32, false, ['0', '1', '2', '3']], w.array);
|
||||
});
|
||||
@@ -72,7 +72,10 @@ suite('Encode', () => {
|
||||
|
||||
let it = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int16));
|
||||
let tr = makeCompoundType(Kind.List, it);
|
||||
let v = new ListLeaf(ms, tr, [new ListLeaf(ms, it, [0]), new ListLeaf(ms, it, [1, 2, 3])]);
|
||||
let v = new NomsList(ms, tr, new ListLeafSequence(tr, [
|
||||
new NomsList(ms, tr, new ListLeafSequence(it, [0])),
|
||||
new NomsList(ms, tr, new ListLeafSequence(it, [1, 2, 3]))
|
||||
]));
|
||||
w.writeTopLevel(tr, v);
|
||||
assert.deepEqual([Kind.List, Kind.List, Kind.Int16, false, [false, ['0'], false, ['1', '2', '3']]], w.array);
|
||||
});
|
||||
@@ -82,7 +85,7 @@ suite('Encode', () => {
|
||||
let w = new JsonArrayWriter(ms);
|
||||
|
||||
let tr = makeCompoundType(Kind.Set, makePrimitiveType(Kind.Uint32));
|
||||
let v = new SetLeaf(ms, tr, [0, 1, 2, 3]);
|
||||
let v = new NomsSet(ms, tr, new SetLeafSequence(tr, [0, 1, 2, 3]));
|
||||
w.writeTopLevel(tr, v);
|
||||
assert.deepEqual([Kind.Set, Kind.Uint32, false, ['0', '1', '2', '3']], w.array);
|
||||
});
|
||||
@@ -93,7 +96,10 @@ suite('Encode', () => {
|
||||
|
||||
let st = makeCompoundType(Kind.Set, makePrimitiveType(Kind.Int32));
|
||||
let tr = makeCompoundType(Kind.Set, st);
|
||||
let v = new SetLeaf(ms, tr, [new SetLeaf(ms, st, [0]), new SetLeaf(ms, st, [1, 2, 3])]);
|
||||
let v = new NomsSet(ms, tr, new SetLeafSequence(tr, [
|
||||
new NomsSet(ms, tr, new SetLeafSequence(st, [0])),
|
||||
new NomsSet(ms, tr, new SetLeafSequence(st, [1, 2, 3]))
|
||||
]));
|
||||
|
||||
w.writeTopLevel(tr, v);
|
||||
assert.deepEqual([Kind.Set, Kind.Set, Kind.Int32, false, [false, ['0'], false, ['1', '2', '3']]], w.array);
|
||||
@@ -104,7 +110,7 @@ suite('Encode', () => {
|
||||
let w = new JsonArrayWriter(ms);
|
||||
|
||||
let tr = makeCompoundType(Kind.Map, makePrimitiveType(Kind.String), makePrimitiveType(Kind.Bool));
|
||||
let v = new MapLeaf(ms, tr, [{key: 'a', value: false}, {key:'b', value:true}]);
|
||||
let v = new NomsMap(ms, tr, new MapLeafSequence(tr, [{key: 'a', value: false}, {key:'b', value:true}]));
|
||||
w.writeTopLevel(tr, v);
|
||||
assert.deepEqual([Kind.Map, Kind.String, Kind.Bool, false, ['a', false, 'b', true]], w.array);
|
||||
});
|
||||
@@ -117,10 +123,9 @@ suite('Encode', () => {
|
||||
let vt = makeCompoundType(Kind.Set, makePrimitiveType(Kind.Bool));
|
||||
let tr = makeCompoundType(Kind.Map, kt, vt);
|
||||
|
||||
|
||||
let s = new SetLeaf(ms, vt, [true]);
|
||||
let m1 = new MapLeaf(ms, kt, [{key: 'a', value: 0}]);
|
||||
let v = new MapLeaf(ms, tr, [{key: m1, value: s}]);
|
||||
let s = new NomsSet(ms, vt, new SetLeafSequence(vt, [true]));
|
||||
let m1 = new NomsMap(ms, kt, new MapLeafSequence(kt, [{key: 'a', value: 0}]));
|
||||
let v = new NomsMap(ms, kt, new MapLeafSequence(tr, [{key: m1, value: s}]));
|
||||
w.writeTopLevel(tr, v);
|
||||
assert.deepEqual([Kind.Map, Kind.Map, Kind.String, Kind.Int64, Kind.Set, Kind.Bool, false, [false, ['a', '0'], false, [true]]], w.array);
|
||||
});
|
||||
@@ -221,11 +226,11 @@ suite('Encode', () => {
|
||||
let pkgRef = pkg.ref;
|
||||
let type = makeType(pkgRef, 0);
|
||||
|
||||
let v = new Struct(type, typeDef, {l: new ListLeaf(ms, ltr, ['a', 'b'])});
|
||||
let v = new Struct(type, typeDef, {l: new NomsList(ms, ltr, new ListLeafSequence(ltr, ['a', 'b']))});
|
||||
w.writeTopLevel(type, v);
|
||||
assert.deepEqual([Kind.Unresolved, pkgRef.toString(), '0', false, ['a', 'b']], w.array);
|
||||
|
||||
v = new Struct(type, typeDef, {l: new ListLeaf(ms, ltr, [])});
|
||||
v = new Struct(type, typeDef, {l: new NomsList(ms, ltr, new ListLeafSequence(ltr, []))});
|
||||
w = new JsonArrayWriter(ms);
|
||||
w.writeTopLevel(type, v);
|
||||
assert.deepEqual([Kind.Unresolved, pkgRef.toString(), '0', false, []], w.array);
|
||||
@@ -275,7 +280,7 @@ suite('Encode', () => {
|
||||
let pkgRef = pkg.ref;
|
||||
let typ = makeType(pkgRef, 0);
|
||||
let listType = makeCompoundType(Kind.List, typ);
|
||||
let l = new ListLeaf(ms, listType, [0, 1, 2]);
|
||||
let l = new NomsList(ms, listType, new ListLeafSequence(listType, [0, 1, 2]));
|
||||
|
||||
w.writeTopLevel(listType, l);
|
||||
assert.deepEqual([Kind.List, Kind.Unresolved, pkgRef.toString(), '0', false, ['0', '1', '2']], w.array);
|
||||
@@ -286,15 +291,15 @@ suite('Encode', () => {
|
||||
let w = new JsonArrayWriter(ms);
|
||||
|
||||
let ltr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int32));
|
||||
let r1 = writeValue(new ListLeaf(ms, ltr, [0, 1]), ltr, ms);
|
||||
let r2 = writeValue(new ListLeaf(ms, ltr, [2, 3]), ltr, ms);
|
||||
let r3 = writeValue(new ListLeaf(ms, ltr, [4, 5]), ltr, ms);
|
||||
let r1 = writeValue(new NomsList(ms, ltr, new ListLeafSequence(ltr, [0, 1])), ltr, ms);
|
||||
let r2 = writeValue(new NomsList(ms, ltr, new ListLeafSequence(ltr, [2, 3])), ltr, ms);
|
||||
let r3 = writeValue(new NomsList(ms, ltr, new ListLeafSequence(ltr, [4, 5])), ltr, ms);
|
||||
let tuples = [
|
||||
new MetaTuple(r1, 2),
|
||||
new MetaTuple(r2, 4),
|
||||
new MetaTuple(r3, 6)
|
||||
];
|
||||
let l = new CompoundList(ms, ltr, tuples);
|
||||
let l = new NomsList(ms, ltr, new IndexedMetaSequence(ltr, tuples));
|
||||
|
||||
w.writeTopLevel(ltr, l);
|
||||
assert.deepEqual([Kind.List, Kind.Int32, true, [r1.toString(), '2', r2.toString(), '4', r3.toString(), '6']], w.array);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import {notNull} from './assert.js';
|
||||
import {search, Sequence, SequenceCursor} from './sequence.js';
|
||||
|
||||
@@ -8,12 +9,12 @@ export class IndexedSequence<T> extends Sequence<T> {
|
||||
throw new Error('override');
|
||||
}
|
||||
|
||||
async newCursorAt(idx: number): Promise<IndexedSequenceCursor> {
|
||||
async newCursorAt(cs: ChunkStore, idx: number): Promise<IndexedSequenceCursor> {
|
||||
let cursor: ?IndexedSequenceCursor = null;
|
||||
let sequence: ?IndexedSequence = this;
|
||||
|
||||
while (sequence) {
|
||||
cursor = new IndexedSequenceCursor(cursor, sequence, 0);
|
||||
cursor = new IndexedSequenceCursor(cs, cursor, sequence, 0);
|
||||
idx -= cursor.advanceToOffset(idx);
|
||||
sequence = await cursor.getChildSequence();
|
||||
}
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
// @flow
|
||||
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import type {valueOrPrimitive} from './value.js'; // eslint-disable-line no-unused-vars
|
||||
import {Collection} from './collection.js';
|
||||
import {IndexedSequence} from './indexed_sequence.js';
|
||||
import {invariant} from './assert.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {MetaTuple, registerMetaValue} from './meta_sequence.js';
|
||||
import {Type} from './type.js';
|
||||
|
||||
export class NomsList<K: valueOrPrimitive, T> extends IndexedSequence<T> {
|
||||
async get(idx: number): Promise<K> {
|
||||
invariant(idx < this.length, idx + ' >= ' + this.length);
|
||||
let cursor = await this.newCursorAt(idx);
|
||||
export class NomsList<T: valueOrPrimitive> extends Collection<IndexedSequence> {
|
||||
async get(idx: number): Promise<T> {
|
||||
// TODO (when |length| works) invariant(idx < this.length, idx + ' >= ' + this.length);
|
||||
let cursor = await this.sequence.newCursorAt(this.cs, idx);
|
||||
return cursor.getCurrent();
|
||||
}
|
||||
|
||||
async forEach(cb: (v: K, i: number) => void): Promise<void> {
|
||||
let cursor = await this.newCursorAt(0);
|
||||
async forEach(cb: (v: T, i: number) => void): Promise<void> {
|
||||
let cursor = await this.sequence.newCursorAt(this.cs, 0);
|
||||
return cursor.iter((v, i) => {
|
||||
cb(v, i);
|
||||
return false;
|
||||
@@ -24,46 +20,16 @@ export class NomsList<K: valueOrPrimitive, T> extends IndexedSequence<T> {
|
||||
}
|
||||
|
||||
get length(): number {
|
||||
return this.items.length;
|
||||
if (this.sequence instanceof ListLeafSequence) {
|
||||
return this.sequence.items.length;
|
||||
}
|
||||
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
export class ListLeaf<T: valueOrPrimitive> extends NomsList<T, T> {
|
||||
export class ListLeafSequence<T: valueOrPrimitive> extends IndexedSequence<T> {
|
||||
getOffset(idx: number): number {
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
export class CompoundList<T: valueOrPrimitive> extends NomsList<T, MetaTuple<number>> {
|
||||
offsets: Array<number>;
|
||||
|
||||
constructor(cs: ChunkStore, type: Type, items: Array<MetaTuple<number>>) {
|
||||
super(cs, type, items);
|
||||
this.isMeta = true;
|
||||
this.offsets = [];
|
||||
let cum = 0;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
let length = items[i].value;
|
||||
this.offsets.push(cum + length - 1);
|
||||
cum += length;
|
||||
}
|
||||
}
|
||||
|
||||
getOffset(idx: number): number {
|
||||
return this.offsets[idx];
|
||||
}
|
||||
|
||||
async getChildSequence(idx: number): Promise<?NomsList> {
|
||||
let mt = this.items[idx];
|
||||
let ms = await mt.readValue(this.cs);
|
||||
invariant(ms instanceof NomsList);
|
||||
return ms;
|
||||
}
|
||||
|
||||
get length(): number {
|
||||
return this.offsets[this.items.length - 1] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
registerMetaValue(Kind.List, (cs, type, tuples) => new CompoundList(cs, type, tuples));
|
||||
|
||||
|
||||
@@ -5,17 +5,17 @@ import {suite} from 'mocha';
|
||||
|
||||
import MemoryStore from './memory_store.js';
|
||||
import test from './async_test.js';
|
||||
import {CompoundList, ListLeaf} from './list.js';
|
||||
import {IndexedMetaSequence, MetaTuple} from './meta_sequence.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {ListLeafSequence, NomsList} from './list.js';
|
||||
import {makeCompoundType, makePrimitiveType} from './type.js';
|
||||
import {MetaTuple} from './meta_sequence.js';
|
||||
import {writeValue} from './encode.js';
|
||||
|
||||
suite('ListLeaf', () => {
|
||||
suite('ListLeafSequence', () => {
|
||||
test('get', async () => {
|
||||
let ms = new MemoryStore();
|
||||
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.String));
|
||||
let l = new ListLeaf(ms, tr, ['z', 'x', 'a', 'b']);
|
||||
let l = new NomsList(ms, tr, new ListLeafSequence(tr, ['z', 'x', 'a', 'b']));
|
||||
assert.strictEqual('z', await l.get(0));
|
||||
assert.strictEqual('x', await l.get(1));
|
||||
assert.strictEqual('a', await l.get(2));
|
||||
@@ -25,7 +25,7 @@ suite('ListLeaf', () => {
|
||||
test('forEach', async () => {
|
||||
let ms = new MemoryStore();
|
||||
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.Int32));
|
||||
let l = new ListLeaf(ms, tr, [4, 2, 10, 16]);
|
||||
let l = new NomsList(ms, tr, new ListLeafSequence(tr, [4, 2, 10, 16]));
|
||||
|
||||
let values = [];
|
||||
await l.forEach((v, i) => { values.push(v, i); });
|
||||
@@ -34,24 +34,24 @@ suite('ListLeaf', () => {
|
||||
});
|
||||
|
||||
suite('CompoundList', () => {
|
||||
function build(): CompoundList {
|
||||
function build(): NomsList {
|
||||
let ms = new MemoryStore();
|
||||
let tr = makeCompoundType(Kind.List, makePrimitiveType(Kind.String));
|
||||
let l1 = new ListLeaf(ms, tr, ['a', 'b']);
|
||||
let l1 = new NomsList(ms, tr, new ListLeafSequence(tr, ['a', 'b']));
|
||||
let r1 = writeValue(l1, tr, ms);
|
||||
let l2 = new ListLeaf(ms, tr, ['e', 'f']);
|
||||
let l2 = new NomsList(ms, tr, new ListLeafSequence(tr, ['e', 'f']));
|
||||
let r2 = writeValue(l2, tr, ms);
|
||||
let l3 = new ListLeaf(ms, tr, ['h', 'i']);
|
||||
let l3 = new NomsList(ms, tr, new ListLeafSequence(tr, ['h', 'i']));
|
||||
let r3 = writeValue(l3, tr, ms);
|
||||
let l4 = new ListLeaf(ms, tr, ['m', 'n']);
|
||||
let l4 = new NomsList(ms, tr, new ListLeafSequence(tr, ['m', 'n']));
|
||||
let r4 = writeValue(l4, tr, ms);
|
||||
|
||||
let m1 = new CompoundList(ms, tr, [new MetaTuple(r1, 2), new MetaTuple(r2, 2)]);
|
||||
let m1 = new NomsList(ms, tr, new IndexedMetaSequence(tr, [new MetaTuple(r1, 2), new MetaTuple(r2, 2)]));
|
||||
let rm1 = writeValue(m1, tr, ms);
|
||||
let m2 = new CompoundList(ms, tr, [new MetaTuple(r3, 2), new MetaTuple(r4, 2)]);
|
||||
let m2 = new NomsList(ms, tr, new IndexedMetaSequence(tr, [new MetaTuple(r3, 2), new MetaTuple(r4, 2)]));
|
||||
let rm2 = writeValue(m2, tr, ms);
|
||||
|
||||
let l = new CompoundList(ms, tr, [new MetaTuple(rm1, 4), new MetaTuple(rm2, 4)]);
|
||||
let l = new NomsList(ms, tr, new IndexedMetaSequence(tr, [new MetaTuple(rm1, 4), new MetaTuple(rm2, 4)]));
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
// @flow
|
||||
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import type {valueOrPrimitive} from './value.js'; // eslint-disable-line no-unused-vars
|
||||
import {Collection} from './collection.js';
|
||||
import {equals} from './value.js';
|
||||
import {invariant} from './assert.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {MetaTuple, registerMetaValue} from './meta_sequence.js';
|
||||
import {OrderedSequence} from './ordered_sequence.js';
|
||||
import {Type} from './type.js';
|
||||
|
||||
type Entry<K: valueOrPrimitive, V: valueOrPrimitive> = {
|
||||
key: K,
|
||||
value: V
|
||||
};
|
||||
|
||||
export class NomsMap<K: valueOrPrimitive, V: valueOrPrimitive, T> extends OrderedSequence<K, T> {
|
||||
export class NomsMap<K: valueOrPrimitive, V: valueOrPrimitive> extends Collection<OrderedSequence> {
|
||||
async has(key: K): Promise<boolean> {
|
||||
let cursor = await this.sequence.newCursorAt(this.cs, key);
|
||||
return cursor.valid && equals(cursor.getCurrentKey(), key);
|
||||
}
|
||||
|
||||
async first(): Promise<?[K, V]> {
|
||||
let cursor = await this.newCursorAt(null);
|
||||
let cursor = await this.sequence.newCursorAt(this.cs, null);
|
||||
if (!cursor.valid) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -26,7 +27,7 @@ export class NomsMap<K: valueOrPrimitive, V: valueOrPrimitive, T> extends Ordere
|
||||
}
|
||||
|
||||
async get(key: K): Promise<?V> {
|
||||
let cursor = await this.newCursorAt(key);
|
||||
let cursor = await this.sequence.newCursorAt(this.cs, key);
|
||||
if (!cursor.valid) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -36,7 +37,7 @@ export class NomsMap<K: valueOrPrimitive, V: valueOrPrimitive, T> extends Ordere
|
||||
}
|
||||
|
||||
async forEach(cb: (v: V, k: K) => void): Promise<void> {
|
||||
let cursor = await this.newCursorAt(null);
|
||||
let cursor = await this.sequence.newCursorAt(this.cs, null);
|
||||
return cursor.iter(entry => {
|
||||
cb(entry.value, entry.key);
|
||||
return false;
|
||||
@@ -44,37 +45,16 @@ export class NomsMap<K: valueOrPrimitive, V: valueOrPrimitive, T> extends Ordere
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this.items.length;
|
||||
if (this.sequence instanceof MapLeafSequence) {
|
||||
return this.sequence.items.length;
|
||||
}
|
||||
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
export class MapLeaf<K: valueOrPrimitive, V: valueOrPrimitive> extends NomsMap<K, V, Entry<K, V>> {
|
||||
export class MapLeafSequence<K: valueOrPrimitive, V: valueOrPrimitive> extends OrderedSequence<K, Entry<K, V>> {
|
||||
getKey(idx: number): K {
|
||||
return this.items[idx].key;
|
||||
}
|
||||
}
|
||||
|
||||
export class CompoundMap<K: valueOrPrimitive, V: valueOrPrimitive> extends NomsMap<K, V, MetaTuple<K>> {
|
||||
constructor(cs: ChunkStore, type: Type, items: Array<MetaTuple>) {
|
||||
super(cs, type, items);
|
||||
this.isMeta = true;
|
||||
}
|
||||
|
||||
getKey(idx: number): K {
|
||||
return this.items[idx].value;
|
||||
}
|
||||
|
||||
async getChildSequence(idx: number): Promise<?MapLeaf> {
|
||||
let mt = this.items[idx];
|
||||
let ms = await mt.readValue(this.cs);
|
||||
invariant(ms instanceof NomsMap);
|
||||
return ms;
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
registerMetaValue(Kind.Map, (cs, type, tuples) => new CompoundMap(cs, type, tuples));
|
||||
|
||||
|
||||
@@ -5,17 +5,18 @@ import {suite} from 'mocha';
|
||||
|
||||
import MemoryStore from './memory_store.js';
|
||||
import test from './async_test.js';
|
||||
import {CompoundMap, MapLeaf} from './map.js';
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {makeCompoundType, makePrimitiveType} from './type.js';
|
||||
import {MetaTuple} from './meta_sequence.js';
|
||||
import {MapLeafSequence, NomsMap} from './map.js';
|
||||
import {MetaTuple, OrderedMetaSequence} from './meta_sequence.js';
|
||||
import {writeValue} from './encode.js';
|
||||
|
||||
suite('MapLeaf', () => {
|
||||
test('has', async () => {
|
||||
let ms = new MemoryStore();
|
||||
let tr = makeCompoundType(Kind.Map, makePrimitiveType(Kind.String), makePrimitiveType(Kind.Bool));
|
||||
let m = new MapLeaf(ms, tr, [{key: 'a', value: false}, {key:'k', value:true}]);
|
||||
let m = new NomsMap(ms, tr, new MapLeafSequence(tr, [{key: 'a', value: false}, {key:'k', value:true}]));
|
||||
assert.isTrue(await m.has('a'));
|
||||
assert.isFalse(await m.has('b'));
|
||||
assert.isTrue(await m.has('k'));
|
||||
@@ -25,7 +26,7 @@ suite('MapLeaf', () => {
|
||||
test('first/get', async () => {
|
||||
let ms = new MemoryStore();
|
||||
let tr = makeCompoundType(Kind.Map, makePrimitiveType(Kind.String), makePrimitiveType(Kind.Int32));
|
||||
let m = new MapLeaf(ms, tr, [{key: 'a', value: 4}, {key:'k', value:8}]);
|
||||
let m = new NomsMap(ms, tr, new MapLeafSequence(tr, [{key: 'a', value: 4}, {key:'k', value:8}]));
|
||||
|
||||
assert.deepEqual(['a', 4], await m.first());
|
||||
|
||||
@@ -38,7 +39,7 @@ suite('MapLeaf', () => {
|
||||
test('forEach', async () => {
|
||||
let ms = new MemoryStore();
|
||||
let tr = makeCompoundType(Kind.Map, makePrimitiveType(Kind.String), makePrimitiveType(Kind.Int32));
|
||||
let m = new MapLeaf(ms, tr, [{key: 'a', value: 4}, {key:'k', value:8}]);
|
||||
let m = new NomsMap(ms, tr, new MapLeafSequence(tr, [{key: 'a', value: 4}, {key:'k', value:8}]));
|
||||
|
||||
let kv = [];
|
||||
await m.forEach((v, k) => { kv.push(k, v); });
|
||||
@@ -47,29 +48,29 @@ suite('MapLeaf', () => {
|
||||
});
|
||||
|
||||
suite('CompoundMap', () => {
|
||||
function build(): Array<CompoundMap> {
|
||||
let ms = new MemoryStore();
|
||||
function build(cs: ChunkStore): Array<NomsMap> {
|
||||
let tr = makeCompoundType(Kind.Map, makePrimitiveType(Kind.String), makePrimitiveType(Kind.Bool));
|
||||
let l1 = new MapLeaf(ms, tr, [{key: 'a', value: false}, {key:'b', value:false}]);
|
||||
let r1 = writeValue(l1, tr, ms);
|
||||
let l2 = new MapLeaf(ms, tr, [{key: 'e', value: true}, {key:'f', value:true}]);
|
||||
let r2 = writeValue(l2, tr, ms);
|
||||
let l3 = new MapLeaf(ms, tr, [{key: 'h', value: false}, {key:'i', value:true}]);
|
||||
let r3 = writeValue(l3, tr, ms);
|
||||
let l4 = new MapLeaf(ms, tr, [{key: 'm', value: true}, {key:'n', value:false}]);
|
||||
let r4 = writeValue(l4, tr, ms);
|
||||
let l1 = new NomsMap(cs, tr, new MapLeafSequence(tr, [{key: 'a', value: false}, {key:'b', value:false}]));
|
||||
let r1 = writeValue(l1, tr, cs);
|
||||
let l2 = new NomsMap(cs, tr, new MapLeafSequence(tr, [{key: 'e', value: true}, {key:'f', value:true}]));
|
||||
let r2 = writeValue(l2, tr, cs);
|
||||
let l3 = new NomsMap(cs, tr, new MapLeafSequence(tr, [{key: 'h', value: false}, {key:'i', value:true}]));
|
||||
let r3 = writeValue(l3, tr, cs);
|
||||
let l4 = new NomsMap(cs, tr, new MapLeafSequence(tr, [{key: 'm', value: true}, {key:'n', value:false}]));
|
||||
let r4 = writeValue(l4, tr, cs);
|
||||
|
||||
let m1 = new CompoundMap(ms, tr, [new MetaTuple(r1, 'b'), new MetaTuple(r2, 'f')]);
|
||||
let rm1 = writeValue(m1, tr, ms);
|
||||
let m2 = new CompoundMap(ms, tr, [new MetaTuple(r3, 'i'), new MetaTuple(r4, 'n')]);
|
||||
let rm2 = writeValue(m2, tr, ms);
|
||||
let m1 = new NomsMap(cs, tr, new OrderedMetaSequence(tr, [new MetaTuple(r1, 'b'), new MetaTuple(r2, 'f')]));
|
||||
let rm1 = writeValue(m1, tr, cs);
|
||||
let m2 = new NomsMap(cs, tr, new OrderedMetaSequence(tr, [new MetaTuple(r3, 'i'), new MetaTuple(r4, 'n')]));
|
||||
let rm2 = writeValue(m2, tr, cs);
|
||||
|
||||
let c = new CompoundMap(ms, tr, [new MetaTuple(rm1, 'f'), new MetaTuple(rm2, 'n')]);
|
||||
let c = new NomsMap(cs, tr, new OrderedMetaSequence(tr, [new MetaTuple(rm1, 'f'), new MetaTuple(rm2, 'n')]));
|
||||
return [c, m1, m2];
|
||||
}
|
||||
|
||||
test('get', async () => {
|
||||
let [c] = build();
|
||||
let ms = new MemoryStore();
|
||||
let [c] = build(ms);
|
||||
|
||||
assert.strictEqual(false, await c.get('a'));
|
||||
assert.strictEqual(false, await c.get('b'));
|
||||
@@ -88,8 +89,8 @@ suite('CompoundMap', () => {
|
||||
});
|
||||
|
||||
test('first/has', async () => {
|
||||
let [c, m1, m2] = build();
|
||||
|
||||
let ms = new MemoryStore();
|
||||
let [c, m1, m2] = build(ms);
|
||||
|
||||
assert.deepEqual(['a', false], await c.first());
|
||||
assert.deepEqual(['a', false], await m1.first());
|
||||
@@ -112,7 +113,8 @@ suite('CompoundMap', () => {
|
||||
});
|
||||
|
||||
test('forEach', async () => {
|
||||
let [c] = build();
|
||||
let ms = new MemoryStore();
|
||||
let [c] = build(ms);
|
||||
|
||||
let kv = [];
|
||||
await c.forEach((v, k) => { kv.push(k, v); });
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
import Ref from './ref.js';
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import type {NomsKind} from './noms_kind.js';
|
||||
import type {valueOrPrimitive} from './value.js'; // eslint-disable-line no-unused-vars
|
||||
import {CompoundDesc, makeCompoundType, makePrimitiveType, Type} from './type.js';
|
||||
import {invariant, notNull} from './assert.js';
|
||||
import {IndexedSequence} from './indexed_sequence.js';
|
||||
import {invariant} from './assert.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {OrderedSequence} from './ordered_sequence.js';
|
||||
import {readValue} from './read_value.js';
|
||||
import {Sequence} from './sequence.js';
|
||||
|
||||
@@ -19,23 +21,73 @@ export class MetaTuple<K> {
|
||||
this.ref = ref;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
readValue(cs: ChunkStore): Promise<any> {
|
||||
return readValue(this.ref, cs);
|
||||
export class IndexedMetaSequence extends IndexedSequence<MetaTuple<number>> {
|
||||
offsets: Array<number>;
|
||||
|
||||
constructor(type: Type, items: Array<MetaTuple<number>>) {
|
||||
super(type, items);
|
||||
this.isMeta = true;
|
||||
this.offsets = [];
|
||||
let cum = 0;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
let length = items[i].value;
|
||||
this.offsets.push(cum + length - 1);
|
||||
cum += length;
|
||||
}
|
||||
}
|
||||
|
||||
async getChildSequence(cs: ChunkStore, idx: number): Promise<?IndexedSequence> {
|
||||
if (!this.isMeta) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let mt = this.items[idx];
|
||||
let collection = await readValue(mt.ref, cs);
|
||||
invariant(collection && collection.sequence instanceof IndexedSequence);
|
||||
return collection.sequence;
|
||||
}
|
||||
|
||||
getOffset(idx: number): number {
|
||||
return this.offsets[idx];
|
||||
}
|
||||
}
|
||||
|
||||
export type metaBuilderFn = (cs: ChunkStore, t: Type, tuples: Array<MetaTuple>) => MetaSequence;
|
||||
export class OrderedMetaSequence<K: valueOrPrimitive> extends OrderedSequence<K, MetaTuple<K>> {
|
||||
constructor(type: Type, items: Array<MetaTuple>) {
|
||||
super(type, items);
|
||||
this.isMeta = true;
|
||||
}
|
||||
|
||||
let metaFuncMap: Map<NomsKind, metaBuilderFn> = new Map();
|
||||
async getChildSequence(cs: ChunkStore, idx: number): Promise<?OrderedSequence> {
|
||||
if (!this.isMeta) {
|
||||
return null;
|
||||
}
|
||||
|
||||
export function newMetaSequenceFromData(cs: ChunkStore, t: Type, data: Array<MetaTuple>): MetaSequence {
|
||||
let ctor = notNull(metaFuncMap.get(t.kind));
|
||||
return ctor(cs, t, data);
|
||||
let mt = this.items[idx];
|
||||
let collection = await readValue(mt.ref, cs);
|
||||
invariant(collection && collection.sequence instanceof OrderedSequence);
|
||||
return collection.sequence;
|
||||
}
|
||||
|
||||
getKey(idx: number): K {
|
||||
return this.items[idx].value;
|
||||
}
|
||||
}
|
||||
|
||||
export function registerMetaValue(k: NomsKind, bf: metaBuilderFn) {
|
||||
metaFuncMap.set(k, bf);
|
||||
export function newMetaSequenceFromData(cs: ChunkStore, type: Type, tuples: Array<MetaTuple>): MetaSequence {
|
||||
switch (type.kind) {
|
||||
case Kind.Map:
|
||||
case Kind.Set:
|
||||
return new OrderedMetaSequence(type, tuples);
|
||||
case Kind.List:
|
||||
return new IndexedMetaSequence(type, tuples);
|
||||
case Kind.Blob:
|
||||
throw new Error('Not implemented');
|
||||
default:
|
||||
throw new Error('Not reached');
|
||||
}
|
||||
}
|
||||
|
||||
let indexedSequenceIndexType = makePrimitiveType(Kind.Uint64);
|
||||
|
||||
@@ -7,10 +7,13 @@ export {default as MemoryStore} from './memory_store.js';
|
||||
export {default as Ref} from './ref.js';
|
||||
export {default as Struct} from './struct.js';
|
||||
export {encodeNomsValue} from './encode.js';
|
||||
export {invariant, notNull} from './assert.js';
|
||||
export {isPrimitiveKind, Kind} from './noms_kind.js';
|
||||
export {ListLeafSequence, NomsList} from './list.js';
|
||||
export {lookupPackage, Package, readPackage, registerPackage} from './package.js';
|
||||
export {NomsList, ListLeaf, CompoundList} from './list.js';
|
||||
export {NomsMap, MapLeaf, CompoundMap} from './map.js';
|
||||
export {NomsSet, SetLeaf, CompoundSet} from './set.js';
|
||||
export {NomsMap, MapLeafSequence} from './map.js';
|
||||
export {NomsSet, SetLeafSequence} from './set.js';
|
||||
export {OrderedMetaSequence, IndexedMetaSequence} from './meta_sequence.js';
|
||||
export {readValue} from './read_value.js';
|
||||
export {
|
||||
CompoundDesc,
|
||||
@@ -22,11 +25,11 @@ export {
|
||||
makeStructType,
|
||||
makeType,
|
||||
makeUnresolvedType,
|
||||
packageType,
|
||||
PrimitiveDesc,
|
||||
StructDesc,
|
||||
Type,
|
||||
typeType,
|
||||
packageType,
|
||||
UnresolvedDesc
|
||||
} from './type.js';
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// @flow
|
||||
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import type {valueOrPrimitive} from './value.js'; // eslint-disable-line no-unused-vars
|
||||
import {invariant, notNull} from './assert.js';
|
||||
import {less, equals} from './value.js';
|
||||
import {less} from './value.js';
|
||||
import {search, Sequence, SequenceCursor} from './sequence.js';
|
||||
|
||||
export class OrderedSequence<K: valueOrPrimitive, T> extends Sequence<T> {
|
||||
@@ -12,12 +13,12 @@ export class OrderedSequence<K: valueOrPrimitive, T> extends Sequence<T> {
|
||||
// -cursor positioned at
|
||||
// -first value, if |key| is null
|
||||
// -first value >= |key|
|
||||
async newCursorAt(key: ?K): Promise<OrderedSequenceCursor> {
|
||||
async newCursorAt(cs: ChunkStore, key: ?K): Promise<OrderedSequenceCursor> {
|
||||
let cursor: ?OrderedSequenceCursor = null;
|
||||
let sequence: ?OrderedSequence = this;
|
||||
|
||||
while (sequence) {
|
||||
cursor = new OrderedSequenceCursor(cursor, sequence, 0);
|
||||
cursor = new OrderedSequenceCursor(cs, cursor, sequence, 0);
|
||||
if (key) {
|
||||
if (!cursor._seekTo(key)) {
|
||||
return cursor; // invalid
|
||||
@@ -33,11 +34,6 @@ export class OrderedSequence<K: valueOrPrimitive, T> extends Sequence<T> {
|
||||
getKey(idx: number): K { // eslint-disable-line no-unused-vars
|
||||
throw new Error('override');
|
||||
}
|
||||
|
||||
async has(key: K): Promise<boolean> {
|
||||
let cursor = await this.newCursorAt(key);
|
||||
return cursor.valid && equals(cursor.getCurrentKey(), key);
|
||||
}
|
||||
}
|
||||
|
||||
export class OrderedSequenceCursor<T, K: valueOrPrimitive> extends SequenceCursor<T, OrderedSequence> {
|
||||
|
||||
@@ -2,9 +2,15 @@
|
||||
|
||||
import Rusha from 'rusha';
|
||||
|
||||
import type {Value} from './value.js';
|
||||
import {invariant} from './assert.js';
|
||||
|
||||
const r = new Rusha();
|
||||
const sha1Size = 20;
|
||||
const pattern = /^sha1-([0-9a-f]{40})$/;
|
||||
const pattern = /^(sha1-[0-9a-f]{40})$/;
|
||||
|
||||
const sha1Prefix = 'sha1-';
|
||||
const emtpyRefStr = sha1Prefix + '0'.repeat(40);
|
||||
|
||||
function uint8ArrayToHex(a: Uint8Array): string {
|
||||
let hex = '';
|
||||
@@ -31,46 +37,36 @@ function hexToUint8(s: string): Uint8Array {
|
||||
}
|
||||
|
||||
export default class Ref {
|
||||
digest: Uint8Array;
|
||||
_refStr: string;
|
||||
|
||||
constructor(digest: Uint8Array = new Uint8Array(sha1Size)) {
|
||||
this.digest = digest;
|
||||
constructor(refStr: string = emtpyRefStr) {
|
||||
this._refStr = refStr;
|
||||
}
|
||||
|
||||
get ref(): Ref {
|
||||
return this;
|
||||
}
|
||||
|
||||
get digest(): Uint8Array {
|
||||
return hexToUint8(this._refStr.substring(5));
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
for (let i = 0; i < sha1Size; i++) {
|
||||
if (this.digest[i] !== 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return this._refStr === emtpyRefStr;
|
||||
}
|
||||
|
||||
equals(other: Ref): boolean {
|
||||
for (let i = 0; i < sha1Size; i++) {
|
||||
if (this.digest[i] !== other.digest[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
equals(other: Value): boolean {
|
||||
invariant(other instanceof Ref);
|
||||
return this._refStr === other._refStr;
|
||||
}
|
||||
|
||||
compare(other: Ref): number {
|
||||
for (let i = 0; i < sha1Size; i++) {
|
||||
if (this.digest[i] < other.digest[i]) {
|
||||
return -1;
|
||||
} else if (this.digest[i] > other.digest[i]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
less(other: Value): boolean {
|
||||
invariant(other instanceof Ref);
|
||||
return this._refStr < other._refStr;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return 'sha1-' + uint8ArrayToHex(this.digest);
|
||||
return this._refStr;
|
||||
}
|
||||
|
||||
static parse(s: string): Ref {
|
||||
@@ -79,11 +75,14 @@ export default class Ref {
|
||||
throw Error('Could not parse ref: ' + s);
|
||||
}
|
||||
|
||||
return new Ref(hexToUint8(m[1]));
|
||||
return new Ref(m[1]);
|
||||
}
|
||||
|
||||
static fromDigest(digest: Uint8Array = new Uint8Array(sha1Size)) {
|
||||
return new Ref(sha1Prefix + uint8ArrayToHex(digest));
|
||||
}
|
||||
|
||||
static fromData(data: Uint8Array): Ref {
|
||||
let digest = r.rawDigest(data);
|
||||
return new Ref(new Uint8Array(digest.buffer));
|
||||
return new Ref(sha1Prefix + r.digest(data));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,11 +56,11 @@ suite('Ref', () => {
|
||||
|
||||
test('isEmpty', () => {
|
||||
let digest = new Uint8Array(20);
|
||||
let r = new Ref(digest);
|
||||
let r = Ref.fromDigest(digest);
|
||||
assert.isTrue(r.isEmpty());
|
||||
|
||||
digest[0] = 10;
|
||||
r = new Ref(digest);
|
||||
r = Ref.fromDigest(digest);
|
||||
assert.isFalse(r.isEmpty());
|
||||
|
||||
r = new Ref();
|
||||
|
||||
@@ -3,32 +3,32 @@
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import {invariant, notNull} from './assert.js';
|
||||
import {Type} from './type.js';
|
||||
import {Value} from './value.js';
|
||||
import {ValueBase} from './value.js';
|
||||
|
||||
export class Sequence<T> extends Value {
|
||||
cs: ChunkStore;
|
||||
export class Sequence<T> extends ValueBase {
|
||||
items: Array<T>;
|
||||
isMeta: boolean;
|
||||
|
||||
constructor(cs: ChunkStore, type: Type, items: Array<T>) {
|
||||
constructor(type: Type, items: Array<T>) {
|
||||
super(type);
|
||||
|
||||
this.cs = cs;
|
||||
this.items = items;
|
||||
this.isMeta = false;
|
||||
}
|
||||
|
||||
getChildSequence(idx: number): Promise<?Sequence> { // eslint-disable-line no-unused-vars
|
||||
getChildSequence(cs: ChunkStore, idx: number): Promise<?Sequence> { // eslint-disable-line no-unused-vars
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
export class SequenceCursor<T, S:Sequence> {
|
||||
cs: ChunkStore;
|
||||
parent: ?SequenceCursor;
|
||||
sequence: S;
|
||||
idx: number;
|
||||
|
||||
constructor(parent: ?SequenceCursor, sequence: S, idx: number) {
|
||||
constructor(cs: ChunkStore, parent: ?SequenceCursor, sequence: S, idx: number) {
|
||||
this.cs = cs;
|
||||
this.parent = parent;
|
||||
this.sequence = sequence;
|
||||
this.idx = idx;
|
||||
@@ -48,7 +48,7 @@ export class SequenceCursor<T, S:Sequence> {
|
||||
}
|
||||
|
||||
getChildSequence(): Promise<?S> {
|
||||
return this.sequence.getChildSequence(this.idx);
|
||||
return this.sequence.getChildSequence(this.cs, this.idx);
|
||||
}
|
||||
|
||||
getCurrent(): T {
|
||||
@@ -125,10 +125,6 @@ export class SequenceCursor<T, S:Sequence> {
|
||||
return false;
|
||||
}
|
||||
|
||||
copy(): SequenceCursor {
|
||||
return new SequenceCursor(this.parent ? this.parent.copy() : null, this.sequence, this.idx);
|
||||
}
|
||||
|
||||
async iter(cb: (v: T, i: number) => boolean): Promise<void> {
|
||||
let idx = 0;
|
||||
while (this.valid) {
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
// @flow
|
||||
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import type {valueOrPrimitive} from './value.js'; // eslint-disable-line no-unused-vars
|
||||
import {Collection} from './collection.js';
|
||||
import {equals, less} from './value.js';
|
||||
import {invariant} from './assert.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {OrderedSequence} from './ordered_sequence.js';
|
||||
import {registerMetaValue, MetaTuple} from './meta_sequence.js';
|
||||
import {Type} from './type.js';
|
||||
|
||||
export class NomsSet<K:valueOrPrimitive, T> extends OrderedSequence<K, T> {
|
||||
export class NomsSet<T:valueOrPrimitive> extends Collection<OrderedSequence> {
|
||||
async has(key: T): Promise<boolean> {
|
||||
let cursor = await this.sequence.newCursorAt(this.cs, key);
|
||||
return cursor.valid && equals(cursor.getCurrentKey(), key);
|
||||
}
|
||||
|
||||
async first(): Promise<?T> {
|
||||
let cursor = await this.newCursorAt(null);
|
||||
let cursor = await this.sequence.newCursorAt(this.cs, null);
|
||||
return cursor.valid ? cursor.getCurrent() : null;
|
||||
}
|
||||
|
||||
async forEach(cb: (v: T) => void): Promise<void> {
|
||||
let cursor = await this.newCursorAt(null);
|
||||
let cursor = await this.sequence.newCursorAt(this.cs, null);
|
||||
return cursor.iter(v => {
|
||||
cb(v);
|
||||
return false;
|
||||
@@ -24,10 +26,14 @@ export class NomsSet<K:valueOrPrimitive, T> extends OrderedSequence<K, T> {
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this.items.length;
|
||||
if (this.sequence instanceof SetLeafSequence) {
|
||||
return this.sequence.items.length;
|
||||
}
|
||||
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
async intersect(...sets: Array<NomsSet>): Promise<NomsSet> {
|
||||
async intersect(...sets: Array<NomsSet<T>>): Promise<NomsSet<T>> {
|
||||
if (sets.length === 0) {
|
||||
return this;
|
||||
}
|
||||
@@ -37,16 +43,17 @@ export class NomsSet<K:valueOrPrimitive, T> extends OrderedSequence<K, T> {
|
||||
invariant(sets[i].type.equals(this.type));
|
||||
}
|
||||
|
||||
let cursor = await this.newCursorAt(null);
|
||||
let cursor = await this.sequence.newCursorAt(this.cs, null);
|
||||
if (!cursor.valid) {
|
||||
return this;
|
||||
}
|
||||
|
||||
let values: Array<K> = [];
|
||||
let values: Array<T> = [];
|
||||
|
||||
for (let i = 0; cursor.valid && i < sets.length; i++) {
|
||||
let first = cursor.getCurrent();
|
||||
let next = await sets[i].newCursorAt(first);
|
||||
let set: NomsSet = sets[i];
|
||||
let next = await set.sequence.newCursorAt(set.cs, first);
|
||||
if (!next.valid) {
|
||||
break;
|
||||
}
|
||||
@@ -61,40 +68,16 @@ export class NomsSet<K:valueOrPrimitive, T> extends OrderedSequence<K, T> {
|
||||
}
|
||||
|
||||
// TODO: Chunk the resulting set.
|
||||
return new SetLeaf(this.cs, this.type, values);
|
||||
return new NomsSet(this.cs, this.type, new SetLeafSequence(this.type, values));
|
||||
}
|
||||
}
|
||||
|
||||
export class SetLeaf<K:valueOrPrimitive> extends NomsSet<K, K> {
|
||||
export class SetLeafSequence<K:valueOrPrimitive> extends OrderedSequence<K, K> {
|
||||
getKey(idx: number): K {
|
||||
return this.items[idx];
|
||||
}
|
||||
}
|
||||
|
||||
export class CompoundSet<K:valueOrPrimitive> extends NomsSet<K, MetaTuple<K>> {
|
||||
constructor(cs: ChunkStore, type: Type, items: Array<MetaTuple>) {
|
||||
super(cs, type, items);
|
||||
this.isMeta = true;
|
||||
}
|
||||
|
||||
getKey(idx: number): K {
|
||||
return this.items[idx].value;
|
||||
}
|
||||
|
||||
async getChildSequence(idx: number): Promise<?SetLeaf> {
|
||||
let mt = this.items[idx];
|
||||
let ms = await mt.readValue(this.cs);
|
||||
invariant(ms instanceof NomsSet);
|
||||
return ms;
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
registerMetaValue(Kind.Set, (cs, type, tuples) => new CompoundSet(cs, type, tuples));
|
||||
|
||||
type OrderedCursor<K: valueOrPrimitive> = {
|
||||
valid: boolean;
|
||||
getCurrent(): K;
|
||||
|
||||
@@ -5,18 +5,21 @@ import {suite} from 'mocha';
|
||||
|
||||
import MemoryStore from './memory_store.js';
|
||||
import test from './async_test.js';
|
||||
import {CompoundSet, NomsSet, SetLeaf} from './set.js';
|
||||
import {notNull} from './assert.js';
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import {invariant} from './assert.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {makeCompoundType, makePrimitiveType} from './type.js';
|
||||
import {MetaTuple} from './meta_sequence.js';
|
||||
import {MetaTuple, OrderedMetaSequence} from './meta_sequence.js';
|
||||
import {NomsSet, SetLeafSequence} from './set.js';
|
||||
import {notNull} from './assert.js';
|
||||
import {OrderedSequence} from './ordered_sequence.js';
|
||||
import {writeValue} from './encode.js';
|
||||
|
||||
suite('SetLeaf', () => {
|
||||
test('first/has', async () => {
|
||||
let ms = new MemoryStore();
|
||||
let tr = makeCompoundType(Kind.Set, makePrimitiveType(Kind.String));
|
||||
let s = new SetLeaf(ms, tr, ['a', 'k']);
|
||||
let s = new NomsSet(ms, tr, new SetLeafSequence(tr, ['a', 'k']));
|
||||
|
||||
assert.strictEqual('a', await s.first());
|
||||
|
||||
@@ -29,7 +32,7 @@ suite('SetLeaf', () => {
|
||||
test('forEach', async () => {
|
||||
let ms = new MemoryStore();
|
||||
let tr = makeCompoundType(Kind.Set, makePrimitiveType(Kind.String));
|
||||
let m = new SetLeaf(ms, tr, ['a', 'b']);
|
||||
let m = new NomsSet(ms, tr, new SetLeafSequence(tr, ['a', 'b']));
|
||||
|
||||
let values = [];
|
||||
await m.forEach((k) => { values.push(k); });
|
||||
@@ -38,16 +41,14 @@ suite('SetLeaf', () => {
|
||||
});
|
||||
|
||||
suite('CompoundSet', () => {
|
||||
function build(values: Array<string>): NomsSet {
|
||||
let ms = new MemoryStore();
|
||||
|
||||
function build(cs: ChunkStore, values: Array<string>): NomsSet {
|
||||
let tr = makeCompoundType(Kind.Set, makePrimitiveType(Kind.String));
|
||||
assert.isTrue(values.length > 1 && Math.log2(values.length) % 1 === 0);
|
||||
|
||||
let tuples = [];
|
||||
for (let i = 0; i < values.length; i += 2) {
|
||||
let l = new SetLeaf(ms, tr, [values[i], values[i + 1]]);
|
||||
let r = writeValue(l, tr, ms);
|
||||
let l = new NomsSet(cs, tr, new SetLeafSequence(tr, [values[i], values[i + 1]]));
|
||||
let r = writeValue(l, tr, cs);
|
||||
tuples.push(new MetaTuple(r, values[i + 1]));
|
||||
}
|
||||
|
||||
@@ -55,8 +56,8 @@ suite('CompoundSet', () => {
|
||||
while (tuples.length > 1) {
|
||||
let next = [];
|
||||
for (let i = 0; i < tuples.length; i += 2) {
|
||||
last = new CompoundSet(ms, tr, [tuples[i], tuples[i + 1]]);
|
||||
let r = writeValue(last, tr, ms);
|
||||
last = new NomsSet(cs, tr, new OrderedMetaSequence(tr, [tuples[i], tuples[i + 1]]));
|
||||
let r = writeValue(last, tr, cs);
|
||||
next.push(new MetaTuple(r, tuples[i + 1].value));
|
||||
}
|
||||
|
||||
@@ -67,7 +68,8 @@ suite('CompoundSet', () => {
|
||||
}
|
||||
|
||||
test('first/has', async () => {
|
||||
let c = build(['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n']);
|
||||
let ms = new MemoryStore();
|
||||
let c = build(ms, ['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n']);
|
||||
assert.strictEqual('a', await c.first());
|
||||
assert.isTrue(await c.has('a'));
|
||||
assert.isTrue(await c.has('b'));
|
||||
@@ -86,7 +88,8 @@ suite('CompoundSet', () => {
|
||||
});
|
||||
|
||||
test('forEach', async () => {
|
||||
let c = build(['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n']);
|
||||
let ms = new MemoryStore();
|
||||
let c = build(ms, ['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n']);
|
||||
let values = [];
|
||||
await c.forEach((k) => { values.push(k); });
|
||||
assert.deepEqual(['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n'], values);
|
||||
@@ -104,9 +107,12 @@ suite('CompoundSet', () => {
|
||||
}
|
||||
|
||||
test('advanceTo', async () => {
|
||||
let c = build(['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n']);
|
||||
let ms = new MemoryStore();
|
||||
|
||||
let cursor = await c.newCursorAt(null);
|
||||
let c = build(ms, ['a', 'b', 'e', 'f', 'h', 'i', 'm', 'n']);
|
||||
|
||||
invariant(c.sequence instanceof OrderedSequence);
|
||||
let cursor = await c.sequence.newCursorAt(c.cs, null);
|
||||
assert.ok(cursor);
|
||||
assert.strictEqual('a', cursor.getCurrent());
|
||||
|
||||
@@ -119,10 +125,12 @@ suite('CompoundSet', () => {
|
||||
assert.isFalse(await cursor.advanceTo('z')); // not found
|
||||
assert.isFalse(cursor.valid);
|
||||
|
||||
cursor = await c.newCursorAt('x'); // not found
|
||||
invariant(c.sequence instanceof OrderedSequence);
|
||||
cursor = await c.sequence.newCursorAt(ms, 'x'); // not found
|
||||
assert.isFalse(cursor.valid);
|
||||
|
||||
cursor = await c.newCursorAt('e');
|
||||
invariant(c.sequence instanceof OrderedSequence);
|
||||
cursor = await c.sequence.newCursorAt(ms, 'e');
|
||||
assert.ok(cursor);
|
||||
assert.strictEqual('e', cursor.getCurrent());
|
||||
|
||||
@@ -141,10 +149,12 @@ suite('CompoundSet', () => {
|
||||
});
|
||||
|
||||
async function testIntersect(expect: Array<string>, seqs: Array<Array<string>>) {
|
||||
let first = build(seqs[0]);
|
||||
let ms = new MemoryStore();
|
||||
|
||||
let first = build(ms, seqs[0]);
|
||||
let sets:Array<NomsSet> = [];
|
||||
for (let i = 1; i < seqs.length; i++) {
|
||||
sets.push(build(seqs[i]));
|
||||
sets.push(build(ms, seqs[i]));
|
||||
}
|
||||
|
||||
let result = await first.intersect(...sets);
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
import {Field, StructDesc, Type} from './type.js';
|
||||
import {invariant, notNull} from './assert.js';
|
||||
import {Value} from './value.js';
|
||||
import {ValueBase} from './value.js';
|
||||
|
||||
type StructData = {[key: string]: any};
|
||||
|
||||
export default class Struct extends Value {
|
||||
export default class Struct extends ValueBase {
|
||||
desc: StructDesc;
|
||||
unionField: ?Field;
|
||||
|
||||
|
||||
@@ -6,7 +6,12 @@ import {ensureRef} from './get_ref.js';
|
||||
import {invariant} from './assert.js';
|
||||
import {Type} from './type.js';
|
||||
|
||||
export class Value {
|
||||
export type Value = {
|
||||
ref: Ref;
|
||||
equals(other: Value): boolean;
|
||||
}
|
||||
|
||||
export class ValueBase {
|
||||
type: Type;
|
||||
_ref: ?Ref;
|
||||
|
||||
@@ -31,16 +36,16 @@ export function less(v1: any, v2: any): boolean {
|
||||
|
||||
if (typeof v1 === 'object') {
|
||||
invariant(typeof v2 === 'object');
|
||||
if (v1 instanceof Value) {
|
||||
if (v1 instanceof ValueBase) {
|
||||
v1 = v1.ref;
|
||||
}
|
||||
if (v2 instanceof Value) {
|
||||
if (v2 instanceof ValueBase) {
|
||||
v2 = v2.ref;
|
||||
}
|
||||
|
||||
invariant(v1 instanceof Ref);
|
||||
invariant(v2 instanceof Ref);
|
||||
return v1.compare(v2) < 0;
|
||||
return v1.less(v2);
|
||||
}
|
||||
|
||||
if (typeof v1 === 'string') {
|
||||
|
||||
Reference in New Issue
Block a user