Skip to content

Commit

Permalink
feat: json 데이터를 모델로 다루기
Browse files Browse the repository at this point in the history
  • Loading branch information
herrero-tranquilo committed Jan 15, 2022
1 parent 42c73d9 commit 2e6c798
Showing 1 changed file with 227 additions and 0 deletions.
227 changes: 227 additions & 0 deletions JS/src/entity/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
const mapValue = (target, block) => {
return Object.fromEntries(
Object.entries(target).map(([key, value]) => [key, block(value)])
);
};
class Field {
constructor(defaultValue) {
const self = this;
self.get = _ => self.v;
self.set = newValue => {
if(!self.typeValidation(newValue)) throw "invalid type: " + newValue;
if(self.validator && !self.validator(newValue)) throw "invalid validation: " + newValue;
self.v = newValue;
}
}
default(v) {
this.set(v);
}
toJSON() {
return this.v;
}
fromJSON(v) {
return v;
}
typeValidation() {
throw "must be override!";
}
validation(validator) {
this.validator = validator;
return this;
}
};
class StringField extends Field {
typeValidation(v) {
return typeof v == "string";
}
};
class StringListField extends Field {
typeValidation(v) {
return v instanceof Array && v.every(item => typeof item == "string");
}
};
class NumberField extends Field {
typeValidation(v) {
return typeof v == "number";
}
};
class NumberListField extends Field {
typeValidation(v) {
return v instanceof Array && v.every(item => typeof item == "number");
}
};
class DateField extends Field {
typeValidation(v) {
return v instanceof Date;
}
toJSON() {
if(this.v && 'toISOString' in this.v) return this.v.toISOString();
return this.v;
}
fromJSON(v) {
return new Date(v);
}
};
class DateMapField extends Field {
typeValidation(v) {
return !(v instanceof Array) && typeof v == "object" && Object.values(v).every(item => item instanceof Date);
}
toJSON() {
if(this.v && this.v instanceof Array) return mapValue(this.v, v => this.v, v => v.toISOString());
return this.v;
}
fromJSON(v) {
return mapValue(v, v => new Date(v));
}
};
class EntityField extends Field {
constructor(cls) {
super();
this.cls = cls;
}
typeValidation(v) {
return v instanceof this.cls;
}
fromJSON(v) {
const result = new this.cls;
result.parse(v);
return result;
}
};
class EntityListField extends Field {
constructor(cls) {
super();
this.cls = cls;
}
typeValidation(v) {
return v instanceof Array && v.every(item => item instanceof this.cls);
}
fromJSON(v) {
return v.map(json => (new this.cls).parse(json));
}
};
class EntityMapField extends Field {
constructor(cls) {
super();
this.cls = cls;
}
typeValidation(v) {
return !(v instanceof Array) && typeof v == "object" && Object.values().every(item => item instanceof this.cls);
}
fromJSON(v) {
return mapValue(v, json => (new this.cls).parse(json));
}
};
class Entity {
constructor() {
Object.defineProperty(this, "_fields", {
value: {},
enumerable: false,
writable: false,
configurable: false,
});
}
parse(json) {
Object.entries(this._fields).forEach(([key, field]) => {
const jsonValue = json[key];
if(jsonValue == undefined) throw 'no key in json: ' + key;
this[key] = field.fromJSON(jsonValue);
})
return this;
}
toJSON() {
return this._fields;
}
define(field, descriptor) {
Object.defineProperty(this, field, this._fields[field] = descriptor);
return descriptor;
}
string(field) {
return this.define(field, new StringField);
}
stringList(field) {
return this.define(field, new StringListField);
}
number(field) {
return this.define(field, new NumberField);
}
numberList(field) {
return this.define(field, new NumberListField);
}
date(field) {
return this.define(field, new DateField);
}
dateMap(field) {
return this.define(field, new DateMapField)
}
entity(field, targetClass) {
return this.define(field, new EntityField(targetClass));
}
entityList(field, targetClass) {
return this.define(field, new EntityListField(targetClass));
}
entityMap(field, targetClass) {
return this.define(field, new EntityMapField(targetClass));
}
};
class Partner extends Entity {
constructor() {
super();
this.string("name");
}
};
class Member extends Entity {
constructor() {
super();
this.string("name").validation(v => 2 <= v.length && v.length <= 10).default("___");
this.number("age").validation(v => 15 <= v && v <= 50).default(15);
this.date("birth");
this.stringList("dev");
this.dateMap('events');
this.entity("partner", Partner);
this.entityList("friends", Member);
}
};

const member = new Member;
member.parse({
name: "kim",
age: 19,
birth: "1992-11-27T00:00:00.000Z",
dev: ['js'],
events: {
"sleep": "2000-01-01T00:00:00.000Z",
},
partner: {
"name": "jin",
},
friends: [
{
name: "ji",
age: 30,
birth: "2000-01-01T00:00:00.000Z",
dev: ['python'],
events: {
"sleep": "2000-01-01T00:00:00.000Z",
},
partner: {
"name": "jin",
},
friends: [],
},
{
name: "jin",
age: 31,
birth: "2000-01-01T00:00:00.000Z",
dev: ['python'],
events: {
"sleep": "2000-01-01T00:00:00.000Z",
},
partner: {
"name": "ji",
},
friends: [],
}
]
});
console.log(JSON.stringify(member));

0 comments on commit 2e6c798

Please sign in to comment.