datafolder 1.0.22 → 1.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ChangeLog.md ADDED
@@ -0,0 +1,33 @@
1
+ 1.0.24 Add HNSW test cases (test/testQyHNSW.ts).
2
+
3
+ 1.0.23 Add ChangeLog.md
4
+
5
+ 1.0.21 Add ArangoDB Query Language (AQL) test case (test/testQyAQL.js)
6
+
7
+ 1.0.20 Add HNSW support.
8
+
9
+ 1.0.19 Add DocumentDB test case (test/testQyDocumentDB.js)
10
+
11
+ 1.0.18 Add Embedding Storage Support. Related APIs: dataFolder.insertEmbedding() and dataFolder.delEmbedding(). TODO: Add HNSW support and vector query.
12
+
13
+ 1.0.17 Add Northwind sample data test (test/testQyNorthwind.js)
14
+
15
+ 1.0.16 Add GraphQL sample data test (test/testQyGraphQL.js) to show how to write complex queries.
16
+
17
+ 1.0.15 Use [Workers](https://nodejs.org/docs/latest/api/worker_threads.html) to implement snapshot compactor, expire service, outdated data cleaner etc.
18
+
19
+ 1.0.14 Expire supports specifying milliseconds.
20
+
21
+ 1.0.13 Added expire support to delete a dir in a specific future time.
22
+
23
+ 1.0.12 Added expire support to expire a file or some properties of the JSON data in future.
24
+
25
+ 1.0.11 Added [SKILL.md](https://github.com/datafolderdev/datafolder/blob/main/SKILL.md) for feeding to AI
26
+
27
+ 1.0.10 Added document [datafolder for high speed SSDs](https://github.com/datafolderdev/datafolder/wiki/datafolder-for-high-speed-SSDs)
28
+
29
+ 1.0.9 Added Typescript type declarations.
30
+
31
+ 1.0.7 Added trigger editor and [Internals of datafolder](https://github.com/datafolderdev/datafolder/wiki/Internals-of-datafolder)
32
+
33
+ 1.0.6 Added code mirror as the query editor.
package/README.md CHANGED
@@ -4,7 +4,7 @@ datafolder is a lightning fluid JSON database for high speed SSDs, featuring an
4
4
 
5
5
  ### Changelog
6
6
 
7
- [ChangeLog] (ChangeLog.md)
7
+ [ChangeLog](./ChangeLog.md)
8
8
 
9
9
  ## Installation
10
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datafolder",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "author": {
5
5
  "name": "lysh",
6
6
  "email": "datafolderdev@outlook.com"
@@ -62,7 +62,7 @@
62
62
  }
63
63
 
64
64
  function prevClusterBreak(str, pos, includeExtending) {
65
- while (pos > 0) {
65
+ while (pos > 1) {
66
66
  let found = nextClusterBreak(str, pos - 2, includeExtending);
67
67
  if (found < pos) return found
68
68
  pos--;
@@ -1750,6 +1750,7 @@
1750
1750
  }
1751
1751
  };
1752
1752
  }
1753
+ get extension() { return this; }
1753
1754
  }
1754
1755
  function compareArray(a, b, compare) {
1755
1756
  if (a.length != b.length)
@@ -1947,6 +1948,7 @@
1947
1948
  this.inner = inner;
1948
1949
  this.prec = prec;
1949
1950
  }
1951
+ get extension() { return this; }
1950
1952
  }
1951
1953
  /**
1952
1954
  Extension compartments can be used to make a configuration
@@ -1981,6 +1983,7 @@
1981
1983
  this.compartment = compartment;
1982
1984
  this.inner = inner;
1983
1985
  }
1986
+ get extension() { return this; }
1984
1987
  }
1985
1988
  class Configuration {
1986
1989
  constructor(base, compartments, dynamicSlots, address, staticValues, facets) {
@@ -2090,6 +2093,8 @@
2090
2093
  else {
2091
2094
  let content = ext.extension;
2092
2095
  if (!content)
2096
+ throw new Error(`Unrecognized extension value in extension set (${ext}).`);
2097
+ if (content == ext)
2093
2098
  throw new Error(`Unrecognized extension value in extension set (${ext}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`);
2094
2099
  inner(content, prec);
2095
2100
  }
@@ -4815,8 +4820,11 @@
4815
4820
  function maxOffset(node) {
4816
4821
  return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
4817
4822
  }
4818
- function flattenRect(rect, left) {
4819
- let x = left ? rect.left : rect.right;
4823
+ function flattenRect(rect, toLeft) {
4824
+ let { left, right } = rect;
4825
+ if (left == right)
4826
+ return rect;
4827
+ let x = toLeft ? left : right;
4820
4828
  return { left: x, right: x, top: rect.top, bottom: rect.bottom };
4821
4829
  }
4822
4830
  function windowRect(win) {
@@ -6080,7 +6088,7 @@
6080
6088
  return this.posBefore(tile) + tile.length;
6081
6089
  }
6082
6090
  covers(side) { return true; }
6083
- coordsIn(pos, side) { return null; }
6091
+ coordsIn(pos, side, rtl) { return null; }
6084
6092
  domPosFor(off, side) {
6085
6093
  let index = domIndex(this.dom);
6086
6094
  let after = this.length ? off > 0 : side > 0;
@@ -6267,6 +6275,9 @@
6267
6275
  }
6268
6276
  get domAttrs() { return this.attrs; }
6269
6277
  // Find the tile associated with a given position in this line.
6278
+ // Side -2/2 is handled specially, in that it allows the position
6279
+ // returned to be before (-2) or after (2) widgets that would always
6280
+ // be after/before a cursor position.
6270
6281
  resolveInline(pos, side, forCoords) {
6271
6282
  let before = null, beforeOff = -1, after = null, afterOff = -1;
6272
6283
  function scan(tile, pos) {
@@ -6276,12 +6287,12 @@
6276
6287
  if (child.isComposite()) {
6277
6288
  scan(child, pos - off);
6278
6289
  }
6279
- else if ((!after || after.isHidden && (side > 0 || forCoords && onSameLine(after, child))) &&
6280
- (end > pos || (child.flags & 32 /* TileFlag.After */))) {
6290
+ else if ((!after || after.isHidden && (side > 0 && !(after.flags & 32 /* TileFlag.After */) || forCoords && onSameLine(after, child))) &&
6291
+ (end > pos || (child.flags & 32 /* TileFlag.After */) && side <= 1)) {
6281
6292
  after = child;
6282
6293
  afterOff = pos - off;
6283
6294
  }
6284
- else if (off < pos || (child.flags & 16 /* TileFlag.Before */) && !child.isHidden) {
6295
+ else if (off < pos || (child.flags & 16 /* TileFlag.Before */) && !child.isHidden && side >= -1) {
6285
6296
  before = child;
6286
6297
  beforeOff = pos - off;
6287
6298
  }
@@ -6293,11 +6304,11 @@
6293
6304
  let target = ((side < 0 ? before : after) || before || after);
6294
6305
  return target ? { tile: target, offset: target == before ? beforeOff : afterOff } : null;
6295
6306
  }
6296
- coordsIn(pos, side) {
6307
+ coordsIn(pos, side, rtl) {
6297
6308
  let found = this.resolveInline(pos, side, true);
6298
6309
  if (!found)
6299
6310
  return fallbackRect(this);
6300
- return found.tile.coordsIn(Math.max(0, found.offset), side);
6311
+ return found.tile.coordsIn(Math.max(0, found.offset), side, rtl);
6301
6312
  }
6302
6313
  domIn(pos, side) {
6303
6314
  let found = this.resolveInline(pos, side);
@@ -6361,7 +6372,7 @@
6361
6372
  }
6362
6373
  isText() { return true; }
6363
6374
  toString() { return JSON.stringify(this.text); }
6364
- coordsIn(pos, side) {
6375
+ coordsIn(pos, side, rtl) {
6365
6376
  let length = this.dom.nodeValue.length;
6366
6377
  if (pos > length)
6367
6378
  pos = length;
@@ -6371,7 +6382,7 @@
6371
6382
  if (pos) {
6372
6383
  from--;
6373
6384
  flatten = 1;
6374
- } // FIXME this is wrong in RTL text
6385
+ }
6375
6386
  else if (to < length) {
6376
6387
  to++;
6377
6388
  flatten = -1;
@@ -6390,7 +6401,7 @@
6390
6401
  let rect = rects[(flatten ? flatten < 0 : side >= 0) ? 0 : rects.length - 1];
6391
6402
  if (browser.safari && !flatten && rect.width == 0)
6392
6403
  rect = Array.prototype.find.call(rects, r => r.width) || rect;
6393
- return flatten ? flattenRect(rect, flatten < 0) : rect || null;
6404
+ return rtl == null ? rect : flattenRect(rect, (flatten ? flatten > 0 : side < 0) == rtl);
6394
6405
  }
6395
6406
  static of(text, dom) {
6396
6407
  let tile = new TextTile(dom || document.createTextNode(text), text);
@@ -6466,7 +6477,10 @@
6466
6477
  }
6467
6478
  get isHidden() { return true; }
6468
6479
  get overrideDOMText() { return Text.empty; }
6469
- coordsIn(pos) { return this.dom.getBoundingClientRect(); }
6480
+ coordsIn(pos, side, rtl) {
6481
+ let rect = this.dom.getBoundingClientRect();
6482
+ return rtl == null ? rect : flattenRect(rect, (side > 0) == rtl);
6483
+ }
6470
6484
  }
6471
6485
  // Represents a position in the tile tree.
6472
6486
  class TilePointer {
@@ -6484,7 +6498,15 @@
6484
6498
  let { tile, index, beforeBreak, parents } = this;
6485
6499
  while (dist || side > 0) {
6486
6500
  if (!tile.isComposite()) {
6487
- if (index == tile.length) {
6501
+ let len = tile.length;
6502
+ if (index < len && dist) {
6503
+ let take = Math.min(dist, len - index);
6504
+ if (walker)
6505
+ walker.skip(tile, index, index + take);
6506
+ dist -= take;
6507
+ index += take;
6508
+ }
6509
+ if (index == len) {
6488
6510
  beforeBreak = !!tile.breakAfter;
6489
6511
  ({ tile, index } = parents.pop());
6490
6512
  index++;
@@ -6492,13 +6514,6 @@
6492
6514
  else if (!dist) {
6493
6515
  break;
6494
6516
  }
6495
- else {
6496
- let take = Math.min(dist, tile.length - index);
6497
- if (walker)
6498
- walker.skip(tile, index, index + take);
6499
- dist -= take;
6500
- index += take;
6501
- }
6502
6517
  }
6503
6518
  else if (beforeBreak) {
6504
6519
  if (!dist)
@@ -6828,8 +6843,8 @@
6828
6843
  find(cls, test, type = 2 /* Reused.DOM */) {
6829
6844
  let i = cls.bucket;
6830
6845
  let bucket = this.buckets[i], off = this.index[i];
6831
- for (let j = bucket.length - 1; j >= 0; j--) {
6832
- // Look at the most recently added items first (last-in, first-out)
6846
+ for (let j = 0; j < bucket.length; j++) {
6847
+ // Look at the most oldest items first (first-in, first-out)
6833
6848
  let index = (j + off) % bucket.length, tile = bucket[index];
6834
6849
  if ((!test || test(tile)) && !this.reused.has(tile)) {
6835
6850
  bucket.splice(index, 1);
@@ -7032,7 +7047,7 @@
7032
7047
  }
7033
7048
  emit(from, to) {
7034
7049
  let pendingLineAttrs = null;
7035
- let b = this.builder, markCount = 0;
7050
+ let b = this.builder, markCount = -1;
7036
7051
  let openEnd = RangeSet.spans(this.decorations, from, to, {
7037
7052
  point: (from, to, deco, active, openStart, index) => {
7038
7053
  if (deco instanceof PointDecoration) {
@@ -7083,9 +7098,11 @@
7083
7098
  }
7084
7099
  pendingLineAttrs = null;
7085
7100
  }
7101
+ markCount = active.length;
7086
7102
  }
7087
7103
  });
7088
- this.openWidget = openEnd > markCount;
7104
+ if (markCount > -1)
7105
+ this.openWidget = openEnd > markCount;
7089
7106
  if (!this.openWidget)
7090
7107
  b.addLineStartIfNotCovered(pendingLineAttrs);
7091
7108
  this.openMarks = openEnd;
@@ -7494,7 +7511,7 @@
7494
7511
  domAtPos(pos, side) {
7495
7512
  let { tile, offset } = this.tile.resolveBlock(pos, side);
7496
7513
  if (tile.isWidget())
7497
- return tile.domPosFor(pos, side);
7514
+ return tile.domPosFor(offset, side);
7498
7515
  return tile.domIn(offset, side);
7499
7516
  }
7500
7517
  inlineDOMNearPos(pos, side) {
@@ -7531,14 +7548,16 @@
7531
7548
  after = null;
7532
7549
  return before && side < 0 || !after ? before.domIn(beforeOff, side) : after.domIn(afterOff, side);
7533
7550
  }
7534
- coordsAt(pos, side) {
7551
+ // Get the coord of the element at the given side of the given
7552
+ // position. If rtl is given, flatten it using that text direction.
7553
+ coordsAt(pos, side, rtl) {
7535
7554
  let { tile, offset } = this.tile.resolveBlock(pos, side);
7536
7555
  if (tile.isWidget()) {
7537
7556
  if (tile.widget instanceof BlockGapWidget)
7538
7557
  return null;
7539
7558
  return tile.coordsInWidget(offset, side, true);
7540
7559
  }
7541
- return tile.coordsIn(offset, side);
7560
+ return tile.coordsIn(offset, side, rtl);
7542
7561
  }
7543
7562
  lineAt(pos, side) {
7544
7563
  let { tile } = this.tile.resolveBlock(pos, side);
@@ -7712,7 +7731,6 @@
7712
7731
  this.blockWrappers = this.view.state.facet(blockWrappers).map(v => typeof v == "function" ? v(this.view) : v);
7713
7732
  }
7714
7733
  scrollIntoView(target) {
7715
- var _a;
7716
7734
  if (target.isSnapshot) {
7717
7735
  let ref = this.view.viewState.lineBlockAt(target.range.head);
7718
7736
  this.view.scrollDOM.scrollTop = ref.top - target.yMargin;
@@ -7729,7 +7747,7 @@
7729
7747
  }
7730
7748
  }
7731
7749
  let { range } = target;
7732
- let rect = this.coordsAt(range.head, (_a = range.assoc) !== null && _a !== void 0 ? _a : (range.empty ? 0 : range.head > range.anchor ? -1 : 1)), other;
7750
+ let rect = this.coordsAt(range.head, range.assoc || (range.head > range.anchor ? -1 : 1)), other;
7733
7751
  if (!rect)
7734
7752
  return;
7735
7753
  if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1)))
@@ -8771,6 +8789,7 @@
8771
8789
  this.view = view;
8772
8790
  this.lastKeyCode = 0;
8773
8791
  this.lastKeyTime = 0;
8792
+ this.touchActive = false;
8774
8793
  this.lastTouchTime = 0;
8775
8794
  this.lastTouchX = 0;
8776
8795
  this.lastTouchY = 0;
@@ -8782,6 +8801,10 @@
8782
8801
  // (after which we retroactively handle them and reset the DOM) to
8783
8802
  // avoid messing up the virtual keyboard state.
8784
8803
  this.pendingIOSKey = undefined;
8804
+ // Set to a time stap by scroll events when touch isn't active on
8805
+ // iOS, to work around an issue where Safari will abort the scroll
8806
+ // momentum if we set scrollTop
8807
+ this.lastIOSMomentumScroll = 0;
8785
8808
  // When enabled (>-1), tab presses are not given to key handlers,
8786
8809
  // leaving the browser's default behavior. If >0, the mode expires
8787
8810
  // at that timestamp, and any other keypress clears it.
@@ -9212,8 +9235,11 @@
9212
9235
  });
9213
9236
  }
9214
9237
  observers.scroll = view => {
9215
- view.inputState.lastScrollTop = view.scrollDOM.scrollTop;
9216
- view.inputState.lastScrollLeft = view.scrollDOM.scrollLeft;
9238
+ let iState = view.inputState;
9239
+ iState.lastScrollTop = view.scrollDOM.scrollTop;
9240
+ iState.lastScrollLeft = view.scrollDOM.scrollLeft;
9241
+ if (browser.ios && !iState.touchActive)
9242
+ iState.lastIOSMomentumScroll = Date.now();
9217
9243
  };
9218
9244
  observers.wheel = observers.mousewheel = view => {
9219
9245
  view.inputState.lastWheelEvent = Date.now();
@@ -9226,6 +9252,7 @@
9226
9252
  };
9227
9253
  observers.touchstart = (view, e) => {
9228
9254
  let iState = view.inputState, touch = e.targetTouches[0];
9255
+ iState.touchActive = true;
9229
9256
  iState.lastTouchTime = Date.now();
9230
9257
  if (touch) {
9231
9258
  iState.lastTouchX = touch.clientX;
@@ -9236,6 +9263,9 @@
9236
9263
  observers.touchmove = view => {
9237
9264
  view.inputState.setSelectionOrigin("select.pointer");
9238
9265
  };
9266
+ observers.touchend = (view, e) => {
9267
+ view.inputState.touchActive = false;
9268
+ };
9239
9269
  handlers.mousedown = (view, event) => {
9240
9270
  view.observer.flush();
9241
9271
  if (view.inputState.lastTouchTime > Date.now() - 2000)
@@ -11261,6 +11291,8 @@
11261
11291
  backgroundColor: "#f5f5f5",
11262
11292
  color: "black"
11263
11293
  },
11294
+ ".cm-panels-top": { top: "0" },
11295
+ ".cm-panels-bottom": { bottom: "0" },
11264
11296
  "&light .cm-panels-top": {
11265
11297
  borderBottom: "1px solid #ddd"
11266
11298
  },
@@ -12497,6 +12529,7 @@
12497
12529
  this.viewState.lineBlockAt(scrollAnchorPos).top;
12498
12530
  let diff = (newAnchorHeight - scrollAnchorHeight) / this.scaleY;
12499
12531
  if ((diff > 1 || diff < -1) &&
12532
+ !(browser.ios && this.inputState.lastIOSMomentumScroll > Date.now() - 100) &&
12500
12533
  (scroll == this.scrollDOM || this.hasFocus ||
12501
12534
  Math.max(this.inputState.lastWheelEvent, this.inputState.lastTouchTime) > Date.now() - 100)) {
12502
12535
  scrollOffset = scrollOffset + diff;
@@ -12788,12 +12821,9 @@
12788
12821
  */
12789
12822
  coordsAtPos(pos, side = 1) {
12790
12823
  this.readMeasured();
12791
- let rect = this.docView.coordsAt(pos, side);
12792
- if (!rect || rect.left == rect.right)
12793
- return rect;
12794
12824
  let line = this.state.doc.lineAt(pos), order = this.bidiSpans(line);
12795
12825
  let span = order[BidiSpan.find(order, pos - line.from, -1, side)];
12796
- return flattenRect(rect, (span.dir == Direction.LTR) == (side > 0));
12826
+ return this.docView.coordsAt(pos, side, span.dir == Direction.RTL);
12797
12827
  }
12798
12828
  /**
12799
12829
  Return the rectangle around a given character. If `pos` does not
@@ -13863,9 +13893,10 @@
13863
13893
  },
13864
13894
  class: "cm-selectionLayer"
13865
13895
  });
13896
+ const selectionBg = browser.gecko && browser.gecko_version >= 153 ? "#ffffff01" : "transparent";
13866
13897
  const hideNativeSelection = /*@__PURE__*/Prec.highest(/*@__PURE__*/EditorView.theme({
13867
13898
  ".cm-line": {
13868
- "& ::selection, &::selection": { backgroundColor: "transparent !important" },
13899
+ "& ::selection, &::selection": { backgroundColor: `${selectionBg} !important` },
13869
13900
  caretColor: "transparent !important"
13870
13901
  },
13871
13902
  ".cm-content": {
@@ -15262,7 +15293,6 @@
15262
15293
  if (!this.dom) {
15263
15294
  this.dom = document.createElement("div");
15264
15295
  this.dom.className = this.top ? "cm-panels cm-panels-top" : "cm-panels cm-panels-bottom";
15265
- this.dom.style[this.top ? "top" : "bottom"] = "0";
15266
15296
  let parent = this.container || this.view.dom;
15267
15297
  parent.insertBefore(this.dom, this.top ? parent.firstChild : null);
15268
15298
  }
@@ -0,0 +1,34 @@
1
+ import test from "node:test";
2
+ import { ok, equal, deepEqual } from "node:assert/strict";
3
+ import { QyHNSW, cosineSimilarity, euclideanSimilarity } from "../src/QyHNSW.js";
4
+ import { logger } from "../src/QyLogger.js";
5
+ logger.level = "warn";
6
+ test("test QyHNSW", async ({ mock }) => {
7
+ let qyHNSW = new QyHNSW(8);
8
+ deepEqual(qyHNSW.probs, [
9
+ 0.875, 0.984375, 0.998046875, 0.999755859375, 0.999969482421875, 0.9999961853027344, 0.9999995231628418,
10
+ 0.9999999403953552, 0.9999999925494194, 0.9999999990686774, 1,
11
+ ]);
12
+ equal(qyHNSW._determineLayer(0.395), 0);
13
+ equal(qyHNSW._determineLayer(0.9), 1);
14
+ equal(qyHNSW._determineLayer(0.99981), 4);
15
+ equal(qyHNSW._determineLayer(0.9999999990686774), 9);
16
+ equal(qyHNSW._determineLayer(0.9999999991), 10);
17
+ qyHNSW = new QyHNSW(16);
18
+ deepEqual(qyHNSW.probs, [
19
+ 0.9375, 0.99609375, 0.999755859375, 0.9999847412109375, 0.9999990463256836, 0.9999999403953552,
20
+ 0.9999999962747097, 0.9999999997671694, 1,
21
+ ]);
22
+ qyHNSW = new QyHNSW(100);
23
+ deepEqual(qyHNSW.probs, [0.99, 0.9999, 0.999999, 0.99999999, 0.9999999999, 1]);
24
+ equal(qyHNSW._determineLayer(0.395), 0);
25
+ equal(qyHNSW._determineLayer(0.9), 0);
26
+ equal(qyHNSW._determineLayer(0.99981), 1);
27
+ equal(qyHNSW._determineLayer(0.9999999990686774), 4);
28
+ equal(qyHNSW._determineLayer(0.9999999991), 4);
29
+ equal(qyHNSW._determineLayer(0.9999999999001), 5);
30
+ equal(cosineSimilarity([1, 1, 1], [2, 2, 2]), 1.0000000000000002);
31
+ equal(euclideanSimilarity([1, 1, 1], [2, 2, 2]), 0.36602540378443865);
32
+ equal(cosineSimilarity([5, 2, 9], [4, 6, 1]), 0.5369694517472824);
33
+ equal(euclideanSimilarity([5, 2, 9], [4, 6, 1]), 0.1);
34
+ });