summaryrefslogtreecommitdiff
path: root/packages/idb-bridge/src/util/makeStoreKeyValue.ts
blob: 4f45e0d8adfda5f1170ea2a57860cd1d115c85d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { Value, Key, KeyPath } from "./types";
import extractKey from "./extractKey";
import { DataError } from "./errors";
import valueToKey from "./valueToKey";
import structuredClone from "./structuredClone";
import injectKey from "./injectKey";

export interface StoreKeyResult {
  updatedKeyGenerator: number;
  key: Key;
  value: Value;
}

export function makeStoreKeyValue(
  value: Value,
  key: Key | undefined,
  currentKeyGenerator: number,
  autoIncrement: boolean,
  keyPath: KeyPath | null,
): StoreKeyResult {
  const haveKey = key !== undefined && key !== null;
  const haveKeyPath = keyPath !== null && keyPath !== undefined;

  // This models a decision table on (haveKey, haveKeyPath, autoIncrement)

  value = structuredClone(value);

  if (haveKey) {
    if (haveKeyPath) {
      // (yes, yes, no)
      // (yes, yes, yes)
      throw new DataError();
    } else {
      if (autoIncrement) {
        // (yes, no, yes)
        key = valueToKey(key)!;
        let updatedKeyGenerator: number;
        if (typeof key !== "number") {
          updatedKeyGenerator = currentKeyGenerator;
        } else {
          updatedKeyGenerator = key;
        }
        return {
          key: key!,
          value: value,
          updatedKeyGenerator,
        };
      } else {
        // (yes, no, no)
        throw new DataError();
      }
    }
  } else {
    if (haveKeyPath) {
      if (autoIncrement) {
        // (no, yes, yes)

        let updatedKeyGenerator: number;
        const maybeInlineKey = extractKey(keyPath!, value);
        if (maybeInlineKey === undefined) {
          value = injectKey(keyPath!, value, currentKeyGenerator);
          key = currentKeyGenerator;
          updatedKeyGenerator = currentKeyGenerator + 1;
        } else if (typeof maybeInlineKey === "number") {
          key = maybeInlineKey;
          if (maybeInlineKey >= currentKeyGenerator) {
            updatedKeyGenerator = maybeInlineKey + 1;
          } else {
            updatedKeyGenerator = currentKeyGenerator;
          }
        } else {
          key = maybeInlineKey;
          updatedKeyGenerator = currentKeyGenerator;
        }
        return {
          key: key,
          value: value,
          updatedKeyGenerator,
        }
      } else {
        // (no, yes, no)
        key = extractKey(keyPath!, value);
        key = valueToKey(key);
        return {
          key: key!,
          value: value,
          updatedKeyGenerator: currentKeyGenerator,
        };
      }
    } else {
      if (autoIncrement) {
        // (no, no, yes)
        return {
          key: currentKeyGenerator,
          value: value,
          updatedKeyGenerator: currentKeyGenerator + 1,
        }
      } else {
        // (no, no, no)
        throw new DataError();
      }
    }
  }
}