Skip to content

Commit

Permalink
Added index stored + getIndices to retrieve all indexed classes
Browse files Browse the repository at this point in the history
  • Loading branch information
jbdemonte committed May 14, 2018
1 parent 3f0a618 commit 4b16d79
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [Unreleased]

- Added index stored + getIndices to retrieve all indexed classes

## [1.1.0] 2018-04-30

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ Extended options provided by IConfigOptions:
| Name | Type | Optional | Description |
|:-----------:|:---------------------------------------------------------------------------------------------------------:|:--------:|---------------------------------|
| client | [elasticsearch.Client](https://github.com/elastic/elasticsearch-js/blob/14.x/docs/configuration.asciidoc) | X | Official client instance to use |
| indexPrefix | string | X | Prefix to set to all indexes |
| indexPrefix | string | X | Prefix to set to all indices |

#### Core functions

Expand All @@ -193,6 +193,7 @@ The main class provides the main part of the [document API](https://www.elastic.
- create: Add a new document to the index [create api](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html#api-create))
- delete: Delete a document from the index [delete api](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html#api-delete))
- get: Retrieve a document by its id [get api](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html#api-get))
- getIndices: Return all Indexed classes
- index: Add or update a document in the index [index api](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html#api-index))
- search: Search documents in the index [search api](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html#api-search))
- update: Update a document [update api](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html#api-update))
Expand Down
20 changes: 19 additions & 1 deletion src/decorators/index.decorator.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DECORATORS } from '../constants';
import { IndexStore } from '../lib/index-store';
import { Index } from './index.decorator';

describe('pathOrOptions as string', () => {
Expand Down Expand Up @@ -101,11 +102,28 @@ describe('only options object', () => {
});
});

describe('requires index', () => {
describe('@index', () => {
it('throw if index is missing', () => {
expect(() => {
@Index('/type')
class Tweet {}
}).toThrow('Index undefined');
});

it('store the class in the IndexStore', () => {
const spy = jest.spyOn(IndexStore, 'add');

const define = () => {
@Index()
class Tweet {}
return Tweet;
};

const cls = define();

expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith(cls);

spy.mockRestore();
});
});
11 changes: 7 additions & 4 deletions src/decorators/index.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { DECORATORS } from '../constants';
import { IndexStore } from '../lib/index-store';
import { AnyClass } from '../types';

export interface IIndexOptions {
index?: string;
Expand All @@ -9,14 +11,14 @@ export interface IIndexOptions {
/**
* Index decorator factory
*/
export function Index(pathOrOptions?: IIndexOptions): any;
export function Index(pathOrOptions: string, indexOptions?: IIndexOptions): any;
export function Index(pathOrOptions?: string | IIndexOptions, indexOptions?: IIndexOptions): any {
export function Index(pathOrOptions?: IIndexOptions): <T extends AnyClass>(target: T) => T;
export function Index(pathOrOptions: string, indexOptions?: IIndexOptions): <T extends AnyClass>(target: T) => T;
export function Index(pathOrOptions?: string | IIndexOptions, indexOptions?: IIndexOptions): <T extends AnyClass>(target: T) => T {
/**
* Index decorator
* Store class description into class metadata using DECORATORS.INDEX key
*/
return <T extends new (...args: any[]) => any>(target: T): T => {
return <T extends AnyClass>(target: T): T => {
const options: IIndexOptions = (pathOrOptions && typeof pathOrOptions === 'object' ? pathOrOptions : indexOptions) || {};
const name: string = (typeof pathOrOptions === 'string' ? pathOrOptions : options.index) || target.name;
const parts = name.split('/');
Expand All @@ -27,6 +29,7 @@ export function Index(pathOrOptions?: string | IIndexOptions, indexOptions?: IIn
throw new Error('Index undefined');
}
Reflect.defineMetadata(DECORATORS.INDEX, { ...meta, index: index.toLowerCase(), type: type.toLowerCase(), settings: options.settings }, target);
IndexStore.add(target);
return target;
};
}
14 changes: 14 additions & 0 deletions src/lib/core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Mock = jest.Mock;

import { Field, Index, Primary } from '../';
import { BULK_ITEMS_COUNT_MAX, Core, ICoreOptions } from './core';
import { IndexStore } from './index-store';
import { deepFreeze } from './testing-tools.test';

import * as tools from './tools';
Expand Down Expand Up @@ -300,6 +301,19 @@ describe('get', () => {
});
});

describe('getIndices', () => {
it('return stored indices', () => {
const indices: any = [{}, {}];
const spy = jest.spyOn(IndexStore, 'getAll');
spy.mockReturnValue(indices);

expect(core.getIndices()).toBe(indices);
expect(spy).toHaveBeenCalledTimes(1);

spy.mockRestore();
});
});

describe('index', () => {
beforeEach(() => (client.index = jest.fn()));

Expand Down
11 changes: 10 additions & 1 deletion src/lib/core.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Client, CountParams, CountResponse, GetParams, GetResponse, ScrollParams, SearchParams, SearchResponse } from 'elasticsearch';
import { Readable } from 'stream';
import { Indexed, IndexedClass } from '../types';

import { AnyClass, Indexed, IndexedClass } from '../types';
import { ArrayStream } from './array-stream';
import { IndexStore } from './index-store';
import { getIndexMetadata } from './metadata-handler';
import { buildBulkQuery, getQueryStructure, instantiateResult } from './tools';

Expand Down Expand Up @@ -156,6 +158,13 @@ export class Core {
return { response, document };
}

/**
* Return all Indexed classes
*/
getIndices(): AnyClass[] {
return IndexStore.getAll();
}

/**
* Index a document or a literal
* When not providing an id, ES will generate it
Expand Down
62 changes: 62 additions & 0 deletions src/lib/index-store.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { IndexStore } from './index-store';

class User {}

class Twitter {}

const store = (IndexStore as any).store;

beforeEach(() => {
// flush internal store
store.length = 0;
});

describe('add', () => {
it('stores classes', () => {
IndexStore.add(User);
IndexStore.add(Twitter);
expect(store).toEqual([User, Twitter]);
});

it('throw if push a non function', () => {
expect.assertions(1);
try {
IndexStore.add(new User() as any);
} catch (err) {
expect(err).toEqual(new Error('Function expected'));
}
});
});

describe('flush', () => {
beforeEach(() => {
store.push(User, Twitter);
});

it('empty internal store', () => {
IndexStore.flush();
expect(store).toEqual([]);
});

it('does not change store reference', () => {
IndexStore.flush();
expect(store).toBe((IndexStore as any).store);
});
});

describe('getAll', () => {
beforeEach(() => {
store.push(User, Twitter);
});

it('returns store content', () => {
expect(IndexStore.getAll()).toEqual([User, Twitter]);
});

it('isolate internal array from the one returned', () => {
const copy1 = IndexStore.getAll();
const copy2 = IndexStore.getAll();
expect(copy1).toEqual(copy2);
expect(copy1).not.toBe(copy2);
});
});
20 changes: 20 additions & 0 deletions src/lib/index-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { AnyClass, IndexedClass } from '../types';

export class IndexStore {
private static store: AnyClass[] = [];

public static add<T>(cls: IndexedClass<T>) {
if (typeof cls !== 'function') {
throw new Error('Function expected');
}
IndexStore.store.push(cls);
}

public static flush(): void {
IndexStore.store.length = 0;
}

public static getAll(): AnyClass[] {
return IndexStore.store.slice();
}
}
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
export type Indexed<T> = Omit<T, 'index' | 'type'>;

export type IndexedClass<T> = new (...args: any[]) => T;

export type AnyClass = new (...args: any[]) => any;

0 comments on commit 4b16d79

Please sign in to comment.