-
Notifications
You must be signed in to change notification settings - Fork 1
feat: update GearData interface and add migrate function #189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@malib/gear': minor | ||
| --- | ||
|
|
||
| feat: update GearData interface and add migrate function |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| import { GearType } from "../data"; | ||
| import { migrate } from "./migrate"; | ||
|
|
||
| describe('migrate', () => { | ||
| it('GearDataV1을 GearDataV2로 마이그레이션한다.', () => { | ||
| const data = { | ||
| meta: { | ||
| id: 1000000, | ||
| version: 1, | ||
| }, | ||
| name: '테스트용 장비', | ||
| type: GearType.cap, | ||
| req: {}, | ||
| attributes: {}, | ||
| }; | ||
| expect(migrate(data)).toEqual({ | ||
| id: 1000000, | ||
| version: 2, | ||
| name: '테스트용 장비', | ||
| type: GearType.cap, | ||
| req: {}, | ||
| attributes: {}, | ||
| }); | ||
| }); | ||
|
|
||
| it('GearDataV2를 GearDataV2로 마이그레이션한다.', () => { | ||
| const data = { | ||
| id: 1000000, | ||
| version: 2, | ||
| name: '테스트용 장비', | ||
| type: GearType.cap, | ||
| req: {}, | ||
| attributes: {}, | ||
| }; | ||
| expect(migrate(data)).toEqual(data); | ||
| }); | ||
|
|
||
| it('GearDataV3을 전달하면 TypeError가 발생한다.', () => { | ||
| const data = { | ||
| id: 1000000, | ||
| version: 3, | ||
| name: '테스트용 장비', | ||
| type: GearType.cap, | ||
| }; | ||
| expect(() => migrate(data)).toThrow(TypeError); | ||
| }); | ||
|
|
||
| it('빈 객체를 전달하면 TypeError가 발생한다.', () => { | ||
| expect(() => migrate({})).toThrow(TypeError); | ||
| }); | ||
|
|
||
| it('GearDataV1에서 id가 숫자가 아닌 경우 TypeError가 발생한다.', () => { | ||
| const data = { | ||
| meta: { | ||
| id: '1000000', | ||
| version: 1, | ||
| }, | ||
| name: '테스트용 장비', | ||
| type: GearType.cap, | ||
| req: {}, | ||
| attributes: {}, | ||
| }; | ||
| expect(() => migrate(data)).toThrow(TypeError); | ||
| }); | ||
|
|
||
| it('GearDataV1에서 id가 없는 경우 TypeError가 발생한다.', () => { | ||
| const data = { | ||
| meta: { | ||
| version: 1, | ||
| }, | ||
| name: '테스트용 장비', | ||
| type: GearType.cap, | ||
| }; | ||
| expect(() => migrate(data)).toThrow(TypeError); | ||
| }); | ||
|
|
||
| it('GearData에 포함되지 않는 속성도 함께 마이그레이션한다.', () => { | ||
| const data = { | ||
| id: 1000000, | ||
| version: 2, | ||
| name: '테스트용 장비', | ||
| type: GearType.cap, | ||
| req: { | ||
| unknown: 123, | ||
| }, | ||
| attributes: {}, | ||
| unknown: 'unknown', | ||
| }; | ||
| expect(migrate(data)).toEqual({ | ||
| id: 1000000, | ||
| version: 2, | ||
| name: '테스트용 장비', | ||
| type: GearType.cap, | ||
| req: { | ||
| unknown: 123, | ||
| }, | ||
| attributes: {}, | ||
| unknown: 'unknown', | ||
| }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| import { VERSION } from '../data'; | ||
| import { ErrorMessage } from '../errors'; | ||
| import { getVersion } from './version'; | ||
|
|
||
| export function migrate(data: object, version: number = VERSION): object { | ||
| const currentVersion = getVersion(data); | ||
| if (currentVersion === undefined) { | ||
| throw new TypeError(ErrorMessage.Migrate_InvalidGearData); | ||
| } | ||
| if (currentVersion > version) { | ||
| throw new TypeError(ErrorMessage.Migrate_DataVersionTooNew); | ||
| } | ||
| if (currentVersion === version) { | ||
| return data; | ||
| } | ||
| switch (currentVersion) { | ||
| case 1: | ||
| return migrateV1ToV2(data); | ||
| default: | ||
| throw new TypeError(ErrorMessage.Migrate_UnknownDataVersion); | ||
| } | ||
| } | ||
|
|
||
| function migrateV1ToV2(data: object): object { | ||
| if ( | ||
| ('id' in data && data.id !== undefined) || | ||
| ('version' in data && data.version !== undefined) | ||
| ) { | ||
| throw new TypeError(ErrorMessage.Migrate_DataPropertyWillBeOverwritten); | ||
| } | ||
| if ( | ||
| !( | ||
| 'meta' in data && | ||
| typeof data.meta === 'object' && | ||
| data.meta !== null && | ||
| 'id' in data.meta && | ||
| typeof data.meta.id === 'number' | ||
| ) | ||
| ) { | ||
| throw new TypeError('Assert: id should exist'); | ||
| } | ||
| const { meta, ...rest } = data; | ||
| return { | ||
| ...rest, | ||
| id: meta.id, | ||
| version: 2, | ||
| }; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Migration doesn't provide default value for required
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Migration silently discards custom properties in
metaobjectThe
migrateV1ToV2function extracts onlyidfrom themetaobject and discards everything else. The oldGearMetadatainterface documentation stated that users could add custom properties prefixed with_tometa. During migration, these custom properties are silently lost since onlymeta.idis preserved in the output.