Skip to content
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

Improve handling Pagination #162

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion projects/ngx-hal/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ngx-hal",
"version": "3.1.1",
"version": "4.0.0-beta",
"description": "Angular library for supporting HAL format APIs",
"author": "Infinum <javascript.team@infinum.co>",
"license": "MIT",
Expand Down
12 changes: 6 additions & 6 deletions projects/ngx-hal/src/lib/classes/hal-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ import { RequestOptions } from '../types/request-options.type';
import { RelationshipRequestDescriptor } from '../types/relationship-request-descriptor.type';
import { generateUUID } from '../helpers/uuid/uuid.helper';

export class HalDocument<T extends HalModel> {
export class HalDocument<T extends HalModel<P>, P extends Pagination> {
public models: Array<T>;
public pagination: Pagination;
public pagination: P;
public uniqueModelIdentificator: string;

constructor(
private rawResource: RawHalResource,
private rawResponse: HttpResponse<any>,
private modelClass: ModelConstructor<T>,
private datastore: DatastoreService,
private modelClass: ModelConstructor<T, P>,
private datastore: DatastoreService<P>,
) {
this.parseRawResources(rawResource);
this.generateUniqueModelIdentificator();
Expand All @@ -50,7 +50,7 @@ export class HalDocument<T extends HalModel> {
includeRelationships: Array<string | RelationshipRequestDescriptor> = [],
requestOptions: RequestOptions = {},
subsequentRequestsOptions: RequestOptions = {},
): Observable<HalDocument<T>> {
): Observable<HalDocument<T, P>> {
requestOptions.params = requestOptions.params || {};

if (pageNumber || pageNumber === 0) {
Expand Down Expand Up @@ -82,7 +82,7 @@ export class HalDocument<T extends HalModel> {
});
}

private generatePagination(pagination: RawHalResource): Pagination {
private generatePagination(pagination: RawHalResource): P {
if (!this.datastore.paginationClass) {
return null;
}
Expand Down
32 changes: 17 additions & 15 deletions projects/ngx-hal/src/lib/classes/hal-storage/etag-hal-storage.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import { HalModel } from '../../models/hal.model';
import { HalDocument } from './../hal-document';
import { HttpResponse } from '@angular/common/http';
import { HalModel } from '../../models/hal.model';
import { RequestOptions } from '../../types/request-options.type';
import { HalStorage } from './hal-storage';
import { setRequestHeader } from '../../utils/set-request-header/set-request-header.util';
import { Pagination } from '../pagination';
import { HalDocument } from './../hal-document';
import { HalStorage } from './hal-storage';

export interface EtagStorageModel<T extends HalModel> {
model: T | HalDocument<T>;
export interface EtagStorageModel<T extends HalModel<P>, P extends Pagination> {
model: T | HalDocument<T, P>;
etag: string;
}

export class EtagHalStorage extends HalStorage {
public save<T extends HalModel>(
model: T | HalDocument<T>,
export class EtagHalStorage<P extends Pagination> extends HalStorage<P> {
public save<T extends HalModel<P>>(
model: T | HalDocument<T, P>,
response?: HttpResponse<T>,
alternateUniqueIdentificators: Array<string> = [],
): Array<EtagStorageModel<T>> {
const storedModels: Array<EtagStorageModel<T>> = [];
): Array<EtagStorageModel<T, P>> {
const storedModels: Array<EtagStorageModel<T, P>> = [];

const identificators: Array<string> = [].concat(alternateUniqueIdentificators);
identificators.push(model.uniqueModelIdentificator);
Expand All @@ -33,16 +34,17 @@ export class EtagHalStorage extends HalStorage {
return storedModels;
}

public get<T extends HalModel>(uniqueModelIdentificator: string): T | HalDocument<T> {
const localModel: EtagStorageModel<T> = this.getRawStorageModel(uniqueModelIdentificator);
public get<T extends HalModel<P>>(uniqueModelIdentificator: string): T | HalDocument<T, P> {
const localModel: EtagStorageModel<T, P> = this.getRawStorageModel(uniqueModelIdentificator);
return localModel ? localModel.model : undefined;
}

public enrichRequestOptions(
uniqueModelIdentificator: string,
requestOptions: RequestOptions,
): void {
const storageModel: EtagStorageModel<any> = this.getRawStorageModel(uniqueModelIdentificator);
const storageModel: EtagStorageModel<any, P> =
this.getRawStorageModel(uniqueModelIdentificator);

if (!storageModel) {
return;
Expand All @@ -57,9 +59,9 @@ export class EtagHalStorage extends HalStorage {
}
}

protected getRawStorageModel<T extends HalModel>(
protected getRawStorageModel<T extends HalModel<P>>(
uniqueModelIdentificator: string,
): EtagStorageModel<T> {
): EtagStorageModel<T, P> {
return this.internalStorage[uniqueModelIdentificator];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import { CacheStrategy } from '../../enums/cache-strategy.enum';
import { SimpleHalStorage } from '../../classes/hal-storage/simple-hal-storage';
import { EtagHalStorage } from '../../classes/hal-storage/etag-hal-storage';
import { HalStorage } from './hal-storage';
import { Pagination } from '../pagination';

export type HalStorageType = SimpleHalStorage | EtagHalStorage;
export type HalStorageType<P extends Pagination> = SimpleHalStorage<P> | EtagHalStorage<P>;

export function createHalStorage(
export function createHalStorage<P extends Pagination>(
cacheStrategy: CacheStrategy = CacheStrategy.NONE,
storageInstance: HalStorage,
): HalStorageType {
let storage: HalStorageType;
storageInstance: HalStorage<P>,
): HalStorageType<P> {
let storage: HalStorageType<P>;

switch (cacheStrategy) {
case CacheStrategy.NONE:
Expand Down
34 changes: 20 additions & 14 deletions projects/ngx-hal/src/lib/classes/hal-storage/hal-storage.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import { HalModel } from '../../models/hal.model';
import { HalDocument } from './../hal-document';
import { HttpResponse } from '@angular/common/http';
import { RequestOptions } from '../../types/request-options.type';
import { Observable } from 'rxjs';
import { HalModel } from '../../models/hal.model';
import { ModelConstructor, ModelConstructorFn } from '../../types/model-constructor.type';
import { RequestOptions } from '../../types/request-options.type';
import { Pagination } from '../pagination';
import { HalDocument } from './../hal-document';

export abstract class HalStorage {
export abstract class HalStorage<P extends Pagination> {
protected internalStorage: { [K: string]: any } = {};

public abstract save<T extends HalModel>(
model: T | HalDocument<T>,
public abstract save<T extends HalModel<P>>(
model: T | HalDocument<T, P>,
response?: HttpResponse<T>,
alternateUniqueIdentificators?: Array<string>,
): void;

public abstract get<T extends HalModel>(uniqueModelIdentificator: string): T | HalDocument<T>;
public abstract get<T extends HalModel<P>>(
uniqueModelIdentificator: string,
): T | HalDocument<T, P>;

public saveAll<T extends HalModel>(models: Array<T>, savePartialModels: boolean = false): void {
public saveAll<T extends HalModel<P>>(
models: Array<T>,
savePartialModels: boolean = false,
): void {
models.forEach((model: T) => {
if (savePartialModels || !this.get(model.uniqueModelIdentificator)) {
this.save(model);
}
});
}

public remove(model: HalModel): void {
public remove(model: HalModel<P>): void {
delete this.internalStorage[model.uniqueModelIdentificator];
}

Expand All @@ -35,13 +41,13 @@ export abstract class HalStorage {
// noop
}

public makeGetRequestWrapper?<T extends HalModel>(
public makeGetRequestWrapper?<T extends HalModel<P>>(
urls: { originalUrl: string; cleanUrl: string; urlWithParams: string },
cachedResource: T | HalDocument<T>,
originalGetRequest$: Observable<T | HalDocument<T>>,
cachedResource: T | HalDocument<T, P>,
originalGetRequest$: Observable<T | HalDocument<T, P>>,
requestOptions: RequestOptions,
modelClass: ModelConstructor<T> | ModelConstructorFn<T>,
modelClass: ModelConstructor<T, P> | ModelConstructorFn<T, P>,
isSingleResource: boolean,
storePartialModels?: boolean,
): Observable<T | HalDocument<T>>;
): Observable<T | HalDocument<T, P>>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { HttpResponse } from '@angular/common/http';
import { HalModel } from '../../models/hal.model';
import { HalDocument } from './../hal-document';
import { HalStorage } from './hal-storage';
import { Pagination } from '../pagination';

export class SimpleHalStorage extends HalStorage {
public save<T extends HalModel>(
model: T | HalDocument<T>,
export class SimpleHalStorage<P extends Pagination> extends HalStorage<P> {
public save<T extends HalModel<P>>(
model: T | HalDocument<T, P>,
response?: HttpResponse<T>,
alternateUniqueIdentificators: Array<string> = [],
): void {
Expand All @@ -17,7 +18,7 @@ export class SimpleHalStorage extends HalStorage {
});
}

public get<T extends HalModel>(uniqueModelIdentificator: string): T | HalDocument<T> {
public get<T extends HalModel<P>>(uniqueModelIdentificator: string): T | HalDocument<T, P> {
return this.internalStorage[uniqueModelIdentificator];
}
}
10 changes: 7 additions & 3 deletions projects/ngx-hal/src/lib/decorators/attribute.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Pagination } from '../classes/pagination';
import { ATTRIBUTE_PROPERTIES_METADATA_KEY } from '../constants/metadata.constant';
import { ModelProperty as ModelPropertyEnum } from '../enums/model-property.enum';
import { getObjProperty } from '../helpers/metadata/metadata.helper';
Expand All @@ -10,9 +11,12 @@ import { AttributeModelProperty } from '../interfaces/model-property.interface';
import { HalModel } from '../models/hal.model';
import { deepmergeWrapper } from '../utils/deepmerge-wrapper';

export function Attribute(options: AttributeOptions = {}) {
return (model: HalModel, propertyName: string) => {
const attributeOptions: AttributeOptions = deepmergeWrapper(DEFAULT_ATTRIBUTE_OPTIONS, options);
export function Attribute<P extends Pagination>(options: AttributeOptions<P> = {}) {
return (model: HalModel<P>, propertyName: string) => {
const attributeOptions: AttributeOptions<P> = deepmergeWrapper(
DEFAULT_ATTRIBUTE_OPTIONS,
options,
);
const existingAttributeProperties: Array<AttributeModelProperty> = getObjProperty(
model,
ATTRIBUTE_PROPERTIES_METADATA_KEY,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { DatastoreOptions } from '../interfaces/datastore-options.interface';
import { Pagination } from '../classes/pagination';
import { HAL_DATASTORE_DOCUMENT_CLASS_METADATA_KEY } from '../constants/metadata.constant';
import { setObjProperty } from '../helpers/metadata/metadata.helper';
import { DatastoreOptions } from '../interfaces/datastore-options.interface';
import { DEFAULT_NETWORK_CONFIG, NetworkConfig } from '../interfaces/network-config.interface';
import { deepmergeWrapper } from '../utils/deepmerge-wrapper';
import { setObjProperty } from '../helpers/metadata/metadata.helper';

export function DatastoreConfig(config: DatastoreOptions) {
export function DatastoreConfig<P extends Pagination>(config: DatastoreOptions<P>) {
return function (target: any) {
const networkConfig = deepmergeWrapper<NetworkConfig>(
DEFAULT_NETWORK_CONFIG,
Expand Down
7 changes: 4 additions & 3 deletions projects/ngx-hal/src/lib/decorators/has-many.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Pagination } from '../classes/pagination';
import { HAS_MANY_PROPERTIES_METADATA_KEY } from '../constants/metadata.constant';
import { ModelProperty } from '../enums/model-property.enum';
import { getObjProperty } from '../helpers/metadata/metadata.helper';
Expand All @@ -7,9 +8,9 @@ import { HasManyModelProperty } from '../interfaces/model-property.interface';
import { HalModel } from '../models/hal.model';
import { deepmergeWrapper } from '../utils/deepmerge-wrapper';

export function HasMany(options: HasManyOptions) {
return (model: HalModel, propertyName: string) => {
const hasManyOptions: HasManyOptions = deepmergeWrapper(DEFAULT_HAS_MANY_OPTIONS, options);
export function HasMany<P extends Pagination>(options: HasManyOptions<P>) {
return (model: HalModel<P>, propertyName: string) => {
const hasManyOptions: HasManyOptions<P> = deepmergeWrapper(DEFAULT_HAS_MANY_OPTIONS, options);

const existingHasManyProperties: Array<HasManyModelProperty> = getObjProperty(
model,
Expand Down
7 changes: 4 additions & 3 deletions projects/ngx-hal/src/lib/decorators/has-one.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Pagination } from '../classes/pagination';
import { HAS_ONE_PROPERTIES_METADATA_KEY } from '../constants/metadata.constant';
import { ModelProperty } from '../enums/model-property.enum';
import { getObjProperty } from '../helpers/metadata/metadata.helper';
Expand All @@ -7,9 +8,9 @@ import { HasOneModelProperty } from '../interfaces/model-property.interface';
import { HalModel } from '../models/hal.model';
import { deepmergeWrapper } from '../utils/deepmerge-wrapper';

export function HasOne(options: HasOneOptions) {
return (model: HalModel, propertyName: string) => {
const hasOneOptions: HasOneOptions = deepmergeWrapper(DEFAULT_HAS_ONE_OPTIONS, options);
export function HasOne<P extends Pagination>(options: HasOneOptions<P>) {
return (model: HalModel<P>, propertyName: string) => {
const hasOneOptions: HasOneOptions<P> = deepmergeWrapper(DEFAULT_HAS_ONE_OPTIONS, options);

const existingHasOneProperties: Array<HasOneModelProperty> = getObjProperty(
model,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Pagination } from '../classes/pagination';
import { HEADER_ATTRIBUTE_PROPERTIES_METADATA_KEY } from '../constants/metadata.constant';
import { ModelProperty as ModelPropertyEnum } from '../enums/model-property.enum';
import { getObjProperty } from '../helpers/metadata/metadata.helper';
Expand All @@ -13,9 +14,9 @@ import {
import { HalModel } from '../models/hal.model';
import { deepmergeWrapper } from '../utils/deepmerge-wrapper';

export function HeaderAttribute(options: HeaderAttributeOptions = {}) {
return (model: HalModel, propertyName: string) => {
const headerAttributeOptions: HeaderAttributeOptions = deepmergeWrapper(
export function HeaderAttribute<P extends Pagination>(options: HeaderAttributeOptions<P> = {}) {
return (model: HalModel<P>, propertyName: string) => {
const headerAttributeOptions: HeaderAttributeOptions<P> = deepmergeWrapper(
DEFAULT_HEADER_ATTRIBUTE_OPTIONS,
options,
);
Expand Down
5 changes: 3 additions & 2 deletions projects/ngx-hal/src/lib/decorators/link.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Pagination } from '../classes/pagination';
import { LINK_PROPERTIES_METADATA_KEY } from '../constants/metadata.constant';
import { ModelProperty } from '../enums/model-property.enum';
import { getObjProperty } from '../helpers/metadata/metadata.helper';
Expand All @@ -6,8 +7,8 @@ import { LinkRelationshipOptions } from '../interfaces/link-relationship-options
import { LinkProperty } from '../interfaces/model-property.interface';
import { HalModel } from '../models/hal.model';

export function Link(options: LinkRelationshipOptions = {}) {
return (model: HalModel, propertyName: string) => {
export function Link<P extends Pagination>(options: LinkRelationshipOptions = {}) {
return (model: HalModel<P>, propertyName: string) => {
const existingLinkProperties: Array<LinkProperty> = getObjProperty(
model,
LINK_PROPERTIES_METADATA_KEY,
Expand Down
9 changes: 5 additions & 4 deletions projects/ngx-hal/src/lib/decorators/model-config.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ModelOptions, DEFAULT_MODEL_OPTIONS } from '../interfaces/model-options.interface';
import { Pagination } from '../classes/pagination';
import { HAL_MODEL_DOCUMENT_CLASS_METADATA_KEY } from '../constants/metadata.constant';
import { deepmergeWrapper } from '../utils/deepmerge-wrapper';
import { setObjProperty } from '../helpers/metadata/metadata.helper';
import { DEFAULT_MODEL_OPTIONS, ModelOptions } from '../interfaces/model-options.interface';
import { deepmergeWrapper } from '../utils/deepmerge-wrapper';

export function ModelConfig(config: ModelOptions) {
export function ModelConfig<P extends Pagination>(config: ModelOptions<P>) {
return function (target: any) {
const configValue = deepmergeWrapper<ModelOptions>(DEFAULT_MODEL_OPTIONS, config);
const configValue = deepmergeWrapper<ModelOptions<P>>(DEFAULT_MODEL_OPTIONS, config);
Object.defineProperty(target.prototype, 'config', {
value: configValue,
writable: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Pagination } from '../classes/pagination';
import { ModelConstructor, ModelConstructorFn } from '../types/model-constructor.type';

export interface AttributeOptions {
useClass?: string | ModelConstructor<any> | ModelConstructorFn<any>;
export interface AttributeOptions<P extends Pagination> {
useClass?: string | ModelConstructor<any, P> | ModelConstructorFn<any, P>;
transformResponseValue?: (rawAttribute: any) => any;
transformBeforeSave?: (raw: any) => any;
externalName?: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { NetworkConfig } from './network-config.interface';
import { HalModel } from '../models/hal.model';
import { HalDocumentConstructor } from '../types/hal-document-construtor.type';
import { PaginationConstructor } from '../types/pagination.type';
import { CacheStrategy } from '../enums/cache-strategy.enum';
import { HalStorage } from '../classes/hal-storage/hal-storage';
import { Pagination } from '../classes/pagination';

export interface DatastoreOptions {
export interface DatastoreOptions<P extends Pagination> {
network?: NetworkConfig;
halDocumentClass?: HalDocumentConstructor<HalModel>;
paginationClass?: PaginationConstructor;
halDocumentClass?: HalDocumentConstructor<HalModel<P>, P>;
paginationClass?: { new (...args): P };
cacheStrategy?: CacheStrategy;
storage?: HalStorage;
storage?: HalStorage<P>;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Pagination } from '../classes/pagination';
import { ModelConstructor, ModelConstructorFn } from '../types/model-constructor.type';

export interface HasManyOptions {
itemsType: string | ModelConstructor<any> | ModelConstructorFn<any>;
export interface HasManyOptions<P extends Pagination> {
itemsType: string | ModelConstructor<any, P> | ModelConstructorFn<any, P>;
includeInPayload?: boolean;
externalName?: string;
}
Expand Down
Loading