Comparing version 0.0.5 to 0.0.6
import { Either } from 'fp-ts/lib/Either'; | ||
import { Error } from "./common"; | ||
export interface Content { | ||
export interface Content<T> { | ||
_id: string; | ||
@@ -18,3 +18,3 @@ name: string; | ||
childOrder: String; | ||
data: any; | ||
data: T; | ||
x: { | ||
@@ -27,3 +27,3 @@ [key: string]: string; | ||
} | ||
interface QueryContentParams { | ||
export interface QueryContentParams { | ||
start?: number; | ||
@@ -37,6 +37,6 @@ count?: number; | ||
} | ||
export interface QueryResponse { | ||
export interface QueryResponse<T> { | ||
aggregations: object; | ||
count: number; | ||
hits: Array<Content>; | ||
hits: Array<Content<T>>; | ||
total: number; | ||
@@ -50,3 +50,3 @@ } | ||
} | ||
export interface CreateContentParams { | ||
export interface CreateContentParams<T> { | ||
name: string; | ||
@@ -60,8 +60,8 @@ parentPath: string; | ||
childOrder?: string; | ||
data: any; | ||
data: T; | ||
x?: string; | ||
} | ||
export interface ModifyContentParams { | ||
export interface ModifyContentParams<T> { | ||
key: string; | ||
editor: (c?: Content) => Content; | ||
editor: (c?: Content<T>) => Content<T>; | ||
requireValid?: boolean; | ||
@@ -77,7 +77,7 @@ } | ||
} | ||
interface ScheduleParams { | ||
export interface ScheduleParams { | ||
from: string; | ||
to: string; | ||
} | ||
interface PublishResponse { | ||
export interface PublishResponse { | ||
pushedContents: Array<string>; | ||
@@ -87,8 +87,7 @@ deletedContents: Array<string>; | ||
} | ||
export declare function get(params: GetContentParams): Either<Error, Content>; | ||
export declare function query(params: QueryContentParams): Either<Error, QueryResponse>; | ||
export declare function create(params: CreateContentParams): Either<Error, Content>; | ||
export declare function modify(params: ModifyContentParams): Either<Error, Content>; | ||
export declare function get<T>(params: GetContentParams): Either<Error, Content<T>>; | ||
export declare function query<T>(params: QueryContentParams): Either<Error, QueryResponse<T>>; | ||
export declare function create<T>(params: CreateContentParams<T>): Either<Error, Content<T>>; | ||
export declare function modify<T>(params: ModifyContentParams<T>): Either<Error, Content<T>>; | ||
export declare function remove(params: DeleteContentParams): Either<Error, boolean>; | ||
export declare function publish(params: PublishContentParams): Either<Error, PublishResponse>; | ||
export {}; |
@@ -5,3 +5,3 @@ import { tryCatch, chain, fromNullable, right, left } from 'fp-ts/lib/Either'; | ||
export function get(params) { | ||
return pipe(tryCatch(function () { return content.get(params); }, function (e) { return ({ errorKey: "InternalServerError", cause: String(e) }); }), chain(fromNullable({ errorKey: "InternalServerError" }))); | ||
return pipe(tryCatch(function () { return content.get(params); }, function (e) { return ({ errorKey: "InternalServerError", cause: String(e) }); }), chain(fromNullable({ errorKey: "NotFoundError" }))); | ||
} | ||
@@ -8,0 +8,0 @@ export function query(params) { |
@@ -32,3 +32,3 @@ import { Either } from "fp-ts/lib/Either"; | ||
contentType: string; | ||
body: string; | ||
body: string | null; | ||
bodyStream: any; | ||
@@ -35,0 +35,0 @@ } |
import { Either } from 'fp-ts/lib/Either'; | ||
import { Error } from "./common"; | ||
export interface Content { | ||
export interface Content<T> { | ||
_id: string; | ||
@@ -18,3 +18,3 @@ name: string; | ||
childOrder: String; | ||
data: any; | ||
data: T; | ||
x: { | ||
@@ -27,3 +27,3 @@ [key: string]: string; | ||
} | ||
interface QueryContentParams { | ||
export interface QueryContentParams { | ||
start?: number; | ||
@@ -37,6 +37,6 @@ count?: number; | ||
} | ||
export interface QueryResponse { | ||
export interface QueryResponse<T> { | ||
aggregations: object; | ||
count: number; | ||
hits: Array<Content>; | ||
hits: Array<Content<T>>; | ||
total: number; | ||
@@ -50,3 +50,3 @@ } | ||
} | ||
export interface CreateContentParams { | ||
export interface CreateContentParams<T> { | ||
name: string; | ||
@@ -60,8 +60,8 @@ parentPath: string; | ||
childOrder?: string; | ||
data: any; | ||
data: T; | ||
x?: string; | ||
} | ||
export interface ModifyContentParams { | ||
export interface ModifyContentParams<T> { | ||
key: string; | ||
editor: (c?: Content) => Content; | ||
editor: (c?: Content<T>) => Content<T>; | ||
requireValid?: boolean; | ||
@@ -77,7 +77,7 @@ } | ||
} | ||
interface ScheduleParams { | ||
export interface ScheduleParams { | ||
from: string; | ||
to: string; | ||
} | ||
interface PublishResponse { | ||
export interface PublishResponse { | ||
pushedContents: Array<string>; | ||
@@ -87,8 +87,7 @@ deletedContents: Array<string>; | ||
} | ||
export declare function get(params: GetContentParams): Either<Error, Content>; | ||
export declare function query(params: QueryContentParams): Either<Error, QueryResponse>; | ||
export declare function create(params: CreateContentParams): Either<Error, Content>; | ||
export declare function modify(params: ModifyContentParams): Either<Error, Content>; | ||
export declare function get<T>(params: GetContentParams): Either<Error, Content<T>>; | ||
export declare function query<T>(params: QueryContentParams): Either<Error, QueryResponse<T>>; | ||
export declare function create<T>(params: CreateContentParams<T>): Either<Error, Content<T>>; | ||
export declare function modify<T>(params: ModifyContentParams<T>): Either<Error, Content<T>>; | ||
export declare function remove(params: DeleteContentParams): Either<Error, boolean>; | ||
export declare function publish(params: PublishContentParams): Either<Error, PublishResponse>; | ||
export {}; |
@@ -7,3 +7,3 @@ "use strict"; | ||
function get(params) { | ||
return pipeable_1.pipe(Either_1.tryCatch(function () { return content.get(params); }, function (e) { return ({ errorKey: "InternalServerError", cause: String(e) }); }), Either_1.chain(Either_1.fromNullable({ errorKey: "InternalServerError" }))); | ||
return pipeable_1.pipe(Either_1.tryCatch(function () { return content.get(params); }, function (e) { return ({ errorKey: "InternalServerError", cause: String(e) }); }), Either_1.chain(Either_1.fromNullable({ errorKey: "NotFoundError" }))); | ||
} | ||
@@ -10,0 +10,0 @@ exports.get = get; |
@@ -32,3 +32,3 @@ import { Either } from "fp-ts/lib/Either"; | ||
contentType: string; | ||
body: string; | ||
body: string | null; | ||
bodyStream: any; | ||
@@ -35,0 +35,0 @@ } |
{ | ||
"name": "enonic-fp", | ||
"version": "0.0.5", | ||
"version": "0.0.6", | ||
"description": "Functional programming helpers for Enonic XP", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
155
README.md
@@ -29,4 +29,7 @@ # Enonic FP | ||
Getting some content content by key. | ||
### Simple get content by key | ||
In this example we ask for content by the key, and then we either return an _Internal Server Error_ or return the | ||
content to the user as json. | ||
```typescript | ||
@@ -40,6 +43,6 @@ import { Response, Request, Error } from "enonic-fp/lib/common"; | ||
return pipe( | ||
getContent({ | ||
key: req.params.key | ||
getContent<Article>({ | ||
key: req.params.key | ||
}), | ||
fold( | ||
fold<Error, Content<Article>, Response>( | ||
(err: Error) => ({ | ||
@@ -50,3 +53,3 @@ status: 500, // 500 = Internal Server Error | ||
}), | ||
(content: Content) => ({ | ||
(content: Content<Article>) => ({ | ||
status: 200, // 200 = Ok | ||
@@ -59,6 +62,17 @@ contentType: 'application/json', | ||
} | ||
interface Article { | ||
title: string, | ||
text: string | ||
} | ||
``` | ||
Deleting some content by key. Deleting it first on the `draft` branch, and then publish it to the `master` branch. | ||
### Delete content by key and publish | ||
In this example we delete come content by `key`. We are first doing this on the `draft` branch. And then we `publish` it | ||
to the `master` branch. | ||
We will return a http error based on the type of error that happened (trough a lookup in the `errorsKeyToStatus` map). | ||
Or we return a http status `204`, indicating success. | ||
```typescript | ||
@@ -71,2 +85,25 @@ import { Response, Request, Error } from "enonic-fp/lib/common"; | ||
function del(req: Request): Response { | ||
const key = req.params.key; | ||
return pipe( | ||
runInDraftContext(() => remove({ key })), | ||
chain(() => publishToMaster(key)), | ||
fold<Error, any, Response>( | ||
(err: Error) => ({ | ||
status: errorKeyToStatus[err.errorKey], | ||
contentType: 'application/json', | ||
body: err | ||
}), | ||
() => ({ | ||
status: 204, // 204 = No content | ||
body: '' | ||
}) | ||
) | ||
); | ||
} | ||
export { del as delete }; // hack since delete is a keyword | ||
// --- HELPER FUNCTIONS --- | ||
function runInDraftContext<T>(f: () => T) { | ||
@@ -78,3 +115,3 @@ return run({ | ||
function publishToMaster(key) { | ||
function publishToMaster(key: string) { | ||
return publish({ | ||
@@ -87,3 +124,3 @@ keys: [key], | ||
const errorsKeyToStatus = { | ||
const errorKeyToStatus : { [key: string]: number; } = { | ||
"InternalServerError": 500, | ||
@@ -93,21 +130,52 @@ "NotFoundError": 404, | ||
}; | ||
``` | ||
function del(req: Request): Response { | ||
### Multiple queries, and http request | ||
In this example we do 3 queries. First we look up an article by `key`, then we search for comments related to that | ||
article based on the articles key. And then we get a list of open positions in the company, that we want to display on | ||
the web page. | ||
The first two are queries in Enonic, and the last one is over http. We do a `sequenceT` taking the 3 `Either<Error, T>` | ||
as input, and getting an Either with the results in a tuple (`Either<Error, [Content, QueryResponse, any]>`). | ||
We then `map` over the tuple, and create an object with all the data, that can be returned to the user. | ||
In the `fold` we either return the an error, with the correct http status (`404`, `500` or `502`), or we return the | ||
result with the http status `200`. | ||
```typescript | ||
import { pipe } from "fp-ts/lib/pipeable"; | ||
import { chain, map, fold, either, Either, parseJSON } from "fp-ts/lib/Either"; | ||
import { sequenceT } from 'fp-ts/lib/Apply' | ||
import { Response, Request, Error } from "enonic-fp/lib/common"; | ||
import { Content, get as getContent, query, QueryResponse } from "enonic-fp/lib/content"; | ||
import { request} from "enonic-fp/lib/http"; | ||
export function get(req: Request): Response { | ||
const key = req.params.key; | ||
return pipe( | ||
runInDraftContext(() => remove({ key })), | ||
chain(() => publishToMaster(key)), | ||
fold( | ||
(err: Error) => { | ||
return { | ||
status: errorsKeyToStatus[err.errorKey], | ||
contentType: 'application/json', | ||
body: err | ||
} | ||
}, | ||
() => ({ | ||
status: 204, // 204 = No content | ||
sequenceT(either)( | ||
getArticle(key), | ||
getCommentsByArticleId(key), | ||
getOpenPositionsOverHttp() | ||
), | ||
map(([article, comments, openPositions]) => { | ||
return { | ||
...article, | ||
openPositions, | ||
comments: comments.hits, | ||
}; | ||
}), | ||
fold<Error, any, Response>( | ||
(err: Error) => ({ | ||
status: errorKeyToStatus[err.errorKey], | ||
contentType: 'application/json', | ||
body: '' | ||
body: err | ||
}), | ||
(res) => ({ | ||
status: 200, | ||
contentType: 'application/json', | ||
body: res | ||
}) | ||
@@ -118,3 +186,44 @@ ) | ||
export { del as delete }; | ||
interface Article { | ||
title: string | ||
text: string | ||
} | ||
interface Comment { | ||
writtenBy: string, | ||
text: string | ||
} | ||
const errorKeyToStatus : { [key: string]: number; } = { | ||
"NotFoundError": 404, | ||
"InternalServerError": 500, | ||
"BadGatewayError": 502 | ||
}; | ||
function getArticle(key: string) : Either<Error, Content<Article>> { | ||
return getContent({ key }); | ||
} | ||
function getCommentsByArticleId(articleId: string) : Either<Error, QueryResponse<Comment>> { | ||
return query({ | ||
query: `data.articleId = ${articleId}`, | ||
contentTypes: ['com.example:comment'] | ||
}); | ||
} | ||
function createBadGatewayError(reason: any): Error { | ||
return { | ||
errorKey: 'BadGatewayError', | ||
cause: String(reason) | ||
}; | ||
} | ||
function getOpenPositionsOverHttp() : Either<Error, any> { | ||
return pipe( | ||
request({ | ||
url: "https://example.com/api/open-positions" | ||
}), | ||
chain(res => parseJSON(res.body!, createBadGatewayError)) | ||
) | ||
} | ||
``` | ||
@@ -121,0 +230,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
28714
227
667