diff --git a/types/redux-orm/index.d.ts b/types/redux-orm/index.d.ts new file mode 100644 index 0000000000..31fffa1273 --- /dev/null +++ b/types/redux-orm/index.d.ts @@ -0,0 +1,215 @@ +// Type definitions for redux-orm 0.9 +// Project: https://github.com/tommikaikkonen/redux-orm#readme +// Definitions by: Andrey Goncharov +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.3 + +export interface ORMId { + id: string; +} + +export interface TableState { + items: string[]; + itemsById: { [index: string]: Item }; + meta: Meta; +} + +export interface ORMCommonState { + [index: string]: TableState; +} + +export type SessionWithModels = Session & { [P in keyof State]: typeof Model }; + +export type ModelWithFields = Model & Fields & VirtualFields & Additional & ORMId; + +// TODO: Refine me +export type ModelProps = any; + +// TODO: Refine me +export interface DB { + getEmptyState: any; + query: any; + update: any; + describe: any; +} + +// TODO: Refine me +export interface SchemaSpec { + tables: any; +} + +// TODO: Refine me +export interface ORMOpts { + createDatabase: (schemaSpec: SchemaSpec) => any; +} + +export interface ModelFields { + [index: string]: Attribute | ForeignKey | ManyToMany | OneToOne; +} + +export interface ModelVirtualFields { + [index: string]: any; +} + +export class ORM { + constructor(opts?: ORMOpts) + register(...model: Array): void; + register(...model: Array): void; + registerManyToManyModelsFor(model: typeof Model): void; + get(modelName: string): typeof Model; + getModelClasses(): Array; + isFieldInstalled(modelName: string, fieldName: string): boolean; + setFieldInstalled(modelName: string, fieldName: string): void; + generateSchemaSpec(): SchemaSpec; + getDatabase(): DB; + getEmptyState(): State; + session(state: State): SessionWithModels; + mutableSession(state: State): SessionWithModels; + + private _attachQuerySetMethods(model: typeof Model): void; + private _setupModelPrototypes(models: Array): void; +} + +export class Model { + static readonly idAttribute: string; + static readonly session: SessionWithModels; + static readonly _sessionData: any; // TODO + static readonly query: QuerySet; + + static modelName: string; + static fields: ModelFields; + static virtualFields: ModelVirtualFields; + static querySetClass: typeof QuerySet; + + static toString(): string; + static options(): object; + static _getTableOpts(): object; + static markAccessed(): void; + static connec(session: Session): void; + static getQuerySet(): QuerySet; + static invalidateClassCache(): void; + static all(): QuerySet; + static create(props: Fields): ModelWithFields; + static upsert(props: Partial): ModelWithFields; + static withId(id: string): ModelWithFields; + static hasId(id: string): boolean; + static _findDatabaseRows(lookupObj: object): any; // TODO + static get(lookupObj: object): ModelWithFields; + static reducer(session: SessionWithModels, action: any): any; + + readonly ref: Fields & Additional & ORMId; + + constructor(props: ModelProps) + + getClass(): string; + getId(): string; + toString(): string; + equals(otherModel: ModelWithFields): boolean; + set(propertyName: string, value: any): void; + update(userMergeObj: Partial): void; + refreshFromState(): void; + delete(): void; + + private _onDelete(): void; + private _initFields(props: ModelProps): void; + private _refreshMany2Many(relations: any): void; // TODO +} + +export type QuerySetClauses = any; // TODO +export type QuerySetOpts = any; // TODO +export class QuerySet { + static addSharedMethod(methodName: string): void; + + constructor(modelClass: typeof Model, clauses: QuerySetClauses, opts: QuerySetOpts) + + toString(): string; + toRefArray(): Array; + toModelArray(): Array>; + count(): number; + exists(): boolean; + at(index: string): ModelWithFields | undefined; + first(): ModelWithFields | undefined; + last(): ModelWithFields | undefined; + all(): QuerySet; + filter(lookupObj: object): QuerySet; // TODO + exclude(lookupObj: object): QuerySet; // TODO + orderBy(iteratees: any, orders: any): QuerySet; // TODO + update(mergeObj: Partial): void; + delete(): void; + + private _evaluate(): void; + private _new(clauses: QuerySetClauses, userOpts: QuerySetOpts): QuerySet; +} + +export class Session { + readonly accessedModels: string[]; + schema: ORM; + db: DB; + initialState: State; + withMutations: boolean; + batchToken: any; + sessionBoundModels: Array; + models: Array; + state: State; + + constructor(schema: ORM, db: DB, state: State, withMutations: boolean, batchToken: any) // TODO + + markAccessed(modelName: string): void; + getDataForModel(modelName: string): object; + applyUpdate(updateSpec: any): any; // TODO + query(querySpec: any): any; // TODO +} + +export interface AttributeOpts { + getDefault?: () => any; +} + +export class Attribute { + constructor(opts: AttributeOpts) + install(model: typeof Model, fieldName: string, orm: ORM): void; +} + +export interface RelationalFieldOpts { + to: string; + relatedName?: string; + through?: string; + throughFields?: { + to: string; + from: string; + }; +} + +export class RelationalField { + constructor(toModelName: string, relatedName?: string) + constructor(opts: RelationalFieldOpts) + getClass: typeof RelationalField; +} + +export class ForeignKey extends RelationalField { + install(model: typeof Model, fieldName: string, orm: ORM): void; +} + +export class ManyToMany extends RelationalField { + install(model: typeof Model, fieldName: string, orm: ORM): void; +} + +export class OneToOne extends RelationalField { + install(model: typeof Model, fieldName: string, orm: ORM): void; +} + +export function attr(opts?: AttributeOpts): Attribute; + +export function fk(toModelName: string, relatedName?: string): ForeignKey; +export function fk(opts: RelationalFieldOpts): ForeignKey; + +export function many(toModelName: string, relatedName?: string): ManyToMany; +export function oneToOne(toModelName: string, relatedName?: string): OneToOne; +export function oneToOne(opts: RelationalFieldOpts): OneToOne; + +export type Updater = (session: SessionWithModels, action: any) => any; + +export function createReducer(orm: ORM, updater?: Updater): (state: State, action: any) => State; + +export type ORMSelector = (session: SessionWithModels, ...args: any[]) => Result; + +export function createSelector(orm: ORM, ...args: Array>): (state: State) => any; diff --git a/types/redux-orm/redux-orm-tests.ts b/types/redux-orm/redux-orm-tests.ts new file mode 100644 index 0000000000..045f4a3554 --- /dev/null +++ b/types/redux-orm/redux-orm-tests.ts @@ -0,0 +1,78 @@ +import { attr, createSelector as createSelectorORM, ORMCommonState, ORMId, QuerySet, TableState, SessionWithModels, Model, ORM } from 'redux-orm'; + +// Model +export class Test extends Model { + static modelName = 'Test'; + + static fields = { + test: attr(), + isFetching: attr({ getDefault: () => false }), + id: attr() + }; +} + +// core data which we do not have defaults for +export interface TestStateItem { + test: string; +} + +// optional data we provide defaults for +export interface FetchIndicatorState { + isFetching: boolean; +} + +// id attr is added automatically by redux-orm therefore we have IORMId interface +export type TestState = TableState; + +export interface TestORMState extends ORMCommonState { + Test: TestState; +} + +interface TestORMModels { + Test: typeof Test; +} + +const orm = new ORM(); +orm.register(Test); + +// Reducer +interface TestDTO { + test: string; +} + +interface Action

