jazz-tools 0.16.2 → 0.16.4
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/.turbo/turbo-build.log +38 -38
- package/CHANGELOG.md +22 -0
- package/dist/{chunk-CL3ROOZM.js → chunk-74LZG2M3.js} +112 -36
- package/dist/chunk-74LZG2M3.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/react-core/hooks.d.ts +150 -2
- package/dist/react-core/hooks.d.ts.map +1 -1
- package/dist/react-core/index.js.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/tools/coValues/coFeed.d.ts.map +1 -1
- package/dist/tools/coValues/coList.d.ts.map +1 -1
- package/dist/tools/coValues/coMap.d.ts.map +1 -1
- package/dist/tools/coValues/interfaces.d.ts.map +1 -1
- package/dist/tools/coValues/schemaUnion.d.ts +7 -2
- package/dist/tools/coValues/schemaUnion.d.ts.map +1 -1
- package/dist/tools/exports.d.ts +1 -1
- package/dist/tools/exports.d.ts.map +1 -1
- package/dist/tools/implementation/schema.d.ts +12 -2
- package/dist/tools/implementation/schema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +2 -4
- package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +2 -4
- package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +23 -7
- package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/typeConverters/CoFieldInit.d.ts +20 -6
- package/dist/tools/implementation/zodSchema/typeConverters/CoFieldInit.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchema.d.ts +4 -4
- package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.d.ts +3 -3
- package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchema.d.ts +3 -25
- package/dist/tools/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.d.ts +3 -25
- package/dist/tools/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/typeConverters/TypeOfZodSchema.d.ts +24 -0
- package/dist/tools/implementation/zodSchema/typeConverters/TypeOfZodSchema.d.ts.map +1 -0
- package/dist/tools/implementation/zodSchema/unionUtils.d.ts +2 -3
- package/dist/tools/implementation/zodSchema/unionUtils.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/zodSchema.d.ts +4 -5
- package/dist/tools/implementation/zodSchema/zodSchema.d.ts.map +1 -1
- package/dist/tools/internal.d.ts +1 -0
- package/dist/tools/internal.d.ts.map +1 -1
- package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/react-core/hooks.ts +143 -0
- package/src/tools/coValues/coFeed.ts +12 -4
- package/src/tools/coValues/coList.ts +41 -19
- package/src/tools/coValues/coMap.ts +12 -2
- package/src/tools/coValues/inbox.ts +1 -1
- package/src/tools/coValues/interfaces.ts +2 -3
- package/src/tools/coValues/schemaUnion.ts +28 -3
- package/src/tools/exports.ts +0 -1
- package/src/tools/implementation/schema.ts +28 -2
- package/src/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +2 -7
- package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +2 -7
- package/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts +61 -12
- package/src/tools/implementation/zodSchema/typeConverters/CoFieldInit.ts +74 -9
- package/src/tools/implementation/zodSchema/typeConverters/InstanceOfSchema.ts +9 -4
- package/src/tools/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.ts +3 -3
- package/src/tools/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchema.ts +3 -114
- package/src/tools/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.ts +5 -129
- package/src/tools/implementation/zodSchema/typeConverters/TypeOfZodSchema.ts +79 -0
- package/src/tools/implementation/zodSchema/unionUtils.ts +6 -9
- package/src/tools/implementation/zodSchema/zodSchema.ts +4 -14
- package/src/tools/internal.ts +1 -0
- package/src/tools/subscribe/SubscriptionScope.ts +4 -2
- package/src/tools/subscribe/utils.ts +2 -2
- package/src/tools/tests/coFeed.test.ts +40 -0
- package/src/tools/tests/coList.test.ts +42 -0
- package/src/tools/tests/coMap.test-d.ts +184 -1
- package/src/tools/tests/coMap.test.ts +182 -58
- package/src/tools/tests/groupsAndAccounts.test.ts +54 -0
- package/src/tools/tests/load.test.ts +19 -0
- package/src/tools/tests/zod.test.ts +16 -0
- package/dist/chunk-CL3ROOZM.js.map +0 -1
@@ -23,11 +23,7 @@ import {
|
|
23
23
|
} from "./schemaTypes/CoDiscriminatedUnionSchema.js";
|
24
24
|
import { CoFeedSchema, CoreCoFeedSchema } from "./schemaTypes/CoFeedSchema.js";
|
25
25
|
import { CoListSchema, CoreCoListSchema } from "./schemaTypes/CoListSchema.js";
|
26
|
-
import {
|
27
|
-
CoMapSchema,
|
28
|
-
CoMapSchemaInit,
|
29
|
-
CoreCoMapSchema,
|
30
|
-
} from "./schemaTypes/CoMapSchema.js";
|
26
|
+
import { CoMapSchema, CoreCoMapSchema } from "./schemaTypes/CoMapSchema.js";
|
31
27
|
import {
|
32
28
|
CoOptionalSchema,
|
33
29
|
CoreCoOptionalSchema,
|
@@ -84,8 +80,8 @@ export type CoValueSchemaFromCoreSchema<S extends CoreCoValueSchema> =
|
|
84
80
|
export type CoValueClassFromAnySchema<S extends CoValueClassOrSchema> =
|
85
81
|
S extends CoValueClass<any>
|
86
82
|
? S
|
87
|
-
: CoValueClass<InstanceOfSchema<S
|
88
|
-
CoValueFromRaw<InstanceOfSchema<S
|
83
|
+
: CoValueClass<NonNullable<InstanceOfSchema<S>>> &
|
84
|
+
CoValueFromRaw<NonNullable<InstanceOfSchema<S>>> &
|
89
85
|
(S extends CoreAccountSchema ? AccountClassEssentials : {});
|
90
86
|
|
91
87
|
type AccountClassEssentials = {
|
@@ -105,7 +101,7 @@ export type AnyCoreCoValueSchema =
|
|
105
101
|
| CoreRichTextSchema
|
106
102
|
| CoreFileStreamSchema;
|
107
103
|
|
108
|
-
type AnyZodSchema = z.core.$ZodType;
|
104
|
+
export type AnyZodSchema = z.core.$ZodType;
|
109
105
|
|
110
106
|
export type AnyZodOrCoValueSchema = AnyZodSchema | CoreCoValueSchema;
|
111
107
|
|
@@ -122,9 +118,3 @@ export type ResolveQueryStrict<
|
|
122
118
|
T extends CoValueClassOrSchema,
|
123
119
|
R extends ResolveQuery<T>,
|
124
120
|
> = RefsToResolveStrict<NonNullable<InstanceOfSchemaCoValuesNullable<T>>, R>;
|
125
|
-
|
126
|
-
export type InitFor<T extends CoValueClassOrSchema> = T extends CoreCoMapSchema<
|
127
|
-
infer Shape
|
128
|
-
>
|
129
|
-
? Simplify<CoMapSchemaInit<Shape>>
|
130
|
-
: never;
|
package/src/tools/internal.ts
CHANGED
@@ -45,6 +45,7 @@ export * from "./implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSc
|
|
45
45
|
export * from "./implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.js";
|
46
46
|
export * from "./implementation/zodSchema/typeConverters/InstanceOfSchema.js";
|
47
47
|
export * from "./implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.js";
|
48
|
+
export * from "./implementation/zodSchema/typeConverters/CoFieldInit.js";
|
48
49
|
export * from "./implementation/zodSchema/runtimeConverters/coValueSchemaTransformation.js";
|
49
50
|
export * from "./implementation/zodSchema/runtimeConverters/schemaFieldToCoFieldDef.js";
|
50
51
|
export * from "./coValues/extensions/imageDef.js";
|
@@ -7,7 +7,7 @@ import {
|
|
7
7
|
type ID,
|
8
8
|
type RefEncoded,
|
9
9
|
type RefsToResolve,
|
10
|
-
|
10
|
+
instantiateRefEncodedFromRaw,
|
11
11
|
isRefEncoded,
|
12
12
|
} from "../internal.js";
|
13
13
|
import { applyCoValueMigrations } from "../lib/migration.js";
|
@@ -75,7 +75,9 @@ export class SubscriptionScope<D extends CoValue> {
|
|
75
75
|
}
|
76
76
|
|
77
77
|
this.migrating = true;
|
78
|
-
applyCoValueMigrations(
|
78
|
+
applyCoValueMigrations(
|
79
|
+
instantiateRefEncodedFromRaw(this.schema, value),
|
80
|
+
);
|
79
81
|
this.migrated = true;
|
80
82
|
this.handleUpdate(lastUpdate);
|
81
83
|
return;
|
@@ -4,7 +4,7 @@ import {
|
|
4
4
|
CoValue,
|
5
5
|
RefEncoded,
|
6
6
|
coValueClassFromCoValueClassOrSchema,
|
7
|
-
|
7
|
+
instantiateRefEncodedFromRaw,
|
8
8
|
} from "../internal.js";
|
9
9
|
import { coValuesCache } from "../lib/cache.js";
|
10
10
|
import { SubscriptionScope } from "./SubscriptionScope.js";
|
@@ -26,7 +26,7 @@ export function createCoValue<D extends CoValue>(
|
|
26
26
|
raw: RawCoValue,
|
27
27
|
subscriptionScope: SubscriptionScope<D>,
|
28
28
|
) {
|
29
|
-
const freshValueInstance =
|
29
|
+
const freshValueInstance = instantiateRefEncodedFromRaw(ref, raw);
|
30
30
|
|
31
31
|
Object.defineProperty(freshValueInstance, "_subscriptionScope", {
|
32
32
|
value: subscriptionScope,
|
@@ -52,6 +52,46 @@ describe("Simple CoFeed operations", async () => {
|
|
52
52
|
expect(stream.perSession[me.sessionID]?.value).toEqual("milk");
|
53
53
|
});
|
54
54
|
|
55
|
+
describe("Create CoFeed with a reference", () => {
|
56
|
+
let me: Account;
|
57
|
+
|
58
|
+
beforeEach(async () => {
|
59
|
+
await setupJazzTestSync();
|
60
|
+
me = await createJazzTestAccount({
|
61
|
+
isCurrentActiveAccount: true,
|
62
|
+
creationProps: { name: "Hermes Puggington" },
|
63
|
+
});
|
64
|
+
});
|
65
|
+
|
66
|
+
test("using a CoValue", () => {
|
67
|
+
const Text = co.plainText();
|
68
|
+
const TextStream = co.feed(Text);
|
69
|
+
|
70
|
+
const stream = TextStream.create([Text.create("milk")], { owner: me });
|
71
|
+
|
72
|
+
const coValue = stream.perAccount[me.id]?.value;
|
73
|
+
expect(coValue?.toString()).toEqual("milk");
|
74
|
+
});
|
75
|
+
|
76
|
+
describe("using JSON", () => {
|
77
|
+
test("automatically creates CoValues for nested objects", () => {
|
78
|
+
const Text = co.plainText();
|
79
|
+
const TextStream = co.feed(Text);
|
80
|
+
|
81
|
+
const stream = TextStream.create(["milk"], { owner: me });
|
82
|
+
|
83
|
+
const coValue = stream.perAccount[me.id]?.value;
|
84
|
+
expect(coValue?.toString()).toEqual("milk");
|
85
|
+
});
|
86
|
+
|
87
|
+
test("can create a coPlainText from an empty string", () => {
|
88
|
+
const Schema = co.feed(co.plainText());
|
89
|
+
const feed = Schema.create([""]);
|
90
|
+
expect(feed.perAccount[me.id]?.value?.toString()).toBe("");
|
91
|
+
});
|
92
|
+
});
|
93
|
+
});
|
94
|
+
|
55
95
|
test("Construction with nullable values", () => {
|
56
96
|
const NullableTestStream = co.feed(z.string().nullable());
|
57
97
|
const stream = NullableTestStream.create(["milk", null], { owner: me });
|
@@ -52,6 +52,48 @@ describe("Simple CoList operations", async () => {
|
|
52
52
|
expect(list[2]).toBe("c");
|
53
53
|
});
|
54
54
|
|
55
|
+
test("create CoList with reference using CoValue", () => {
|
56
|
+
const Dog = co.map({
|
57
|
+
name: z.string(),
|
58
|
+
});
|
59
|
+
const Person = co.map({
|
60
|
+
pets: co.list(Dog),
|
61
|
+
});
|
62
|
+
|
63
|
+
const person = Person.create({
|
64
|
+
pets: [Dog.create({ name: "Rex" }), Dog.create({ name: "Fido" })],
|
65
|
+
});
|
66
|
+
|
67
|
+
expect(person.pets.length).toEqual(2);
|
68
|
+
expect(person.pets[0]?.name).toEqual("Rex");
|
69
|
+
expect(person.pets[1]?.name).toEqual("Fido");
|
70
|
+
});
|
71
|
+
|
72
|
+
describe("create CoList with reference using JSON", () => {
|
73
|
+
test("automatically creates CoValues for nested objects", () => {
|
74
|
+
const Dog = co.map({
|
75
|
+
name: z.string(),
|
76
|
+
});
|
77
|
+
const Person = co.map({
|
78
|
+
pets: co.list(Dog),
|
79
|
+
});
|
80
|
+
|
81
|
+
const person = Person.create({
|
82
|
+
pets: [{ name: "Rex" }, { name: "Fido" }],
|
83
|
+
});
|
84
|
+
|
85
|
+
expect(person.pets.length).toEqual(2);
|
86
|
+
expect(person.pets[0]?.name).toEqual("Rex");
|
87
|
+
expect(person.pets[1]?.name).toEqual("Fido");
|
88
|
+
});
|
89
|
+
|
90
|
+
test("can create a coPlainText from an empty string", () => {
|
91
|
+
const Schema = co.list(co.plainText());
|
92
|
+
const list = Schema.create([""]);
|
93
|
+
expect(list[0]?.toString()).toBe("");
|
94
|
+
});
|
95
|
+
});
|
96
|
+
|
55
97
|
test("list with nullable content", () => {
|
56
98
|
const List = co.list(z.string().nullable());
|
57
99
|
const list = List.create(["a", "b", "c", null]);
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { assert, describe, expectTypeOf, test } from "vitest";
|
2
|
+
import { ZodNumber, ZodOptional, ZodString } from "zod/v4";
|
2
3
|
import { Group, co, z } from "../exports.js";
|
3
4
|
import { Account } from "../index.js";
|
4
5
|
import { CoMap, Loaded } from "../internal.js";
|
@@ -54,7 +55,7 @@ describe("CoMap", async () => {
|
|
54
55
|
expectTypeOf(john._owner).toEqualTypeOf<Account | Group>();
|
55
56
|
});
|
56
57
|
|
57
|
-
test("CoMap with reference", () => {
|
58
|
+
test("create CoMap with reference using CoValue", () => {
|
58
59
|
const Dog = co.map({
|
59
60
|
name: z.string(),
|
60
61
|
breed: z.string(),
|
@@ -85,6 +86,46 @@ describe("CoMap", async () => {
|
|
85
86
|
matches(person);
|
86
87
|
});
|
87
88
|
|
89
|
+
test("create CoMap with reference using JSON", () => {
|
90
|
+
const Dog = co.map({
|
91
|
+
name: z.string(),
|
92
|
+
breed: z.string(),
|
93
|
+
});
|
94
|
+
const Person = co.map({
|
95
|
+
dog1: Dog,
|
96
|
+
dog2: Dog,
|
97
|
+
get friend() {
|
98
|
+
return Person.optional();
|
99
|
+
},
|
100
|
+
});
|
101
|
+
|
102
|
+
const person = Person.create({
|
103
|
+
// @ts-expect-error - breed is missing
|
104
|
+
dog1: { name: "Rex", items },
|
105
|
+
// @ts-expect-error - Object literal may only specify known properties
|
106
|
+
dog2: { name: "Fido", breed: "Labrador", extra: "extra" },
|
107
|
+
friend: {
|
108
|
+
dog1: {
|
109
|
+
name: "Rex",
|
110
|
+
breed: "Labrador",
|
111
|
+
},
|
112
|
+
dog2: { name: "Fido", breed: "Labrador" },
|
113
|
+
},
|
114
|
+
});
|
115
|
+
|
116
|
+
type ExpectedType = {
|
117
|
+
dog1: Loaded<typeof Dog>;
|
118
|
+
dog2: Loaded<typeof Dog>;
|
119
|
+
friend: Loaded<typeof Person> | undefined;
|
120
|
+
};
|
121
|
+
|
122
|
+
function matches(value: ExpectedType) {
|
123
|
+
return value;
|
124
|
+
}
|
125
|
+
|
126
|
+
matches(person);
|
127
|
+
});
|
128
|
+
|
88
129
|
test("CoMap with optional reference", () => {
|
89
130
|
const Dog = co.map({
|
90
131
|
name: z.string(),
|
@@ -310,6 +351,148 @@ describe("CoMap", async () => {
|
|
310
351
|
matchesNarrowed(mapWithEnum.child);
|
311
352
|
}
|
312
353
|
});
|
354
|
+
|
355
|
+
test("CoMap.pick()", () => {
|
356
|
+
const Person = co.map({
|
357
|
+
name: z.string(),
|
358
|
+
age: z.number(),
|
359
|
+
dog: co.map({
|
360
|
+
name: z.string(),
|
361
|
+
breed: z.string(),
|
362
|
+
}),
|
363
|
+
});
|
364
|
+
|
365
|
+
const PersonWithoutDog = Person.pick({
|
366
|
+
name: true,
|
367
|
+
age: true,
|
368
|
+
});
|
369
|
+
|
370
|
+
type ExpectedType = co.Map<{
|
371
|
+
name: ZodString;
|
372
|
+
age: ZodNumber;
|
373
|
+
}>;
|
374
|
+
|
375
|
+
function matches(value: ExpectedType) {
|
376
|
+
return value;
|
377
|
+
}
|
378
|
+
|
379
|
+
matches(PersonWithoutDog);
|
380
|
+
});
|
381
|
+
|
382
|
+
test("CoMap.pick() with a recursive reference", () => {
|
383
|
+
const Person = co.map({
|
384
|
+
name: z.string(),
|
385
|
+
age: z.number(),
|
386
|
+
dog: co.map({
|
387
|
+
name: z.string(),
|
388
|
+
breed: z.string(),
|
389
|
+
}),
|
390
|
+
get friend() {
|
391
|
+
return Person.pick({
|
392
|
+
name: true,
|
393
|
+
age: true,
|
394
|
+
}).optional();
|
395
|
+
},
|
396
|
+
});
|
397
|
+
|
398
|
+
type ExpectedType = co.Map<{
|
399
|
+
name: ZodString;
|
400
|
+
age: ZodNumber;
|
401
|
+
dog: co.Map<{
|
402
|
+
name: ZodString;
|
403
|
+
breed: ZodString;
|
404
|
+
}>;
|
405
|
+
friend: co.Optional<
|
406
|
+
co.Map<{
|
407
|
+
name: ZodString;
|
408
|
+
age: ZodNumber;
|
409
|
+
}>
|
410
|
+
>;
|
411
|
+
}>;
|
412
|
+
|
413
|
+
function matches(value: ExpectedType) {
|
414
|
+
return value;
|
415
|
+
}
|
416
|
+
|
417
|
+
matches(Person);
|
418
|
+
});
|
419
|
+
|
420
|
+
test("CoMap.partial()", () => {
|
421
|
+
const Person = co.map({
|
422
|
+
name: z.string(),
|
423
|
+
age: z.number(),
|
424
|
+
dog: co.map({
|
425
|
+
name: z.string(),
|
426
|
+
breed: z.string(),
|
427
|
+
}),
|
428
|
+
});
|
429
|
+
|
430
|
+
const PersonPartial = Person.partial();
|
431
|
+
|
432
|
+
type ExpectedType = co.Map<{
|
433
|
+
name: ZodOptional<ZodString>;
|
434
|
+
age: ZodOptional<ZodNumber>;
|
435
|
+
dog: co.Optional<
|
436
|
+
co.Map<{
|
437
|
+
name: ZodString;
|
438
|
+
breed: ZodString;
|
439
|
+
}>
|
440
|
+
>;
|
441
|
+
}>;
|
442
|
+
|
443
|
+
function matches(value: ExpectedType) {
|
444
|
+
return value;
|
445
|
+
}
|
446
|
+
|
447
|
+
matches(PersonPartial);
|
448
|
+
});
|
449
|
+
|
450
|
+
test("CoMap.partial() with a recursive reference", () => {
|
451
|
+
const Person = co.map({
|
452
|
+
get draft() {
|
453
|
+
return Person.partial()
|
454
|
+
.pick({
|
455
|
+
name: true,
|
456
|
+
age: true,
|
457
|
+
dog: true,
|
458
|
+
})
|
459
|
+
.optional();
|
460
|
+
},
|
461
|
+
name: z.string(),
|
462
|
+
age: z.number(),
|
463
|
+
dog: co.map({
|
464
|
+
name: z.string(),
|
465
|
+
breed: z.string(),
|
466
|
+
}),
|
467
|
+
});
|
468
|
+
|
469
|
+
type ExpectedType = co.Map<{
|
470
|
+
draft: co.Optional<
|
471
|
+
co.Map<{
|
472
|
+
name: ZodOptional<ZodString>;
|
473
|
+
age: ZodOptional<ZodNumber>;
|
474
|
+
dog: co.Optional<
|
475
|
+
co.Map<{
|
476
|
+
name: ZodString;
|
477
|
+
breed: ZodString;
|
478
|
+
}>
|
479
|
+
>;
|
480
|
+
}>
|
481
|
+
>;
|
482
|
+
name: ZodString;
|
483
|
+
age: ZodNumber;
|
484
|
+
dog: co.Map<{
|
485
|
+
name: ZodString;
|
486
|
+
breed: ZodString;
|
487
|
+
}>;
|
488
|
+
}>;
|
489
|
+
|
490
|
+
function matches(value: ExpectedType) {
|
491
|
+
return value;
|
492
|
+
}
|
493
|
+
|
494
|
+
matches(Person);
|
495
|
+
});
|
313
496
|
});
|
314
497
|
|
315
498
|
describe("CoMap resolution", async () => {
|
@@ -117,10 +117,9 @@ describe("CoMap", async () => {
|
|
117
117
|
expect(emptyMap.color).toEqual(undefined);
|
118
118
|
});
|
119
119
|
|
120
|
-
test("CoMap with reference", () => {
|
120
|
+
test("create CoMap with reference using CoValue", () => {
|
121
121
|
const Dog = co.map({
|
122
122
|
name: z.string(),
|
123
|
-
breed: z.string(),
|
124
123
|
});
|
125
124
|
|
126
125
|
const Person = co.map({
|
@@ -132,11 +131,89 @@ describe("CoMap", async () => {
|
|
132
131
|
const person = Person.create({
|
133
132
|
name: "John",
|
134
133
|
age: 20,
|
135
|
-
dog: Dog.create({ name: "Rex"
|
134
|
+
dog: Dog.create({ name: "Rex" }),
|
136
135
|
});
|
137
136
|
|
138
137
|
expect(person.dog?.name).toEqual("Rex");
|
139
|
-
|
138
|
+
});
|
139
|
+
|
140
|
+
describe("create CoMap with references using JSON", () => {
|
141
|
+
const Dog = co.map({
|
142
|
+
type: z.literal("dog"),
|
143
|
+
name: z.string(),
|
144
|
+
});
|
145
|
+
const Cat = co.map({
|
146
|
+
type: z.literal("cat"),
|
147
|
+
name: z.string(),
|
148
|
+
});
|
149
|
+
|
150
|
+
const Person = co.map({
|
151
|
+
name: co.plainText(),
|
152
|
+
bio: co.richText(),
|
153
|
+
dog: Dog,
|
154
|
+
get friends() {
|
155
|
+
return co.list(Person);
|
156
|
+
},
|
157
|
+
reactions: co.feed(co.plainText()),
|
158
|
+
pet: co.discriminatedUnion("type", [Dog, Cat]),
|
159
|
+
});
|
160
|
+
|
161
|
+
let person: ReturnType<typeof Person.create>;
|
162
|
+
|
163
|
+
beforeEach(() => {
|
164
|
+
person = Person.create({
|
165
|
+
name: "John",
|
166
|
+
bio: "I am a software engineer",
|
167
|
+
dog: { type: "dog", name: "Rex" },
|
168
|
+
friends: [
|
169
|
+
{
|
170
|
+
name: "Jane",
|
171
|
+
bio: "I am a mechanical engineer",
|
172
|
+
dog: { type: "dog", name: "Fido" },
|
173
|
+
friends: [],
|
174
|
+
reactions: [],
|
175
|
+
pet: { type: "dog", name: "Fido" },
|
176
|
+
},
|
177
|
+
],
|
178
|
+
reactions: ["👎", "👍"],
|
179
|
+
pet: { type: "cat", name: "Whiskers" },
|
180
|
+
});
|
181
|
+
});
|
182
|
+
|
183
|
+
it("automatically creates CoValues for each CoValue reference", () => {
|
184
|
+
expect(person.name.toString()).toEqual("John");
|
185
|
+
expect(person.bio.toString()).toEqual("I am a software engineer");
|
186
|
+
expect(person.dog?.name).toEqual("Rex");
|
187
|
+
expect(person.friends.length).toEqual(1);
|
188
|
+
expect(person.friends[0]?.name.toString()).toEqual("Jane");
|
189
|
+
expect(person.friends[0]?.bio.toString()).toEqual(
|
190
|
+
"I am a mechanical engineer",
|
191
|
+
);
|
192
|
+
expect(person.friends[0]?.dog.name).toEqual("Fido");
|
193
|
+
expect(person.friends[0]?.friends.length).toEqual(0);
|
194
|
+
expect(person.reactions.byMe?.value?.toString()).toEqual("👍");
|
195
|
+
expect(person.pet.name).toEqual("Whiskers");
|
196
|
+
});
|
197
|
+
|
198
|
+
it("creates a group for each new CoValue that is a child of the referencing CoValue's owner", () => {
|
199
|
+
for (const value of Object.values(person)) {
|
200
|
+
expect(
|
201
|
+
value._owner.getParentGroups().map((group: Group) => group.id),
|
202
|
+
).toContain(person._owner.id);
|
203
|
+
}
|
204
|
+
const friend = person.friends[0]!;
|
205
|
+
for (const value of Object.values(friend)) {
|
206
|
+
expect(
|
207
|
+
value._owner.getParentGroups().map((group: Group) => group.id),
|
208
|
+
).toContain(friend._owner.id);
|
209
|
+
}
|
210
|
+
});
|
211
|
+
|
212
|
+
it("can create a coPlainText from an empty string", () => {
|
213
|
+
const Schema = co.map({ text: co.plainText() });
|
214
|
+
const map = Schema.create({ text: "" });
|
215
|
+
expect(map.text.toString()).toBe("");
|
216
|
+
});
|
140
217
|
});
|
141
218
|
|
142
219
|
test("CoMap with self reference", () => {
|
@@ -209,7 +286,7 @@ describe("CoMap", async () => {
|
|
209
286
|
const Person = co.map({
|
210
287
|
name: z.string(),
|
211
288
|
age: z.number(),
|
212
|
-
get friend()
|
289
|
+
get friend() {
|
213
290
|
return co.optional(Person);
|
214
291
|
},
|
215
292
|
});
|
@@ -2104,84 +2181,131 @@ describe("CoMap migration", () => {
|
|
2104
2181
|
expect(loaded?.friend?.name).toEqual("Charlie");
|
2105
2182
|
expect(loaded?.friend?.version).toEqual(2);
|
2106
2183
|
});
|
2107
|
-
|
2108
|
-
|
2109
|
-
|
2110
|
-
|
2111
|
-
|
2184
|
+
});
|
2185
|
+
|
2186
|
+
describe("createdAt & lastUpdatedAt", () => {
|
2187
|
+
test("empty map created time", () => {
|
2188
|
+
const emptyMap = co.map({}).create({});
|
2112
2189
|
|
2113
|
-
|
2114
|
-
|
2190
|
+
expect(emptyMap._lastUpdatedAt).toEqual(emptyMap._createdAt);
|
2191
|
+
});
|
2192
|
+
|
2193
|
+
test("created time and last updated time", async () => {
|
2194
|
+
const Person = co.map({
|
2195
|
+
name: z.string(),
|
2115
2196
|
});
|
2116
2197
|
|
2117
|
-
|
2118
|
-
const Person = co.map({
|
2119
|
-
name: z.string(),
|
2120
|
-
});
|
2198
|
+
const person = Person.create({ name: "John" });
|
2121
2199
|
|
2122
|
-
|
2123
|
-
|
2200
|
+
const createdAt = person._createdAt;
|
2201
|
+
expect(person._lastUpdatedAt).toEqual(createdAt);
|
2124
2202
|
|
2125
|
-
|
2126
|
-
|
2127
|
-
expect(createdAtInSeconds).toEqual(currentTimestampInSeconds);
|
2128
|
-
expect(person._lastUpdatedAt).toEqual(createdAt);
|
2203
|
+
await new Promise((r) => setTimeout(r, 10));
|
2204
|
+
person.name = "Jane";
|
2129
2205
|
|
2130
|
-
|
2131
|
-
|
2132
|
-
|
2206
|
+
expect(person._createdAt).toEqual(createdAt);
|
2207
|
+
expect(person._lastUpdatedAt).not.toEqual(createdAt);
|
2208
|
+
});
|
2209
|
+
});
|
2133
2210
|
|
2134
|
-
|
2135
|
-
|
2136
|
-
|
2137
|
-
|
2211
|
+
describe("co.map schema", () => {
|
2212
|
+
test("can access the inner schemas of a co.map", () => {
|
2213
|
+
const Person = co.map({
|
2214
|
+
name: co.plainText(),
|
2138
2215
|
});
|
2139
2216
|
|
2140
|
-
|
2217
|
+
const person = Person.create({
|
2218
|
+
name: Person.shape["name"].create("John"),
|
2219
|
+
});
|
2220
|
+
|
2221
|
+
expect(person.name.toString()).toEqual("John");
|
2222
|
+
});
|
2223
|
+
|
2224
|
+
describe("pick()", () => {
|
2225
|
+
test("creates a new CoMap schema by picking fields of another CoMap schema", () => {
|
2141
2226
|
const Person = co.map({
|
2142
2227
|
name: z.string(),
|
2228
|
+
age: z.number(),
|
2143
2229
|
});
|
2144
2230
|
|
2145
|
-
|
2146
|
-
|
2147
|
-
|
2148
|
-
|
2149
|
-
|
2231
|
+
const PersonWithName = Person.pick({
|
2232
|
+
name: true,
|
2233
|
+
});
|
2234
|
+
|
2235
|
+
const person = PersonWithName.create({
|
2236
|
+
name: "John",
|
2237
|
+
});
|
2150
2238
|
|
2151
|
-
|
2152
|
-
const createdAtInSeconds = Math.floor(createdAt / 1000);
|
2153
|
-
expect(createdAtInSeconds).toEqual(currentTimestampInSeconds);
|
2239
|
+
expect(person.name).toEqual("John");
|
2154
2240
|
});
|
2155
2241
|
|
2156
|
-
test("
|
2157
|
-
const Person = co
|
2158
|
-
|
2242
|
+
test("the new schema does not include catchall properties", () => {
|
2243
|
+
const Person = co
|
2244
|
+
.map({
|
2245
|
+
name: z.string(),
|
2246
|
+
age: z.number(),
|
2247
|
+
})
|
2248
|
+
.catchall(z.string());
|
2249
|
+
|
2250
|
+
const PersonWithName = Person.pick({
|
2251
|
+
name: true,
|
2159
2252
|
});
|
2160
2253
|
|
2161
|
-
|
2162
|
-
const person = Person.create(
|
2163
|
-
{},
|
2164
|
-
{ unique: "name", owner: Account.getMe() },
|
2165
|
-
);
|
2254
|
+
expect(PersonWithName.catchAll).toBeUndefined();
|
2166
2255
|
|
2167
|
-
const
|
2168
|
-
|
2169
|
-
|
2256
|
+
const person = PersonWithName.create({
|
2257
|
+
name: "John",
|
2258
|
+
});
|
2259
|
+
// @ts-expect-error - property `extraField` does not exist in person
|
2260
|
+
expect(person.extraField).toBeUndefined();
|
2170
2261
|
});
|
2171
2262
|
});
|
2172
|
-
});
|
2173
2263
|
|
2174
|
-
describe("
|
2175
|
-
|
2176
|
-
|
2177
|
-
|
2178
|
-
|
2264
|
+
describe("partial()", () => {
|
2265
|
+
test("creates a new CoMap schema by making all properties optional", () => {
|
2266
|
+
const Dog = co.map({
|
2267
|
+
name: z.string(),
|
2268
|
+
breed: z.string(),
|
2269
|
+
});
|
2270
|
+
const Person = co.map({
|
2271
|
+
name: z.string(),
|
2272
|
+
age: z.number(),
|
2273
|
+
pet: Dog,
|
2274
|
+
});
|
2179
2275
|
|
2180
|
-
|
2181
|
-
|
2276
|
+
const DraftPerson = Person.partial();
|
2277
|
+
|
2278
|
+
const draftPerson = DraftPerson.create({});
|
2279
|
+
|
2280
|
+
expect(draftPerson.name).toBeUndefined();
|
2281
|
+
expect(draftPerson.age).toBeUndefined();
|
2282
|
+
expect(draftPerson.pet).toBeUndefined();
|
2283
|
+
|
2284
|
+
draftPerson.name = "John";
|
2285
|
+
draftPerson.age = 20;
|
2286
|
+
const rex = Dog.create({ name: "Rex", breed: "Labrador" });
|
2287
|
+
draftPerson.pet = rex;
|
2288
|
+
|
2289
|
+
expect(draftPerson.name).toEqual("John");
|
2290
|
+
expect(draftPerson.age).toEqual(20);
|
2291
|
+
expect(draftPerson.pet).toEqual(rex);
|
2182
2292
|
});
|
2183
2293
|
|
2184
|
-
|
2294
|
+
test("the new schema includes catchall properties", () => {
|
2295
|
+
const Person = co
|
2296
|
+
.map({
|
2297
|
+
name: z.string(),
|
2298
|
+
age: z.number(),
|
2299
|
+
})
|
2300
|
+
.catchall(z.string());
|
2301
|
+
|
2302
|
+
const DraftPerson = Person.partial();
|
2303
|
+
|
2304
|
+
const draftPerson = DraftPerson.create({});
|
2305
|
+
draftPerson.extraField = "extra";
|
2306
|
+
|
2307
|
+
expect(draftPerson.extraField).toEqual("extra");
|
2308
|
+
});
|
2185
2309
|
});
|
2186
2310
|
});
|
2187
2311
|
|