@palantir/pack.schema 0.7.0 → 0.9.0
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-lint.log +6 -6
- package/.turbo/turbo-transpileBrowser.log +1 -1
- package/.turbo/turbo-transpileCjs.log +1 -1
- package/.turbo/turbo-transpileEsm.log +1 -1
- package/.turbo/turbo-transpileTypes.log +1 -1
- package/.turbo/turbo-typecheck.log +1 -1
- package/CHANGELOG.md +24 -0
- package/build/browser/index.js +78 -61
- package/build/browser/index.js.map +1 -1
- package/build/cjs/index.cjs +78 -61
- package/build/cjs/index.cjs.map +1 -1
- package/build/cjs/index.d.cts +31 -36
- package/build/esm/index.js +78 -61
- package/build/esm/index.js.map +1 -1
- package/build/types/defineMigration.d.ts +24 -36
- package/build/types/defineMigration.d.ts.map +1 -1
- package/build/types/defineSchemaUpdate.d.ts +6 -0
- package/build/types/defineSchemaUpdate.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/addFieldOptions.test.ts +27 -256
- package/src/defineMigration.ts +87 -105
- package/src/defineSchemaUpdate.ts +78 -23
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import type { SchemaBuilder } from "./defineMigration.js";
|
|
17
|
+
import type { FieldDeprecation, SchemaBuilder } from "./defineMigration.js";
|
|
18
18
|
import { applyMigration } from "./defineMigration.js";
|
|
19
19
|
import type { ModelDefs } from "./defs.js";
|
|
20
|
+
import { isRecordDef } from "./utils.js";
|
|
20
21
|
|
|
21
22
|
export interface InitialSchema<T extends ModelDefs = ModelDefs> {
|
|
22
23
|
readonly type: "initial";
|
|
@@ -30,12 +31,19 @@ export interface FieldMigration {
|
|
|
30
31
|
|
|
31
32
|
export type VersionMigrations = Record<string, Record<string, FieldMigration>>;
|
|
32
33
|
|
|
34
|
+
export interface FieldDeprecationInfo {
|
|
35
|
+
readonly fromVersion: number;
|
|
36
|
+
readonly message?: string;
|
|
37
|
+
}
|
|
38
|
+
export type VersionDeprecations = Record<string, Record<string, FieldDeprecationInfo>>;
|
|
39
|
+
|
|
33
40
|
export interface VersionedSchema<T extends ModelDefs = ModelDefs> {
|
|
34
41
|
readonly type: "versioned";
|
|
35
42
|
readonly models: T;
|
|
36
43
|
readonly version: number;
|
|
37
44
|
readonly previous: SchemaDefinition;
|
|
38
45
|
readonly migrations?: VersionMigrations;
|
|
46
|
+
readonly deprecations?: VersionDeprecations;
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
export type SchemaDefinition<T extends ModelDefs = ModelDefs> =
|
|
@@ -67,18 +75,18 @@ export interface SchemaVersionBuilder<T extends ModelDefs> {
|
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
78
|
+
* Shallow-merge two `[modelKey][fieldName]` maps; `override` wins per field.
|
|
79
|
+
* Used for both migrations (so `withMigrations` supplements `addField` sugar)
|
|
80
|
+
* and deprecations (so each version's deprecations accumulate forward). The
|
|
81
|
+
* maps are combined at both the model and field level.
|
|
74
82
|
*/
|
|
75
|
-
function
|
|
76
|
-
base:
|
|
77
|
-
override:
|
|
78
|
-
):
|
|
83
|
+
function mergeByModelField<V>(
|
|
84
|
+
base: Record<string, Record<string, V>> | undefined,
|
|
85
|
+
override: Record<string, Record<string, V>> | undefined,
|
|
86
|
+
): Record<string, Record<string, V>> | undefined {
|
|
79
87
|
if (base == null) return override;
|
|
80
88
|
if (override == null) return base;
|
|
81
|
-
const result:
|
|
89
|
+
const result: Record<string, Record<string, V>> = { ...base };
|
|
82
90
|
for (const [modelKey, fields] of Object.entries(override)) {
|
|
83
91
|
result[modelKey] = { ...result[modelKey], ...fields };
|
|
84
92
|
}
|
|
@@ -87,7 +95,7 @@ function mergeMigrations(
|
|
|
87
95
|
|
|
88
96
|
/**
|
|
89
97
|
* Drop migration entries that no longer correspond to a field on a record in
|
|
90
|
-
* `models`. Required because `
|
|
98
|
+
* `models`. Required because `mergeByModelField` is monotonic — a later
|
|
91
99
|
* `addSchemaUpdate` that removes or retypes a field would otherwise leave a
|
|
92
100
|
* stale entry in the accumulator. Entries are dropped when:
|
|
93
101
|
* - the model key is no longer present,
|
|
@@ -102,7 +110,7 @@ function pruneMigrations(
|
|
|
102
110
|
const result: VersionMigrations = {};
|
|
103
111
|
for (const [modelKey, fields] of Object.entries(migrations)) {
|
|
104
112
|
const def = models[modelKey];
|
|
105
|
-
if (def
|
|
113
|
+
if (!isRecordDef(def)) continue;
|
|
106
114
|
const recordFields = def.fields;
|
|
107
115
|
const kept: Record<string, FieldMigration> = {};
|
|
108
116
|
for (const [fieldName, migration] of Object.entries(fields)) {
|
|
@@ -117,44 +125,82 @@ function pruneMigrations(
|
|
|
117
125
|
return Object.keys(result).length > 0 ? result : undefined;
|
|
118
126
|
}
|
|
119
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Convert the version-agnostic `FieldDeprecations` collected by `applyMigration`
|
|
130
|
+
* (just `{ message? }`) into `VersionDeprecations` by stamping `fromVersion`.
|
|
131
|
+
*/
|
|
132
|
+
function stampDeprecationVersions(
|
|
133
|
+
deprecations: Record<string, Record<string, FieldDeprecation>> | undefined,
|
|
134
|
+
version: number,
|
|
135
|
+
): VersionDeprecations | undefined {
|
|
136
|
+
if (deprecations == null) return undefined;
|
|
137
|
+
const result: VersionDeprecations = {};
|
|
138
|
+
for (const [modelKey, fields] of Object.entries(deprecations)) {
|
|
139
|
+
const out: Record<string, FieldDeprecationInfo> = {};
|
|
140
|
+
for (const [fieldName, info] of Object.entries(fields)) {
|
|
141
|
+
out[fieldName] = { fromVersion: version, ...info };
|
|
142
|
+
}
|
|
143
|
+
result[modelKey] = out;
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
|
|
120
148
|
class SchemaVersionBuilderImpl<T extends ModelDefs> implements SchemaVersionBuilder<T> {
|
|
121
149
|
private readonly models: T;
|
|
122
150
|
private readonly version: number;
|
|
123
151
|
private readonly previous: SchemaDefinition;
|
|
124
152
|
private readonly _migrations: VersionMigrations | undefined;
|
|
153
|
+
private readonly _deprecations: VersionDeprecations | undefined;
|
|
125
154
|
|
|
126
155
|
constructor(
|
|
127
156
|
models: T,
|
|
128
157
|
version: number,
|
|
129
158
|
previous: SchemaDefinition,
|
|
130
|
-
migrations
|
|
159
|
+
migrations: VersionMigrations | undefined,
|
|
160
|
+
deprecations?: VersionDeprecations,
|
|
131
161
|
) {
|
|
132
162
|
this.models = models;
|
|
133
163
|
this.version = version;
|
|
134
164
|
this.previous = previous;
|
|
135
165
|
this._migrations = migrations;
|
|
166
|
+
this._deprecations = deprecations;
|
|
136
167
|
}
|
|
137
168
|
|
|
138
169
|
addSchemaUpdate<S extends ModelDefs>(
|
|
139
170
|
update: SchemaUpdate<T, S>,
|
|
140
171
|
): SchemaVersionBuilder<T & S> {
|
|
141
|
-
// applyMigration returns
|
|
142
|
-
//
|
|
143
|
-
const { models, upgrades } = applyMigration(this.models, update.migration);
|
|
144
|
-
const merged =
|
|
172
|
+
// applyMigration returns the merged models, any sugar-form upgrades from
|
|
173
|
+
// `addField(name, type, { derivedFrom })`, and any `deprecateField` calls.
|
|
174
|
+
const { models, upgrades, deprecations } = applyMigration(this.models, update.migration);
|
|
175
|
+
const merged = mergeByModelField(
|
|
145
176
|
this._migrations,
|
|
146
177
|
upgrades as VersionMigrations | undefined,
|
|
147
178
|
);
|
|
148
|
-
// Reconcile against the new models: a later update that
|
|
149
|
-
//
|
|
179
|
+
// Reconcile against the new models: a later update that retypes a field
|
|
180
|
+
// must drop the prior step's stale migration entry.
|
|
150
181
|
const pruned = pruneMigrations(merged, models);
|
|
151
|
-
|
|
182
|
+
// Attach this version to each freshly-deprecated field, then merge forward.
|
|
183
|
+
const thisVersionDeprecations = stampDeprecationVersions(deprecations, this.version);
|
|
184
|
+
const mergedDeprecations = mergeByModelField(this._deprecations, thisVersionDeprecations);
|
|
185
|
+
return new SchemaVersionBuilderImpl(
|
|
186
|
+
models,
|
|
187
|
+
this.version,
|
|
188
|
+
this.previous,
|
|
189
|
+
pruned,
|
|
190
|
+
mergedDeprecations,
|
|
191
|
+
);
|
|
152
192
|
}
|
|
153
193
|
|
|
154
194
|
withMigrations(migrations: VersionMigrations): SchemaVersionBuilder<T> {
|
|
155
|
-
const merged =
|
|
195
|
+
const merged = mergeByModelField(this._migrations, migrations);
|
|
156
196
|
const pruned = pruneMigrations(merged, this.models);
|
|
157
|
-
return new SchemaVersionBuilderImpl(
|
|
197
|
+
return new SchemaVersionBuilderImpl(
|
|
198
|
+
this.models,
|
|
199
|
+
this.version,
|
|
200
|
+
this.previous,
|
|
201
|
+
pruned,
|
|
202
|
+
this._deprecations,
|
|
203
|
+
);
|
|
158
204
|
}
|
|
159
205
|
|
|
160
206
|
build(): VersionedSchema<T> {
|
|
@@ -164,6 +210,7 @@ class SchemaVersionBuilderImpl<T extends ModelDefs> implements SchemaVersionBuil
|
|
|
164
210
|
version: this.version,
|
|
165
211
|
previous: this.previous,
|
|
166
212
|
...(this._migrations != null ? { migrations: this._migrations } : {}),
|
|
213
|
+
...(this._deprecations != null ? { deprecations: this._deprecations } : {}),
|
|
167
214
|
};
|
|
168
215
|
}
|
|
169
216
|
}
|
|
@@ -171,5 +218,13 @@ class SchemaVersionBuilderImpl<T extends ModelDefs> implements SchemaVersionBuil
|
|
|
171
218
|
export function nextSchema<T extends ModelDefs>(
|
|
172
219
|
previous: SchemaDefinition<T>,
|
|
173
220
|
): SchemaVersionBuilder<T> {
|
|
174
|
-
|
|
221
|
+
const version = previous.version + 1;
|
|
222
|
+
const deprecations = "deprecations" in previous ? previous.deprecations : undefined;
|
|
223
|
+
return new SchemaVersionBuilderImpl(
|
|
224
|
+
previous.models,
|
|
225
|
+
version,
|
|
226
|
+
previous,
|
|
227
|
+
undefined,
|
|
228
|
+
deprecations,
|
|
229
|
+
);
|
|
175
230
|
}
|