{ + type: string; + payload: P; +} + +const reducerAddItem = (state: TestORMState, action: Action): TestORMState => { + const session = orm.session(state); + session.Test.upsert(action.payload); + return session.state; +}; + +// Selector +interface TestDisplayItem { + test: string; +} +type TestDisplayItemList = TestDisplayItem[]; + +// Just for the example below. Use real createSelector from reselect in your app +const createSelector = (param1Creator: (state: S) => P1, combiner: (param1: P1) => R): (state: S) => R => (state) => + combiner(param1Creator(state)); + +interface RootState { + test: TestORMState; +} + +export const makeGetTestDisplayList = () => { + const ormSelector = createSelectorORM(orm, (session: SessionWithModels) => + (session.Test.all() as QuerySet) + .toRefArray() + .map((item) => ({ ...item })) + ); + return createSelector( + ({ test }) => test, + ormSelector + ); +}; diff --git a/types/redux-orm/tsconfig.json b/types/redux-orm/tsconfig.json new file mode 100644 index 0000000000..f981bceb20 --- /dev/null +++ b/types/redux-orm/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "redux-orm-tests.ts" + ] +} diff --git a/types/redux-orm/tslint.json b/types/redux-orm/tslint.json new file mode 100644 index 0000000000..3db14f85ea --- /dev/null +++ b/types/redux-orm/tslint.json @@ -0,0 +1 @@ +{ "extends": "dtslint/dt.json" }