Daruk配合sqlite,typeorm的TypeScript编写体验

核心提示上周五写了一篇Daruk文章,里面相关的例子代码只有一个简单的hello world,周末花了点时间写了一个简易的comments web demo,带大家实际感受一下,Daruk编写一个web站点的体验。全部代码可见Daruk源码的exa

上周五写了一篇Daruk文章,里面相关的例子代码只有一个简单的hello world,周末花了点时间写了一个简易的comments web demo,带大家实际感受一下,Daruk编写一个web站点的体验。全部代码可见Daruk源码的example下的02-comments目录:

首先,要编写一个这里我们不使用脚手架工具,从零开始写一个daruk项目要怎么开始呢?$ npm init先在本地目录初始化安装项目,使用npm init命令初始化package脚本。

然后我们使用yarn 安装所需要的依赖:$ yarn add daruk koa-ejs koa-bodyparser koa-favicon sqlite3 typeorm$ yarn add --dev ts-nodets-node为dev模式下需要的依赖,不需要安装在dependencies目录。

然后我们增加npm script 方便我们调试:"script":{ dev:"TS_NODE_FILES=true NODE_ENV=dev ts-node index.ts"}这段算是启动代码,在调试的时候指定开发环境变量NODE_ENV为dev,入口未index.ts,因为项目中我们会编写d.ts文件所以加上TS_NODE_FILES变量。然后我们创建目录和文件如下:── controllers│ ├── comments.ts│ └── index.ts├── daruk.config.ts├── database│ └── comments.db├── entity│ └── comments.ts├── glues│ └── connection.ts├── index.ts├── package.json├── public│ └── favicon.png├── services│ └── CommentsModel├── tsconfig.json├── typings│ ├── context.d.ts│ ├── glues.d.ts│ └── service.d.ts├── view│ ├── index.tpl│ └── layout.tpl我下面来一一介绍一下:首先是tsconfig.json文件,用来定义ts的配置项,简单来说就是:

{

"compileOnSave"

:

true

,

"compilerOptions"

:

{

"target"

:

"es2017"

,

"module"

:

"commonjs"

,

"sourceMap"

:

true

,

"outDir"

:

"./build"

,

"rootDir"

:

"./"

,

"removeComments"

:

true

,

"noImplicitAny"

:

true

,

"experimentalDecorators"

:

true

,

"emitDecoratormetadata"

:

true

},

"exclude"

:

[

"node_modules"

],

"include"

:

[

"./typings*.ts"

]

}

简单说一下,include要设置一下,自动读取项目里的types下的声明文件,然后就是把装饰器选项打开,experimentalDecorators和emitDecoratormetadata,就可以继续下一步了。其他选项的含义看注释或者官网文档自行了解。

到了这里,基本上是把ts的运行环境和项目初始化搞定了,下面我们开始编写项目:首先创建对应所需要的几个目录:controllers为路由所在目录,文件名就是path,使用装饰器定义子path,比如首页的路由是这么写的:

import

{

baseController

,

Context

,

get

}

from

'daruk'

;

export

default

class

Index

extends

baseController

{

@

get

public

async

index

{

let

{

page

=

1

,

limit

=

5

}

=

ctx

.

query

;

page

=

page

-

1

;

let

[

comments

,

counts

]

=

await

ctx

.

service

.

CommentsModel

.

findAllAndCount

;

await

ctx

.

render

;

}

}

我们首先引入baseController,然后导出我们的Index Controller类,定义了一个get方法,然后我们从query上获取了page,limit参数,默认值设置一下即可,这里只是demo演示。

然后我们使用ctx.service.CommentsModel这个service类上findAllAndCount方法,把page和limit传入,返回所有评论和评论总数。然后我们渲染index.tpl,传入controller里获取的这些值。非常简单,下面我们就从这个入口文件分别说起,其他的部分是如何设置的,首先是看一下service的那个model类是如何挂载在ctx上的。

我们创建对应的services目录,然后创建子目录CommentsModel目录,然后创建index.ts文件,Daruk都是按照目录路径自动挂载的,这在Daruk里是一种约束和默认配置。然后我们看一下service下的model类如何来定义:

import

{

baseService

,

Context

}

from

'daruk'

;

import

Comments

from

'../../entity/comments'

;

export

default

class

CommentsModel

extends

baseService

{

public

constructor

{

super

;

}

public

async

findAllAndCount

{

let

connection

=

await

this

.

ctx

.

glue

.

connection

;

let

comments

=

await

connection

.

getRepository

.

findAndCount

;

return

comments

;

}

public

async

insert

{

let

connection

=

await

this

.

ctx

.

glue

.

connection

;

let

EntityManager

=

connection

.

manager

;

let

comments

=

await

EntityManager

.

create

;

return

await

EntityManager

.

save

;

}

}

首先引入baseService类并继承,然后导出我们的CommentModel类,定义了2个对应的方法,findAllAndCount还有insert方法。

我们先说findAllAndCount方法,我们先定义了2个参数,配置了默认参数,然后我们获取数据库连接,数据库连接保存在ctx.glue.connection上,这个后边再说,glue的写法,我们只需要知道,这里我们拿到了一个数据库连接实例,然后我们使用typeorm的connection的getRepository方法获取Comments表,然后我们执行findAndCount方法,传入对应的skip跳页,take截取数,order排序,然后返回查找结果。

