背景

树形结构是一种常用的存储查询模型,比如后台菜单或评论列表,展开就是一棵树,对于数据库的表来讲,意味着自引用,即有一个外键字段关联本表的主键,该外键字段一般称为parent_id,由该字段串联起整颗树的结构,在数据量不大的场景中,单纯一个parent_id即可胜任树形数据的查询,只需对全表数据循环遍历组装,这种方案在前者后台菜单中比较常用

当数据超过一定量级,一次性load全部数据并循环遍历对于io和cpu都是很大的负担也不现实,此时一般增加辅助字段来提升查询性能(空间换时间),以及满足更多样性的查询需求。这里只介绍一种常用的方案-path,类似于unix的文件夹层级,该字段存储从根节点到该节点的整条路径,比如100.120.200.:代表这棵树根节点为100,该节点为200,该节点的父节点为120,最大的好处是比单纯的parent_id更容易获取任意节点的所有子节点

很多orm都内置了树形模型方案,包括typeorm,具体可查看文档Tree Entities,而Materialized Path就是上述path方案的实现,开箱即用

问题

不同场景有不同的方案需求,我们限定当前的需求是评论列表,结合当前各大平台如知乎的交互方案,更细化的需求是二级评论列表(非完整树形),第一层为所有的一级评论,一级评论分页加载所有的子评论

继续看typeorm提供的查询方案,有几个相关的方法:findTreesfindRootsfindDescendants、和findDescendantsTree

  • findTrees:一次性返回所有的评论树
  • findRoots:一次性返回所有的根节点
  • findDescendants/findDescendantsTree:返回一棵树
    阅读全文 »

上题

先上前菜看段代码,思考以下几个问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# test.ts
class Thing {
born = () => {
console.log("time to born");
};

die() {
console.log("time to die");
}
}

class Animal extends Thing {
name: string;
constructor(name = "dog") {
super();
this.name = name;
}

eat = () => {
console.log("eat");
};

say() {
console.log(`Hi, i'm ${this.name}`);
}
}

const cat = new Animal("cat");
const dog = new Thing();

以下几个的值分别是什么

  1. Object.getOwnPropertyNames(cat)
  2. Object.getOwnPropertyNames(dog)
  3. Object.getOwnPropertyNames(Object.getPrototypeOf(cat))
  4. Object.getOwnPropertyNames(Object.getPrototypeOf(dog))
  5. Object.getOwnPropertyNames(Animal)
  6. Object.getOwnPropertyNames(Thing)
    阅读全文 »

背景

nest官方未提供自定义命令的模块,所以出现很多功能丰富的第三方库,比如的有nestjs-console(基于commande)、nestjs-command(基于yargs),两者都提供了完善的命令行工具所需配置,引入项目及使用也很方便,但都不支持批量注册命令,每个命令的注册都要提供完整的配置信息,对于某些场景可能不是特别合适(比如偷懒),所以奔着学习的目的新开一个项目实现缺失的功能

开发

整个项目功能非常简单,逻辑也很清晰,主要有以下三点:

  1. 遍历出nest所有Moduleproviders,对使用了指定装饰器的provider及其属性做处理
  2. 将处理结果组装为合法的yargs命令,并且注册至yargs
  3. 提供entrypoint,用于上述步骤1和2及命令的执行

具体实现可以在nest-command项目中查看

使用

项目提供了@Command@Commands@OriginYargsCommand三个装饰器,分别用于单个命令、多个命令及原生yargs命令的注册.

阅读全文 »

十万个为什么

nest库是什么?nest是一个typescript构建的node框架,那nest库可以理解为依赖nest框架的node库?node是一个javascript服务端的运行环境,那又要怎样用typescript编写javascript库呢?做为一只从其他语言(js几乎零基础只会简单的jQuery)转来学习nest的菜鸟刚开始总会在某些时刻冷不丁得被这些概念绕的云里雾里,不过是因为直接跨过jsnodets直接啃nest的原因,底层建筑不牢固直接搬砖终究是雾里看花,而从零手撸一个nest库不妨可以视为一个敲门砖,可以带我们看一探js世界的冰山一角.

撸起袖子开干

给它一个家

nest库终究也是一个独立的项目,和其他开源库一样我们使用github来做版本管理,新建一个空白仓库clone到本地.

1
2
$: git clone https://github.com/tashuo/nestjs-config
$: cd nestjs-config

给它一支指挥棒

npm is the world’s largest software registry. Open source developers from every continent use npm to share and borrow packages, and many organizations use npm to manage private development as well.

阅读全文 »

Nestjs websocket开发记录

