|
| 1 | +import {NodeBuilder, s, nodes} from '../../../json-crdt-patch'; |
| 2 | +import {deepEqual} from '../../../json-equal/deepEqual'; |
| 3 | +import {cmpUint8Array} from '../../../util/buffers/cmpUint8Array'; |
| 4 | +import {Model} from '../../model'; |
| 5 | +import {toSchema} from '../toSchema'; |
| 6 | + |
| 7 | +const cmp = (a: NodeBuilder, b: NodeBuilder): boolean => { |
| 8 | + if (a instanceof nodes.con && b instanceof nodes.con) return deepEqual(a.raw, b.raw); |
| 9 | + else if (a instanceof nodes.val && b instanceof nodes.val) return cmp(a.value, b.value); |
| 10 | + else if (a instanceof nodes.obj && b instanceof nodes.obj) { |
| 11 | + const objAKeys = Object.keys(a.obj); |
| 12 | + const objBKeys = Object.keys(a.obj); |
| 13 | + const objALen = objAKeys.length; |
| 14 | + const objBLen = objBKeys.length; |
| 15 | + if (objALen !== objBLen) return false; |
| 16 | + const optAKeys = Object.keys(a.opt || {}); |
| 17 | + const optBKeys = Object.keys(b.opt || {}); |
| 18 | + const optALen = optAKeys.length; |
| 19 | + const optBLen = optBKeys.length; |
| 20 | + if (optALen !== optBLen) return false; |
| 21 | + for (let i = 0; i < objALen; i++) { |
| 22 | + const key = objAKeys[i]; |
| 23 | + if (!cmp(a.obj[key], b.obj[key])) return false; |
| 24 | + } |
| 25 | + for (let i = 0; i < optALen; i++) { |
| 26 | + const key = optAKeys[i]; |
| 27 | + if (!cmp(a.opt![key], b.opt![key])) return false; |
| 28 | + } |
| 29 | + return true; |
| 30 | + } else if (a instanceof nodes.vec && b instanceof nodes.vec) { |
| 31 | + const vecA = a.value; |
| 32 | + const vecB = b.value; |
| 33 | + const len = vecA.length; |
| 34 | + if (len !== vecB.length) return false; |
| 35 | + for (let i = 0; i < len; i++) if (!cmp(vecA[i], vecA[i])) return false; |
| 36 | + return true; |
| 37 | + } else if (a instanceof nodes.str && b instanceof nodes.str) return a.raw === b.raw; |
| 38 | + else if (a instanceof nodes.bin && b instanceof nodes.bin) return cmpUint8Array(a.raw, b.raw); |
| 39 | + else if (a instanceof nodes.arr && b instanceof nodes.arr) { |
| 40 | + const arrA = a.arr; |
| 41 | + const arrB = b.arr; |
| 42 | + const len = arrA.length; |
| 43 | + if (len !== arrB.length) return false; |
| 44 | + for (let i = 0; i < len; i++) if (!cmp(arrA[i], arrB[i])) return false; |
| 45 | + return true; |
| 46 | + } |
| 47 | + return false; |
| 48 | +}; |
| 49 | + |
| 50 | +test('can infer schema of a document nodes', () => { |
| 51 | + const con = s.con('con'); |
| 52 | + const str = s.str('hello'); |
| 53 | + const obj = s.obj({ |
| 54 | + id: s.con('id'), |
| 55 | + val: s.val(s.str('world')), |
| 56 | + }); |
| 57 | + const schema = s.obj({ |
| 58 | + con, |
| 59 | + str, |
| 60 | + bin: s.bin(new Uint8Array([1, 2, 3])), |
| 61 | + obj, |
| 62 | + vec: s.vec(s.con(1), s.con({foo: 'bar'})), |
| 63 | + arr: s.arr([s.con(1), s.con({foo: 'bar'})]), |
| 64 | + }); |
| 65 | + const model = Model.withLogicalClock().setSchema(schema); |
| 66 | + const node = model.root.node(); |
| 67 | + const schema2 = toSchema(node); |
| 68 | + expect(cmp(schema, schema2)).toBe(true); |
| 69 | + const conSchema = toSchema(model.api.const('con').node); |
| 70 | + expect(cmp(con, conSchema)).toBe(true); |
| 71 | + expect(cmp(str, conSchema)).toBe(false); |
| 72 | + const strSchema = toSchema(model.api.str('str').node); |
| 73 | + expect(cmp(str, strSchema)).toBe(true); |
| 74 | + expect(cmp(con, strSchema)).toBe(false); |
| 75 | + const objSchema = toSchema(model.api.obj('obj').node); |
| 76 | + expect(cmp(obj, objSchema)).toBe(true); |
| 77 | + expect(cmp(con, objSchema)).toBe(false); |
| 78 | +}); |
| 79 | + |
| 80 | +test('can infer schema of a typed model', () => { |
| 81 | + const schema = s.obj({ |
| 82 | + id: s.con('id'), |
| 83 | + val: s.val(s.str('world')), |
| 84 | + }); |
| 85 | + const model = Model.withLogicalClock().setSchema(schema); |
| 86 | + const schema2 = toSchema(model.root.node()); |
| 87 | + expect(schema2.obj.id).toBeInstanceOf(nodes.con); |
| 88 | + expect(schema2.obj.val).toBeInstanceOf(nodes.val); |
| 89 | +}); |
0 commit comments