@tinybirdco/sdk 0.0.1
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/README.md +518 -0
- package/bin/tinybird.js +7 -0
- package/dist/api/branches.d.ts +98 -0
- package/dist/api/branches.d.ts.map +1 -0
- package/dist/api/branches.js +203 -0
- package/dist/api/branches.js.map +1 -0
- package/dist/api/branches.test.d.ts +2 -0
- package/dist/api/branches.test.d.ts.map +1 -0
- package/dist/api/branches.test.js +286 -0
- package/dist/api/branches.test.js.map +1 -0
- package/dist/api/build.d.ts +130 -0
- package/dist/api/build.d.ts.map +1 -0
- package/dist/api/build.js +143 -0
- package/dist/api/build.js.map +1 -0
- package/dist/api/build.test.d.ts +2 -0
- package/dist/api/build.test.d.ts.map +1 -0
- package/dist/api/build.test.js +138 -0
- package/dist/api/build.test.js.map +1 -0
- package/dist/api/deploy.d.ts +39 -0
- package/dist/api/deploy.d.ts.map +1 -0
- package/dist/api/deploy.js +135 -0
- package/dist/api/deploy.js.map +1 -0
- package/dist/api/deploy.test.d.ts +2 -0
- package/dist/api/deploy.test.d.ts.map +1 -0
- package/dist/api/deploy.test.js +118 -0
- package/dist/api/deploy.test.js.map +1 -0
- package/dist/api/workspaces.d.ts +46 -0
- package/dist/api/workspaces.d.ts.map +1 -0
- package/dist/api/workspaces.js +39 -0
- package/dist/api/workspaces.js.map +1 -0
- package/dist/api/workspaces.test.d.ts +2 -0
- package/dist/api/workspaces.test.d.ts.map +1 -0
- package/dist/api/workspaces.test.js +65 -0
- package/dist/api/workspaces.test.js.map +1 -0
- package/dist/cli/auth.d.ts +86 -0
- package/dist/cli/auth.d.ts.map +1 -0
- package/dist/cli/auth.js +284 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/branch-store.d.ts +53 -0
- package/dist/cli/branch-store.d.ts.map +1 -0
- package/dist/cli/branch-store.js +91 -0
- package/dist/cli/branch-store.js.map +1 -0
- package/dist/cli/branch-store.test.d.ts +2 -0
- package/dist/cli/branch-store.test.d.ts.map +1 -0
- package/dist/cli/branch-store.test.js +115 -0
- package/dist/cli/branch-store.test.js.map +1 -0
- package/dist/cli/commands/branch.d.ts +82 -0
- package/dist/cli/commands/branch.d.ts.map +1 -0
- package/dist/cli/commands/branch.js +215 -0
- package/dist/cli/commands/branch.js.map +1 -0
- package/dist/cli/commands/build.d.ts +43 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +138 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +78 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +226 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/init.d.ts +45 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +277 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/init.test.d.ts +2 -0
- package/dist/cli/commands/init.test.d.ts.map +1 -0
- package/dist/cli/commands/init.test.js +158 -0
- package/dist/cli/commands/init.test.js.map +1 -0
- package/dist/cli/commands/login.d.ts +37 -0
- package/dist/cli/commands/login.d.ts.map +1 -0
- package/dist/cli/commands/login.js +64 -0
- package/dist/cli/commands/login.js.map +1 -0
- package/dist/cli/config.d.ts +114 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +258 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/config.test.d.ts +2 -0
- package/dist/cli/config.test.d.ts.map +1 -0
- package/dist/cli/config.test.js +243 -0
- package/dist/cli/config.test.js.map +1 -0
- package/dist/cli/env.d.ts +29 -0
- package/dist/cli/env.d.ts.map +1 -0
- package/dist/cli/env.js +66 -0
- package/dist/cli/env.js.map +1 -0
- package/dist/cli/git.d.ts +29 -0
- package/dist/cli/git.d.ts.map +1 -0
- package/dist/cli/git.js +114 -0
- package/dist/cli/git.js.map +1 -0
- package/dist/cli/git.test.d.ts +2 -0
- package/dist/cli/git.test.d.ts.map +1 -0
- package/dist/cli/git.test.js +125 -0
- package/dist/cli/git.test.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +337 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/schema-validation.d.ts +95 -0
- package/dist/cli/utils/schema-validation.d.ts.map +1 -0
- package/dist/cli/utils/schema-validation.js +175 -0
- package/dist/cli/utils/schema-validation.js.map +1 -0
- package/dist/cli/utils/schema-validation.test.d.ts +5 -0
- package/dist/cli/utils/schema-validation.test.d.ts.map +1 -0
- package/dist/cli/utils/schema-validation.test.js +173 -0
- package/dist/cli/utils/schema-validation.test.js.map +1 -0
- package/dist/client/base.d.ts +116 -0
- package/dist/client/base.d.ts.map +1 -0
- package/dist/client/base.js +328 -0
- package/dist/client/base.js.map +1 -0
- package/dist/client/types.d.ts +137 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +43 -0
- package/dist/client/types.js.map +1 -0
- package/dist/generator/client.d.ts +44 -0
- package/dist/generator/client.d.ts.map +1 -0
- package/dist/generator/client.js +144 -0
- package/dist/generator/client.js.map +1 -0
- package/dist/generator/datasource.d.ts +57 -0
- package/dist/generator/datasource.d.ts.map +1 -0
- package/dist/generator/datasource.js +169 -0
- package/dist/generator/datasource.js.map +1 -0
- package/dist/generator/datasource.test.d.ts +2 -0
- package/dist/generator/datasource.test.d.ts.map +1 -0
- package/dist/generator/datasource.test.js +254 -0
- package/dist/generator/datasource.test.js.map +1 -0
- package/dist/generator/index.d.ts +131 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +121 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/index.test.d.ts +2 -0
- package/dist/generator/index.test.d.ts.map +1 -0
- package/dist/generator/index.test.js +175 -0
- package/dist/generator/index.test.js.map +1 -0
- package/dist/generator/loader.d.ts +156 -0
- package/dist/generator/loader.d.ts.map +1 -0
- package/dist/generator/loader.js +295 -0
- package/dist/generator/loader.js.map +1 -0
- package/dist/generator/pipe.d.ts +72 -0
- package/dist/generator/pipe.d.ts.map +1 -0
- package/dist/generator/pipe.js +174 -0
- package/dist/generator/pipe.js.map +1 -0
- package/dist/generator/pipe.test.d.ts +2 -0
- package/dist/generator/pipe.test.d.ts.map +1 -0
- package/dist/generator/pipe.test.js +393 -0
- package/dist/generator/pipe.test.js.map +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/infer/index.d.ts +202 -0
- package/dist/infer/index.d.ts.map +1 -0
- package/dist/infer/index.js +5 -0
- package/dist/infer/index.js.map +1 -0
- package/dist/schema/datasource.d.ts +135 -0
- package/dist/schema/datasource.d.ts.map +1 -0
- package/dist/schema/datasource.js +105 -0
- package/dist/schema/datasource.js.map +1 -0
- package/dist/schema/datasource.test.d.ts +2 -0
- package/dist/schema/datasource.test.d.ts.map +1 -0
- package/dist/schema/datasource.test.js +142 -0
- package/dist/schema/datasource.test.js.map +1 -0
- package/dist/schema/engines.d.ts +157 -0
- package/dist/schema/engines.d.ts.map +1 -0
- package/dist/schema/engines.js +155 -0
- package/dist/schema/engines.js.map +1 -0
- package/dist/schema/engines.test.d.ts +2 -0
- package/dist/schema/engines.test.d.ts.map +1 -0
- package/dist/schema/engines.test.js +221 -0
- package/dist/schema/engines.test.js.map +1 -0
- package/dist/schema/params.d.ts +106 -0
- package/dist/schema/params.d.ts.map +1 -0
- package/dist/schema/params.js +138 -0
- package/dist/schema/params.js.map +1 -0
- package/dist/schema/params.test.d.ts +2 -0
- package/dist/schema/params.test.d.ts.map +1 -0
- package/dist/schema/params.test.js +175 -0
- package/dist/schema/params.test.js.map +1 -0
- package/dist/schema/pipe.d.ts +436 -0
- package/dist/schema/pipe.d.ts.map +1 -0
- package/dist/schema/pipe.js +484 -0
- package/dist/schema/pipe.js.map +1 -0
- package/dist/schema/pipe.test.d.ts +2 -0
- package/dist/schema/pipe.test.d.ts.map +1 -0
- package/dist/schema/pipe.test.js +488 -0
- package/dist/schema/pipe.test.js.map +1 -0
- package/dist/schema/project.d.ts +202 -0
- package/dist/schema/project.d.ts.map +1 -0
- package/dist/schema/project.js +188 -0
- package/dist/schema/project.js.map +1 -0
- package/dist/schema/project.test.d.ts +2 -0
- package/dist/schema/project.test.d.ts.map +1 -0
- package/dist/schema/project.test.js +180 -0
- package/dist/schema/project.test.js.map +1 -0
- package/dist/schema/types.d.ts +140 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +174 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/schema/types.test.d.ts +2 -0
- package/dist/schema/types.test.d.ts.map +1 -0
- package/dist/schema/types.test.js +176 -0
- package/dist/schema/types.test.js.map +1 -0
- package/dist/test/handlers.d.ts +58 -0
- package/dist/test/handlers.d.ts.map +1 -0
- package/dist/test/handlers.js +62 -0
- package/dist/test/handlers.js.map +1 -0
- package/dist/test/setup.d.ts +5 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/dist/test/setup.js +11 -0
- package/dist/test/setup.js.map +1 -0
- package/package.json +57 -0
- package/src/api/branches.test.ts +377 -0
- package/src/api/branches.ts +334 -0
- package/src/api/build.test.ts +216 -0
- package/src/api/build.ts +266 -0
- package/src/api/deploy.test.ts +193 -0
- package/src/api/deploy.ts +163 -0
- package/src/api/workspaces.test.ts +81 -0
- package/src/api/workspaces.ts +77 -0
- package/src/cli/auth.ts +358 -0
- package/src/cli/branch-store.test.ts +139 -0
- package/src/cli/branch-store.ts +137 -0
- package/src/cli/commands/branch.ts +306 -0
- package/src/cli/commands/build.ts +183 -0
- package/src/cli/commands/dev.ts +334 -0
- package/src/cli/commands/init.test.ts +249 -0
- package/src/cli/commands/init.ts +323 -0
- package/src/cli/commands/login.ts +98 -0
- package/src/cli/config.test.ts +359 -0
- package/src/cli/config.ts +335 -0
- package/src/cli/env.ts +86 -0
- package/src/cli/git.test.ts +147 -0
- package/src/cli/git.ts +125 -0
- package/src/cli/index.ts +382 -0
- package/src/cli/utils/schema-validation.test.ts +222 -0
- package/src/cli/utils/schema-validation.ts +272 -0
- package/src/client/base.ts +414 -0
- package/src/client/types.ts +165 -0
- package/src/generator/client.ts +194 -0
- package/src/generator/datasource.test.ts +297 -0
- package/src/generator/datasource.ts +217 -0
- package/src/generator/index.test.ts +209 -0
- package/src/generator/index.ts +203 -0
- package/src/generator/loader.ts +406 -0
- package/src/generator/pipe.test.ts +441 -0
- package/src/generator/pipe.ts +220 -0
- package/src/index.ts +191 -0
- package/src/infer/index.ts +247 -0
- package/src/schema/datasource.test.ts +187 -0
- package/src/schema/datasource.ts +195 -0
- package/src/schema/engines.test.ts +247 -0
- package/src/schema/engines.ts +271 -0
- package/src/schema/params.test.ts +208 -0
- package/src/schema/params.ts +249 -0
- package/src/schema/pipe.test.ts +588 -0
- package/src/schema/pipe.ts +832 -0
- package/src/schema/project.test.ts +236 -0
- package/src/schema/project.ts +394 -0
- package/src/schema/types.test.ts +212 -0
- package/src/schema/types.ts +366 -0
- package/src/test/handlers.ts +79 -0
- package/src/test/setup.ts +13 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { t, isTypeValidator, getTinybirdType, getModifiers } from './types.js';
|
|
3
|
+
|
|
4
|
+
describe('Type Validators (t.*)', () => {
|
|
5
|
+
describe('Basic types', () => {
|
|
6
|
+
it('generates String type', () => {
|
|
7
|
+
const type = t.string();
|
|
8
|
+
expect(type._tinybirdType).toBe('String');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('generates Int32 type', () => {
|
|
12
|
+
const type = t.int32();
|
|
13
|
+
expect(type._tinybirdType).toBe('Int32');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('generates DateTime type', () => {
|
|
17
|
+
const type = t.dateTime();
|
|
18
|
+
expect(type._tinybirdType).toBe('DateTime');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('generates DateTime with timezone', () => {
|
|
22
|
+
const type = t.dateTime('UTC');
|
|
23
|
+
expect(type._tinybirdType).toBe("DateTime('UTC')");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('generates Bool type', () => {
|
|
27
|
+
const type = t.bool();
|
|
28
|
+
expect(type._tinybirdType).toBe('Bool');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('generates UUID type', () => {
|
|
32
|
+
const type = t.uuid();
|
|
33
|
+
expect(type._tinybirdType).toBe('UUID');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('generates Float64 type', () => {
|
|
37
|
+
const type = t.float64();
|
|
38
|
+
expect(type._tinybirdType).toBe('Float64');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('generates UInt64 type', () => {
|
|
42
|
+
const type = t.uint64();
|
|
43
|
+
expect(type._tinybirdType).toBe('UInt64');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('Nullable modifier', () => {
|
|
48
|
+
it('wraps type in Nullable', () => {
|
|
49
|
+
const type = t.string().nullable();
|
|
50
|
+
expect(type._tinybirdType).toBe('Nullable(String)');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('wraps Int32 in Nullable', () => {
|
|
54
|
+
const type = t.int32().nullable();
|
|
55
|
+
expect(type._tinybirdType).toBe('Nullable(Int32)');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('sets nullable modifier', () => {
|
|
59
|
+
const type = t.string().nullable();
|
|
60
|
+
expect(type._modifiers.nullable).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('LowCardinality modifier', () => {
|
|
65
|
+
it('wraps type in LowCardinality', () => {
|
|
66
|
+
const type = t.string().lowCardinality();
|
|
67
|
+
expect(type._tinybirdType).toBe('LowCardinality(String)');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('sets lowCardinality modifier', () => {
|
|
71
|
+
const type = t.string().lowCardinality();
|
|
72
|
+
expect(type._modifiers.lowCardinality).toBe(true);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('LowCardinality + Nullable ordering', () => {
|
|
77
|
+
it('generates LowCardinality(Nullable(X)) when chaining .lowCardinality().nullable()', () => {
|
|
78
|
+
const type = t.string().lowCardinality().nullable();
|
|
79
|
+
expect(type._tinybirdType).toBe('LowCardinality(Nullable(String))');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('generates LowCardinality(Nullable(X)) when chaining .nullable().lowCardinality()', () => {
|
|
83
|
+
const type = t.string().nullable().lowCardinality();
|
|
84
|
+
expect(type._tinybirdType).toBe('LowCardinality(Nullable(String))');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('preserves both modifiers when chained', () => {
|
|
88
|
+
const type = t.string().lowCardinality().nullable();
|
|
89
|
+
expect(type._modifiers.lowCardinality).toBe(true);
|
|
90
|
+
expect(type._modifiers.nullable).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('Default values', () => {
|
|
95
|
+
it('sets hasDefault modifier', () => {
|
|
96
|
+
const type = t.string().default('test');
|
|
97
|
+
expect(type._modifiers.hasDefault).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('stores defaultValue in modifiers', () => {
|
|
101
|
+
const type = t.string().default('test');
|
|
102
|
+
expect(type._modifiers.defaultValue).toBe('test');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('works with numeric defaults', () => {
|
|
106
|
+
const type = t.int32().default(42);
|
|
107
|
+
expect(type._modifiers.defaultValue).toBe(42);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('Codec modifier', () => {
|
|
112
|
+
it('sets codec in modifiers', () => {
|
|
113
|
+
const type = t.string().codec('LZ4');
|
|
114
|
+
expect(type._modifiers.codec).toBe('LZ4');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('Complex types', () => {
|
|
119
|
+
it('generates Array type', () => {
|
|
120
|
+
const type = t.array(t.string());
|
|
121
|
+
expect(type._tinybirdType).toBe('Array(String)');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('generates nested Array type', () => {
|
|
125
|
+
const type = t.array(t.int32());
|
|
126
|
+
expect(type._tinybirdType).toBe('Array(Int32)');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('generates Map type', () => {
|
|
130
|
+
const type = t.map(t.string(), t.int32());
|
|
131
|
+
expect(type._tinybirdType).toBe('Map(String, Int32)');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('generates Decimal type', () => {
|
|
135
|
+
const type = t.decimal(10, 2);
|
|
136
|
+
expect(type._tinybirdType).toBe('Decimal(10, 2)');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('generates FixedString type', () => {
|
|
140
|
+
const type = t.fixedString(3);
|
|
141
|
+
expect(type._tinybirdType).toBe('FixedString(3)');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('generates Tuple type', () => {
|
|
145
|
+
const type = t.tuple(t.string(), t.int32());
|
|
146
|
+
expect(type._tinybirdType).toBe('Tuple(String, Int32)');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('generates DateTime64 type', () => {
|
|
150
|
+
const type = t.dateTime64(3);
|
|
151
|
+
expect(type._tinybirdType).toBe('DateTime64(3)');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('generates DateTime64 with timezone', () => {
|
|
155
|
+
const type = t.dateTime64(3, 'UTC');
|
|
156
|
+
expect(type._tinybirdType).toBe("DateTime64(3, 'UTC')");
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
describe('Helper functions', () => {
|
|
161
|
+
it('isTypeValidator returns true for validators', () => {
|
|
162
|
+
expect(isTypeValidator(t.string())).toBe(true);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('isTypeValidator returns false for non-validators', () => {
|
|
166
|
+
expect(isTypeValidator('string')).toBe(false);
|
|
167
|
+
expect(isTypeValidator({})).toBe(false);
|
|
168
|
+
expect(isTypeValidator(null)).toBe(false);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('getTinybirdType returns type string', () => {
|
|
172
|
+
expect(getTinybirdType(t.string())).toBe('String');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('getModifiers returns modifiers object', () => {
|
|
176
|
+
const modifiers = getModifiers(t.string().nullable());
|
|
177
|
+
expect(modifiers.nullable).toBe(true);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('Chained modifiers', () => {
|
|
182
|
+
it('supports multiple modifiers', () => {
|
|
183
|
+
const type = t.string().lowCardinality().default('test');
|
|
184
|
+
expect(type._tinybirdType).toBe('LowCardinality(String)');
|
|
185
|
+
expect(type._modifiers.lowCardinality).toBe(true);
|
|
186
|
+
expect(type._modifiers.hasDefault).toBe(true);
|
|
187
|
+
expect(type._modifiers.defaultValue).toBe('test');
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('Enum types', () => {
|
|
192
|
+
it('generates Enum8 with value mapping', () => {
|
|
193
|
+
const type = t.enum8('active', 'inactive', 'pending');
|
|
194
|
+
expect(type._tinybirdType).toBe("Enum8('active' = 1, 'inactive' = 2, 'pending' = 3)");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('generates Enum16 with value mapping', () => {
|
|
198
|
+
const type = t.enum16('draft', 'published', 'archived');
|
|
199
|
+
expect(type._tinybirdType).toBe("Enum16('draft' = 1, 'published' = 2, 'archived' = 3)");
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('escapes single quotes in enum values', () => {
|
|
203
|
+
const type = t.enum8("it's ok", 'normal');
|
|
204
|
+
expect(type._tinybirdType).toBe("Enum8('it\\'s ok' = 1, 'normal' = 2)");
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('handles single enum value', () => {
|
|
208
|
+
const type = t.enum8('only');
|
|
209
|
+
expect(type._tinybirdType).toBe("Enum8('only' = 1)");
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
});
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Column type validators for Tinybird datasources
|
|
3
|
+
* Similar to Convex's `v.*` pattern, but for ClickHouse types
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Symbol for brand typing
|
|
7
|
+
const VALIDATOR_BRAND = Symbol("tinybird.validator");
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Base interface for all type validators
|
|
11
|
+
* The phantom types enable TypeScript to infer the correct types
|
|
12
|
+
*/
|
|
13
|
+
export interface TypeValidator<
|
|
14
|
+
TType,
|
|
15
|
+
TTinybirdType extends string = string,
|
|
16
|
+
TModifiers extends TypeModifiers = TypeModifiers
|
|
17
|
+
> {
|
|
18
|
+
readonly [VALIDATOR_BRAND]: true;
|
|
19
|
+
/** The inferred TypeScript type */
|
|
20
|
+
readonly _type: TType;
|
|
21
|
+
/** The Tinybird/ClickHouse type string */
|
|
22
|
+
readonly _tinybirdType: TTinybirdType;
|
|
23
|
+
/** Metadata about modifiers applied */
|
|
24
|
+
readonly _modifiers: TModifiers;
|
|
25
|
+
|
|
26
|
+
/** Make this column nullable */
|
|
27
|
+
nullable(): TypeValidator<TType | null, `Nullable(${TTinybirdType})`, TModifiers & { nullable: true }>;
|
|
28
|
+
/** Apply LowCardinality optimization (for strings with few unique values) */
|
|
29
|
+
lowCardinality(): TypeValidator<TType, `LowCardinality(${TTinybirdType})`, TModifiers & { lowCardinality: true }>;
|
|
30
|
+
/** Set a default value for the column */
|
|
31
|
+
default(value: TType): TypeValidator<TType, TTinybirdType, TModifiers & { hasDefault: true; defaultValue: TType }>;
|
|
32
|
+
/** Set a codec for compression */
|
|
33
|
+
codec(codec: string): TypeValidator<TType, TTinybirdType, TModifiers & { codec: string }>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface TypeModifiers {
|
|
37
|
+
nullable?: boolean;
|
|
38
|
+
lowCardinality?: boolean;
|
|
39
|
+
hasDefault?: boolean;
|
|
40
|
+
defaultValue?: unknown;
|
|
41
|
+
codec?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Internal implementation
|
|
45
|
+
interface ValidatorImpl<TType, TTinybirdType extends string, TModifiers extends TypeModifiers>
|
|
46
|
+
extends TypeValidator<TType, TTinybirdType, TModifiers> {
|
|
47
|
+
readonly tinybirdType: TTinybirdType;
|
|
48
|
+
readonly modifiers: TModifiers;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function createValidator<TType, TTinybirdType extends string>(
|
|
52
|
+
tinybirdType: TTinybirdType,
|
|
53
|
+
modifiers: TypeModifiers = {}
|
|
54
|
+
): TypeValidator<TType, TTinybirdType, TypeModifiers> {
|
|
55
|
+
const validator: ValidatorImpl<TType, TTinybirdType, TypeModifiers> = {
|
|
56
|
+
[VALIDATOR_BRAND]: true,
|
|
57
|
+
_type: undefined as unknown as TType,
|
|
58
|
+
_tinybirdType: tinybirdType,
|
|
59
|
+
_modifiers: modifiers,
|
|
60
|
+
tinybirdType,
|
|
61
|
+
modifiers,
|
|
62
|
+
|
|
63
|
+
nullable() {
|
|
64
|
+
// If already has LowCardinality, we need to move Nullable inside
|
|
65
|
+
// ClickHouse requires: LowCardinality(Nullable(X)), not Nullable(LowCardinality(X))
|
|
66
|
+
if (modifiers.lowCardinality) {
|
|
67
|
+
// Extract base type from LowCardinality(X) and wrap as LowCardinality(Nullable(X))
|
|
68
|
+
const baseType = tinybirdType.replace(/^LowCardinality\((.+)\)$/, '$1');
|
|
69
|
+
const newType = `LowCardinality(Nullable(${baseType}))`;
|
|
70
|
+
return createValidator<TType | null, `LowCardinality(Nullable(${string}))`>(
|
|
71
|
+
newType as `LowCardinality(Nullable(${string}))`,
|
|
72
|
+
{ ...modifiers, nullable: true }
|
|
73
|
+
) as unknown as TypeValidator<TType | null, `Nullable(${TTinybirdType})`, TypeModifiers & { nullable: true }>;
|
|
74
|
+
}
|
|
75
|
+
return createValidator<TType | null, `Nullable(${TTinybirdType})`>(
|
|
76
|
+
`Nullable(${tinybirdType})` as `Nullable(${TTinybirdType})`,
|
|
77
|
+
{ ...modifiers, nullable: true }
|
|
78
|
+
) as TypeValidator<TType | null, `Nullable(${TTinybirdType})`, TypeModifiers & { nullable: true }>;
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
lowCardinality() {
|
|
82
|
+
// If already nullable, wrap as LowCardinality(Nullable(X))
|
|
83
|
+
if (modifiers.nullable) {
|
|
84
|
+
// Extract base type from Nullable(X) and wrap as LowCardinality(Nullable(X))
|
|
85
|
+
const baseType = tinybirdType.replace(/^Nullable\((.+)\)$/, '$1');
|
|
86
|
+
const newType = `LowCardinality(Nullable(${baseType}))`;
|
|
87
|
+
return createValidator<TType, `LowCardinality(Nullable(${string}))`>(
|
|
88
|
+
newType as `LowCardinality(Nullable(${string}))`,
|
|
89
|
+
{ ...modifiers, lowCardinality: true }
|
|
90
|
+
) as unknown as TypeValidator<TType, `LowCardinality(${TTinybirdType})`, TypeModifiers & { lowCardinality: true }>;
|
|
91
|
+
}
|
|
92
|
+
return createValidator<TType, `LowCardinality(${TTinybirdType})`>(
|
|
93
|
+
`LowCardinality(${tinybirdType})` as `LowCardinality(${TTinybirdType})`,
|
|
94
|
+
{ ...modifiers, lowCardinality: true }
|
|
95
|
+
) as TypeValidator<TType, `LowCardinality(${TTinybirdType})`, TypeModifiers & { lowCardinality: true }>;
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
default(value: TType) {
|
|
99
|
+
return createValidator<TType, TTinybirdType>(tinybirdType, {
|
|
100
|
+
...modifiers,
|
|
101
|
+
hasDefault: true,
|
|
102
|
+
defaultValue: value,
|
|
103
|
+
}) as TypeValidator<TType, TTinybirdType, TypeModifiers & { hasDefault: true; defaultValue: TType }>;
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
codec(codec: string) {
|
|
107
|
+
return createValidator<TType, TTinybirdType>(tinybirdType, {
|
|
108
|
+
...modifiers,
|
|
109
|
+
codec,
|
|
110
|
+
}) as TypeValidator<TType, TTinybirdType, TypeModifiers & { codec: string }>;
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
return validator;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Type validators for Tinybird columns
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* import { t } from '@tinybirdco/sdk';
|
|
123
|
+
*
|
|
124
|
+
* const schema = {
|
|
125
|
+
* id: t.string(),
|
|
126
|
+
* count: t.int32(),
|
|
127
|
+
* timestamp: t.dateTime(),
|
|
128
|
+
* tags: t.array(t.string()),
|
|
129
|
+
* metadata: t.json(),
|
|
130
|
+
* };
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export const t = {
|
|
134
|
+
// ============ String Types ============
|
|
135
|
+
|
|
136
|
+
/** String type - variable length UTF-8 string */
|
|
137
|
+
string: () => createValidator<string, "String">("String"),
|
|
138
|
+
|
|
139
|
+
/** FixedString(N) - fixed length string, padded with null bytes */
|
|
140
|
+
fixedString: (length: number) =>
|
|
141
|
+
createValidator<string, `FixedString(${number})`>(`FixedString(${length})`),
|
|
142
|
+
|
|
143
|
+
/** UUID - 16-byte universally unique identifier */
|
|
144
|
+
uuid: () => createValidator<string, "UUID">("UUID"),
|
|
145
|
+
|
|
146
|
+
// ============ Integer Types ============
|
|
147
|
+
|
|
148
|
+
/** Int8 - signed 8-bit integer (-128 to 127) */
|
|
149
|
+
int8: () => createValidator<number, "Int8">("Int8"),
|
|
150
|
+
|
|
151
|
+
/** Int16 - signed 16-bit integer */
|
|
152
|
+
int16: () => createValidator<number, "Int16">("Int16"),
|
|
153
|
+
|
|
154
|
+
/** Int32 - signed 32-bit integer */
|
|
155
|
+
int32: () => createValidator<number, "Int32">("Int32"),
|
|
156
|
+
|
|
157
|
+
/** Int64 - signed 64-bit integer (represented as number, may lose precision) */
|
|
158
|
+
int64: () => createValidator<number, "Int64">("Int64"),
|
|
159
|
+
|
|
160
|
+
/** Int128 - signed 128-bit integer (represented as bigint) */
|
|
161
|
+
int128: () => createValidator<bigint, "Int128">("Int128"),
|
|
162
|
+
|
|
163
|
+
/** Int256 - signed 256-bit integer (represented as bigint) */
|
|
164
|
+
int256: () => createValidator<bigint, "Int256">("Int256"),
|
|
165
|
+
|
|
166
|
+
/** UInt8 - unsigned 8-bit integer (0 to 255) */
|
|
167
|
+
uint8: () => createValidator<number, "UInt8">("UInt8"),
|
|
168
|
+
|
|
169
|
+
/** UInt16 - unsigned 16-bit integer */
|
|
170
|
+
uint16: () => createValidator<number, "UInt16">("UInt16"),
|
|
171
|
+
|
|
172
|
+
/** UInt32 - unsigned 32-bit integer */
|
|
173
|
+
uint32: () => createValidator<number, "UInt32">("UInt32"),
|
|
174
|
+
|
|
175
|
+
/** UInt64 - unsigned 64-bit integer (represented as number, may lose precision) */
|
|
176
|
+
uint64: () => createValidator<number, "UInt64">("UInt64"),
|
|
177
|
+
|
|
178
|
+
/** UInt128 - unsigned 128-bit integer (represented as bigint) */
|
|
179
|
+
uint128: () => createValidator<bigint, "UInt128">("UInt128"),
|
|
180
|
+
|
|
181
|
+
/** UInt256 - unsigned 256-bit integer (represented as bigint) */
|
|
182
|
+
uint256: () => createValidator<bigint, "UInt256">("UInt256"),
|
|
183
|
+
|
|
184
|
+
// ============ Float Types ============
|
|
185
|
+
|
|
186
|
+
/** Float32 - 32-bit floating point */
|
|
187
|
+
float32: () => createValidator<number, "Float32">("Float32"),
|
|
188
|
+
|
|
189
|
+
/** Float64 - 64-bit floating point (double precision) */
|
|
190
|
+
float64: () => createValidator<number, "Float64">("Float64"),
|
|
191
|
+
|
|
192
|
+
/** Decimal(precision, scale) - fixed-point decimal number */
|
|
193
|
+
decimal: (precision: number, scale: number) =>
|
|
194
|
+
createValidator<number, `Decimal(${number}, ${number})`>(
|
|
195
|
+
`Decimal(${precision}, ${scale})`
|
|
196
|
+
),
|
|
197
|
+
|
|
198
|
+
// ============ Boolean ============
|
|
199
|
+
|
|
200
|
+
/** Bool - boolean value (true/false) */
|
|
201
|
+
bool: () => createValidator<boolean, "Bool">("Bool"),
|
|
202
|
+
|
|
203
|
+
// ============ Date/Time Types ============
|
|
204
|
+
|
|
205
|
+
/** Date - date without time (YYYY-MM-DD) */
|
|
206
|
+
date: () => createValidator<Date, "Date">("Date"),
|
|
207
|
+
|
|
208
|
+
/** Date32 - extended date range */
|
|
209
|
+
date32: () => createValidator<Date, "Date32">("Date32"),
|
|
210
|
+
|
|
211
|
+
/** DateTime - date and time with second precision */
|
|
212
|
+
dateTime: (timezone?: string) =>
|
|
213
|
+
timezone
|
|
214
|
+
? createValidator<Date, `DateTime('${string}')`>(`DateTime('${timezone}')`)
|
|
215
|
+
: createValidator<Date, "DateTime">("DateTime"),
|
|
216
|
+
|
|
217
|
+
/** DateTime64 - date and time with sub-second precision */
|
|
218
|
+
dateTime64: (precision: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 = 3, timezone?: string) =>
|
|
219
|
+
timezone
|
|
220
|
+
? createValidator<Date, `DateTime64(${number}, '${string}')`>(
|
|
221
|
+
`DateTime64(${precision}, '${timezone}')`
|
|
222
|
+
)
|
|
223
|
+
: createValidator<Date, `DateTime64(${number})`>(`DateTime64(${precision})`),
|
|
224
|
+
|
|
225
|
+
// ============ Complex Types ============
|
|
226
|
+
|
|
227
|
+
/** Array(T) - array of elements of type T */
|
|
228
|
+
array: <TElement extends TypeValidator<unknown, string, TypeModifiers>>(
|
|
229
|
+
element: TElement
|
|
230
|
+
): TypeValidator<
|
|
231
|
+
TElement["_type"][],
|
|
232
|
+
`Array(${TElement["_tinybirdType"]})`,
|
|
233
|
+
TypeModifiers
|
|
234
|
+
> =>
|
|
235
|
+
createValidator<TElement["_type"][], `Array(${TElement["_tinybirdType"]})`>(
|
|
236
|
+
`Array(${element._tinybirdType})` as `Array(${TElement["_tinybirdType"]})`
|
|
237
|
+
),
|
|
238
|
+
|
|
239
|
+
/** Tuple(T1, T2, ...) - tuple of heterogeneous types */
|
|
240
|
+
tuple: <TElements extends readonly TypeValidator<unknown, string, TypeModifiers>[]>(
|
|
241
|
+
...elements: TElements
|
|
242
|
+
): TypeValidator<
|
|
243
|
+
{ [K in keyof TElements]: TElements[K]["_type"] },
|
|
244
|
+
`Tuple(${string})`,
|
|
245
|
+
TypeModifiers
|
|
246
|
+
> =>
|
|
247
|
+
createValidator<
|
|
248
|
+
{ [K in keyof TElements]: TElements[K]["_type"] },
|
|
249
|
+
`Tuple(${string})`
|
|
250
|
+
>(`Tuple(${elements.map((e) => e._tinybirdType).join(", ")})`),
|
|
251
|
+
|
|
252
|
+
/** Map(K, V) - dictionary/map type */
|
|
253
|
+
map: <
|
|
254
|
+
TKey extends TypeValidator<string | number, string, TypeModifiers>,
|
|
255
|
+
TValue extends TypeValidator<unknown, string, TypeModifiers>
|
|
256
|
+
>(
|
|
257
|
+
keyType: TKey,
|
|
258
|
+
valueType: TValue
|
|
259
|
+
): TypeValidator<
|
|
260
|
+
Map<TKey["_type"], TValue["_type"]>,
|
|
261
|
+
`Map(${TKey["_tinybirdType"]}, ${TValue["_tinybirdType"]})`,
|
|
262
|
+
TypeModifiers
|
|
263
|
+
> =>
|
|
264
|
+
createValidator<
|
|
265
|
+
Map<TKey["_type"], TValue["_type"]>,
|
|
266
|
+
`Map(${TKey["_tinybirdType"]}, ${TValue["_tinybirdType"]})`
|
|
267
|
+
>(`Map(${keyType._tinybirdType}, ${valueType._tinybirdType})`),
|
|
268
|
+
|
|
269
|
+
/** JSON - semi-structured JSON data */
|
|
270
|
+
json: <TShape = unknown>() => createValidator<TShape, "JSON">("JSON"),
|
|
271
|
+
|
|
272
|
+
// ============ Enum Types ============
|
|
273
|
+
|
|
274
|
+
/** Enum8 - enumeration stored as Int8 */
|
|
275
|
+
enum8: <TValues extends readonly string[]>(...values: TValues) => {
|
|
276
|
+
const enumMapping = values
|
|
277
|
+
.map((v, i) => `'${v.replace(/'/g, "\\'")}' = ${i + 1}`)
|
|
278
|
+
.join(", ");
|
|
279
|
+
return createValidator<TValues[number], `Enum8(${string})`>(
|
|
280
|
+
`Enum8(${enumMapping})` as `Enum8(${string})`
|
|
281
|
+
);
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
/** Enum16 - enumeration stored as Int16 */
|
|
285
|
+
enum16: <TValues extends readonly string[]>(...values: TValues) => {
|
|
286
|
+
const enumMapping = values
|
|
287
|
+
.map((v, i) => `'${v.replace(/'/g, "\\'")}' = ${i + 1}`)
|
|
288
|
+
.join(", ");
|
|
289
|
+
return createValidator<TValues[number], `Enum16(${string})`>(
|
|
290
|
+
`Enum16(${enumMapping})` as `Enum16(${string})`
|
|
291
|
+
);
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
// ============ Special Types ============
|
|
295
|
+
|
|
296
|
+
/** IPv4 - IPv4 address */
|
|
297
|
+
ipv4: () => createValidator<string, "IPv4">("IPv4"),
|
|
298
|
+
|
|
299
|
+
/** IPv6 - IPv6 address */
|
|
300
|
+
ipv6: () => createValidator<string, "IPv6">("IPv6"),
|
|
301
|
+
|
|
302
|
+
// ============ Aggregate Function States ============
|
|
303
|
+
|
|
304
|
+
/** SimpleAggregateFunction - for materialized views with simple aggregates */
|
|
305
|
+
simpleAggregateFunction: <
|
|
306
|
+
TFunc extends string,
|
|
307
|
+
TType extends TypeValidator<unknown, string, TypeModifiers>
|
|
308
|
+
>(
|
|
309
|
+
func: TFunc,
|
|
310
|
+
type: TType
|
|
311
|
+
): TypeValidator<
|
|
312
|
+
TType["_type"],
|
|
313
|
+
`SimpleAggregateFunction(${TFunc}, ${TType["_tinybirdType"]})`,
|
|
314
|
+
TypeModifiers
|
|
315
|
+
> =>
|
|
316
|
+
createValidator<
|
|
317
|
+
TType["_type"],
|
|
318
|
+
`SimpleAggregateFunction(${TFunc}, ${TType["_tinybirdType"]})`
|
|
319
|
+
>(`SimpleAggregateFunction(${func}, ${type._tinybirdType})`),
|
|
320
|
+
|
|
321
|
+
/** AggregateFunction - for materialized views with complex aggregates */
|
|
322
|
+
aggregateFunction: <
|
|
323
|
+
TFunc extends string,
|
|
324
|
+
TType extends TypeValidator<unknown, string, TypeModifiers>
|
|
325
|
+
>(
|
|
326
|
+
func: TFunc,
|
|
327
|
+
type: TType
|
|
328
|
+
): TypeValidator<
|
|
329
|
+
TType["_type"],
|
|
330
|
+
`AggregateFunction(${TFunc}, ${TType["_tinybirdType"]})`,
|
|
331
|
+
TypeModifiers
|
|
332
|
+
> =>
|
|
333
|
+
createValidator<
|
|
334
|
+
TType["_type"],
|
|
335
|
+
`AggregateFunction(${TFunc}, ${TType["_tinybirdType"]})`
|
|
336
|
+
>(`AggregateFunction(${func}, ${type._tinybirdType})`),
|
|
337
|
+
} as const;
|
|
338
|
+
|
|
339
|
+
/** Type alias for any type validator */
|
|
340
|
+
export type AnyTypeValidator = TypeValidator<unknown, string, TypeModifiers>;
|
|
341
|
+
|
|
342
|
+
/** Extract the TypeScript type from a type validator */
|
|
343
|
+
export type InferType<T extends AnyTypeValidator> = T["_type"];
|
|
344
|
+
|
|
345
|
+
/** Extract the Tinybird type string from a type validator */
|
|
346
|
+
export type TinybirdType<T extends AnyTypeValidator> = T["_tinybirdType"];
|
|
347
|
+
|
|
348
|
+
/** Helper to check if a value is a type validator */
|
|
349
|
+
export function isTypeValidator(value: unknown): value is AnyTypeValidator {
|
|
350
|
+
return (
|
|
351
|
+
typeof value === "object" &&
|
|
352
|
+
value !== null &&
|
|
353
|
+
VALIDATOR_BRAND in value &&
|
|
354
|
+
(value as Record<symbol, unknown>)[VALIDATOR_BRAND] === true
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** Get the Tinybird type string from a validator */
|
|
359
|
+
export function getTinybirdType(validator: AnyTypeValidator): string {
|
|
360
|
+
return validator._tinybirdType;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/** Get the modifiers from a validator */
|
|
364
|
+
export function getModifiers(validator: AnyTypeValidator): TypeModifiers {
|
|
365
|
+
return validator._modifiers;
|
|
366
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MSW handlers for API mocking in tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { http, HttpResponse } from "msw";
|
|
6
|
+
|
|
7
|
+
export const BASE_URL = "https://api.tinybird.co";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Create build success response
|
|
11
|
+
*/
|
|
12
|
+
export function createBuildSuccessResponse(options?: {
|
|
13
|
+
buildId?: string;
|
|
14
|
+
changedPipes?: string[];
|
|
15
|
+
newPipes?: string[];
|
|
16
|
+
deletedPipes?: string[];
|
|
17
|
+
changedDatasources?: string[];
|
|
18
|
+
newDatasources?: string[];
|
|
19
|
+
deletedDatasources?: string[];
|
|
20
|
+
}) {
|
|
21
|
+
return {
|
|
22
|
+
result: "success",
|
|
23
|
+
build: {
|
|
24
|
+
id: options?.buildId ?? "build-123",
|
|
25
|
+
changed_pipe_names: options?.changedPipes ?? [],
|
|
26
|
+
new_pipe_names: options?.newPipes ?? [],
|
|
27
|
+
deleted_pipe_names: options?.deletedPipes ?? [],
|
|
28
|
+
changed_datasource_names: options?.changedDatasources ?? [],
|
|
29
|
+
new_datasource_names: options?.newDatasources ?? [],
|
|
30
|
+
deleted_datasource_names: options?.deletedDatasources ?? [],
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create build failure response
|
|
37
|
+
*/
|
|
38
|
+
export function createBuildFailureResponse(error: string) {
|
|
39
|
+
return {
|
|
40
|
+
result: "failed",
|
|
41
|
+
error,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create build failure response with multiple errors
|
|
47
|
+
*/
|
|
48
|
+
export function createBuildMultipleErrorsResponse(
|
|
49
|
+
errors: Array<{ filename?: string; error: string }>
|
|
50
|
+
) {
|
|
51
|
+
return {
|
|
52
|
+
result: "failed",
|
|
53
|
+
errors,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Create no changes response
|
|
59
|
+
*/
|
|
60
|
+
export function createNoChangesResponse() {
|
|
61
|
+
return {
|
|
62
|
+
result: "no_changes",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Default handlers for build and deploy endpoints
|
|
68
|
+
*/
|
|
69
|
+
export const handlers = [
|
|
70
|
+
// Build endpoint - success by default
|
|
71
|
+
http.post(`${BASE_URL}/v1/build`, () => {
|
|
72
|
+
return HttpResponse.json(createBuildSuccessResponse());
|
|
73
|
+
}),
|
|
74
|
+
|
|
75
|
+
// Deploy endpoint - success by default
|
|
76
|
+
http.post(`${BASE_URL}/v1/deploy`, () => {
|
|
77
|
+
return HttpResponse.json(createBuildSuccessResponse());
|
|
78
|
+
}),
|
|
79
|
+
];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test setup file for MSW
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { beforeAll, afterEach, afterAll } from "vitest";
|
|
6
|
+
import { setupServer } from "msw/node";
|
|
7
|
+
import { handlers } from "./handlers.js";
|
|
8
|
+
|
|
9
|
+
export const server = setupServer(...handlers);
|
|
10
|
+
|
|
11
|
+
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
|
|
12
|
+
afterEach(() => server.resetHandlers());
|
|
13
|
+
afterAll(() => server.close());
|