From 3f5a376dae04f6547cc2cf9b6749bcc70e971a9d Mon Sep 17 00:00:00 2001 From: Alexandro Date: Sat, 26 Nov 2016 21:41:57 +0700 Subject: [PATCH] add typings for waterline --- waterline/index.d.ts | 239 +++++++++++++++++++++++++++ waterline/tsconfig.json | 22 +++ waterline/tslint.json | 9 + waterline/waterline-tests.ts | 311 +++++++++++++++++++++++++++++++++++ 4 files changed, 581 insertions(+) create mode 100644 waterline/index.d.ts create mode 100644 waterline/tsconfig.json create mode 100644 waterline/tslint.json create mode 100644 waterline/waterline-tests.ts diff --git a/waterline/index.d.ts b/waterline/index.d.ts new file mode 100644 index 0000000000..55bfd1673c --- /dev/null +++ b/waterline/index.d.ts @@ -0,0 +1,239 @@ +import BluebirdPromise = require("bluebird"); +declare namespace Waterline { + type Adapter = Object; + type Connection = { + adapter: string; + } + interface Config { + adapters: { [index: string]: Adapter }; + connections: { [index: string]: Connection } + } + type Ontology = { + collections: any; + } + interface Waterline { + loadCollection(collection: CollectionClass): void; + initialize: (config: Config, cb: (err: Error, ontology: Ontology) => any) => any; + collections: any; + } + interface CollectionClass { + (): Collection + } + // used this comment https://github.com/balderdashy/waterline/issues/1154#issuecomment-167262575 + export type LifecycleCallbacks = { + beforeValidate?: { (vaues: any, next: Function): void }[] | { (vaues: any, next: Function): void }; + beforeCreate?: { (values: any, next: Function): void }[] | { (vaues: any, next: Function): void }; + afterCreate?: { (newlyCreatedRecord: any, next: Function): void }[] | { (newlyCreatedRecord: any, next: Function): void }; + beforeUpdate?: { (valuesToUpdate: any, next: Function): void }[] | { (valuesToUpdate: any, next: Function): void }; + afterUpdate?: { (valuesToUpdate: any, next: Function): void }[] | { (valuesToUpdate: any, next: Function): void }; + beforeDestroy?: { (criteria: any, next: Function): void }[] | { (valuesToUpdate: any, next: Function): void }; + afterDestroy?: { (destroyedInstance: any, next: Function): void }[] | { (destroyedInstance: any, next: Function): void }; + } + export type CollectionDefinition = LifecycleCallbacks & { + attributes?: Attributes; + connection?: string; + identity?: string; + tableName?: string; + migrate?: "alter" | "drop" | "safe"; + autoPK?: boolean; + autoCreatedAt?: boolean; + autoUpdatedAt?: boolean; + schema?: boolean; + types?: any; + } + export type Collection = CollectionDefinition; + export type Attributes = { [index: string]: Attribute } & { + toJSON?: () => string; + toObject?: () => any; + }; + export type FunctionAttribute = () => any; + // Data types https://github.com/balderdashy/waterline-docs/blob/master/models/data-types-attributes.md#data-types + export type AttributeType = "string" | "text" | "integer" | "float" | "date" | "time" + | "datetime" | "boolean" | "binary" | "array" | "json"; + export type Attribute = string | StringAttribute | EmailAttribute | + IntegerAttribute | FloatAttribute | + DateAttribute | TimeAttribute | DatetimeAttribute | + BooleanAttribute | BinaryAttribute | ArrayAttribute | JsonAttribute | + OneToOneAttribute | OneToManyAttribute | ManyToManyAttribute | + FunctionAttribute; + export type DefaultsToFn = () => T; + export type BaseAttribute = AttributeValidations & { + type?: string; + primaryKey?: boolean; + unique?: boolean; + required?: boolean; + enum?: Array; + size?: number; + columnName?: string; + index?: boolean; + defaultsTo?: T | DefaultsToFn; + } + export type StringAttribute = BaseAttribute & { + type: "string"; + } + export type EmailAttribute = BaseAttribute & { + type: "email" + } + export type TextAttribute = BaseAttribute & { + type: "text"; + } + export type IntegerAttribute = BaseAttribute & { + type: "integer"; + autoIncrement?: boolean; + } + export type FloatAttribute = BaseAttribute & { + type: "float"; + } + export type DateAttribute = BaseAttribute & { + type: 'date'; + } + export type TimeAttribute = BaseAttribute & { + type: 'time'; + } + export type DatetimeAttribute = BaseAttribute & { + type: 'datetime'; + } + export type BooleanAttribute = BaseAttribute & { + type: 'boolean'; + } + export type BinaryAttribute = BaseAttribute & { + type: 'binary'; + } + export type ArrayAttribute = BaseAttribute & { + type: 'array'; + } + export type JsonAttribute = BaseAttribute & { + type: 'json'; + } + export type OneToOneAttribute = BaseAttribute & { + model: string; + } + export type OneToManyAttribute = BaseAttribute & { + collection: string; + via: string; + } + export type ManyToManyAttribute = BaseAttribute & { + collection: string; + via: string; + dominant?: boolean; + } + type AttributeValidationSyncFn = () => T; + type AttributeValidationAsyncFn = (cb: (value: T) => any) => void; + + export type AttributeValidation = T | AttributeValidationSyncFn | AttributeValidationAsyncFn; + export interface AttributeValidations { + after?: AttributeValidation; + alpha?: AttributeValidation; + alphanumeric?: AttributeValidation; + array?: AttributeValidation; + before?: AttributeValidation; + boolean?: AttributeValidation, + contains?: AttributeValidation, + creditcard?: AttributeValidation, + date?: AttributeValidation, + decimal?: AttributeValidation, + email?: AttributeValidation, + empty?: AttributeValidation, + equals?: AttributeValidation, + falsey?: AttributeValidation, + finite?: AttributeValidation, + float?: AttributeValidation, + hexColor?: AttributeValidation, + hexadecimal?: AttributeValidation, + in?: AttributeValidation, + int?: AttributeValidation, + integer?: AttributeValidation, + ip?: AttributeValidation, + ipv4?: AttributeValidation, + ipv6?: AttributeValidation, + is?: AttributeValidation, + len?: AttributeValidation, + lowercase?: AttributeValidation, + max?: AttributeValidation, + maxLength?: AttributeValidation + min?: AttributeValidation, + minLength?: AttributeValidation, + not?: AttributeValidation, + notContains?: AttributeValidation, + notEmpty?: AttributeValidation, + notIn?: AttributeValidation, + notNull?: AttributeValidation, + notRegex?: AttributeValidation, + null?: AttributeValidation, + number?: AttributeValidation, + numeric?: AttributeValidation, + regex?: AttributeValidation, + required?: AttributeValidation, + string?: AttributeValidation, + truthy?: AttributeValidation, + undefined?: AttributeValidation, + uppercase?: AttributeValidation, + url?: AttributeValidation, + urlish?: AttributeValidation, + uuid?: AttributeValidation, + uuidv3?: AttributeValidation, + uuidv4?: AttributeValidation, + } + + type WaterlinePromise = BluebirdPromise & { + exec(cb: (err: Error, result: T) => any): void; + } + type QueryBuilder = WaterlinePromise & { + where(condition: any): QueryBuilder; + limit(lim: number): QueryBuilder; + skip(num: number): QueryBuilder; + sort(criteria: string | { [attribute: string]: string }): QueryBuilder; + paginate(pagination?: { page: number, limit: number }): QueryBuilder; + populate(association: string): QueryBuilder; + populate(association: string, filter: any): QueryBuilder; + groupBy(attrOrExpr: string): QueryBuilder; + max(attribute: string): QueryBuilder; + min(attribute: string): QueryBuilder; + sum(attribute: string): QueryBuilder; + average(attribute: string): QueryBuilder; + } + interface ModelInstance { + id?: number | string; + createdAt?: Date; + updatedAt?: Date; + toJSON(): any; + save(): WaterlinePromise; + } + export interface Callback { + (err: any, result: T): any; + } + export interface Model extends ModelInstance { + create(params: any, cb?: Callback): WaterlinePromise; + create(params: any[], cb?: Callback): WaterlinePromise; + + find(criteria?: any, cb?: Callback): QueryBuilder; + + findOne(criteria?: any, cb?: Callback): QueryBuilder; + + findOrCreate(criteria?: any, values?: any, cb?: Callback): QueryBuilder; + + update(criteria: any, changes: any, cb?: Callback): WaterlinePromise; + update(criteria: any, changes: any[], cb?: Callback): WaterlinePromise; + + destroy(criteria: any, cb?: Callback): WaterlinePromise; + destroy(criteria: any[], cb?: Callback): WaterlinePromise; + + count(criteria: any): WaterlinePromise; + count(criteria: any[]): WaterlinePromise; + + query(sqlQuery: string, cb: Callback): void; + query(sqlQuery: string, data: any, cb: Callback): void; + + native(cb: (err: Error, collection: any) => void): void; + + stream(criteria: any, writeEnd: any): NodeJS.WritableStream | Error; + } +} +declare interface WaterlineStatic { + Collection: { + extend: (params: Waterline.CollectionDefinition) => Waterline.CollectionClass; + } + new (): Waterline.Waterline; +} +declare var Waterline: WaterlineStatic; +export = Waterline; diff --git a/waterline/tsconfig.json b/waterline/tsconfig.json new file mode 100644 index 0000000000..d53e4133d4 --- /dev/null +++ b/waterline/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "noImplicitAny": true, + "strictNullChecks": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [ + "node", + "bluebird" + ], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "waterline-tests.ts" + ] +} \ No newline at end of file diff --git a/waterline/tslint.json b/waterline/tslint.json new file mode 100644 index 0000000000..206c358c87 --- /dev/null +++ b/waterline/tslint.json @@ -0,0 +1,9 @@ +{ + "extends": "tslint:latest", + "rules": { + "no-empty": false, + "object-literal-sort-keys": false, + "trailing-comma": [], + "no-unused-variable": [] + } +} \ No newline at end of file diff --git a/waterline/waterline-tests.ts b/waterline/waterline-tests.ts new file mode 100644 index 0000000000..aeb799b9a2 --- /dev/null +++ b/waterline/waterline-tests.ts @@ -0,0 +1,311 @@ +import Waterline = require("."); +const waterline = new Waterline(); +const userCollection = Waterline.Collection.extend({ + identity: "user", + connection: "default", + attributes: { + firstName: "string", + lastName: "string", + + // Add a reference to Pets + pets: { + collection: "pet", + via: "owner", + dominant: true, + }, + }, +}); +const petCollection = Waterline.Collection.extend({ + identity: "pet", + connection: "default", + attributes: { + breed: "string", + type: "string", + name: "string", + + // Add a reference to User + owner: { + model: "user", + }, + }, +}); + +waterline.loadCollection(userCollection); +waterline.loadCollection(petCollection); + +const config: Waterline.Config = { + adapters: { + memory: {}, + }, + connections: { + default: { + adapter: "memory", + }, + }, +}; + +waterline.initialize(config, (err, ontology) => { + if (err) { + return console.error(err); + } + + // Tease out fully initialised models. + const User: Waterline.Model = ontology.collections.user; + const Pet: Waterline.Model = ontology.collections.pet; + + User.create({ // First we create a user. + firstName: "Neil", + lastName: "Armstrong", + }).then((user: any) => { // Then we create the pet + return Pet.create({ + breed: "beagle", + type: "dog", + name: "Astro", + owner: user.id, + }); + + }).then((pet) => { // Then we grab all users and their pets + return User.find().populate("pets"); + + }).then((users) => { // Results of the previous then clause are passed to the next + console.dir(users); + + }).catch((errCatch) => { // If any errors occur execution jumps to the catch block. + console.error(errCatch); + }); +}); + +const Person = Waterline.Collection.extend({ + identity: "person", + connection: "local-postgresql", + + attributes: { + + // Don"t allow two objects with the same value + lastName: { + type: "string", + unique: true + }, + + // Ensure a value is set + age: { + type: "integer", + required: true + }, + + // Set a default value if no value is set + phoneNumber: { + type: "string", + defaultsTo: "111-222-3333" + }, + + // Create an auto-incrementing value (not supported by all datastores) + incrementMe: { + type: "integer", + autoIncrement: true + }, + + // Index a value for faster queries + emailAddress: { + type: "email", // Email type will get validated by the ORM + index: true + } + } +}); +// https://github.com/balderdashy/waterline-docs/blob/master/models/validations.md +const validations: Waterline.Attribute = { + type: "string", + empty: true, + required: true, + notEmpty: true, + undefined: true, + string: true, + alpha: true, + numeric: true, + alphanumeric: true, + email: true, + url: true, + urlish: true, + ip: true, + ipv4: true, + ipv6: true, + creditcard: true, + uuid: true, + uuidv3: true, + uuidv4: true, + int: true, + integer: true, + number: true, + finite: true, + decimal: true, + float: true, + falsey: true, + truthy: true, + null: true, + notNull: true, + boolean: true, + array: true, + date: true, + hexadecimal: true, + hexColor: true, + lowercase: true, + uppercase: true, + after: "12/12/2001", + before: "12/12/2001", + is: /ab+c/, + regex: /ab+c/, + not: /ab+c/, + notRegex: /ab+c/, + equals: 45, + contains: "foobar", + notContains: "foobar", + len: 35, + in: ["foo", "bar"], + notIn: ["foo", "bar"], + max: 24, + min: 4, + minLength: 4, + maxLength: 24, +}; +const valid2 = { + contains: (cb: (val: string) => any) => { + setTimeout(() => { + cb("http://"); + }, 1); + }, + before: () => { + return this.endDate; + }, + after: () => { + return this.startDate; + } +}; +const model: Waterline.CollectionDefinition = { + attributes: { + email: { + type: "email", + special: true // ignored by validation + }, + cousins: { + collection: "related", + via: "property", + async: true // ignored by validation + } + } +}; +// Lifecycle Callbacks https://github.com/balderdashy/waterline-docs/blob/master/models/lifecycle-callbacks.md + +const attr1: Waterline.CollectionDefinition = { + beforeValidate: (values, next) => { + next(); + next(""); + }, + beforeCreate: (values, next) => { + next(new Error("")); + next(); + }, + afterCreate: (values, next) => { + next(new Error("")); + next(); + }, + beforeUpdate: (values, next) => { + next(new Error("")); + next(); + }, + afterUpdate: (values, next) => { + next(new Error("")); + next(); + }, + beforeDestroy: (values, next) => { + next(new Error("")); + next(); + }, + afterDestroy: (values, next) => { + next(new Error("")); + next(); + }, +}; +// Queries https://github.com/balderdashy/waterline-docs/blob/master/queries/query.md +let User: Waterline.Model = {} as any; +User.find() + .where({ name: { contains: "foo" } }) + .populate("animals", { type: "dog", limit: 10 }) + .skip(20) + .limit(10) + .exec((err, users) => { + users.map((u) => u.any); + }); +let Comment: Waterline.Model = {} as any; +User.findOne() + .where({ id: 2 }) + .then((user) => { + const comments = Comment.find({ userId: user.id }).then((comments2) => { + return comments2; + }); + + return [user.id, user.friendsList, comments]; + }) + .spread((userId, friendsList, comments) => { + + }) + .catch((err: any) => { + // An error occured + }); + +User.find() + .where({ name: { startsWith: "w" } }) + .exec((err, results) => { + throw err; + }); +// Simple Population +User.find() + .populate("foo") + .exec((err, users) => { }); +// Collection Filtering +User.find() + .populate("foo", { type: "bar", limit: 20 }) + .exec((err, users) => { }); +User.find() + .limit(10) + .exec((err, users) => { }); +User.find() + .skip(10) + .exec((err, users) => { }); +User.find() + .skip(10) + .limit(10) + .exec((err, users) => { }); +User.find() + .paginate({ page: 2, limit: 10 }) + .exec((err, users) => { }); +User.find().sort("roleId asc") + .sort({ createdAt: "desc" }).exec((err, users) => { }); +User.find().exec((err, users) => { }); +// Query methods https://github.com/balderdashy/waterline-docs/blob/master/queries/query-methods.md +// .find( criteria, [callback] ) +User.find(1, (err, values) => { values.map((v) => v); }); +User.find({ name: "Walter Jr" }).exec((err, users) => { users.map((u) => u.id); }); +// .findOne( criteria, [callback] ) +User.findOne({ name: "Walter Jr" }).exec((err, users) => { users.map((u: any) => u.id); }); +User.findOne(1).exec((err, users) => { users.map((u: any) => u.id); }); +User.findOne("1").exec((err, users) => { users.map((u: any) => u.id); }); +User.findOne(1, (err, value) => { }); +// .create( criteria, [callback] ) +User.create({ name: "Walter Jr" }).exec((err, user) => { }); +User.findOrCreate({ name: "Walter Jr" }, {}, (err, user) => { }).exec((err, users) => { }); +// .update( search criteria , values , [callback] ) +User.update({ name: "Walter Jr" }, { name: "Flynn" }, (err, value) => { }).exec((err, users) => { }); +// .destroy( criteria , [callback] ) +User.destroy({ name: "Flynn" }, (err, value) => { }).exec((err) => { }); +// .query( query, [data], callback ) +const Movie: Waterline.Model = {} as any; +const title = "The Speech"; +Movie.query("SELECT * FROM movie WHERE title = $1", [title], (err, results) => { }); +// Aggregates https://github.com/balderdashy/waterline-docs/blob/master/queries/query-methods.md#aggregates +Movie.find() + .groupBy("genre") + .max("revenue") + .min("title") + .sum("imdb") + .average("cost") + .then((results: any) => { });