官方文档介绍的比较详细了,但实际开发过程中还是遇到了不少问题,在此做一下记录.

背景知识

websocket

https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API

流行的websocket库

ws

socket.io

Nest配套

In Nest, a gateway is simply a class annotated with @WebSocketGateway() decorator. Technically, gateways are platform-agnostic which makes them compatible with any WebSockets library once an adapter is created. There are two WS platforms supported out-of-the-box: socket.io and ws.

nest提供了gateway的概念,gateway与平台无关,底层可以适配任何websocket库,此处选用更为流行的socket.io做为示例,而且项目切换驱动的代码改动非常小,即便后面要改为ws也没有太大负担,架构设计甚是优雅.

开发

安装依赖

1
$ pnpm i --save @nestjs/websockets @nestjs/platform-socket.io socket.io

使用ws库:

1
$ pnpm i --save @nestjs/websockets @nestjs/platform-ws ws
阅读全文 »

背景

前段时间用flarum搭了个论坛,由于docker设置mysql端口对外开放且密码很简单,不出意外中招了:) 一大早有群友找上来说网站又打不开,我收住了即将第五十三次劝她换掉e家宽的冲动,打开网页一看事情没那么简单~

中招

LGKvq.png

错误日志:这他娘的库子都没了:)
LGoEN.png

阅读全文 »

背景

之前博客许久未打理,本地的node环境和hexo版本也比较陈旧,删除了github旧仓库重新跑了一遍,做下记录以便日后参考

参考文档

hexo文档

next主题文档

流程

  1. 安装hexo及项目初始化

    1
    2
    3
    $: npm install -g hexo-cli # 安装hexo

    $: hexo init my_project # 初始化项目
  2. 项目配置

    配置

  3. 安装next主题

    Getting Started

    此处使用git方式下载的包在生成静态文件时index.html中包含模板标签,访问有问题,暂时没找到原因,所以使用了npm方式安装:

    1
    2
    3
    $: cd my_project && npm install hexo-theme-next # 安装next主题
    $: cp -rp node_modules/hexo-theme-next themes/next # 此处将npm包拷贝到项目的themes目录,方便主题配置文件的版本管理
    $: npm uninstall hexo-theme-next
    阅读全文 »

连接池

hyperf/database 组件是基于 illuminate/database 衍生出来的组件,我们对它进行了一些改造,从设计上是允许用于其它 PHP-FPM 框架或基于 Swoole 的框架中的,而在 Hyperf 里就需要提一下 hyperf/db-connection 组件,它基于 hyperf/pool 实现了数据库连接池并对模型进行了新的抽象,以它作为桥梁,Hyperf 才能把数据库组件及事件组件接入进来。

实现

Hyperf的db使用有两种方式,是否走ORM,ORM会对db查询及响应做多一层封装,底层最终也是通过connection 发起db请求。

阅读全文 »

背景

在前后端分离的应用中,需要使用CORS完成跨域访问。在CORS中发送 非简单请求时,前端会发一个请求方式为OPTIONS的预请求,前端只有收到服务器对这个OPTIONS请求的正确响应,才会发送正常的请求,否则将抛出跨域相关的错误。

跨域

可实现跨域的方式
  • JSONP
  • CORS
  • Flash
  • 服务器中转

比较常用的是 JSONPCORS,而后者相对前者来说有更方便实用:

  1. JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
  2. 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。

此文暂不介绍jsonp

CORS

CORS是一种网络浏览器的技术规范,它为Web服务器定义了一种方式,允许网页从不同的域访问其资源。而这种访问是被同源策略所禁止的。CORS系统定义了一种浏览器和服务器交互的方式来确定是否允许跨域请求。
使用 CORS的方式非常简单,但是需要同时对前端和服务器端做相应处理。

客户端使用XmlHttpRequest发起Ajax请求,当前绝大部分浏览器已经支持CORS方式,且主流浏览器均提供了对跨域资源共享的支持。

如上所述,接着只需在服务端配置可允许跨域的header即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php # TestController.php
class TestController
{
public function __construct()
{
// 跨域头
header('Access-Control-Allow-Origin: *');
}

public function test()
{
echo 'test';
}
}

阅读全文 »

翻译自 https://gobyexample.com/

Go by Example

Go is an open source programming language designed for building simple, fast, and reliable software.

Go by Example is a hands-on introduction to Go using annotated example programs. Check out the first example or browse the full list below.

Go by Example: Sorting

golang的sort包可以对内置类型和用户定义的类型进行排序操作,接下来我们先看下内置类型。

阅读全文 »