这里都是typeorm的对应方法,不多做介绍,可以去学习相关的typeorm文档知识,然后insert方法就更简单了。我们同样获得数据库连接,这次是EntityManager对象,然后创建一个新的Comment元素对象,传入初始值,name和content,最后调用save方法保存。嗯,正常来说,无论开发什么网站,model层在Daruk里就是这样的写法了,我们尽量不引入太多其他高级概念比如框架装饰器,这次主要说一下各个目录得功能作用。

然后我们看一下glue目录是怎么用的,glue顾名思义,放置是与请求无关的实例类,services在文档里写的很清楚,每次请求都会重新实例化,请求结束会被销毁,适合编写围绕ctx的抽象功能,数据库连接不是每次都建立,所以放置到gule里非常合适。glues目录下我们创建一个connection.ts文件:

import

{

Daruk

}

from

'daruk'

;

import

{

join

}

from

'path'

;

import

{

createConnection

}

from

'typeorm'

;

import

Comments

from

'../entity/comments'

;

export

default

async

function

{

const

connection

=

await

createConnection

,

entities

:

[

Comments

],

synchronize

:

true

,

logging

:

process

.

env

.

NODE_ENV

===

'dev'

});

return

connection

;

}

这个文件也比较简单,我们引入Comments model,这是typeorm的概念,代表数据库里的comments表模型,然后我们导出一个函数,函数返回值是typeorm创建的connection,我们的数据库选用的是sqlite3,所以参数都是sqlite3的参数,数据库保存在database目录下。那么通过glue和service,controller大家应该知道如何做关联了。我们下面看一下entity目录下的comment model是怎么定义的:

import

{

Column

,

Entity

,

PrimaryGeneratedColumn

}

from

'typeorm'

;

@

Entity

class

Comments

{

@

PrimaryGeneratedColumn

public

comments_id

:

number

;

@

Column

public

name

:

string

;

@

Column

public

content

:

string

;

}

export

default

Comments

;

这里的model都是基于typeorm的api来写的,typeorm是基于ts的一款开源orm,非常适合在ts项目中使用,这里简单来说创建的表结构就是3个column,其中comments_id是一个自增key。

然后我们看一下我们comments.ts这个controller是怎么写的:

import

{

baseController

,

Context

,

post

}

from

'daruk'

;

export

default

class

Comments

extends

baseController

{

@

post

public

async

index

{

let

{

name

,

content

}

=

ctx

.

request

.

body

;

await

ctx

.

service

.

CommentsModel

.

insert

;

ctx

.

redirect

;

await

next

;

}

}

这里和index不同的是调用完model的insert方法后,我们使用ctx.redirect调回了首页。这里和koa2的开发方式是一致的,拿到的ctx就是koa里的ctx。基本上到这里已经快结束了,最后我说一下view部分的设置是如何实现的,要说这个部分,就要看一下这个文件,daruk.config.ts,这个文件可以用可编程的方式来描述Daruk的gule,middleware,utils,service等等的一个配置文件,如果存在,它是会被自动读取的,不多说直接看下内容:

import

{

Daruk

}

from

'daruk'

;

import

{

join

}

from

'path'

;

interface

Middleware

{

[

key

:

string

]

:

=>

any

;

}

interface

DarukConfig

{

middlewareOrder

:

string

[];

middleware

:

Middleware

;

}

export

default

function

{

const

globalConfig

:

DarukConfig

=

{

middlewareOrder

:

[

'koa-ejs'

,

'koa-favicon'

,

'koa-bodyparser'

],

middleware

:

{

'koa-favicon'

{

return

mid

;

},

// https://github.com/koajs/ejs

'koa-ejs'

{

mid

,

viewExt

:

'tpl'

});

return

false

;

},

// https://github.com/koajs/bodyparser

'koa-bodyparser'

{

return

mid

;

}

}

};

return

globalConfig

;

}

这个daruk.config.ts文件导出一个函数,函数返回值就是对应的配置文件,这里就只用到了2个options,一个是middlewareOrder,用来描述中间件调用顺序的,一个就是middleware对象,用来配置middleware的。从代码中可以看到我们使用了koa-favicon,在对应回调里我们设置了favicon的地址,然后我们配置koa-ejs,定义了一些设置和view模板目录,最后是koa-bodyparser,用来获取post请求上的request.body.通过daruk.config.ts文件,我们把所有的中间件配置和挂载统一到了一个配置项中,非常方便和灵活,当然自己定义的middleware这里没有示例,我之后会专门讲Daruk的middware的用法,这里只是演示全局中间件的配置和调用方法。

最后我们再编写我们的入口启动文件,根目录的index.ts:

import

{

Daruk

}

from

'daruk'

;

const

port

=

3000

;

const

myApp

=

new

Daruk

;

myApp

.

run

;

和helloworld差不多,就不介绍了,debug是控制log开关的,在dev模式下打印的log会更美观。成果就是这个样子的,view层模板就不贴了,不是重要部分,大家可以直接看源代码,就是ejs。这是typeorm上的方法,通过glue.connection拿到的提示,说明类型没有丢失。
 
友情链接
鄂ICP备19019357号-22