odata-v4-server
Version:
OData V4 Server
302 lines (267 loc) • 9.77 kB
text/typescript
import * as fs from "fs";
import * as path from "path";
import { Writable } from "stream";
import { MongoClient, Db, ObjectID } from "mongodb";
import { createQuery, createFilter } from "odata-v4-mongodb";
import { Readable, PassThrough } from "stream";
import { ODataServer, ODataController, Edm, odata, ODataStream, ODataQuery, ODataHttpContext } from "../lib";
import { Category, Product } from "./model";
import { createMetadataJSON } from "../lib/metadata";
const mongodb = async function():Promise<Db>{
return (await MongoClient.connect("mongodb://localhost:27017/odataserver")).db();
};
const delay = async function(ms:number):Promise<any>{
return new Promise(resolve => setTimeout(resolve, ms));
};
.type(Product)
class ProductsController extends ODataController{
/*@odata.GET
*find(@odata.query query:ODataQuery, @odata.stream stream:Writable):any{
let db:Db = yield mongodb();
let mongodbQuery = createQuery(query);
if (typeof mongodbQuery.query._id == "string") mongodbQuery.query._id = new ObjectID(mongodbQuery.query._id);
if (typeof mongodbQuery.query.CategoryId == "string") mongodbQuery.query.CategoryId = new ObjectID(mongodbQuery.query.CategoryId);
return db.collection("Products")
.find(
mongodbQuery.query,
mongodbQuery.projection,
mongodbQuery.skip,
mongodbQuery.limit
).stream().pipe(stream);
}*/
// example using generator with mongodb .next() and passing entity data into OData stream
.GET
*find(.query query:ODataQuery, .stream stream:Writable){
let db:Db = yield mongodb();
let mongodbQuery = createQuery(query);
if (typeof mongodbQuery.query._id == "string") mongodbQuery.query._id = new ObjectID(mongodbQuery.query._id);
if (typeof mongodbQuery.query.CategoryId == "string") mongodbQuery.query.CategoryId = new ObjectID(mongodbQuery.query.CategoryId);
let cursor = db.collection("Products")
.find(
mongodbQuery.query, {
projection: mongodbQuery.projection,
skip: mongodbQuery.skip,
limit: mongodbQuery.limit
}
);
let item = yield cursor.next();
while (item){
stream.write(item);
item = yield cursor.next();
}
stream.end();
}
.GET
*findOne(.key() key:string, .query query:ODataQuery){
let db:Db = yield mongodb();
let mongodbQuery = createQuery(query);
return db.collection("Products").findOne({ _id: new ObjectID(key) }, {
fields: mongodbQuery.projection
});
}
.POST
async insert(.body data:any){
let db = await mongodb();
if (data.CategoryId) data.CategoryId = new ObjectID(data.CategoryId);
return await db.collection("Products").insert(data).then((result) => {
data._id = result.insertedId;
return data;
});
}
}
.type(Category)
class CategoriesController extends ODataController{
.GET
*find(.query query:ODataQuery):any{
let db:Db = yield mongodb();
let mongodbQuery = createQuery(query);
if (typeof mongodbQuery.query._id == "string") mongodbQuery.query._id = new ObjectID(mongodbQuery.query._id);
let cursor = db.collection("Categories")
.find(
mongodbQuery.query, {
projection: mongodbQuery.projection,
skip: mongodbQuery.skip,
limit: mongodbQuery.limit
}
);
let result = yield cursor.toArray();
result.inlinecount = yield cursor.count(false);
return result;
}
.GET
*findOne(.key() key:string, .query query:ODataQuery){
let db:Db = yield mongodb();
let mongodbQuery = createQuery(query);
return db.collection("Categories").findOne({ _id: new ObjectID(key) }, {
fields: mongodbQuery.projection
});
}
}
enum Genre{
Unknown,
Pop,
Rock,
Metal,
Classic
}
.MediaEntity("audio/mp3")
class Music extends PassThrough{
.Key
.Computed
.TypeDefinition(ObjectID)
//@Edm.Int32
Id:ObjectID
.String
Artist:string
.String
Title:string
.EnumType(Genre)
Genre:Genre
.TypeDefinition(ObjectID)
uid:ObjectID
}
.namespace("NorthwindTypes")
class NorthwindTypes extends Edm.ContainerBase{
.Flags
.Int64
.Serialize(value => `NorthwindTypes.Genre2'${value}'`)
Genre2 = Genre
.String
.URLDeserialize((value:string) => new Promise(resolve => setTimeout(_ => resolve(new ObjectID(value)), 1000)))
.Deserialize(value => new ObjectID(value))
ObjectID2 = ObjectID
Music2 = Music
}
.type(Music)
.container("Media")
class MusicController extends ODataController{
.GET
find(.filter filter:ODataQuery, .query query:ODataQuery){
console.log(JSON.stringify(createQuery(query).query, null, 2), JSON.stringify(createFilter(filter), null, 2));
let music = new Music();
music.Id = new ObjectID;
music.Artist = "Dream Theater";
music.Title = "Six degrees of inner turbulence";
music.Genre = Genre.Metal;
music.uid = new ObjectID();
return [music];
}
.GET
findOne(.key() _:number){
let music = new Music();
music.Id = new ObjectID;
music.Artist = "Dream Theater";
music.Title = "Six degrees of inner turbulence";
music.Genre = Genre.Metal;
music.uid = new ObjectID();
return music;
}
.POST
insert(.body body: Music){
body.Id = new ObjectID();
console.log(body);
return body;
}
.GET.$value
mp3(.key _:number, .context context:ODataHttpContext){
let file = fs.createReadStream("tmp.mp3");
return new Promise((resolve, reject) => {
file.on("open", () => {
context.response.on("finish", () => {
file.close();
});
resolve(file);
}).on("error", reject);
});
}
.POST.$value
post(.key _:number, .body upload:Readable){
let file = fs.createWriteStream("tmp.mp3");
return new Promise((resolve, reject) => {
file.on('open', () => {
upload.pipe(file);
}).on('error', reject);
upload.on('end', resolve);
});
}
}
class ImageMember{
.String
value:string
}
.OpenType
class Image{
.Key
.Computed
.Int32
Id:number
.String
Filename:string
.Collection(Edm.ComplexType(ImageMember))
Members:ImageMember[]
.Stream("image/png")
Data:ODataStream
.Stream("image/png")
Data2:ODataStream
}
.type(Image)
.container("Media")
class ImagesController extends ODataController{
.GET
images(.key id:number){
let image = new Image();
image.Id = id;
image.Filename = "tmp.png";
(<any>image).mm = [[1,2],[3,4]];
return image;
}
.GET("Members")
*getMembers(.key _:number, .stream stream:Writable){
for (let i = 0; i < 10; i++){
stream.write({ value: `Member #${i}` });
yield delay(1);
}
stream.end();
}
.GET("Data")
.GET("Data2").$value
getData(.key _:number, .context context:ODataHttpContext, .result result: Image){
return new ODataStream(fs.createReadStream(result.Filename)).pipe(context.response);
}
.POST("Data")
.POST("Data2").$value
postData(.key _:number, .body data:Readable, .result result: Image){
return new ODataStream(fs.createWriteStream(result.Filename)).write(data);
}
}
.OpenType
class PlainObject{}
.Container(NorthwindTypes)
.controller(ProductsController, true)
.controller(CategoriesController, true)
.controller(MusicController, true)
.controller(ImagesController, true)
class StreamServer extends ODataServer{
.TypeDefinition(ObjectID)
.FunctionImport
objid(.TypeDefinition(ObjectID) v:ObjectID){
return v.toHexString();
}
.FunctionImport(Edm.String)
stringify(.EntityType(PlainObject) obj:any):string {
return JSON.stringify(obj);
}
.container("almafa")
.FunctionImport(Edm.Stream)
async Fetch(.String filename:string, .stream stream:Writable, .context context:any){
let file = fs.createReadStream(filename);
return file.on("open", () => {
context.response.contentType(path.extname(filename));
file.pipe(stream);
});
}
}
//console.dir(createMetadataJSON(StreamServer).dataServices.schema[0]["function"][1].parameter);
//console.log(createMetadataJSON(StreamServer).dataServices.schema[0].entityType[2]);
//console.log(StreamServer.$metadata().edmx.dataServices.schemas[0].typeDefinitions);
StreamServer.create("/odata", 3000);