This commit is contained in:
Yossi Kolesnicov 2017-12-21 17:09:43 +02:00
Родитель 9bf2f50f65
Коммит 814c5686c5
6 изменённых файлов: 127 добавлений и 63 удалений

Просмотреть файл

@ -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 });