@flink-app/flink 0.11.4 → 0.11.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -100,6 +100,10 @@ export interface FlinkOptions {
100
100
  * Options for json body parser
101
101
  */
102
102
  jsonOptions?: OptionsJson;
103
+ /**
104
+ * Optional: content-types that should be parsed as raw body, and passed as a Buffer object instead of json
105
+ */
106
+ rawContentTypes?: string | string[];
103
107
  scheduling?: {
104
108
  /**
105
109
  * If true, the scheduler will be enabled.
@@ -164,6 +168,7 @@ export declare class FlinkApp<C extends FlinkContext> {
164
168
  private corsOpts;
165
169
  private routingConfigured;
166
170
  private jsonOptions?;
171
+ private rawContentTypes?;
167
172
  private schedulingOptions?;
168
173
  private disableHttpServer;
169
174
  private repos;
@@ -107,6 +107,7 @@ var FlinkApp = /** @class */ (function () {
107
107
  this.onDbConnection = opts.onDbConnection;
108
108
  this.plugins = opts.plugins || [];
109
109
  this.corsOpts = __assign(__assign({}, defaultCorsOptions), opts.cors);
110
+ this.rawContentTypes = Array.isArray(opts.rawContentTypes) ? opts.rawContentTypes : (typeof opts.rawContentTypes === 'string' ? [opts.rawContentTypes] : undefined);
110
111
  this.auth = opts.auth;
111
112
  this.jsonOptions = opts.jsonOptions || { limit: "1mb" };
112
113
  this.schedulingOptions = opts.scheduling;
@@ -126,23 +127,23 @@ var FlinkApp = /** @class */ (function () {
126
127
  FlinkApp.prototype.start = function () {
127
128
  var _a;
128
129
  return __awaiter(this, void 0, void 0, function () {
129
- var startTime, offsetTime, _i, _b, plugin, db;
130
+ var startTime, offsetTime, _i, _b, type, _c, _d, plugin, db;
130
131
  var _this = this;
131
- return __generator(this, function (_c) {
132
- switch (_c.label) {
132
+ return __generator(this, function (_e) {
133
+ switch (_e.label) {
133
134
  case 0:
134
135
  startTime = Date.now();
135
136
  offsetTime = 0;
136
137
  return [4 /*yield*/, this.initDb()];
137
138
  case 1:
138
- _c.sent();
139
+ _e.sent();
139
140
  if (this.debug) {
140
141
  offsetTime = Date.now();
141
142
  FlinkLog_1.log.bgColorLog("cyan", "Init db took " + (offsetTime - startTime) + " ms");
142
143
  }
143
144
  return [4 /*yield*/, this.buildContext()];
144
145
  case 2:
145
- _c.sent();
146
+ _e.sent();
146
147
  if (this.debug) {
147
148
  FlinkLog_1.log.bgColorLog("cyan", "Build context took " + (Date.now() - offsetTime) + " ms");
148
149
  offsetTime = Date.now();
@@ -156,6 +157,12 @@ var FlinkApp = /** @class */ (function () {
156
157
  if (!this.disableHttpServer) {
157
158
  this.expressApp = express_1.default();
158
159
  this.expressApp.use(cors_1.default(this.corsOpts));
160
+ if (this.rawContentTypes) {
161
+ for (_i = 0, _b = this.rawContentTypes; _i < _b.length; _i++) {
162
+ type = _b[_i];
163
+ this.expressApp.use(express_1.default.raw({ type: type }));
164
+ }
165
+ }
159
166
  this.expressApp.use(body_parser_1.default.json(this.jsonOptions));
160
167
  if (this.accessLog.enabled) {
161
168
  this.expressApp.use(morgan_1.default(this.accessLog.format));
@@ -165,32 +172,32 @@ var FlinkApp = /** @class */ (function () {
165
172
  next();
166
173
  });
167
174
  }
168
- _i = 0, _b = this.plugins;
169
- _c.label = 3;
175
+ _c = 0, _d = this.plugins;
176
+ _e.label = 3;
170
177
  case 3:
171
- if (!(_i < _b.length)) return [3 /*break*/, 9];
172
- plugin = _b[_i];
178
+ if (!(_c < _d.length)) return [3 /*break*/, 9];
179
+ plugin = _d[_c];
173
180
  db = void 0;
174
181
  if (!plugin.db) return [3 /*break*/, 5];
175
182
  return [4 /*yield*/, this.initPluginDb(plugin)];
176
183
  case 4:
177
- db = _c.sent();
178
- _c.label = 5;
184
+ db = _e.sent();
185
+ _e.label = 5;
179
186
  case 5:
180
187
  if (!plugin.init) return [3 /*break*/, 7];
181
188
  return [4 /*yield*/, plugin.init(this, db)];
182
189
  case 6:
183
- _c.sent();
184
- _c.label = 7;
190
+ _e.sent();
191
+ _e.label = 7;
185
192
  case 7:
186
193
  FlinkLog_1.log.info("Initialized plugin '" + plugin.id + "'");
187
- _c.label = 8;
194
+ _e.label = 8;
188
195
  case 8:
189
- _i++;
196
+ _c++;
190
197
  return [3 /*break*/, 3];
191
198
  case 9: return [4 /*yield*/, this.registerAutoRegisterableHandlers()];
192
199
  case 10:
193
- _c.sent();
200
+ _e.sent();
194
201
  if (this.debug) {
195
202
  FlinkLog_1.log.bgColorLog("cyan", "Register handlers took " + (Date.now() - offsetTime) + " ms");
196
203
  offsetTime = Date.now();
@@ -198,12 +205,12 @@ var FlinkApp = /** @class */ (function () {
198
205
  if (!this.isSchedulingEnabled) return [3 /*break*/, 12];
199
206
  return [4 /*yield*/, this.registerAutoRegisterableJobs()];
200
207
  case 11:
201
- _c.sent();
208
+ _e.sent();
202
209
  if (this.debug) {
203
210
  FlinkLog_1.log.bgColorLog("cyan", "Register jobs took " + (Date.now() - offsetTime) + " ms");
204
211
  offsetTime = Date.now();
205
212
  }
206
- _c.label = 12;
213
+ _e.label = 12;
207
214
  case 12:
208
215
  // Register 404 with slight delay to allow all manually added routes to be added
209
216
  // TODO: Is there a better solution to force this handler to always run last?
@@ -17,4 +17,5 @@ export declare abstract class FlinkRepo<C extends FlinkContext, Model = any> {
17
17
  updateOne<U = Partial<Model>>(id: string, model: U): Promise<Model>;
18
18
  updateMany<U = Partial<Model>>(query: any, model: U): Promise<number>;
19
19
  deleteById(id: string): Promise<number>;
20
+ private buildId;
20
21
  }
@@ -67,7 +67,7 @@ var FlinkRepo = /** @class */ (function () {
67
67
  FlinkRepo.prototype.getById = function (id) {
68
68
  return __awaiter(this, void 0, void 0, function () {
69
69
  return __generator(this, function (_a) {
70
- return [2 /*return*/, this.collection.findOne({ _id: new mongodb_1.ObjectID(id) })];
70
+ return [2 /*return*/, this.collection.findOne({ _id: this.buildId(id) })];
71
71
  });
72
72
  });
73
73
  };
@@ -98,7 +98,7 @@ var FlinkRepo = /** @class */ (function () {
98
98
  return __generator(this, function (_a) {
99
99
  switch (_a.label) {
100
100
  case 0:
101
- oid = new mongodb_1.ObjectID(id);
101
+ oid = this.buildId(id);
102
102
  return [4 /*yield*/, this.collection.updateOne({
103
103
  _id: oid,
104
104
  }, {
@@ -132,7 +132,7 @@ var FlinkRepo = /** @class */ (function () {
132
132
  return __generator(this, function (_a) {
133
133
  switch (_a.label) {
134
134
  case 0: return [4 /*yield*/, this.collection.deleteOne({
135
- _id: new mongodb_1.ObjectID(id),
135
+ _id: this.buildId(id),
136
136
  })];
137
137
  case 1:
138
138
  deletedCount = (_a.sent()).deletedCount;
@@ -141,6 +141,19 @@ var FlinkRepo = /** @class */ (function () {
141
141
  });
142
142
  });
143
143
  };
144
+ FlinkRepo.prototype.buildId = function (id) {
145
+ var oid;
146
+ if (typeof id === "string") {
147
+ oid = new mongodb_1.ObjectId(id);
148
+ }
149
+ else if (id instanceof mongodb_1.ObjectId) {
150
+ oid = id;
151
+ }
152
+ else {
153
+ throw new Error("Invalid id type");
154
+ }
155
+ return oid;
156
+ };
144
157
  return FlinkRepo;
145
158
  }());
146
159
  exports.FlinkRepo = FlinkRepo;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flink-app/flink",
3
- "version": "0.11.4",
3
+ "version": "0.11.9",
4
4
  "description": "Typescript only framework for creating REST-like APIs on top of Express and mongodb",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "main": "dist/src/index.js",
@@ -67,5 +67,5 @@
67
67
  "rimraf": "^3.0.2",
68
68
  "ts-node": "^9.1.1"
69
69
  },
70
- "gitHead": "5f36b236f3059fbd77cb01b363d60e3061bdf714"
70
+ "gitHead": "cc04e10ae82ed022031ef8bcfaafa9beb1d6564f"
71
71
  }
@@ -2,61 +2,68 @@ import { FlinkRepo } from "../src/FlinkRepo";
2
2
  import mongodb, { Collection, Db } from "mongodb";
3
3
 
4
4
  interface Model {
5
- _id: string;
6
- name: string;
5
+ _id: string;
6
+ name: string;
7
7
  }
8
8
 
9
9
  class Repo extends FlinkRepo<any, Model> {}
10
10
 
11
11
  describe("FlinkRepo", () => {
12
- if (!process.env.CI) {
13
- console.warn("Skipping repo test which requires db if CI flag is not set");
14
- return;
15
- }
12
+ if (!process.env.CI) {
13
+ console.warn("Skipping repo test which requires db if CI flag is not set");
14
+ return;
15
+ }
16
16
 
17
- let db: Db;
18
- let collection: Collection;
19
- let repo: Repo;
17
+ let db: Db;
18
+ let collection: Collection;
19
+ let repo: Repo;
20
20
 
21
- beforeAll(async () => {
22
- const client = await mongodb.connect(
23
- "mongodb://localhost:27017/flink-test-db"
24
- );
25
- db = client.db();
26
- collection = db.collection("test-coll");
21
+ beforeAll(async () => {
22
+ const client = await mongodb.connect("mongodb://localhost:27017/flink-test-db");
23
+ db = client.db();
24
+ collection = db.collection("test-coll");
27
25
 
28
- repo = new Repo("test-coll", db);
29
- });
26
+ repo = new Repo("test-coll", db);
27
+ });
28
+
29
+ it("should get document by id", async () => {
30
+ const { insertedId } = await collection.insertOne({ name: "foo" });
30
31
 
31
- it("should get document by id", async () => {
32
- const { insertedId } = await collection.insertOne({ name: "foo" });
32
+ const doc = await repo.getById(insertedId + "");
33
33
 
34
- const doc = await repo.getById(insertedId + "");
34
+ expect(doc).toBeDefined();
35
+ expect(doc?.name).toBe("foo");
36
+ });
35
37
 
36
- expect(doc).toBeDefined();
37
- expect(doc?.name).toBe("foo");
38
- });
38
+ it("should get document by id using ObjectId", async () => {
39
+ const { insertedId } = await collection.insertOne({ name: "foo" });
39
40
 
40
- it("should create and delete document", async () => {
41
- const createdDoc = await repo.create<{ name: string }>({ name: "bar" });
41
+ const doc = await repo.getById(insertedId);
42
42
 
43
- expect(createdDoc).toBeDefined();
44
- expect(createdDoc?._id).toBeDefined();
45
- expect(createdDoc?.name).toBe("bar");
43
+ expect(doc).toBeDefined();
44
+ expect(doc?.name).toBe("foo");
45
+ });
46
46
 
47
- const delCount = await repo.deleteById(createdDoc._id);
47
+ it("should create and delete document", async () => {
48
+ const createdDoc = await repo.create<{ name: string }>({ name: "bar" });
48
49
 
49
- expect(delCount).toBe(1);
50
- });
50
+ expect(createdDoc).toBeDefined();
51
+ expect(createdDoc?._id).toBeDefined();
52
+ expect(createdDoc?.name).toBe("bar");
51
53
 
52
- it("should update document", async () => {
53
- const createdDoc = await repo.create({ name: "bar" });
54
+ const delCount = await repo.deleteById(createdDoc._id);
54
55
 
55
- const updatedDoc = await repo.updateOne(createdDoc._id + "", {
56
- name: "foo",
56
+ expect(delCount).toBe(1);
57
57
  });
58
58
 
59
- expect(updatedDoc).toBeDefined();
60
- expect(updatedDoc.name).toBe("foo");
61
- });
59
+ it("should update document", async () => {
60
+ const createdDoc = await repo.create({ name: "bar" });
61
+
62
+ const updatedDoc = await repo.updateOne(createdDoc._id + "", {
63
+ name: "foo",
64
+ });
65
+
66
+ expect(updatedDoc).toBeDefined();
67
+ expect(updatedDoc.name).toBe("foo");
68
+ });
62
69
  });
package/src/FlinkApp.ts CHANGED
@@ -138,6 +138,11 @@ export interface FlinkOptions {
138
138
  */
139
139
  jsonOptions?: OptionsJson;
140
140
 
141
+ /**
142
+ * Optional: content-types that should be parsed as raw body, and passed as a Buffer object instead of json
143
+ */
144
+ rawContentTypes?: string | string[];
145
+
141
146
  scheduling?: {
142
147
  /**
143
148
  * If true, the scheduler will be enabled.
@@ -226,6 +231,7 @@ export class FlinkApp<C extends FlinkContext> {
226
231
  private corsOpts: FlinkOptions["cors"];
227
232
  private routingConfigured = false;
228
233
  private jsonOptions?: OptionsJson;
234
+ private rawContentTypes?: string[];
229
235
  private schedulingOptions?: FlinkOptions["scheduling"];
230
236
  private disableHttpServer = false;
231
237
 
@@ -248,6 +254,7 @@ export class FlinkApp<C extends FlinkContext> {
248
254
  this.onDbConnection = opts.onDbConnection;
249
255
  this.plugins = opts.plugins || [];
250
256
  this.corsOpts = { ...defaultCorsOptions, ...opts.cors };
257
+ this.rawContentTypes = Array.isArray(opts.rawContentTypes) ? opts.rawContentTypes : (typeof opts.rawContentTypes === 'string' ? [opts.rawContentTypes] : undefined);
251
258
  this.auth = opts.auth;
252
259
  this.jsonOptions = opts.jsonOptions || { limit: "1mb" };
253
260
  this.schedulingOptions = opts.scheduling;
@@ -289,6 +296,13 @@ export class FlinkApp<C extends FlinkContext> {
289
296
  if (!this.disableHttpServer) {
290
297
  this.expressApp = express();
291
298
  this.expressApp.use(cors(this.corsOpts));
299
+
300
+ if (this.rawContentTypes) {
301
+ for (const type of this.rawContentTypes) {
302
+ this.expressApp.use(express.raw({ type }));
303
+ }
304
+ }
305
+
292
306
  this.expressApp.use(bodyParser.json(this.jsonOptions));
293
307
 
294
308
  if (this.accessLog.enabled) {
package/src/FlinkRepo.ts CHANGED
@@ -1,66 +1,80 @@
1
- import { Collection, Db, ObjectID } from "mongodb";
1
+ import { Collection, Db, ObjectId } from "mongodb";
2
2
  import { FlinkContext } from "./FlinkContext";
3
3
 
4
4
  export abstract class FlinkRepo<C extends FlinkContext, Model = any> {
5
- collection: Collection;
6
-
7
- private _ctx?: C;
8
-
9
- set ctx(ctx: FlinkContext) {
10
- this._ctx = ctx as C;
11
- }
12
-
13
- get ctx() {
14
- if (!this._ctx) throw new Error("Missing FlinkContext");
15
- return this._ctx;
16
- }
17
-
18
- constructor(private collectionName: string, private db: Db) {
19
- this.collection = db.collection(this.collectionName);
20
- }
21
-
22
- async findAll(query = {}): Promise<Model[]> {
23
- return this.collection.find(query).toArray();
24
- }
25
-
26
- async getById(id: string): Promise<Model | null> {
27
- return this.collection.findOne({ _id: new ObjectID(id) });
28
- }
29
-
30
- async getOne(query = {}): Promise<Model | null> {
31
- return this.collection.findOne(query);
32
- }
33
-
34
- async create<C = Omit<Model, "_id">>(model: C): Promise<C & { _id: string }> {
35
- const { ops } = await this.collection.insertOne(model);
36
- return ops[0];
37
- }
38
-
39
- async updateOne<U = Partial<Model>>(id: string, model: U): Promise<Model> {
40
- const oid = new ObjectID(id);
41
-
42
- await this.collection.updateOne(
43
- {
44
- _id: oid,
45
- },
46
- {
47
- $set: model,
48
- }
49
- );
50
- return this.collection.findOne({ _id: oid });
51
- }
52
-
53
- async updateMany<U = Partial<Model>>(query: any, model: U): Promise<number> {
54
- const { modifiedCount } = await this.collection.updateMany(query, {
55
- $set: model,
56
- });
57
- return modifiedCount;
58
- }
59
-
60
- async deleteById(id: string): Promise<number> {
61
- const { deletedCount } = await this.collection.deleteOne({
62
- _id: new ObjectID(id),
63
- });
64
- return deletedCount || 0;
65
- }
5
+ collection: Collection;
6
+
7
+ private _ctx?: C;
8
+
9
+ set ctx(ctx: FlinkContext) {
10
+ this._ctx = ctx as C;
11
+ }
12
+
13
+ get ctx() {
14
+ if (!this._ctx) throw new Error("Missing FlinkContext");
15
+ return this._ctx;
16
+ }
17
+
18
+ constructor(private collectionName: string, private db: Db) {
19
+ this.collection = db.collection(this.collectionName);
20
+ }
21
+
22
+ async findAll(query = {}): Promise<Model[]> {
23
+ return this.collection.find(query).toArray();
24
+ }
25
+
26
+ async getById(id: string): Promise<Model | null> {
27
+ return this.collection.findOne({ _id: this.buildId(id) });
28
+ }
29
+
30
+ async getOne(query = {}): Promise<Model | null> {
31
+ return this.collection.findOne(query);
32
+ }
33
+
34
+ async create<C = Omit<Model, "_id">>(model: C): Promise<C & { _id: string }> {
35
+ const { ops } = await this.collection.insertOne(model);
36
+ return ops[0];
37
+ }
38
+
39
+ async updateOne<U = Partial<Model>>(id: string, model: U): Promise<Model> {
40
+ const oid = this.buildId(id);
41
+
42
+ await this.collection.updateOne(
43
+ {
44
+ _id: oid,
45
+ },
46
+ {
47
+ $set: model,
48
+ }
49
+ );
50
+ return this.collection.findOne({ _id: oid });
51
+ }
52
+
53
+ async updateMany<U = Partial<Model>>(query: any, model: U): Promise<number> {
54
+ const { modifiedCount } = await this.collection.updateMany(query, {
55
+ $set: model,
56
+ });
57
+ return modifiedCount;
58
+ }
59
+
60
+ async deleteById(id: string): Promise<number> {
61
+ const { deletedCount } = await this.collection.deleteOne({
62
+ _id: this.buildId(id),
63
+ });
64
+ return deletedCount || 0;
65
+ }
66
+
67
+ private buildId(id: string | ObjectId) {
68
+ let oid: ObjectId | string;
69
+
70
+ if (typeof id === "string") {
71
+ oid = new ObjectId(id);
72
+ } else if (id instanceof ObjectId) {
73
+ oid = id;
74
+ } else {
75
+ throw new Error("Invalid id type");
76
+ }
77
+
78
+ return oid;
79
+ }
66
80
  }