зеркало из https://github.com/microsoft/paris.git
Saving entities
This commit is contained in:
Родитель
9bf2f50f65
Коммит
814c5686c5
|
@ -10,10 +10,10 @@ export interface IRepository{
|
|||
createNewItem:() => EntityModelBase,
|
||||
getItemById:(id:any) => Observable<any>,
|
||||
query:(options?:DataQuery) => Observable<DataSet<any>>,
|
||||
getItemSaveData:(item:EntityModelBase) => Object,
|
||||
serializeItem:(item:EntityModelBase) => Object,
|
||||
allItems$:Observable<Array<any>>,
|
||||
endpointName:string,
|
||||
endpointUrl:string,
|
||||
//save:(item:EntityModelBase) => Observable<EntityModelBase>,
|
||||
save:(item:EntityModelBase) => Observable<EntityModelBase>
|
||||
//save$:Observable<any>
|
||||
}
|
||||
|
|
|
@ -343,43 +343,94 @@ export class Repository<T extends EntityModelBase> implements IRepository {
|
|||
}).map(dataSet => dataSet.items);
|
||||
}
|
||||
|
||||
// save(item: T): Observable<T> {
|
||||
// let saveData: Index = this.getItemSaveData(item);
|
||||
//
|
||||
// return this.dataStore.post(`${this.endpoint}/${item.id || ''}`, saveData)
|
||||
// .flatMap((savedItemData: Index) => this.createItem(savedItemData))
|
||||
// .do((item: T) => {
|
||||
// if (this._allValues) {
|
||||
// this._allValues = [...this._allValues, item];
|
||||
// this._allItemsSubject$.next(this._allValues);
|
||||
// }
|
||||
//
|
||||
// this._saveSubject$.next(item);
|
||||
// });
|
||||
// }
|
||||
/**
|
||||
* Saves an entity to the server
|
||||
* @param {T} item
|
||||
* @returns {Observable<T extends EntityModelBase>}
|
||||
*/
|
||||
save(item: T): Observable<T> {
|
||||
if (!this.entity.endpoint)
|
||||
throw new Error(`Entity ${this.entity.entityConstructor.name} can be saved - it doesn't specify an endpoint.`);
|
||||
|
||||
try {
|
||||
let saveData: Index = this.serializeItem(item);
|
||||
return this.dataStore.save(`${this.entity.endpoint}/${item.id || ''}`, item.id === undefined ? "POST" : "PUT", { data: saveData })
|
||||
.flatMap((savedItemData: Index) => this.createItem(savedItemData))
|
||||
.do((item: T) => {
|
||||
if (this._allValues) {
|
||||
this._allValues = [...this._allValues, item];
|
||||
this._allItemsSubject$.next(this._allValues);
|
||||
}
|
||||
|
||||
this._saveSubject$.next(item);
|
||||
});
|
||||
}
|
||||
catch(e){
|
||||
return Observable.throw(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the specified item is valid, according to the requirements of the entity (or value object) it belongs to.
|
||||
* @param item
|
||||
* @param {EntityConfigBase} entity
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static validateItem(item:any, entity:EntityConfigBase):boolean{
|
||||
entity.fields.forEach((entityField:Field) => {
|
||||
let itemFieldValue: any = (<any>item)[entityField.id];
|
||||
|
||||
if (entityField.required && (itemFieldValue === undefined || itemFieldValue === null))
|
||||
throw new Error(`Missing value for field '${entityField.id}'`);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON object that can be saved to server, with the reverse logic of getItemModelData
|
||||
* @param {T} item
|
||||
* @returns {Index}
|
||||
*/
|
||||
serializeItem(item:T): Index {
|
||||
Repository.validateItem(item, this.entity);
|
||||
|
||||
return Repository.serializeItem(item, this.entity, this.paris);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes an object value
|
||||
* @param item
|
||||
* @returns {Index}
|
||||
*/
|
||||
static serializeItem(item:any, entity:EntityConfigBase, paris:Paris):Index{
|
||||
Repository.validateItem(item, entity);
|
||||
|
||||
getItemSaveData(item: T): Index {
|
||||
let modelData: Index = {};
|
||||
|
||||
for (let propertyId in item) {
|
||||
if (item.hasOwnProperty(propertyId)) {
|
||||
let modelValue: any;
|
||||
entity.fields.forEach((entityField:Field) => {
|
||||
let itemFieldValue:any = (<any>item)[entityField.id],
|
||||
fieldRepository = paris.getRepository(entityField.type),
|
||||
fieldValueObjectType:EntityConfigBase = !fieldRepository && valueObjectsService.getEntityByType(entityField.type),
|
||||
isNilValue = itemFieldValue === undefined || itemFieldValue === null;
|
||||
|
||||
let propertyValue: any = item[propertyId],
|
||||
entityField: Field = this.entity.fields.get(propertyId);
|
||||
let modelValue:any;
|
||||
|
||||
if (entityField) {
|
||||
let propertyRepository: IRepository = this.paris.getRepository(entityField.type);
|
||||
if (entityField.isArray)
|
||||
modelValue = itemFieldValue ? itemFieldValue.map((element:any) => Repository.serializeItem(element, fieldRepository ? fieldRepository.entity : fieldValueObjectType, paris)) : null;
|
||||
else if (fieldRepository)
|
||||
modelValue = isNilValue ? fieldRepository.entity.getDefaultValue() || null : itemFieldValue.id;
|
||||
else if (fieldValueObjectType)
|
||||
modelValue = isNilValue ? fieldValueObjectType.getDefaultValue() || null : Repository.serializeItem(itemFieldValue, fieldValueObjectType, paris);
|
||||
else
|
||||
modelValue = DataTransformersService.serialize(entityField.type, itemFieldValue);
|
||||
|
||||
if (propertyRepository)
|
||||
modelValue = (<EntityModelBase>propertyValue).id;
|
||||
else
|
||||
modelValue = DataTransformersService.serialize(entityField.type, propertyValue);
|
||||
let modelProperty:string = entityField.data
|
||||
? entityField.data instanceof Array ? entityField.data[0] : entityField.data
|
||||
: entityField.id;
|
||||
|
||||
modelData[entityField.id] = modelValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
modelData[modelProperty] = modelValue;
|
||||
});
|
||||
|
||||
return modelData;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {ParisConfig} from "../config/paris-config";
|
||||
import {Http, HttpOptions} from "./http.service";
|
||||
import {Http, HttpOptions, RequestMethod} from "./http.service";
|
||||
import {Observable} from "rxjs/Observable";
|
||||
|
||||
export class DataStoreService{
|
||||
|
@ -8,19 +8,19 @@ export class DataStoreService{
|
|||
constructor(private config:ParisConfig){}
|
||||
|
||||
get(endpoint:string, data?:HttpOptions, baseUrl?:string):Observable<any>{
|
||||
return this.setActiveRequest(Observable.from(Http.get(this.getEndpointUrl(endpoint, baseUrl), data, this.config.http)), HttpVerb.get, endpoint, data);
|
||||
return this.setActiveRequest(Observable.from(Http.get(this.getEndpointUrl(endpoint, baseUrl), data, this.config.http)), "GET", endpoint, data);
|
||||
}
|
||||
|
||||
// post(endpoint:string, data?:RequestData, baseUrl?:string):Observable<any>{
|
||||
// return this.http.post(this.getEndpointUrl(endpoint, baseUrl), data);
|
||||
// }
|
||||
save(endpoint:string, method:RequestMethod = "POST", data?:HttpOptions, baseUrl?:string):Observable<any>{
|
||||
return Http.request(method, this.getEndpointUrl(endpoint, baseUrl), data);
|
||||
}
|
||||
|
||||
private getEndpointUrl(endpoint:string, baseUrl?:string):string{
|
||||
return `${baseUrl || this.config.apiRoot || ""}/${endpoint}`;
|
||||
}
|
||||
|
||||
private setActiveRequest(obs:Observable<any>, verb:HttpVerb, endpoint:string, data?:RequestData):Observable<any>{
|
||||
let activeRequestId:string = DataStoreService.getActiveRequestId(verb, endpoint, data),
|
||||
private setActiveRequest(obs:Observable<any>, method:RequestMethod, endpoint:string, data?:RequestData):Observable<any>{
|
||||
let activeRequestId:string = DataStoreService.getActiveRequestId(method, endpoint, data),
|
||||
existingActiveRequest = this.activeRequests.get(activeRequestId);
|
||||
|
||||
if (existingActiveRequest)
|
||||
|
@ -34,16 +34,11 @@ export class DataStoreService{
|
|||
}
|
||||
}
|
||||
|
||||
private static getActiveRequestId(verb:HttpVerb, endpoint:string, data?:RequestData):string{
|
||||
return `${verb}__${endpoint}__${data ? JSON.stringify(data) : '|'}`;
|
||||
private static getActiveRequestId(method:RequestMethod, endpoint:string, data?:RequestData):string{
|
||||
return `${method}__${endpoint}__${data ? JSON.stringify(data) : '|'}`;
|
||||
}
|
||||
}
|
||||
|
||||
export interface RequestData{
|
||||
[index:string]:any
|
||||
}
|
||||
|
||||
enum HttpVerb{
|
||||
get = "GET",
|
||||
post = "POST"
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ const transformers:Array<DataTransformer> = [
|
|||
{
|
||||
type: Date,
|
||||
parse: (dateValue:string) => new Date(dateValue),
|
||||
serialize: (date:Date) => date.valueOf()
|
||||
serialize: (date:Date) => date ? date.valueOf() : null
|
||||
},
|
||||
{
|
||||
type: RegExp,
|
||||
|
|
|
@ -26,20 +26,6 @@ export abstract class EntitiesServiceBase<T extends EntityConfigBase>{
|
|||
return entity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
getEntityByPluralName(pluralName:string):DataEntityType{
|
||||
let allEntities:Array<DataEntityType> = Array.from(this._allEntities.keys()),
|
||||
pluralNameLowerCase = pluralName.toLowerCase();
|
||||
|
||||
for(let i=0, entity:DataEntityType; entity = allEntities[i]; i++){
|
||||
if (entity.entityConfig.pluralName.toLowerCase() === pluralNameLowerCase)
|
||||
return entity;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private getDataEntityTypeFields(dataEntityType:DataEntityType):EntityFields{
|
||||
if (!dataEntityType)
|
||||
return null;
|
||||
|
|
|
@ -1,13 +1,45 @@
|
|||
import {ParisHttpConfig} from "../config/paris-config";
|
||||
import {Observable} from "rxjs/Observable";
|
||||
|
||||
export type RequestMethod = "GET"|"POST"|"PUT"|"PATCH"|"DELETE";
|
||||
|
||||
export class Http{
|
||||
static get(url:string, options?:HttpOptions, httpConfig?:ParisHttpConfig):Observable<any>{
|
||||
return Http.request("GET", url, options, httpConfig);
|
||||
}
|
||||
|
||||
static post(url:string, options?:HttpOptions, httpConfig?:ParisHttpConfig):Observable<any>{
|
||||
return Http.request("POST", url, options, httpConfig);
|
||||
}
|
||||
|
||||
static put(url:string, options?:HttpOptions, httpConfig?:ParisHttpConfig):Observable<any>{
|
||||
return Http.request("PUT", url, options, httpConfig);
|
||||
}
|
||||
|
||||
static delete(url:string, options?:HttpOptions, httpConfig?:ParisHttpConfig):Observable<any>{
|
||||
return Http.request("DELETE", url, options, httpConfig);
|
||||
}
|
||||
|
||||
static patch(url:string, options?:HttpOptions, httpConfig?:ParisHttpConfig):Observable<any>{
|
||||
return Http.request("PATCH", url, options, httpConfig);
|
||||
}
|
||||
|
||||
static request(method:RequestMethod, url:string, options?:HttpOptions, httpConfig?:ParisHttpConfig):Observable<any> {
|
||||
let fullUrl:string = options && options.params ? Http.addParamsToUrl(url, options.params) : url,
|
||||
tmpError:Error = new Error(`Failed to GET from ${url}.`);
|
||||
tmpError:Error = new Error(`Failed to ${method} from ${url}.`);
|
||||
|
||||
if (options && options.data) {
|
||||
httpConfig = httpConfig || {};
|
||||
if (!httpConfig.headers)
|
||||
httpConfig.headers = {};
|
||||
|
||||
httpConfig.headers["Content-Type"] = "application/json";
|
||||
}
|
||||
|
||||
return Observable.ajax(Object.assign({
|
||||
url: fullUrl
|
||||
method: method,
|
||||
url: fullUrl,
|
||||
body: options && options.data
|
||||
}, Http.httpOptionsToRequestInit(options, httpConfig)))
|
||||
.map(e => e.response)
|
||||
.catch(() => { throw tmpError });
|
||||
|
|
Загрузка…
Ссылка в новой задаче