diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 4ca50a19..74f2fdf0 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -10,6 +10,67 @@ on: branches: [ master ] jobs: + test-postgresql-fs-nfs: + runs-on: ${{ matrix.os }} + + services: + # https://docs.github.com/en/actions/use-cases-and-examples/using-containerized-services/creating-postgresql-service-containers + # Label used to access the service container + postgres: + # Docker Hub image + image: postgres + # Provide the password for postgres + env: + POSTGRES_PASSWORD: postgres + # Set health checks to wait until postgres has started + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + # Maps tcp port 5432 on service container to the host + - 5432:5432 + redis: + # https://docs.github.com/en/actions/using-containerized-services/about-service-containers#example-mapping-redis-ports + image: redis + ports: + # Opens tcp port 6379 on the host and service container + - 6379:6379 + + strategy: + fail-fast: false + matrix: + node-version: [18.20.0, 18, 20, 22] + os: [ubuntu-latest] + + steps: + - name: Checkout Git Source + uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Install Dependencies + run: npm i -g npminstall && npminstall + + - name: Continuous Integration + run: npm run ci:postgresql + env: + # The hostname used to communicate with the PostgreSQL service container + POSTGRES_HOST: localhost + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + # The default PostgreSQL port + POSTGRES_PORT: 5432 + + - name: Code Coverage + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + test-mysql57-fs-nfs: runs-on: ${{ matrix.os }} @@ -37,10 +98,10 @@ jobs: steps: - name: Checkout Git Source - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -88,10 +149,10 @@ jobs: steps: - name: Checkout Git Source - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} diff --git a/DEVELOPER.md b/DEVELOPER.md index 3c448851..0b9430b3 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -2,7 +2,7 @@ ## 环境初始化 -本项目的外部服务依赖有:MySQL 数据服务、Redis 缓存服务。 +本项目的外部服务依赖有:MySQL 数据库或 PostgreSQL 数据库、Redis 缓存服务。 可以通过 Docker 来快速启动本地开发环境: @@ -14,7 +14,7 @@ docker-compose up -d docker-compose down ``` -> 手动初始化依赖服务参见[文档](./docs/setup.md) +> 手动初始化依赖服务参见[本地开发环境 - MySQL](./docs/setup.md) 或 [本地开发环境 - PostgreSQL](./docs/setup-with-postgresql.md) ## 本地开发 @@ -24,11 +24,11 @@ docker-compose down npm install ``` -### 开发运行 +### 开发运行 - MySQL ```bash # 初始化数据库 -MYSQL_DATABASE=cnpmcore bash ./prepare-database.sh +CNPMCORE_DATABASE_NAME=cnpmcore bash ./prepare-database-mysql.sh # 启动 Web 服务 npm run dev @@ -37,12 +37,33 @@ npm run dev curl -v http://127.0.0.1:7001 ``` +### 开发运行 - PostgreSQL + +```bash +# 初始化数据库 +CNPMCORE_DATABASE_NAME=cnpmcore bash ./prepare-database-postgresql.sh + +# 启动 Web 服务 +npm run dev:postgresql + +# 访问 +curl -v http://127.0.0.1:7001 +``` + ### 单元测试 +MySQL + ```bash npm run test ``` +PostgreSQL + +```bash +npm run test:postgresql +``` + ## 项目结构 ```txt @@ -268,9 +289,9 @@ Repository 依赖 Model,然后被 Service 和 Controller 依赖 可能需要涉及3个地方的修改: -1. sql/*.sql -2. repository/model/*.ts -3. core/entity/*.ts +1. `sql/mysql/*.sql`, `sql/postgresql/*.sql` +2. `repository/model/*.ts` +3. `core/entity/*.ts` 目前还不会做 Model 到 SQL 的自动转换生成,核心原因有: diff --git a/Dockerfile b/Dockerfile index 28510d29..eb161ea3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18 +FROM node:20 # Create app directory WORKDIR /usr/src/app diff --git a/README.md b/README.md index 12f9974b..1c2bbcb7 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![CodeQL](https://github.com/cnpm/cnpmcore/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/cnpm/cnpmcore/actions/workflows/codeql-analysis.yml) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fcnpm%2Fcnpmcore.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fcnpm%2Fcnpmcore?ref=badge_shield) -Reimplementation based on [cnpmjs.org](https://github.com/cnpm/cnpmjs.org) with TypeScript. +Reimplement based on [cnpmjs.org](https://github.com/cnpm/cnpmjs.org) with TypeScript. ## Registry HTTP API @@ -23,19 +23,10 @@ See [INTEGRATE.md](INTEGRATE.md) [MIT](LICENSE) - - ## Contributors -|[
fengmk2](https://github.com/fengmk2)
|[
semantic-release-bot](https://github.com/semantic-release-bot)
|[
elrrrrrrr](https://github.com/elrrrrrrr)
|[
killagu](https://github.com/killagu)
|[
hezhengxu2018](https://github.com/hezhengxu2018)
|[
Beace](https://github.com/Beace)
| -| :---: | :---: | :---: | :---: | :---: | :---: | -|[
gemwuu](https://github.com/gemwuu)
|[
Zian502](https://github.com/Zian502)
|[
laibao101](https://github.com/laibao101)
|[
coolyuantao](https://github.com/coolyuantao)
|[
Wellaiyo](https://github.com/Wellaiyo)
|[
atian25](https://github.com/atian25)
| -|[
hljwkwm](https://github.com/hljwkwm)
|[
BlackHole1](https://github.com/BlackHole1)
|[
xiekw2010](https://github.com/xiekw2010)
|[
Zheaoli](https://github.com/Zheaoli)
|[
OpportunityLiu](https://github.com/OpportunityLiu)
|[
thonatos](https://github.com/thonatos)
| -|[
chilingling](https://github.com/chilingling)
|[
chenpx976](https://github.com/chenpx976)
|[
fossabot](https://github.com/fossabot)
|[
looksgood](https://github.com/looksgood)
|[
laoboxie](https://github.com/laoboxie)
|[
unbyte](https://github.com/unbyte)
| -[
wandergis](https://github.com/wandergis)
|[
windhc](https://github.com/windhc)
|[
yisibl](https://github.com/yisibl)
|[
vimplus](https://github.com/vimplus)
|[
feichao93](https://github.com/feichao93)
- -This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Fri May 17 2024 22:31:22 GMT+0800`. +[![Contributors](https://contrib.rocks/image?repo=cnpm/cnpmcore)](https://github.com/cnpm/cnpmcore/graphs/contributors) - +Made with [contributors-img](https://contrib.rocks). [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fcnpm%2Fcnpmcore.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fcnpm%2Fcnpmcore?ref=badge_large) diff --git a/app/core/service/PackageManagerService.ts b/app/core/service/PackageManagerService.ts index e2c12c4b..4451d0cf 100644 --- a/app/core/service/PackageManagerService.ts +++ b/app/core/service/PackageManagerService.ts @@ -10,6 +10,7 @@ import { BadRequestError, ForbiddenError, NotFoundError } from 'egg-errors'; import { RequireAtLeastOne } from 'type-fest'; import npa from 'npm-package-arg'; import semver from 'semver'; +import pMap from 'p-map'; import { calculateIntegrity, detectInstallScript, @@ -23,6 +24,7 @@ import { AbbreviatedPackageJSONType, AbbreviatedPackageManifestType, PackageJSON import { PackageVersionBlockRepository } from '../../repository/PackageVersionBlockRepository'; import { PackageVersionDownloadRepository } from '../../repository/PackageVersionDownloadRepository'; import { DistRepository } from '../../repository/DistRepository'; +import { isDuplicateKeyError } from '../../repository/util/ErrorUtil'; import { Package } from '../entity/Package'; import { PackageVersion } from '../entity/PackageVersion'; import { PackageVersionBlock } from '../entity/PackageVersionBlock'; @@ -47,7 +49,6 @@ import { BugVersion } from '../entity/BugVersion'; import { RegistryManagerService } from './RegistryManagerService'; import { Registry } from '../entity/Registry'; import { PackageVersionService } from './PackageVersionService'; -import pMap from 'p-map'; export interface PublishPackageCmd { // maintainer: Maintainer; @@ -271,7 +272,7 @@ export class PackageManagerService extends AbstractService { try { await this.packageRepository.createPackageVersion(pkgVersion); } catch (e) { - if (e.code === 'ER_DUP_ENTRY') { + if (isDuplicateKeyError(e)) { throw new ForbiddenError(`Can't modify pre-existing version: ${pkg.fullname}@${cmd.version}`); } throw e; diff --git a/app/core/service/PackageVersionFileService.ts b/app/core/service/PackageVersionFileService.ts index 84e8dd87..f02827fa 100644 --- a/app/core/service/PackageVersionFileService.ts +++ b/app/core/service/PackageVersionFileService.ts @@ -21,6 +21,7 @@ import { import { PackageVersionFileRepository } from '../../repository/PackageVersionFileRepository'; import { PackageVersionRepository } from '../../repository/PackageVersionRepository'; import { DistRepository } from '../../repository/DistRepository'; +import { isDuplicateKeyError } from '../../repository/util/ErrorUtil'; import { PackageVersionFile } from '../entity/PackageVersionFile'; import { PackageVersion } from '../entity/PackageVersion'; import { Package } from '../entity/Package'; @@ -272,7 +273,9 @@ export class PackageVersionFileService extends AbstractService { file.packageVersionFileId, dist.size, file.path); } catch (err) { // ignore Duplicate entry - if (err.code === 'ER_DUP_ENTRY') return file; + if (isDuplicateKeyError(err)) { + return file; + } throw err; } return file; diff --git a/app/port/config.ts b/app/port/config.ts index e87ba150..f8872e90 100644 --- a/app/port/config.ts +++ b/app/port/config.ts @@ -1,4 +1,5 @@ import { SyncDeleteMode, SyncMode, ChangesStreamMode } from '../common/constants'; +import { DATABASE_TYPE } from '../../config/database'; export { cnpmcoreConfig } from '../../config/config.default'; @@ -94,7 +95,7 @@ export type CnpmcoreConfig = { /** * white scope list */ - allowScopes: string [], + allowScopes: string[], /** * allow publish non-scope package, disable by default */ @@ -175,4 +176,11 @@ export type CnpmcoreConfig = { * strictly enforces/validates dependencies version when publish or sync */ strictValidatePackageDeps?: boolean, + + /** + * database config + */ + database: { + type: DATABASE_TYPE | string, + }, }; diff --git a/app/repository/PackageRepository.ts b/app/repository/PackageRepository.ts index 59ca134b..71cec497 100644 --- a/app/repository/PackageRepository.ts +++ b/app/repository/PackageRepository.ts @@ -18,6 +18,7 @@ import type { User as UserModel } from './model/User'; import { User as UserEntity } from '../core/entity/User'; import { AbstractRepository } from './AbstractRepository'; import { BugVersionPackages } from '../core/entity/BugVersion'; +import { DATABASE_TYPE } from '../../config/database'; export type PackageManifestType = Pick & { _id: string; @@ -406,18 +407,25 @@ export class PackageRepository extends AbstractRepository { return ModelConvertor.convertModelToEntity(model, this.PackageVersionManifest); } - private getCountSql(model: typeof Bone):string { - const { database } = this.config.orm; - const sql = ` - SELECT - TABLE_ROWS - FROM - information_schema.tables - WHERE - table_schema = '${database}' - AND table_name = '${model.table}' - `; - return sql; + private async getTotalCountByModel(model: typeof Bone): Promise { + if (this.config.cnpmcore.database.type === DATABASE_TYPE.MySQL) { + const { database } = this.config.orm as { database: string }; + const sql = ` + SELECT + TABLE_ROWS as table_rows + FROM + information_schema.tables + WHERE + table_schema = '${database}' + AND table_name = '${model.table}'; + `; + const result = await this.orm.client.query(sql); + return result.rows?.[0].table_rows as number; + } + const sql = `SELECT count(id) as total FROM ${model.table};`; + const result = await this.orm.client.query(sql); + const total = Number(result.rows?.[0].total); + return total; } public async queryTotal() { @@ -432,8 +440,7 @@ export class PackageRepository extends AbstractRepository { lastPackage = lastPkg.scope ? `${lastPkg.scope}/${lastPkg.name}` : lastPkg.name; // FIXME: id will be out of range number // 可能存在 id 增长不连续的情况,通过 count 查询 - const queryRes = await this.orm.client.query(this.getCountSql(PackageModel)); - packageCount = queryRes.rows?.[0].TABLE_ROWS as number; + packageCount = await this.getTotalCountByModel(PackageModel); } if (lastVersion) { @@ -442,8 +449,7 @@ export class PackageRepository extends AbstractRepository { const fullname = pkg.scope ? `${pkg.scope}/${pkg.name}` : pkg.name; lastPackageVersion = `${fullname}@${lastVersion.version}`; } - const queryRes = await this.orm.client.query(this.getCountSql(PackageVersionModel)); - packageVersionCount = queryRes.rows?.[0].TABLE_ROWS as number; + packageVersionCount = await this.getTotalCountByModel(PackageVersionModel); } return { packageCount, diff --git a/app/repository/TaskRepository.ts b/app/repository/TaskRepository.ts index a844ef14..227947b7 100644 --- a/app/repository/TaskRepository.ts +++ b/app/repository/TaskRepository.ts @@ -1,12 +1,13 @@ import { strict as assert } from 'node:assert'; +import { uniq } from 'lodash'; import { AccessLevel, SingletonProto, Inject } from '@eggjs/tegg'; import { ModelConvertor } from './util/ModelConvertor'; +import { isDuplicateKeyError } from './util/ErrorUtil'; import type { Task as TaskModel } from './model/Task'; import type { HistoryTask as HistoryTaskModel } from './model/HistoryTask'; -import { Task as TaskEntity, TaskUpdateCondition } from '../core/entity/Task'; import { AbstractRepository } from './AbstractRepository'; import { TaskType, TaskState } from '../../app/common/enum/Task'; -import { uniq } from 'lodash'; +import { Task as TaskEntity, TaskUpdateCondition } from '../core/entity/Task'; @SingletonProto({ accessLevel: AccessLevel.PUBLIC, @@ -28,7 +29,7 @@ export class TaskRepository extends AbstractRepository { await ModelConvertor.convertEntityToModel(task, this.Task); } catch (e) { e.message = '[TaskRepository] insert Task failed: ' + e.message; - if (e.code === 'ER_DUP_ENTRY') { + if (isDuplicateKeyError(e)) { this.logger.warn(e); const taskModel = await this.Task.findOne({ bizId: task.bizId }); // 覆盖 bizId 相同的 id 和 taskId diff --git a/app/repository/util/ErrorUtil.ts b/app/repository/util/ErrorUtil.ts new file mode 100644 index 00000000..7b2f924c --- /dev/null +++ b/app/repository/util/ErrorUtil.ts @@ -0,0 +1,10 @@ +export function isDuplicateKeyError(err: any) { + if (err.code === 'ER_DUP_ENTRY') { + return true; + } + if (err.message.includes('duplicate key value violates unique constraint')) { + // pg: duplicate key value violates unique constraint "tasks_uk_task_id" + // code: '23505' + return true; + } +} diff --git a/config/config.default.ts b/config/config.default.ts index 2cf7904a..d807ef38 100644 --- a/config/config.default.ts +++ b/config/config.default.ts @@ -5,7 +5,8 @@ import { EggAppConfig, PowerPartial } from 'egg'; import OSSClient from 'oss-cnpm'; import { patchAjv } from '../app/port/typebox'; import { ChangesStreamMode, NOT_IMPLEMENTED_PATH, SyncDeleteMode, SyncMode } from '../app/common/constants'; -import { CnpmcoreConfig } from '../app/port/config'; +import type { CnpmcoreConfig } from '../app/port/config'; +import { database } from './database'; export const cnpmcoreConfig: CnpmcoreConfig = { name: 'cnpm', @@ -60,6 +61,9 @@ export const cnpmcoreConfig: CnpmcoreConfig = { elasticsearchIndex: 'cnpmcore_packages', strictValidateTarballPkg: false, strictValidatePackageDeps: false, + database: { + type: database.type, + }, }; export default (appInfo: EggAppConfig) => { @@ -70,19 +74,17 @@ export default (appInfo: EggAppConfig) => { // override config from framework / plugin config.dataDir = process.env.CNPMCORE_DATA_DIR || join(appInfo.root, '.cnpmcore'); - config.orm = { - client: 'mysql2', - database: process.env.CNPMCORE_MYSQL_DATABASE || process.env.MYSQL_DATABASE || 'cnpmcore', - host: process.env.CNPMCORE_MYSQL_HOST || process.env.MYSQL_HOST || '127.0.0.1', - port: process.env.CNPMCORE_MYSQL_PORT || process.env.MYSQL_PORT || 3306, - user: process.env.CNPMCORE_MYSQL_USER || process.env.MYSQL_USER || 'root', - password: process.env.CNPMCORE_MYSQL_PASSWORD || process.env.MYSQL_PASSWORD, + ...database, + database: database.name ?? 'cnpmcore', charset: 'utf8mb4', logger: { // https://github.com/cyjake/leoric/blob/master/docs/zh/logging.md#logqueryerror // ignore query error logQueryError() {}, + // logQueryError(...args: any[]) { + // console.log(args); + // }, }, }; diff --git a/config/config.unittest.ts b/config/config.unittest.ts index 81425e4a..070884da 100644 --- a/config/config.unittest.ts +++ b/config/config.unittest.ts @@ -1,6 +1,7 @@ import { join } from 'path'; import { EggAppConfig, PowerPartial } from 'egg'; import Mock from '@elastic/elasticsearch-mock'; +import { database } from './database'; export const mockES = new Mock(); @@ -9,7 +10,7 @@ export default (appInfo: EggAppConfig) => { config.dataDir = join(appInfo.root, '.cnpmcore_unittest'); config.orm = { - database: process.env.MYSQL_DATABASE || 'cnpmcore_unittest', + database: database.name ?? 'cnpmcore_unittest', }; config.nfs = { diff --git a/config/database.ts b/config/database.ts new file mode 100644 index 00000000..bc6a61c9 --- /dev/null +++ b/config/database.ts @@ -0,0 +1,44 @@ +export enum DATABASE_TYPE { + MySQL = 'MySQL', + PostgreSQL = 'PostgreSQL', + SQLite = 'SQLite', +} + +const dbType = process.env.CNPMCORE_DATABASE_TYPE ?? DATABASE_TYPE.MySQL; +let dbName = process.env.CNPMCORE_DATABASE_NAME; +let dbHost = process.env.CNPMCORE_DATABASE_HOST; +let dbPort = process.env.CNPMCORE_DATABASE_PORT; +let dbUser = process.env.CNPMCORE_DATABASE_USER; +let dbPassword = process.env.CNPMCORE_DATABASE_PASSWORD; +let dialect = 'mysql'; +let dbClient = 'mysql2'; +if (dbType === DATABASE_TYPE.MySQL) { + // Compatible mysql configurations + dbName = dbName ?? process.env.CNPMCORE_MYSQL_DATABASE ?? process.env.MYSQL_DATABASE; + dbHost = dbHost ?? process.env.CNPMCORE_MYSQL_HOST ?? process.env.MYSQL_HOST ?? '127.0.0.1'; + dbPort = dbPort ?? process.env.CNPMCORE_MYSQL_PORT ?? process.env.MYSQL_PORT ?? '3306'; + dbUser = dbUser ?? process.env.CNPMCORE_MYSQL_USER ?? process.env.MYSQL_USER ?? 'root'; + dbPassword = dbPassword ?? process.env.CNPMCORE_MYSQL_PASSWORD ?? process.env.MYSQL_PASSWORD; +} else if (dbType === DATABASE_TYPE.PostgreSQL) { + dbClient = 'pg'; + dialect = 'postgres'; + dbHost = dbHost ?? process.env.CNPMCORE_POSTGRES_HOST ?? process.env.POSTGRES_HOST; + dbPort = dbPort ?? process.env.CNPMCORE_POSTGRES_PORT ?? process.env.POSTGRES_PORT ?? '5432'; + dbUser = dbUser ?? process.env.CNPMCORE_POSTGRES_USER ?? process.env.POSTGRES_USER; + dbPassword = dbPassword ?? process.env.CNPMCORE_POSTGRES_PASSWORD ?? process.env.POSTGRES_PASSWORD; +} else if (dbType === DATABASE_TYPE.SQLite) { + // TODO + dbClient = 'sqlite'; + dialect = 'sqlite'; +} + +export const database = { + type: dbType, + dialect, + client: dbClient, + name: dbName, + host: dbHost, + port: dbPort, + user: dbUser, + password: dbPassword, +}; diff --git a/docs/deploy-in-docker.md b/docs/deploy-in-docker.md index 01a03ef2..bd631c74 100644 --- a/docs/deploy-in-docker.md +++ b/docs/deploy-in-docker.md @@ -13,11 +13,23 @@ docker build -t cnpmcore . ### MySQL ```bash -CNPMCORE_MYSQL_DATABASE=cnpmcore -CNPMCORE_MYSQL_HOST=127.0.0.1 -CNPMCORE_MYSQL_PORT=3306 -CNPMCORE_MYSQL_USER=your-db-user-name -CNPMCORE_MYSQL_PASSWORD=your-db-user-password +CNPMCORE_DATABASE_TYPE=MySQL +CNPMCORE_DATABASE_NAME=cnpmcore +CNPMCORE_DATABASE_HOST=127.0.0.1 +CNPMCORE_DATABASE_PORT=3306 +CNPMCORE_DATABASE_USER=your-db-user-name +CNPMCORE_DATABASE_PASSWORD=your-db-user-password +``` + +### PostgreSQL + +```bash +CNPMCORE_DATABASE_TYPE=PostgreSQL +CNPMCORE_DATABASE_NAME=cnpmcore +CNPMCORE_DATABASE_HOST=127.0.0.1 +CNPMCORE_DATABASE_PORT=5432 +CNPMCORE_DATABASE_USER=your-db-user-name +CNPMCORE_DATABASE_PASSWORD=your-db-user-password ``` ### Redis @@ -134,14 +146,43 @@ docker run -p 7001:7001 -it --rm \ ## 运行容器 +### 基于 MySQL 运行 + +```bash +docker run -p 7001:7001 -it --rm \ + -e CNPMCORE_CONFIG_REGISTRY=https://your-registry.com \ + -e CNPMCORE_DATABASE_TYPE=MySQL \ + -e CNPMCORE_DATABASE_NAME=cnpmcore \ + -e CNPMCORE_DATABASE_HOST=127.0.0.1 \ + -e CNPMCORE_DATABASE_PORT=3306 \ + -e CNPMCORE_DATABASE_USER=your-db-user-name \ + -e CNPMCORE_DATABASE_PASSWORD=your-db-user-password \ + -e CNPMCORE_NFS_TYPE=s3 \ + -e CNPMCORE_NFS_S3_CLIENT_ENDPOINT=https://your-s3-endpoint \ + -e CNPMCORE_NFS_S3_CLIENT_BUCKET=your-bucket-name \ + -e CNPMCORE_NFS_S3_CLIENT_ID=s3-ak \ + -e CNPMCORE_NFS_S3_CLIENT_SECRET=s3-sk \ + -e CNPMCORE_NFS_S3_CLIENT_FORCE_PATH_STYLE=true \ + -e CNPMCORE_NFS_S3_CLIENT_DISABLE_URL=true \ + -e CNPMCORE_REDIS_HOST=127.0.0.1 \ + -e CNPMCORE_REDIS_PORT=6379 \ + -e CNPMCORE_REDIS_PASSWORD=your-redis-password \ + -e CNPMCORE_REDIS_DB=1 \ + -e TZ=Asia/Shanghai \ + --name cnpmcore-prod cnpmcore +``` + +### 基于 PostgreSQL 运行 + ```bash docker run -p 7001:7001 -it --rm \ -e CNPMCORE_CONFIG_REGISTRY=https://your-registry.com \ - -e CNPMCORE_MYSQL_DATABASE=cnpmcore \ - -e CNPMCORE_MYSQL_HOST=127.0.0.1 \ - -e CNPMCORE_MYSQL_PORT=3306 \ - -e CNPMCORE_MYSQL_USER=your-db-user-name \ - -e CNPMCORE_MYSQL_PASSWORD=your-db-user-password \ + -e CNPMCORE_DATABASE_TYPE=PostgreSQL \ + -e CNPMCORE_DATABASE_NAME=cnpmcore \ + -e CNPMCORE_DATABASE_HOST=127.0.0.1 \ + -e CNPMCORE_DATABASE_PORT=5432 \ + -e CNPMCORE_DATABASE_USER=your-db-user-name \ + -e CNPMCORE_DATABASE_PASSWORD=your-db-user-password \ -e CNPMCORE_NFS_TYPE=s3 \ -e CNPMCORE_NFS_S3_CLIENT_ENDPOINT=https://your-s3-endpoint \ -e CNPMCORE_NFS_S3_CLIENT_BUCKET=your-bucket-name \ @@ -161,7 +202,7 @@ docker run -p 7001:7001 -it --rm \ https://registry-demo.fengmk2.com:9443 -管理员账号:cnpmcore_admin/12345678 +管理员账号:`cnpmcore_admin/12345678` 通过 npm login 可以登录 diff --git a/docs/elasticsearch-setup.md b/docs/elasticsearch-setup.md index 534a8ebd..6c9dc621 100644 --- a/docs/elasticsearch-setup.md +++ b/docs/elasticsearch-setup.md @@ -1,6 +1,7 @@ # 本地搭建 ES 搜索环境 ## 单机搭建 + ### 下载安装 ES 首先我们进入 [ES 下载的官方网站](https://www.elastic.co/cn/downloads/elasticsearch) ,选择合适的操作系统版本并下载。下载完成后再适当位置解压并运行 @@ -50,7 +51,6 @@ path.logs: ./logs 此时,访问 http://localhost:5601 ,即可看到 Kibana 引导页面。 - 我们仅仅将其作为一个可视化的操作 API 的可视化工具,可以跳过其引导,访问 `/app/dev_tools#/console` 进入 devtool 页面。 ## docker compose @@ -247,14 +247,13 @@ ENCRYPTION_KEY=c34d38b3a14956121ff2170e5030b471551370178f43e5626eec58b04a30fae2 执行如下命令,启动服务 ```bash -$ docker compose up +docker compose up ``` ### 访问 Elastic 浏览器打开 http://localhost:5601/app/dev_tools#/console,默认账号为 `elastic` 密码为 .env 文件中定义的 `abcdef` - ## 创建索引 ES 可以通过 Kibana devtool 进行数据的写入和查询操作。下面创建一个索引,`cnpmcore_packages` 为索引名称。 @@ -982,8 +981,9 @@ $ curl -X PUT https://r.cnpmjs.org/-/v1/search/sync/${pkgName} ### 删除一条数据 注意需要添加管理员 token,管理员在本地进行登录后,可通过查询 `~/.npmrc` 查看 + ```bash -$ curl -X DELETE -H 'Authorization: Bearer ${token}' http://localhost:7001/-/v1/search/${pkgName} +curl -X DELETE -H 'Authorization: Bearer ${token}' http://localhost:7001/-/v1/search/${pkgName} ``` ### 修改数据 @@ -993,5 +993,5 @@ $ curl -X DELETE -H 'Authorization: Bearer ${token}' http://localhost:7001/-/v1/ ### 查询 ```bash -$ npm search colors --registry=http://localhost:7001 +npm search colors --registry=http://localhost:7001 ``` diff --git a/docs/setup-with-postgresql.md b/docs/setup-with-postgresql.md new file mode 100644 index 00000000..44ff49a4 --- /dev/null +++ b/docs/setup-with-postgresql.md @@ -0,0 +1,36 @@ +# 本地开发环境 - PostgreSQL + +## 依赖列表 + +本项目的外部服务依赖有: + +- 数据库:PostgreSQL +- 缓存:Redis + +## 手动初始化 + +假设大家使用 macOS 开发,Linux 和 Windows 环境自行参考。 + +### PostgreSQL 17 + +> https://wiki.postgresql.org/wiki/Homebrew + +```bash +brew install postgresql@17 +brew services start postgresql@17 + +echo 'export PATH="/opt/homebrew/opt/postgresql@17/bin:$PATH"' >> ~/.zshrc +``` + +验证是否安装成功 + +```bash +psql postgres +``` + +### Redis + +```bash +brew install redis +brew services start redis +``` diff --git a/docs/setup.md b/docs/setup.md index 40d21014..9ab5bffe 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -1,4 +1,4 @@ -# 本地开发环境 +# 本地开发环境 - MySQL ## 依赖列表 diff --git a/package.json b/package.json index 428f25d8..95d9ba3b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cnpmcore", "version": "3.69.0", - "description": "npm core", + "description": "Private NPM Registry for Enterprise", "files": [ "dist/**/*" ], @@ -35,18 +35,24 @@ } }, "scripts": { - "contributor": "git-contributor", "dev": "egg-bin dev", + "dev:postgresql": "CNPMCORE_DATABASE_TYPE=PostgreSQL egg-bin dev", "lint": "eslint --cache --ext .ts .", "lint:fix": "eslint --cache --ext .ts --fix .", - "test": "npm run lint:fix && npm run test-local", - "pretest-local": "bash ./prepare-database.sh", - "test-local": "egg-bin test", - "pret": "bash ./prepare-database.sh", + "test:postgresql": "npm run lint:fix && npm run test:local:postgresql", + "pretest:local:postgresql": "bash prepare-database-postgresql.sh", + "test:local:postgresql": "CNPMCORE_DATABASE_TYPE=PostgreSQL egg-bin test", + "test": "npm run lint:fix && npm run test:local", + "pretest:local": "bash prepare-database-mysql.sh", + "test:local": "egg-bin test", + "pret": "bash prepare-database-mysql.sh", "t": "npm run lint:fix && egg-bin test --changed", - "precov": "bash ./prepare-database.sh", + "precov": "bash prepare-database-mysql.sh", "cov": "egg-bin cov", + "precov:postgresql": "bash prepare-database-postgresql.sh", + "cov:postgresql": "CNPMCORE_DATABASE_TYPE=PostgreSQL egg-bin cov", "ci": "npm run lint && npm run cov && npm run tsc:prod", + "ci:postgresql": "npm run lint && npm run cov:postgresql && npm run tsc:prod", "clean": "tsc -b --clean && rm -rf dist", "tsc": "npm run clean && tsc -p ./tsconfig.json", "tsc:prod": "npm run clean && tsc -p ./tsconfig.prod.json", @@ -87,7 +93,7 @@ "base64url": "^3.0.1", "bson-objectid": "^2.0.1", "dayjs": "^1.10.7", - "egg": "^3.9.2", + "egg": "^3.29.0", "egg-cors": "^3.0.0", "egg-errors": "^2.3.0", "egg-redis": "^2.4.0", @@ -107,6 +113,7 @@ "npm-package-arg": "^10.1.0", "oss-cnpm": "^5.0.1", "p-map": "^4.0.0", + "pg": "^8.13.1", "s3-cnpmcore": "^1.1.2", "semver": "^7.3.5", "ssri": "^8.0.1", @@ -127,6 +134,7 @@ "@types/mysql": "^2.15.21", "@types/node-rsa": "^1.1.4", "@types/npm-package-arg": "^6.1.1", + "@types/pg": "^8.11.10", "@types/semver": "^7.3.12", "@types/tar": "^6.1.4", "@types/ua-parser-js": "^0.7.36", @@ -136,7 +144,6 @@ "egg-mock": "^5.10.4", "eslint": "^8.29.0", "eslint-config-egg": "^13.0.0", - "git-contributor": "2", "typescript": "5.2.2" }, "author": "killagu", diff --git a/prepare-database.sh b/prepare-database-mysql.sh similarity index 60% rename from prepare-database.sh rename to prepare-database-mysql.sh index 4e57a31b..b323d82a 100644 --- a/prepare-database.sh +++ b/prepare-database-mysql.sh @@ -1,13 +1,13 @@ #!/bin/bash # read variables from environment -db_host=${MYSQL_HOST:-127.0.0.1} -db_port=${MYSQL_PORT:-3306} -db_username=${MYSQL_USER:-root} -db_password=${MYSQL_PASSWORD:-} # default to empty password -db_name=${MYSQL_DATABASE:-cnpmcore_unittest} +db_host=${CNPMCORE_DATABASE_HOST:-127.0.0.1} +db_port=${CNPMCORE_DATABASE_PORT:-3306} +db_username=${CNPMCORE_DATABASE_USER:-root} +db_password=${CNPMCORE_DATABASE_PASSWORD:-} # default to empty password +db_name=${CNPMCORE_DATABASE_NAME:-cnpmcore_unittest} -# preapre mysql param +# prepare MySQL param param="-h $db_host -P $db_port -u $db_username" if [ -n "$db_password" ]; then param="$param -p$db_password" @@ -17,14 +17,14 @@ if [ "$CI" ]; then echo "⛷️ Skipping database creation in CI environment." else # reset database - echo "️😈 Reset database in local" + echo "️😈 Reset database $db_name in local" mysql $param -e "DROP DATABASE IF EXISTS $db_name" mysql $param -e "CREATE DATABASE $db_name CHARACTER SET utf8" fi # find all sql files and sort -sql_files=$(ls sql/*.sql | sort) +sql_files=$(ls sql/mysql/*.sql | sort) echo "🤖 Running the following SQL files:" # execute sql files @@ -33,5 +33,5 @@ for file in $sql_files; do mysql $param $db_name < "$file" done -echo "🎉 prepare database done" +echo "🎉 prepare database $db_name done" mysql $param -e "USE $db_name; SHOW TABLES;" diff --git a/prepare-database-postgresql.sh b/prepare-database-postgresql.sh new file mode 100644 index 00000000..a4522c78 --- /dev/null +++ b/prepare-database-postgresql.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# set -ex + +# read variables from environment +db_host=${POSTGRES_HOST:-} +db_port=${POSTGRES_PORT:-5432} +db_username=${POSTGRES_USER:-} +db_password=${POSTGRES_PASSWORD:-} # default to empty password +db_name=${CNPMCORE_DATABASE_NAME:-cnpmcore_unittest} + +# prepare PostgreSQL param +param="" +if [ -n "$db_host" ]; then + param="$param --host=$db_host" +fi +if [ -n "$db_port" ]; then + param="$param --port=$db_port" +fi +if [ -n "$db_username" ]; then + param="$param --username=$db_username" +fi +if [ -n "$db_password" ]; then + # https://stackoverflow.com/questions/6405127/how-do-i-specify-a-password-to-psql-non-interactively + export PGPASSWORD=$db_password +fi + +# reset database +echo "️😈 Reset database $db_name in local" +dropdb $param $db_name || echo "ignore database not exists" +# http://www.postgres.cn/docs/15/app-createdb.html +createdb $param --echo --encoding=UTF8 $db_name + +# find all sql files and sort +sql_files=$(ls sql/postgresql/*.sql | sort) +echo "🤖 Running the following SQL files:" + +# execute sql files +for file in $sql_files; do + echo "🔖 Running $file..." + # psql $param --dbname=$db_name --file=$file --echo-all + psql $param --dbname=$db_name --file=$file --quiet +done + +echo "🎉 prepare database $db_name done" +# psql $param --dbname=$db_name -c "SELECT * FROM pg_catalog.pg_tables where schemaname = 'public';" +psql $param --dbname=$db_name -c "\dt" diff --git a/sql/ddl_mysql.sql b/sql/ddl_mysql.sql new file mode 100644 index 00000000..d8d5af61 --- /dev/null +++ b/sql/ddl_mysql.sql @@ -0,0 +1,434 @@ +CREATE TABLE `binaries` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `binary_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'binary id', + `category` varchar(50) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL COMMENT 'binary category, e.g.: node, sass', + `parent` varchar(500) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL COMMENT 'binary parent name, e.g.: /, /v1.0.0/, /v1.0.0/docs/', + `name` varchar(200) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL COMMENT 'binary name, dir should ends with /', + `is_dir` tinyint NOT NULL DEFAULT '0' COMMENT 'is dir or not, 1: true, other: false', + `size` int unsigned NOT NULL COMMENT 'file size', + `date` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT 'date display string', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_binary_id` (`binary_id`), + UNIQUE KEY `uk_category_parent_name` (`category`,`parent`,`name`), + KEY `idx_category_parent` (`category`,`parent`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='binary info' +; + + +CREATE TABLE `changes` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `change_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'change id', + `type` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT 'change type', + `target_name` varchar(214) COLLATE utf8_unicode_ci NOT NULL COMMENT 'target name, like package name / user name', + `data` json DEFAULT NULL COMMENT 'change params', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_change_id` (`change_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='change info' +; + + +CREATE TABLE `dists` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `dist_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'dist id', + `name` varchar(428) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT 'dist name, 2x size of package name', + `path` varchar(767) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL COMMENT 'access path', + `size` int unsigned NOT NULL COMMENT 'file size', + `shasum` varchar(512) COLLATE utf8_unicode_ci NOT NULL COMMENT 'dist shasum', + `integrity` varchar(512) COLLATE utf8_unicode_ci NOT NULL COMMENT 'dist integrity', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_dist_id` (`dist_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='dist info' +; + + +CREATE TABLE `history_tasks` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `task_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'task id', + `type` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT 'task type', + `state` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT 'task state', + `target_name` varchar(214) COLLATE utf8_unicode_ci NOT NULL COMMENT 'target name, like package name / user name', + `author_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'create task user id', + `author_ip` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT 'create task user request ip', + `data` json DEFAULT NULL COMMENT 'task params', + `log_path` varchar(512) COLLATE utf8_unicode_ci NOT NULL COMMENT 'access path', + `log_store_position` varchar(10) COLLATE utf8_unicode_ci NOT NULL COMMENT 'cloud store disk position', + `attempts` int unsigned DEFAULT '0' COMMENT 'task execute attempts times', + `error` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'error description', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_task_id` (`task_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='history task info' +; + + +CREATE TABLE `hooks` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `hook_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'hook id', + `type` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT 'hook type, scope, name, owner', + `name` varchar(428) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'hook name', + `owner_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'hook owner id', + `endpoint` varchar(2048) COLLATE utf8_unicode_ci NOT NULL COMMENT 'hook url', + `secret` varchar(200) COLLATE utf8_unicode_ci NOT NULL COMMENT 'sign secret', + `latest_task_id` varchar(24) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'latest task id', + `enable` tinyint NOT NULL DEFAULT '0' COMMENT 'hook is enable not, 1: true, other: false', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_type_name_owner_id` (`type`,`name`,`owner_id`), + KEY `idx_type_name_id` (`type`,`name`,`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='task info' +; + + +CREATE TABLE `maintainers` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `package_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package id', + `user_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'user id', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_package_id_user_id` (`package_id`,`user_id`), + KEY `idx_package_id` (`package_id`), + KEY `idx_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='package maintainers' +; + + +CREATE TABLE `package_deps` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `package_version_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package version id', + `package_dep_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package dep id', + `scope` varchar(214) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package scope', + `name` varchar(214) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'package name', + `spec` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package dep spec', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_package_dep_id` (`package_dep_id`), + UNIQUE KEY `uk_package_version_id_scope_name` (`package_version_id`,`scope`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='package dependency info' +; + + +CREATE TABLE `package_tags` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `package_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package id', + `package_tag_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package tag id', + `tag` varchar(214) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package tag', + `version` varchar(256) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package version', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_package_tag_id` (`package_tag_id`), + UNIQUE KEY `uk_package_tag` (`package_id`,`tag`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='package tag info' +; + + +CREATE TABLE `package_version_blocks` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `package_version_block_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package version block id', + `package_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package id', + `version` varchar(256) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package version, "*" meaning all versions', + `reason` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'block reason', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_package_version_block_id` (`package_version_block_id`), + UNIQUE KEY `uk_name_version` (`package_id`,`version`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='blocklist package versions' +; + + +CREATE TABLE `package_version_downloads` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `year_month` int unsigned NOT NULL COMMENT 'YYYYMM format', + `package_id` varchar(214) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package id, maybe scope name', + `version` varchar(256) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package version', + `d01` int unsigned NOT NULL DEFAULT '0' COMMENT '01 download count', + `d02` int unsigned NOT NULL DEFAULT '0' COMMENT '02 download count', + `d03` int unsigned NOT NULL DEFAULT '0' COMMENT '03 download count', + `d04` int unsigned NOT NULL DEFAULT '0' COMMENT '04 download count', + `d05` int unsigned NOT NULL DEFAULT '0' COMMENT '05 download count', + `d06` int unsigned NOT NULL DEFAULT '0' COMMENT '06 download count', + `d07` int unsigned NOT NULL DEFAULT '0' COMMENT '07 download count', + `d08` int unsigned NOT NULL DEFAULT '0' COMMENT '08 download count', + `d09` int unsigned NOT NULL DEFAULT '0' COMMENT '09 download count', + `d10` int unsigned NOT NULL DEFAULT '0' COMMENT '10 download count', + `d11` int unsigned NOT NULL DEFAULT '0' COMMENT '11 download count', + `d12` int unsigned NOT NULL DEFAULT '0' COMMENT '12 download count', + `d13` int unsigned NOT NULL DEFAULT '0' COMMENT '13 download count', + `d14` int unsigned NOT NULL DEFAULT '0' COMMENT '14 download count', + `d15` int unsigned NOT NULL DEFAULT '0' COMMENT '15 download count', + `d16` int unsigned NOT NULL DEFAULT '0' COMMENT '16 download count', + `d17` int unsigned NOT NULL DEFAULT '0' COMMENT '17 download count', + `d18` int unsigned NOT NULL DEFAULT '0' COMMENT '18 download count', + `d19` int unsigned NOT NULL DEFAULT '0' COMMENT '19 download count', + `d20` int unsigned NOT NULL DEFAULT '0' COMMENT '20 download count', + `d21` int unsigned NOT NULL DEFAULT '0' COMMENT '21 download count', + `d22` int unsigned NOT NULL DEFAULT '0' COMMENT '22 download count', + `d23` int unsigned NOT NULL DEFAULT '0' COMMENT '23 download count', + `d24` int unsigned NOT NULL DEFAULT '0' COMMENT '24 download count', + `d25` int unsigned NOT NULL DEFAULT '0' COMMENT '25 download count', + `d26` int unsigned NOT NULL DEFAULT '0' COMMENT '26 download count', + `d27` int unsigned NOT NULL DEFAULT '0' COMMENT '27 download count', + `d28` int unsigned NOT NULL DEFAULT '0' COMMENT '28 download count', + `d29` int unsigned NOT NULL DEFAULT '0' COMMENT '29 download count', + `d30` int unsigned NOT NULL DEFAULT '0' COMMENT '30 download count', + `d31` int unsigned NOT NULL DEFAULT '0' COMMENT '31 download count', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_year_month_package_id_version` (`year_month`,`package_id`,`version`), + KEY `idx_year_month` (`year_month`), + KEY `idx_packageid_yearmonth` (`package_id`,`year_month`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='package version download total info' +; + + +CREATE TABLE `package_version_files` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `package_version_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package version id', + `package_version_file_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package version file id', + `dist_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'file dist id', + `directory` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'directory path, e.g.: /bin', + `name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'file name, e.g.: index.js', + `content_type` varchar(200) COLLATE utf8_unicode_ci NOT NULL COMMENT 'file content type, e.g.: application/javascript', + `mtime` datetime(3) NOT NULL COMMENT 'file modified time', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_package_version_file_id` (`package_version_file_id`), + UNIQUE KEY `ux_package_version_id_directory_name` (`package_version_id`,`directory`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='package version file' +; + + +CREATE TABLE `package_version_manifests` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `package_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package id', + `package_version_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package version id', + `package_version_manifest_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package version manifest id', + `manifest` json NOT NULL COMMENT 'manifest JSON, including README text', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_package_version_manifest_id` (`package_version_manifest_id`), + UNIQUE KEY `uk_package_version_id` (`package_version_id`), + KEY `idx_package_id` (`package_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='package version manifest' +; + + +CREATE TABLE `package_versions` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `package_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package id', + `package_version_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package version id', + `version` varchar(256) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package version', + `abbreviated_dist_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'abbreviated manifest dist id', + `manifest_dist_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'manifest dist id', + `tar_dist_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'tar dist id', + `readme_dist_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'readme dist id', + `publish_time` datetime(3) NOT NULL COMMENT 'publish time', + `padding_version` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'token name', + `is_pre_release` tinyint DEFAULT NULL COMMENT '是否是先行版本', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_package_version_id` (`package_version_id`), + UNIQUE KEY `uk_package_id_version` (`package_id`,`version`), + KEY `idx_pkg_id_is_pre_release_padding_version` (`package_id`,`padding_version`,`is_pre_release`,`version`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='package version info' +; + + +CREATE TABLE `packages` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `package_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package id', + `is_private` tinyint NOT NULL DEFAULT '0' COMMENT 'private pkg or not, 1: true, other: false', + `name` varchar(214) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'package name', + `scope` varchar(214) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package name, empty string meaning no scope', + `description` varchar(10240) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'package description', + `abbreviateds_dist_id` varchar(24) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'all abbreviated manifests dist id', + `manifests_dist_id` varchar(24) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'all full manifests dist id', + `registry_id` varchar(24) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'source registry', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_package_id` (`package_id`), + UNIQUE KEY `uk_scope_name` (`scope`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='package info' +; + + +CREATE TABLE `proxy_caches` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modify time', + `fullname` varchar(214) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '@scope/package name', + `version` varchar(214) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'package version', + `file_type` varchar(30) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'file type', + `file_path` varchar(512) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'nfs file path', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_package_version_path_name` (`file_path`), + UNIQUE KEY `ux_package_version_file_name` (`fullname`,`file_type`,`version`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='proxy mode cached files index' +; + + +CREATE TABLE `registries` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `registry_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'registry id', + `name` varchar(256) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'registry name', + `host` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'registry host', + `change_stream` varchar(4096) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'change stream url', + `type` varchar(256) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'registry type cnpmjsorg/cnpmcore/npm ', + `user_prefix` varchar(256) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'user prefix', + `auth_token` varchar(256) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'registry auth token', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='registry info' +; + + +CREATE TABLE `scopes` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `scope_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'scope id', + `name` varchar(214) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'scope name', + `registry_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'registry id', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='scope info' +; + + +CREATE TABLE `tasks` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `task_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'task id', + `type` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT 'task type', + `state` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT 'task state', + `target_name` varchar(214) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'target name, like package name / user name', + `author_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'create task user id', + `author_ip` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT 'create task user request ip', + `data` json DEFAULT NULL COMMENT 'task params', + `log_path` varchar(512) COLLATE utf8_unicode_ci NOT NULL COMMENT 'access path', + `log_store_position` varchar(10) COLLATE utf8_unicode_ci NOT NULL COMMENT 'cloud store disk position', + `attempts` int unsigned DEFAULT '0' COMMENT 'task execute attempts times', + `error` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'error description', + `biz_id` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'unique biz id to keep task unique', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_task_id` (`task_id`), + UNIQUE KEY `uk_biz_id` (`biz_id`), + KEY `idx_type_state_target_name` (`target_name`,`type`,`state`), + KEY `idx_type_state_gmt_modified` (`type`,`state`,`gmt_modified`), + KEY `idx_gmt_modified` (`gmt_modified`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='task info' +; + + +CREATE TABLE `token_packages` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `token_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'token id', + `package_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'package id', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_token_id_package_id` (`token_id`,`package_id`), + KEY `idx_token_id` (`token_id`), + KEY `idx_package_id` (`package_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='token allowed packages' +; + + +CREATE TABLE `tokens` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `token_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'token id', + `token_mark` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT 'token mark value', + `token_key` varchar(200) COLLATE utf8_unicode_ci NOT NULL COMMENT 'token value sha512 hex', + `is_readonly` tinyint NOT NULL DEFAULT '0' COMMENT 'readonly token or not, 1: true, other: false', + `is_automation` tinyint NOT NULL DEFAULT '0' COMMENT 'automation token or not, 1: true, other: false', + `cidr_whitelist` json NOT NULL COMMENT 'ip list, ["127.0.0.1"]', + `user_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'user id', + `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'token name', + `type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'token type, granular or legacy', + `description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'token description', + `allowed_scopes` text COLLATE utf8_unicode_ci COMMENT 'scope allowed list', + `expired_at` datetime(3) DEFAULT NULL COMMENT 'token expiration time', + `last_used_at` datetime(3) DEFAULT NULL COMMENT 'token last used time', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_token_id` (`token_id`), + UNIQUE KEY `uk_token_key` (`token_key`), + UNIQUE KEY `uk_user_id_name` (`user_id`,`name`), + KEY `idx_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='token info' +; + + +CREATE TABLE `total` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `total_id` varchar(24) NOT NULL COMMENT 'total id, should set it to "global"', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `package_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'package count', + `package_file_size` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'package all files total size', + `package_version_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'package version count', + `package_version_delete_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'package version delete count', + `private_package_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'private package count', + `private_package_file_size` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'private package all files total size', + `private_package_version_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'private package version count', + `private_package_version_delete_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'private package version delete count', + `change_stream_seq` varchar(100) DEFAULT NULL COMMENT 'npm change stream sync data seq id', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_total_id` (`total_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='total info' +; + + +CREATE TABLE `users` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `user_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'user id', + `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT 'user name', + `email` varchar(400) COLLATE utf8_unicode_ci NOT NULL COMMENT 'user email', + `password_salt` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT 'password salt', + `password_integrity` varchar(512) COLLATE utf8_unicode_ci NOT NULL COMMENT 'password integrity', + `ip` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT 'user login request ip', + `is_private` tinyint NOT NULL DEFAULT '1' COMMENT 'private user or not, 1: true, other: false', + `scopes` json DEFAULT NULL COMMENT 'white scope list, ["@cnpm", "@foo"]', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_user_id` (`user_id`), + UNIQUE KEY `uk_name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='user info' +; + + +CREATE TABLE `webauthn_credentials` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', + `gmt_create` datetime(3) NOT NULL COMMENT 'create time', + `gmt_modified` datetime(3) NOT NULL COMMENT 'modified time', + `wanc_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'webauthn credential id', + `user_id` varchar(24) COLLATE utf8_unicode_ci NOT NULL COMMENT 'user id', + `credential_id` varchar(200) COLLATE utf8_unicode_ci NOT NULL COMMENT 'webauthn credential id', + `public_key` varchar(512) COLLATE utf8_unicode_ci NOT NULL COMMENT 'webauthn credential publick key', + `browser_type` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'user browser name', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_wanc_id` (`wanc_id`), + KEY `idx_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci COMMENT='webauthn credential info' +; diff --git a/sql/ddl_postgresql.sql b/sql/ddl_postgresql.sql new file mode 100644 index 00000000..38298c34 --- /dev/null +++ b/sql/ddl_postgresql.sql @@ -0,0 +1,704 @@ +CREATE TABLE binaries ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + binary_id varchar(24) NOT NULL, + category varchar(50) NOT NULL, + parent varchar(500) NOT NULL, + name varchar(200) NOT NULL, + is_dir boolean NOT NULL DEFAULT false, + size integer NOT NULL, + date varchar(100) NOT NULL +); + +CREATE UNIQUE INDEX binaries_uk_binary_id ON binaries (binary_id); +CREATE UNIQUE INDEX binaries_uk_category_parent_name ON binaries (category, parent, name); +CREATE INDEX binaries_idx_category_parent ON binaries (category, parent); + +COMMENT ON TABLE binaries IS 'binary info'; +COMMENT ON COLUMN binaries.id IS 'primary key'; +COMMENT ON COLUMN binaries.gmt_create IS 'create time'; +COMMENT ON COLUMN binaries.gmt_modified IS 'modified time'; +COMMENT ON COLUMN binaries.binary_id IS 'binary id'; +COMMENT ON COLUMN binaries.category IS 'binary category, e.g.: node, sass'; +COMMENT ON COLUMN binaries.parent IS 'binary parent name, e.g.: /, /v1.0.0/, /v1.0.0/docs/'; +COMMENT ON COLUMN binaries.name IS 'binary name, dir should ends with /'; +COMMENT ON COLUMN binaries.is_dir IS 'is dir or not, 1: true, other: false'; +COMMENT ON COLUMN binaries.size IS 'file size'; +COMMENT ON COLUMN binaries.date IS 'date display string'; + + +CREATE TABLE changes ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + change_id varchar(24) NOT NULL, + type varchar(50) NOT NULL, + target_name varchar(214) NOT NULL, + data json DEFAULT NULL +); + +CREATE UNIQUE INDEX changes_uk_change_id ON changes (change_id); + +COMMENT ON TABLE changes IS 'change info'; +COMMENT ON COLUMN changes.id IS 'primary key'; +COMMENT ON COLUMN changes.gmt_create IS 'create time'; +COMMENT ON COLUMN changes.gmt_modified IS 'modified time'; +COMMENT ON COLUMN changes.change_id IS 'change id'; +COMMENT ON COLUMN changes.type IS 'change type'; +COMMENT ON COLUMN changes.target_name IS 'target name, like package name / user name'; +COMMENT ON COLUMN changes.data IS 'change params'; + + +CREATE TABLE dists ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + dist_id varchar(24) NOT NULL, + name varchar(428) NOT NULL, + path varchar(767) NOT NULL, + size integer NOT NULL, + shasum varchar(512) NOT NULL, + integrity varchar(512) NOT NULL +); + +CREATE UNIQUE INDEX dists_uk_dist_id ON dists (dist_id); + +COMMENT ON TABLE dists IS 'dist info'; +COMMENT ON COLUMN dists.id IS 'primary key'; +COMMENT ON COLUMN dists.gmt_create IS 'create time'; +COMMENT ON COLUMN dists.gmt_modified IS 'modified time'; +COMMENT ON COLUMN dists.dist_id IS 'dist id'; +COMMENT ON COLUMN dists.name IS 'dist name, 2x size of package name'; +COMMENT ON COLUMN dists.path IS 'access path'; +COMMENT ON COLUMN dists.size IS 'file size'; +COMMENT ON COLUMN dists.shasum IS 'dist shasum'; +COMMENT ON COLUMN dists.integrity IS 'dist integrity'; + + +CREATE TABLE history_tasks ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + task_id varchar(24) NOT NULL, + type varchar(20) NOT NULL, + state varchar(20) NOT NULL, + target_name varchar(214) NOT NULL, + author_id varchar(24) NOT NULL, + author_ip varchar(100) NOT NULL, + data json DEFAULT NULL, + log_path varchar(512) NOT NULL, + log_store_position varchar(10) NOT NULL, + attempts integer DEFAULT 0, + error text +); + +CREATE UNIQUE INDEX history_tasks_uk_task_id ON history_tasks (task_id); + +COMMENT ON TABLE history_tasks IS 'history task info'; +COMMENT ON COLUMN history_tasks.id IS 'primary key'; +COMMENT ON COLUMN history_tasks.gmt_create IS 'create time'; +COMMENT ON COLUMN history_tasks.gmt_modified IS 'modified time'; +COMMENT ON COLUMN history_tasks.task_id IS 'task id'; +COMMENT ON COLUMN history_tasks.type IS 'task type'; +COMMENT ON COLUMN history_tasks.state IS 'task state'; +COMMENT ON COLUMN history_tasks.target_name IS 'target name, like package name / user name'; +COMMENT ON COLUMN history_tasks.author_id IS 'create task user id'; +COMMENT ON COLUMN history_tasks.author_ip IS 'create task user request ip'; +COMMENT ON COLUMN history_tasks.data IS 'task params'; +COMMENT ON COLUMN history_tasks.log_path IS 'access path'; +COMMENT ON COLUMN history_tasks.log_store_position IS 'cloud store disk position'; +COMMENT ON COLUMN history_tasks.attempts IS 'task execute attempts times'; +COMMENT ON COLUMN history_tasks.error IS 'error description'; + + +CREATE TABLE hooks ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + hook_id varchar(24) NOT NULL, + type varchar(20) NOT NULL, + name varchar(428) NOT NULL, + owner_id varchar(24) NOT NULL, + endpoint varchar(2048) NOT NULL, + secret varchar(200) NOT NULL, + latest_task_id varchar(24) DEFAULT NULL, + enable boolean NOT NULL DEFAULT false +); + +CREATE UNIQUE INDEX hooks_uk_type_name_owner_id ON hooks (type, name, owner_id); +CREATE INDEX hooks_idx_type_name_id ON hooks (type, name, id); + +COMMENT ON TABLE hooks IS 'task info'; +COMMENT ON COLUMN hooks.id IS 'primary key'; +COMMENT ON COLUMN hooks.gmt_create IS 'create time'; +COMMENT ON COLUMN hooks.gmt_modified IS 'modified time'; +COMMENT ON COLUMN hooks.hook_id IS 'hook id'; +COMMENT ON COLUMN hooks.type IS 'hook type, scope, name, owner'; +COMMENT ON COLUMN hooks.name IS 'hook name'; +COMMENT ON COLUMN hooks.owner_id IS 'hook owner id'; +COMMENT ON COLUMN hooks.endpoint IS 'hook url'; +COMMENT ON COLUMN hooks.secret IS 'sign secret'; +COMMENT ON COLUMN hooks.latest_task_id IS 'latest task id'; +COMMENT ON COLUMN hooks.enable IS 'hook is enable not, 1: true, other: false'; + + +CREATE TABLE maintainers ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_id varchar(24) NOT NULL, + user_id varchar(24) NOT NULL +); + +CREATE UNIQUE INDEX maintainers_uk_package_id_user_id ON maintainers (package_id, user_id); +CREATE INDEX maintainers_idx_package_id ON maintainers (package_id); +CREATE INDEX maintainers_idx_user_id ON maintainers (user_id); + +COMMENT ON TABLE maintainers IS 'package maintainers'; +COMMENT ON COLUMN maintainers.id IS 'primary key'; +COMMENT ON COLUMN maintainers.gmt_create IS 'create time'; +COMMENT ON COLUMN maintainers.gmt_modified IS 'modified time'; +COMMENT ON COLUMN maintainers.package_id IS 'package id'; +COMMENT ON COLUMN maintainers.user_id IS 'user id'; + + +CREATE TABLE package_deps ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_version_id varchar(24) NOT NULL, + package_dep_id varchar(24) NOT NULL, + scope varchar(214) NOT NULL, + name varchar(214) NOT NULL, + spec varchar(100) NOT NULL +); + +CREATE UNIQUE INDEX package_deps_uk_package_dep_id ON package_deps (package_dep_id); +CREATE UNIQUE INDEX package_deps_uk_package_version_id_scope_name ON package_deps (package_version_id, scope, name); + +COMMENT ON TABLE package_deps IS 'package dependency info'; +COMMENT ON COLUMN package_deps.id IS 'primary key'; +COMMENT ON COLUMN package_deps.gmt_create IS 'create time'; +COMMENT ON COLUMN package_deps.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_deps.package_version_id IS 'package version id'; +COMMENT ON COLUMN package_deps.package_dep_id IS 'package dep id'; +COMMENT ON COLUMN package_deps.scope IS 'package scope'; +COMMENT ON COLUMN package_deps.name IS 'package name'; +COMMENT ON COLUMN package_deps.spec IS 'package dep spec'; + + +CREATE TABLE package_tags ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_id varchar(24) NOT NULL, + package_tag_id varchar(24) NOT NULL, + tag varchar(214) NOT NULL, + version varchar(256) NOT NULL +); + +CREATE UNIQUE INDEX package_tags_uk_package_tag_id ON package_tags (package_tag_id); +CREATE UNIQUE INDEX package_tags_uk_package_tag ON package_tags (package_id, tag); + +COMMENT ON TABLE package_tags IS 'package tag info'; +COMMENT ON COLUMN package_tags.id IS 'primary key'; +COMMENT ON COLUMN package_tags.gmt_create IS 'create time'; +COMMENT ON COLUMN package_tags.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_tags.package_id IS 'package id'; +COMMENT ON COLUMN package_tags.package_tag_id IS 'package tag id'; +COMMENT ON COLUMN package_tags.tag IS 'package tag'; +COMMENT ON COLUMN package_tags.version IS 'package version'; + + +CREATE TABLE package_version_blocks ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_version_block_id varchar(24) NOT NULL, + package_id varchar(24) NOT NULL, + version varchar(256) NOT NULL, + reason text NOT NULL +); + +CREATE UNIQUE INDEX package_version_blocks_uk_package_version_block_id ON package_version_blocks (package_version_block_id); +CREATE UNIQUE INDEX package_version_blocks_uk_name_version ON package_version_blocks (package_id, version); + +COMMENT ON TABLE package_version_blocks IS 'blocklist package versions'; +COMMENT ON COLUMN package_version_blocks.id IS 'primary key'; +COMMENT ON COLUMN package_version_blocks.gmt_create IS 'create time'; +COMMENT ON COLUMN package_version_blocks.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_version_blocks.package_version_block_id IS 'package version block id'; +COMMENT ON COLUMN package_version_blocks.package_id IS 'package id'; +COMMENT ON COLUMN package_version_blocks.version IS 'package version, "*" meaning all versions'; +COMMENT ON COLUMN package_version_blocks.reason IS 'block reason'; + + +CREATE TABLE package_version_downloads ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + year_month integer NOT NULL, + package_id varchar(214) NOT NULL, + version varchar(256) NOT NULL, + d01 integer NOT NULL DEFAULT 0, + d02 integer NOT NULL DEFAULT 0, + d03 integer NOT NULL DEFAULT 0, + d04 integer NOT NULL DEFAULT 0, + d05 integer NOT NULL DEFAULT 0, + d06 integer NOT NULL DEFAULT 0, + d07 integer NOT NULL DEFAULT 0, + d08 integer NOT NULL DEFAULT 0, + d09 integer NOT NULL DEFAULT 0, + d10 integer NOT NULL DEFAULT 0, + d11 integer NOT NULL DEFAULT 0, + d12 integer NOT NULL DEFAULT 0, + d13 integer NOT NULL DEFAULT 0, + d14 integer NOT NULL DEFAULT 0, + d15 integer NOT NULL DEFAULT 0, + d16 integer NOT NULL DEFAULT 0, + d17 integer NOT NULL DEFAULT 0, + d18 integer NOT NULL DEFAULT 0, + d19 integer NOT NULL DEFAULT 0, + d20 integer NOT NULL DEFAULT 0, + d21 integer NOT NULL DEFAULT 0, + d22 integer NOT NULL DEFAULT 0, + d23 integer NOT NULL DEFAULT 0, + d24 integer NOT NULL DEFAULT 0, + d25 integer NOT NULL DEFAULT 0, + d26 integer NOT NULL DEFAULT 0, + d27 integer NOT NULL DEFAULT 0, + d28 integer NOT NULL DEFAULT 0, + d29 integer NOT NULL DEFAULT 0, + d30 integer NOT NULL DEFAULT 0, + d31 integer NOT NULL DEFAULT 0 +); + +CREATE UNIQUE INDEX package_version_downloads_uk_year_month_package_id_version ON package_version_downloads (year_month, package_id, version); +CREATE INDEX package_version_downloads_idx_year_month ON package_version_downloads (year_month); +CREATE INDEX package_version_downloads_idx_packageid_yearmonth ON package_version_downloads (package_id, year_month); + +COMMENT ON TABLE package_version_downloads IS 'package version download total info'; +COMMENT ON COLUMN package_version_downloads.id IS 'primary key'; +COMMENT ON COLUMN package_version_downloads.gmt_create IS 'create time'; +COMMENT ON COLUMN package_version_downloads.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_version_downloads.year_month IS 'YYYYMM format'; +COMMENT ON COLUMN package_version_downloads.package_id IS 'package id, maybe scope name'; +COMMENT ON COLUMN package_version_downloads.version IS 'package version'; +COMMENT ON COLUMN package_version_downloads.d01 IS '01 download count'; +COMMENT ON COLUMN package_version_downloads.d02 IS '02 download count'; +COMMENT ON COLUMN package_version_downloads.d03 IS '03 download count'; +COMMENT ON COLUMN package_version_downloads.d04 IS '04 download count'; +COMMENT ON COLUMN package_version_downloads.d05 IS '05 download count'; +COMMENT ON COLUMN package_version_downloads.d06 IS '06 download count'; +COMMENT ON COLUMN package_version_downloads.d07 IS '07 download count'; +COMMENT ON COLUMN package_version_downloads.d08 IS '08 download count'; +COMMENT ON COLUMN package_version_downloads.d09 IS '09 download count'; +COMMENT ON COLUMN package_version_downloads.d10 IS '10 download count'; +COMMENT ON COLUMN package_version_downloads.d11 IS '11 download count'; +COMMENT ON COLUMN package_version_downloads.d12 IS '12 download count'; +COMMENT ON COLUMN package_version_downloads.d13 IS '13 download count'; +COMMENT ON COLUMN package_version_downloads.d14 IS '14 download count'; +COMMENT ON COLUMN package_version_downloads.d15 IS '15 download count'; +COMMENT ON COLUMN package_version_downloads.d16 IS '16 download count'; +COMMENT ON COLUMN package_version_downloads.d17 IS '17 download count'; +COMMENT ON COLUMN package_version_downloads.d18 IS '18 download count'; +COMMENT ON COLUMN package_version_downloads.d19 IS '19 download count'; +COMMENT ON COLUMN package_version_downloads.d20 IS '20 download count'; +COMMENT ON COLUMN package_version_downloads.d21 IS '21 download count'; +COMMENT ON COLUMN package_version_downloads.d22 IS '22 download count'; +COMMENT ON COLUMN package_version_downloads.d23 IS '23 download count'; +COMMENT ON COLUMN package_version_downloads.d24 IS '24 download count'; +COMMENT ON COLUMN package_version_downloads.d25 IS '25 download count'; +COMMENT ON COLUMN package_version_downloads.d26 IS '26 download count'; +COMMENT ON COLUMN package_version_downloads.d27 IS '27 download count'; +COMMENT ON COLUMN package_version_downloads.d28 IS '28 download count'; +COMMENT ON COLUMN package_version_downloads.d29 IS '29 download count'; +COMMENT ON COLUMN package_version_downloads.d30 IS '30 download count'; +COMMENT ON COLUMN package_version_downloads.d31 IS '31 download count'; + + +CREATE TABLE package_version_files ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_version_id varchar(24) NOT NULL, + package_version_file_id varchar(24) NOT NULL, + dist_id varchar(24) NOT NULL, + directory varchar(500) NOT NULL, + name varchar(200) NOT NULL, + content_type varchar(200) NOT NULL, + mtime timestamp(3) NOT NULL +); + +CREATE UNIQUE INDEX package_version_files_uk_package_version_file_id ON package_version_files (package_version_file_id); +CREATE UNIQUE INDEX package_version_files_ux_package_version_id_directory_name ON package_version_files (package_version_id, directory, name); + +COMMENT ON TABLE package_version_files IS 'package version file'; +COMMENT ON COLUMN package_version_files.id IS 'primary key'; +COMMENT ON COLUMN package_version_files.gmt_create IS 'create time'; +COMMENT ON COLUMN package_version_files.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_version_files.package_version_id IS 'package version id'; +COMMENT ON COLUMN package_version_files.package_version_file_id IS 'package version file id'; +COMMENT ON COLUMN package_version_files.dist_id IS 'file dist id'; +COMMENT ON COLUMN package_version_files.directory IS 'directory path, e.g.: /bin'; +COMMENT ON COLUMN package_version_files.name IS 'file name, e.g.: index.js'; +COMMENT ON COLUMN package_version_files.content_type IS 'file content type, e.g.: application/javascript'; +COMMENT ON COLUMN package_version_files.mtime IS 'file modified time'; + + +CREATE TABLE package_version_manifests ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_id varchar(24) NOT NULL, + package_version_id varchar(24) NOT NULL, + package_version_manifest_id varchar(24) NOT NULL, + manifest json NOT NULL +); + +CREATE UNIQUE INDEX package_version_manifests_uk_package_version_manifest_id ON package_version_manifests (package_version_manifest_id); +CREATE UNIQUE INDEX package_version_manifests_uk_package_version_id ON package_version_manifests (package_version_id); +CREATE INDEX package_version_manifests_idx_package_id ON package_version_manifests (package_id); + +COMMENT ON TABLE package_version_manifests IS 'package version manifest'; +COMMENT ON COLUMN package_version_manifests.id IS 'primary key'; +COMMENT ON COLUMN package_version_manifests.gmt_create IS 'create time'; +COMMENT ON COLUMN package_version_manifests.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_version_manifests.package_id IS 'package id'; +COMMENT ON COLUMN package_version_manifests.package_version_id IS 'package version id'; +COMMENT ON COLUMN package_version_manifests.package_version_manifest_id IS 'package version manifest id'; +COMMENT ON COLUMN package_version_manifests.manifest IS 'manifest JSON, including README text'; + + +CREATE TABLE package_versions ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_id varchar(24) NOT NULL, + package_version_id varchar(24) NOT NULL, + version varchar(256) NOT NULL, + abbreviated_dist_id varchar(24) NOT NULL, + manifest_dist_id varchar(24) NOT NULL, + tar_dist_id varchar(24) NOT NULL, + readme_dist_id varchar(24) NOT NULL, + publish_time timestamp(3) NOT NULL, + padding_version varchar(255) DEFAULT NULL, + is_pre_release boolean DEFAULT NULL +); + +CREATE UNIQUE INDEX package_versions_uk_package_version_id ON package_versions (package_version_id); +CREATE UNIQUE INDEX package_versions_uk_package_id_version ON package_versions (package_id, version); +CREATE INDEX package_versions_idx_pkg_id_is_pre_release_padding_version ON package_versions (package_id, padding_version, is_pre_release, version); + +COMMENT ON TABLE package_versions IS 'package version info'; +COMMENT ON COLUMN package_versions.id IS 'primary key'; +COMMENT ON COLUMN package_versions.gmt_create IS 'create time'; +COMMENT ON COLUMN package_versions.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_versions.package_id IS 'package id'; +COMMENT ON COLUMN package_versions.package_version_id IS 'package version id'; +COMMENT ON COLUMN package_versions.version IS 'package version'; +COMMENT ON COLUMN package_versions.abbreviated_dist_id IS 'abbreviated manifest dist id'; +COMMENT ON COLUMN package_versions.manifest_dist_id IS 'manifest dist id'; +COMMENT ON COLUMN package_versions.tar_dist_id IS 'tar dist id'; +COMMENT ON COLUMN package_versions.readme_dist_id IS 'readme dist id'; +COMMENT ON COLUMN package_versions.publish_time IS 'publish time'; +COMMENT ON COLUMN package_versions.padding_version IS 'token name'; +COMMENT ON COLUMN package_versions.is_pre_release IS '是否是先行版本'; + + +CREATE TABLE packages ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_id varchar(24) NOT NULL, + is_private boolean NOT NULL DEFAULT false, + name varchar(214) NOT NULL, + scope varchar(214) NOT NULL, + description varchar(10240) DEFAULT NULL, + abbreviateds_dist_id varchar(24) DEFAULT NULL, + manifests_dist_id varchar(24) DEFAULT NULL, + registry_id varchar(24) DEFAULT NULL +); + +CREATE UNIQUE INDEX packages_uk_package_id ON packages (package_id); +CREATE UNIQUE INDEX packages_uk_scope_name ON packages (scope, name); + +COMMENT ON TABLE packages IS 'package info'; +COMMENT ON COLUMN packages.id IS 'primary key'; +COMMENT ON COLUMN packages.gmt_create IS 'create time'; +COMMENT ON COLUMN packages.gmt_modified IS 'modified time'; +COMMENT ON COLUMN packages.package_id IS 'package id'; +COMMENT ON COLUMN packages.is_private IS 'private pkg or not, 1: true, other: false'; +COMMENT ON COLUMN packages.name IS 'package name'; +COMMENT ON COLUMN packages.scope IS 'package name, empty string meaning no scope'; +COMMENT ON COLUMN packages.description IS 'package description'; +COMMENT ON COLUMN packages.abbreviateds_dist_id IS 'all abbreviated manifests dist id'; +COMMENT ON COLUMN packages.manifests_dist_id IS 'all full manifests dist id'; +COMMENT ON COLUMN packages.registry_id IS 'source registry'; + + +CREATE TABLE proxy_caches ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + fullname varchar(214) NOT NULL DEFAULT '', + version varchar(214) DEFAULT NULL, + file_type varchar(30) NOT NULL DEFAULT '', + file_path varchar(512) NOT NULL DEFAULT '' +); + +CREATE UNIQUE INDEX proxy_caches_uk_package_version_path_name ON proxy_caches (file_path); +CREATE UNIQUE INDEX proxy_caches_ux_package_version_file_name ON proxy_caches (fullname, file_type, version); + +COMMENT ON TABLE proxy_caches IS 'proxy mode cached files index'; +COMMENT ON COLUMN proxy_caches.id IS 'primary key'; +COMMENT ON COLUMN proxy_caches.gmt_create IS 'create time'; +COMMENT ON COLUMN proxy_caches.gmt_modified IS 'modify time'; +COMMENT ON COLUMN proxy_caches.fullname IS '@scope/package name'; +COMMENT ON COLUMN proxy_caches.version IS 'package version'; +COMMENT ON COLUMN proxy_caches.file_type IS 'file type'; +COMMENT ON COLUMN proxy_caches.file_path IS 'nfs file path'; + + +CREATE TABLE registries ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + registry_id varchar(24) NOT NULL, + name varchar(256) DEFAULT NULL, + host varchar(4096) DEFAULT NULL, + change_stream varchar(4096) DEFAULT NULL, + type varchar(256) DEFAULT NULL, + user_prefix varchar(256) DEFAULT NULL, + auth_token varchar(256) DEFAULT NULL +); + +CREATE UNIQUE INDEX registries_uk_name ON registries (name); + +COMMENT ON TABLE registries IS 'registry info'; +COMMENT ON COLUMN registries.id IS 'primary key'; +COMMENT ON COLUMN registries.gmt_create IS 'create time'; +COMMENT ON COLUMN registries.gmt_modified IS 'modified time'; +COMMENT ON COLUMN registries.registry_id IS 'registry id'; +COMMENT ON COLUMN registries.name IS 'registry name'; +COMMENT ON COLUMN registries.host IS 'registry host'; +COMMENT ON COLUMN registries.change_stream IS 'change stream url'; +COMMENT ON COLUMN registries.type IS 'registry type cnpmjsorg/cnpmcore/npm'; +COMMENT ON COLUMN registries.user_prefix IS 'user prefix'; +COMMENT ON COLUMN registries.auth_token IS 'registry auth token'; + + +CREATE TABLE scopes ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + scope_id varchar(24) NOT NULL, + name varchar(214) DEFAULT NULL, + registry_id varchar(24) NOT NULL +); + +CREATE UNIQUE INDEX scopes_uk_name ON scopes (name); + +COMMENT ON TABLE scopes IS 'scope info'; +COMMENT ON COLUMN scopes.id IS 'primary key'; +COMMENT ON COLUMN scopes.gmt_create IS 'create time'; +COMMENT ON COLUMN scopes.gmt_modified IS 'modified time'; +COMMENT ON COLUMN scopes.scope_id IS 'scope id'; +COMMENT ON COLUMN scopes.name IS 'scope name'; +COMMENT ON COLUMN scopes.registry_id IS 'registry id'; + + +CREATE TABLE tasks ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + task_id varchar(24) NOT NULL, + type varchar(20) NOT NULL, + state varchar(20) NOT NULL, + target_name varchar(214) NOT NULL, + author_id varchar(24) NOT NULL, + author_ip varchar(100) NOT NULL, + data json DEFAULT NULL, + log_path varchar(512) NOT NULL, + log_store_position varchar(10) NOT NULL, + attempts integer DEFAULT 0, + error text, + biz_id varchar(100) DEFAULT NULL +); + +CREATE UNIQUE INDEX tasks_uk_task_id ON tasks (task_id); +CREATE UNIQUE INDEX tasks_uk_biz_id ON tasks (biz_id); +CREATE INDEX tasks_idx_type_state_target_name ON tasks (target_name, type, state); +CREATE INDEX tasks_idx_type_state_gmt_modified ON tasks (type, state, gmt_modified); +CREATE INDEX tasks_idx_gmt_modified ON tasks (gmt_modified); + +COMMENT ON TABLE tasks IS 'task info'; +COMMENT ON COLUMN tasks.id IS 'primary key'; +COMMENT ON COLUMN tasks.gmt_create IS 'create time'; +COMMENT ON COLUMN tasks.gmt_modified IS 'modified time'; +COMMENT ON COLUMN tasks.task_id IS 'task id'; +COMMENT ON COLUMN tasks.type IS 'task type'; +COMMENT ON COLUMN tasks.state IS 'task state'; +COMMENT ON COLUMN tasks.target_name IS 'target name, like package name / user name'; +COMMENT ON COLUMN tasks.author_id IS 'create task user id'; +COMMENT ON COLUMN tasks.author_ip IS 'create task user request ip'; +COMMENT ON COLUMN tasks.data IS 'task params'; +COMMENT ON COLUMN tasks.log_path IS 'access path'; +COMMENT ON COLUMN tasks.log_store_position IS 'cloud store disk position'; +COMMENT ON COLUMN tasks.attempts IS 'task execute attempts times'; +COMMENT ON COLUMN tasks.error IS 'error description'; +COMMENT ON COLUMN tasks.biz_id IS 'unique biz id to keep task unique'; + + +CREATE TABLE token_packages ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + token_id varchar(24) NOT NULL, + package_id varchar(24) NOT NULL +); + +CREATE UNIQUE INDEX token_packages_uk_token_id_package_id ON token_packages (token_id, package_id); +CREATE INDEX token_packages_idx_token_id ON token_packages (token_id); +CREATE INDEX token_packages_idx_package_id ON token_packages (package_id); + +COMMENT ON TABLE token_packages IS 'token allowed packages'; +COMMENT ON COLUMN token_packages.id IS 'primary key'; +COMMENT ON COLUMN token_packages.gmt_create IS 'create time'; +COMMENT ON COLUMN token_packages.gmt_modified IS 'modified time'; +COMMENT ON COLUMN token_packages.token_id IS 'token id'; +COMMENT ON COLUMN token_packages.package_id IS 'package id'; + + +CREATE TABLE tokens ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + token_id varchar(24) NOT NULL, + token_mark varchar(20) NOT NULL, + token_key varchar(200) NOT NULL, + is_readonly boolean NOT NULL DEFAULT false, + is_automation boolean NOT NULL DEFAULT false, + cidr_whitelist json NOT NULL, + user_id varchar(24) NOT NULL, + name varchar(255) DEFAULT NULL, + type varchar(255) DEFAULT NULL, + description varchar(255) DEFAULT NULL, + allowed_scopes text, + expired_at timestamp(3) DEFAULT NULL, + last_used_at timestamp(3) DEFAULT NULL +); + +CREATE UNIQUE INDEX tokens_uk_token_id ON tokens (token_id); +CREATE UNIQUE INDEX tokens_uk_token_key ON tokens (token_key); +CREATE UNIQUE INDEX tokens_uk_user_id_name ON tokens (user_id, name); +CREATE INDEX tokens_idx_user_id ON tokens (user_id); + +COMMENT ON TABLE tokens IS 'token info'; +COMMENT ON COLUMN tokens.id IS 'primary key'; +COMMENT ON COLUMN tokens.gmt_create IS 'create time'; +COMMENT ON COLUMN tokens.gmt_modified IS 'modified time'; +COMMENT ON COLUMN tokens.token_id IS 'token id'; +COMMENT ON COLUMN tokens.token_mark IS 'token mark value'; +COMMENT ON COLUMN tokens.token_key IS 'token value sha512 hex'; +COMMENT ON COLUMN tokens.is_readonly IS 'readonly token or not, 1: true, other: false'; +COMMENT ON COLUMN tokens.is_automation IS 'automation token or not, 1: true, other: false'; +COMMENT ON COLUMN tokens.cidr_whitelist IS 'ip list, ["127.0.0.1"]'; +COMMENT ON COLUMN tokens.user_id IS 'user id'; +COMMENT ON COLUMN tokens.name IS 'token name'; +COMMENT ON COLUMN tokens.type IS 'token type, granular or legacy'; +COMMENT ON COLUMN tokens.description IS 'token description'; +COMMENT ON COLUMN tokens.allowed_scopes IS 'scope allowed list'; +COMMENT ON COLUMN tokens.expired_at IS 'token expiration time'; +COMMENT ON COLUMN tokens.last_used_at IS 'token last used time'; + + +CREATE TABLE total ( + id BIGSERIAL PRIMARY KEY, + total_id varchar(24) NOT NULL, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_count bigint NOT NULL DEFAULT 0, + package_file_size bigint NOT NULL DEFAULT 0, + package_version_count bigint NOT NULL DEFAULT 0, + package_version_delete_count bigint NOT NULL DEFAULT 0, + private_package_count bigint NOT NULL DEFAULT 0, + private_package_file_size bigint NOT NULL DEFAULT 0, + private_package_version_count bigint NOT NULL DEFAULT 0, + private_package_version_delete_count bigint NOT NULL DEFAULT 0, + change_stream_seq varchar(100) DEFAULT NULL +); + +CREATE UNIQUE INDEX total_uk_total_id ON total (total_id); + +COMMENT ON TABLE total IS 'total info'; +COMMENT ON COLUMN total.id IS 'primary key'; +COMMENT ON COLUMN total.total_id IS 'total id, should set it to "global"'; +COMMENT ON COLUMN total.gmt_create IS 'create time'; +COMMENT ON COLUMN total.gmt_modified IS 'modified time'; +COMMENT ON COLUMN total.package_count IS 'package count'; +COMMENT ON COLUMN total.package_file_size IS 'package all files total size'; +COMMENT ON COLUMN total.package_version_count IS 'package version count'; +COMMENT ON COLUMN total.package_version_delete_count IS 'package version delete count'; +COMMENT ON COLUMN total.private_package_count IS 'private package count'; +COMMENT ON COLUMN total.private_package_file_size IS 'private package all files total size'; +COMMENT ON COLUMN total.private_package_version_count IS 'private package version count'; +COMMENT ON COLUMN total.private_package_version_delete_count IS 'private package version delete count'; +COMMENT ON COLUMN total.change_stream_seq IS 'npm change stream sync data seq id'; + + +CREATE TABLE users ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + user_id varchar(24) NOT NULL, + name varchar(100) NOT NULL, + email varchar(400) NOT NULL, + password_salt varchar(100) NOT NULL, + password_integrity varchar(512) NOT NULL, + ip varchar(100) NOT NULL, + is_private boolean NOT NULL DEFAULT true, + scopes json DEFAULT NULL +); + +CREATE UNIQUE INDEX users_uk_user_id ON users (user_id); +CREATE UNIQUE INDEX users_uk_name ON users (name); + +COMMENT ON TABLE users IS 'user info'; +COMMENT ON COLUMN users.id IS 'primary key'; +COMMENT ON COLUMN users.gmt_create IS 'create time'; +COMMENT ON COLUMN users.gmt_modified IS 'modified time'; +COMMENT ON COLUMN users.user_id IS 'user id'; +COMMENT ON COLUMN users.name IS 'user name'; +COMMENT ON COLUMN users.email IS 'user email'; +COMMENT ON COLUMN users.password_salt IS 'password salt'; +COMMENT ON COLUMN users.password_integrity IS 'password integrity'; +COMMENT ON COLUMN users.ip IS 'user login request ip'; +COMMENT ON COLUMN users.is_private IS 'private user or not, 1: true, other: false'; +COMMENT ON COLUMN users.scopes IS 'white scope list, ["@cnpm", "@foo"]'; + + +CREATE TABLE webauthn_credentials ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + wanc_id varchar(24) NOT NULL, + user_id varchar(24) NOT NULL, + credential_id varchar(200) NOT NULL, + public_key varchar(512) NOT NULL, + browser_type varchar(20) DEFAULT NULL +); + +CREATE UNIQUE INDEX webauthn_credentials_uk_wanc_id ON webauthn_credentials (wanc_id); +CREATE INDEX webauthn_credentials_idx_user_id ON webauthn_credentials (user_id); + +COMMENT ON TABLE webauthn_credentials IS 'webauthn credential info'; +COMMENT ON COLUMN webauthn_credentials.id IS 'primary key'; +COMMENT ON COLUMN webauthn_credentials.gmt_create IS 'create time'; +COMMENT ON COLUMN webauthn_credentials.gmt_modified IS 'modified time'; +COMMENT ON COLUMN webauthn_credentials.wanc_id IS 'webauthn credential id'; +COMMENT ON COLUMN webauthn_credentials.user_id IS 'user id'; +COMMENT ON COLUMN webauthn_credentials.credential_id IS 'webauthn credential id'; +COMMENT ON COLUMN webauthn_credentials.public_key IS 'webauthn credential publick key'; +COMMENT ON COLUMN webauthn_credentials.browser_type IS 'user browser name'; diff --git a/sql/1.10.0.sql b/sql/mysql/1.10.0.sql similarity index 100% rename from sql/1.10.0.sql rename to sql/mysql/1.10.0.sql diff --git a/sql/1.11.0.sql b/sql/mysql/1.11.0.sql similarity index 100% rename from sql/1.11.0.sql rename to sql/mysql/1.11.0.sql diff --git a/sql/1.12.0.sql b/sql/mysql/1.12.0.sql similarity index 100% rename from sql/1.12.0.sql rename to sql/mysql/1.12.0.sql diff --git a/sql/1.13.0.sql b/sql/mysql/1.13.0.sql similarity index 100% rename from sql/1.13.0.sql rename to sql/mysql/1.13.0.sql diff --git a/sql/1.14.0.sql b/sql/mysql/1.14.0.sql similarity index 100% rename from sql/1.14.0.sql rename to sql/mysql/1.14.0.sql diff --git a/sql/1.15.0.sql b/sql/mysql/1.15.0.sql similarity index 100% rename from sql/1.15.0.sql rename to sql/mysql/1.15.0.sql diff --git a/sql/1.16.0.sql b/sql/mysql/1.16.0.sql similarity index 100% rename from sql/1.16.0.sql rename to sql/mysql/1.16.0.sql diff --git a/sql/3.28.0.sql b/sql/mysql/3.28.0.sql similarity index 100% rename from sql/3.28.0.sql rename to sql/mysql/3.28.0.sql diff --git a/sql/3.46.0.sql b/sql/mysql/3.46.0.sql similarity index 100% rename from sql/3.46.0.sql rename to sql/mysql/3.46.0.sql diff --git a/sql/3.63.0.sql b/sql/mysql/3.63.0.sql similarity index 100% rename from sql/3.63.0.sql rename to sql/mysql/3.63.0.sql diff --git a/sql/postgresql/3.68.0.sql b/sql/postgresql/3.68.0.sql new file mode 100644 index 00000000..38298c34 --- /dev/null +++ b/sql/postgresql/3.68.0.sql @@ -0,0 +1,704 @@ +CREATE TABLE binaries ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + binary_id varchar(24) NOT NULL, + category varchar(50) NOT NULL, + parent varchar(500) NOT NULL, + name varchar(200) NOT NULL, + is_dir boolean NOT NULL DEFAULT false, + size integer NOT NULL, + date varchar(100) NOT NULL +); + +CREATE UNIQUE INDEX binaries_uk_binary_id ON binaries (binary_id); +CREATE UNIQUE INDEX binaries_uk_category_parent_name ON binaries (category, parent, name); +CREATE INDEX binaries_idx_category_parent ON binaries (category, parent); + +COMMENT ON TABLE binaries IS 'binary info'; +COMMENT ON COLUMN binaries.id IS 'primary key'; +COMMENT ON COLUMN binaries.gmt_create IS 'create time'; +COMMENT ON COLUMN binaries.gmt_modified IS 'modified time'; +COMMENT ON COLUMN binaries.binary_id IS 'binary id'; +COMMENT ON COLUMN binaries.category IS 'binary category, e.g.: node, sass'; +COMMENT ON COLUMN binaries.parent IS 'binary parent name, e.g.: /, /v1.0.0/, /v1.0.0/docs/'; +COMMENT ON COLUMN binaries.name IS 'binary name, dir should ends with /'; +COMMENT ON COLUMN binaries.is_dir IS 'is dir or not, 1: true, other: false'; +COMMENT ON COLUMN binaries.size IS 'file size'; +COMMENT ON COLUMN binaries.date IS 'date display string'; + + +CREATE TABLE changes ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + change_id varchar(24) NOT NULL, + type varchar(50) NOT NULL, + target_name varchar(214) NOT NULL, + data json DEFAULT NULL +); + +CREATE UNIQUE INDEX changes_uk_change_id ON changes (change_id); + +COMMENT ON TABLE changes IS 'change info'; +COMMENT ON COLUMN changes.id IS 'primary key'; +COMMENT ON COLUMN changes.gmt_create IS 'create time'; +COMMENT ON COLUMN changes.gmt_modified IS 'modified time'; +COMMENT ON COLUMN changes.change_id IS 'change id'; +COMMENT ON COLUMN changes.type IS 'change type'; +COMMENT ON COLUMN changes.target_name IS 'target name, like package name / user name'; +COMMENT ON COLUMN changes.data IS 'change params'; + + +CREATE TABLE dists ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + dist_id varchar(24) NOT NULL, + name varchar(428) NOT NULL, + path varchar(767) NOT NULL, + size integer NOT NULL, + shasum varchar(512) NOT NULL, + integrity varchar(512) NOT NULL +); + +CREATE UNIQUE INDEX dists_uk_dist_id ON dists (dist_id); + +COMMENT ON TABLE dists IS 'dist info'; +COMMENT ON COLUMN dists.id IS 'primary key'; +COMMENT ON COLUMN dists.gmt_create IS 'create time'; +COMMENT ON COLUMN dists.gmt_modified IS 'modified time'; +COMMENT ON COLUMN dists.dist_id IS 'dist id'; +COMMENT ON COLUMN dists.name IS 'dist name, 2x size of package name'; +COMMENT ON COLUMN dists.path IS 'access path'; +COMMENT ON COLUMN dists.size IS 'file size'; +COMMENT ON COLUMN dists.shasum IS 'dist shasum'; +COMMENT ON COLUMN dists.integrity IS 'dist integrity'; + + +CREATE TABLE history_tasks ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + task_id varchar(24) NOT NULL, + type varchar(20) NOT NULL, + state varchar(20) NOT NULL, + target_name varchar(214) NOT NULL, + author_id varchar(24) NOT NULL, + author_ip varchar(100) NOT NULL, + data json DEFAULT NULL, + log_path varchar(512) NOT NULL, + log_store_position varchar(10) NOT NULL, + attempts integer DEFAULT 0, + error text +); + +CREATE UNIQUE INDEX history_tasks_uk_task_id ON history_tasks (task_id); + +COMMENT ON TABLE history_tasks IS 'history task info'; +COMMENT ON COLUMN history_tasks.id IS 'primary key'; +COMMENT ON COLUMN history_tasks.gmt_create IS 'create time'; +COMMENT ON COLUMN history_tasks.gmt_modified IS 'modified time'; +COMMENT ON COLUMN history_tasks.task_id IS 'task id'; +COMMENT ON COLUMN history_tasks.type IS 'task type'; +COMMENT ON COLUMN history_tasks.state IS 'task state'; +COMMENT ON COLUMN history_tasks.target_name IS 'target name, like package name / user name'; +COMMENT ON COLUMN history_tasks.author_id IS 'create task user id'; +COMMENT ON COLUMN history_tasks.author_ip IS 'create task user request ip'; +COMMENT ON COLUMN history_tasks.data IS 'task params'; +COMMENT ON COLUMN history_tasks.log_path IS 'access path'; +COMMENT ON COLUMN history_tasks.log_store_position IS 'cloud store disk position'; +COMMENT ON COLUMN history_tasks.attempts IS 'task execute attempts times'; +COMMENT ON COLUMN history_tasks.error IS 'error description'; + + +CREATE TABLE hooks ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + hook_id varchar(24) NOT NULL, + type varchar(20) NOT NULL, + name varchar(428) NOT NULL, + owner_id varchar(24) NOT NULL, + endpoint varchar(2048) NOT NULL, + secret varchar(200) NOT NULL, + latest_task_id varchar(24) DEFAULT NULL, + enable boolean NOT NULL DEFAULT false +); + +CREATE UNIQUE INDEX hooks_uk_type_name_owner_id ON hooks (type, name, owner_id); +CREATE INDEX hooks_idx_type_name_id ON hooks (type, name, id); + +COMMENT ON TABLE hooks IS 'task info'; +COMMENT ON COLUMN hooks.id IS 'primary key'; +COMMENT ON COLUMN hooks.gmt_create IS 'create time'; +COMMENT ON COLUMN hooks.gmt_modified IS 'modified time'; +COMMENT ON COLUMN hooks.hook_id IS 'hook id'; +COMMENT ON COLUMN hooks.type IS 'hook type, scope, name, owner'; +COMMENT ON COLUMN hooks.name IS 'hook name'; +COMMENT ON COLUMN hooks.owner_id IS 'hook owner id'; +COMMENT ON COLUMN hooks.endpoint IS 'hook url'; +COMMENT ON COLUMN hooks.secret IS 'sign secret'; +COMMENT ON COLUMN hooks.latest_task_id IS 'latest task id'; +COMMENT ON COLUMN hooks.enable IS 'hook is enable not, 1: true, other: false'; + + +CREATE TABLE maintainers ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_id varchar(24) NOT NULL, + user_id varchar(24) NOT NULL +); + +CREATE UNIQUE INDEX maintainers_uk_package_id_user_id ON maintainers (package_id, user_id); +CREATE INDEX maintainers_idx_package_id ON maintainers (package_id); +CREATE INDEX maintainers_idx_user_id ON maintainers (user_id); + +COMMENT ON TABLE maintainers IS 'package maintainers'; +COMMENT ON COLUMN maintainers.id IS 'primary key'; +COMMENT ON COLUMN maintainers.gmt_create IS 'create time'; +COMMENT ON COLUMN maintainers.gmt_modified IS 'modified time'; +COMMENT ON COLUMN maintainers.package_id IS 'package id'; +COMMENT ON COLUMN maintainers.user_id IS 'user id'; + + +CREATE TABLE package_deps ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_version_id varchar(24) NOT NULL, + package_dep_id varchar(24) NOT NULL, + scope varchar(214) NOT NULL, + name varchar(214) NOT NULL, + spec varchar(100) NOT NULL +); + +CREATE UNIQUE INDEX package_deps_uk_package_dep_id ON package_deps (package_dep_id); +CREATE UNIQUE INDEX package_deps_uk_package_version_id_scope_name ON package_deps (package_version_id, scope, name); + +COMMENT ON TABLE package_deps IS 'package dependency info'; +COMMENT ON COLUMN package_deps.id IS 'primary key'; +COMMENT ON COLUMN package_deps.gmt_create IS 'create time'; +COMMENT ON COLUMN package_deps.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_deps.package_version_id IS 'package version id'; +COMMENT ON COLUMN package_deps.package_dep_id IS 'package dep id'; +COMMENT ON COLUMN package_deps.scope IS 'package scope'; +COMMENT ON COLUMN package_deps.name IS 'package name'; +COMMENT ON COLUMN package_deps.spec IS 'package dep spec'; + + +CREATE TABLE package_tags ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_id varchar(24) NOT NULL, + package_tag_id varchar(24) NOT NULL, + tag varchar(214) NOT NULL, + version varchar(256) NOT NULL +); + +CREATE UNIQUE INDEX package_tags_uk_package_tag_id ON package_tags (package_tag_id); +CREATE UNIQUE INDEX package_tags_uk_package_tag ON package_tags (package_id, tag); + +COMMENT ON TABLE package_tags IS 'package tag info'; +COMMENT ON COLUMN package_tags.id IS 'primary key'; +COMMENT ON COLUMN package_tags.gmt_create IS 'create time'; +COMMENT ON COLUMN package_tags.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_tags.package_id IS 'package id'; +COMMENT ON COLUMN package_tags.package_tag_id IS 'package tag id'; +COMMENT ON COLUMN package_tags.tag IS 'package tag'; +COMMENT ON COLUMN package_tags.version IS 'package version'; + + +CREATE TABLE package_version_blocks ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_version_block_id varchar(24) NOT NULL, + package_id varchar(24) NOT NULL, + version varchar(256) NOT NULL, + reason text NOT NULL +); + +CREATE UNIQUE INDEX package_version_blocks_uk_package_version_block_id ON package_version_blocks (package_version_block_id); +CREATE UNIQUE INDEX package_version_blocks_uk_name_version ON package_version_blocks (package_id, version); + +COMMENT ON TABLE package_version_blocks IS 'blocklist package versions'; +COMMENT ON COLUMN package_version_blocks.id IS 'primary key'; +COMMENT ON COLUMN package_version_blocks.gmt_create IS 'create time'; +COMMENT ON COLUMN package_version_blocks.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_version_blocks.package_version_block_id IS 'package version block id'; +COMMENT ON COLUMN package_version_blocks.package_id IS 'package id'; +COMMENT ON COLUMN package_version_blocks.version IS 'package version, "*" meaning all versions'; +COMMENT ON COLUMN package_version_blocks.reason IS 'block reason'; + + +CREATE TABLE package_version_downloads ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + year_month integer NOT NULL, + package_id varchar(214) NOT NULL, + version varchar(256) NOT NULL, + d01 integer NOT NULL DEFAULT 0, + d02 integer NOT NULL DEFAULT 0, + d03 integer NOT NULL DEFAULT 0, + d04 integer NOT NULL DEFAULT 0, + d05 integer NOT NULL DEFAULT 0, + d06 integer NOT NULL DEFAULT 0, + d07 integer NOT NULL DEFAULT 0, + d08 integer NOT NULL DEFAULT 0, + d09 integer NOT NULL DEFAULT 0, + d10 integer NOT NULL DEFAULT 0, + d11 integer NOT NULL DEFAULT 0, + d12 integer NOT NULL DEFAULT 0, + d13 integer NOT NULL DEFAULT 0, + d14 integer NOT NULL DEFAULT 0, + d15 integer NOT NULL DEFAULT 0, + d16 integer NOT NULL DEFAULT 0, + d17 integer NOT NULL DEFAULT 0, + d18 integer NOT NULL DEFAULT 0, + d19 integer NOT NULL DEFAULT 0, + d20 integer NOT NULL DEFAULT 0, + d21 integer NOT NULL DEFAULT 0, + d22 integer NOT NULL DEFAULT 0, + d23 integer NOT NULL DEFAULT 0, + d24 integer NOT NULL DEFAULT 0, + d25 integer NOT NULL DEFAULT 0, + d26 integer NOT NULL DEFAULT 0, + d27 integer NOT NULL DEFAULT 0, + d28 integer NOT NULL DEFAULT 0, + d29 integer NOT NULL DEFAULT 0, + d30 integer NOT NULL DEFAULT 0, + d31 integer NOT NULL DEFAULT 0 +); + +CREATE UNIQUE INDEX package_version_downloads_uk_year_month_package_id_version ON package_version_downloads (year_month, package_id, version); +CREATE INDEX package_version_downloads_idx_year_month ON package_version_downloads (year_month); +CREATE INDEX package_version_downloads_idx_packageid_yearmonth ON package_version_downloads (package_id, year_month); + +COMMENT ON TABLE package_version_downloads IS 'package version download total info'; +COMMENT ON COLUMN package_version_downloads.id IS 'primary key'; +COMMENT ON COLUMN package_version_downloads.gmt_create IS 'create time'; +COMMENT ON COLUMN package_version_downloads.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_version_downloads.year_month IS 'YYYYMM format'; +COMMENT ON COLUMN package_version_downloads.package_id IS 'package id, maybe scope name'; +COMMENT ON COLUMN package_version_downloads.version IS 'package version'; +COMMENT ON COLUMN package_version_downloads.d01 IS '01 download count'; +COMMENT ON COLUMN package_version_downloads.d02 IS '02 download count'; +COMMENT ON COLUMN package_version_downloads.d03 IS '03 download count'; +COMMENT ON COLUMN package_version_downloads.d04 IS '04 download count'; +COMMENT ON COLUMN package_version_downloads.d05 IS '05 download count'; +COMMENT ON COLUMN package_version_downloads.d06 IS '06 download count'; +COMMENT ON COLUMN package_version_downloads.d07 IS '07 download count'; +COMMENT ON COLUMN package_version_downloads.d08 IS '08 download count'; +COMMENT ON COLUMN package_version_downloads.d09 IS '09 download count'; +COMMENT ON COLUMN package_version_downloads.d10 IS '10 download count'; +COMMENT ON COLUMN package_version_downloads.d11 IS '11 download count'; +COMMENT ON COLUMN package_version_downloads.d12 IS '12 download count'; +COMMENT ON COLUMN package_version_downloads.d13 IS '13 download count'; +COMMENT ON COLUMN package_version_downloads.d14 IS '14 download count'; +COMMENT ON COLUMN package_version_downloads.d15 IS '15 download count'; +COMMENT ON COLUMN package_version_downloads.d16 IS '16 download count'; +COMMENT ON COLUMN package_version_downloads.d17 IS '17 download count'; +COMMENT ON COLUMN package_version_downloads.d18 IS '18 download count'; +COMMENT ON COLUMN package_version_downloads.d19 IS '19 download count'; +COMMENT ON COLUMN package_version_downloads.d20 IS '20 download count'; +COMMENT ON COLUMN package_version_downloads.d21 IS '21 download count'; +COMMENT ON COLUMN package_version_downloads.d22 IS '22 download count'; +COMMENT ON COLUMN package_version_downloads.d23 IS '23 download count'; +COMMENT ON COLUMN package_version_downloads.d24 IS '24 download count'; +COMMENT ON COLUMN package_version_downloads.d25 IS '25 download count'; +COMMENT ON COLUMN package_version_downloads.d26 IS '26 download count'; +COMMENT ON COLUMN package_version_downloads.d27 IS '27 download count'; +COMMENT ON COLUMN package_version_downloads.d28 IS '28 download count'; +COMMENT ON COLUMN package_version_downloads.d29 IS '29 download count'; +COMMENT ON COLUMN package_version_downloads.d30 IS '30 download count'; +COMMENT ON COLUMN package_version_downloads.d31 IS '31 download count'; + + +CREATE TABLE package_version_files ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_version_id varchar(24) NOT NULL, + package_version_file_id varchar(24) NOT NULL, + dist_id varchar(24) NOT NULL, + directory varchar(500) NOT NULL, + name varchar(200) NOT NULL, + content_type varchar(200) NOT NULL, + mtime timestamp(3) NOT NULL +); + +CREATE UNIQUE INDEX package_version_files_uk_package_version_file_id ON package_version_files (package_version_file_id); +CREATE UNIQUE INDEX package_version_files_ux_package_version_id_directory_name ON package_version_files (package_version_id, directory, name); + +COMMENT ON TABLE package_version_files IS 'package version file'; +COMMENT ON COLUMN package_version_files.id IS 'primary key'; +COMMENT ON COLUMN package_version_files.gmt_create IS 'create time'; +COMMENT ON COLUMN package_version_files.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_version_files.package_version_id IS 'package version id'; +COMMENT ON COLUMN package_version_files.package_version_file_id IS 'package version file id'; +COMMENT ON COLUMN package_version_files.dist_id IS 'file dist id'; +COMMENT ON COLUMN package_version_files.directory IS 'directory path, e.g.: /bin'; +COMMENT ON COLUMN package_version_files.name IS 'file name, e.g.: index.js'; +COMMENT ON COLUMN package_version_files.content_type IS 'file content type, e.g.: application/javascript'; +COMMENT ON COLUMN package_version_files.mtime IS 'file modified time'; + + +CREATE TABLE package_version_manifests ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_id varchar(24) NOT NULL, + package_version_id varchar(24) NOT NULL, + package_version_manifest_id varchar(24) NOT NULL, + manifest json NOT NULL +); + +CREATE UNIQUE INDEX package_version_manifests_uk_package_version_manifest_id ON package_version_manifests (package_version_manifest_id); +CREATE UNIQUE INDEX package_version_manifests_uk_package_version_id ON package_version_manifests (package_version_id); +CREATE INDEX package_version_manifests_idx_package_id ON package_version_manifests (package_id); + +COMMENT ON TABLE package_version_manifests IS 'package version manifest'; +COMMENT ON COLUMN package_version_manifests.id IS 'primary key'; +COMMENT ON COLUMN package_version_manifests.gmt_create IS 'create time'; +COMMENT ON COLUMN package_version_manifests.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_version_manifests.package_id IS 'package id'; +COMMENT ON COLUMN package_version_manifests.package_version_id IS 'package version id'; +COMMENT ON COLUMN package_version_manifests.package_version_manifest_id IS 'package version manifest id'; +COMMENT ON COLUMN package_version_manifests.manifest IS 'manifest JSON, including README text'; + + +CREATE TABLE package_versions ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_id varchar(24) NOT NULL, + package_version_id varchar(24) NOT NULL, + version varchar(256) NOT NULL, + abbreviated_dist_id varchar(24) NOT NULL, + manifest_dist_id varchar(24) NOT NULL, + tar_dist_id varchar(24) NOT NULL, + readme_dist_id varchar(24) NOT NULL, + publish_time timestamp(3) NOT NULL, + padding_version varchar(255) DEFAULT NULL, + is_pre_release boolean DEFAULT NULL +); + +CREATE UNIQUE INDEX package_versions_uk_package_version_id ON package_versions (package_version_id); +CREATE UNIQUE INDEX package_versions_uk_package_id_version ON package_versions (package_id, version); +CREATE INDEX package_versions_idx_pkg_id_is_pre_release_padding_version ON package_versions (package_id, padding_version, is_pre_release, version); + +COMMENT ON TABLE package_versions IS 'package version info'; +COMMENT ON COLUMN package_versions.id IS 'primary key'; +COMMENT ON COLUMN package_versions.gmt_create IS 'create time'; +COMMENT ON COLUMN package_versions.gmt_modified IS 'modified time'; +COMMENT ON COLUMN package_versions.package_id IS 'package id'; +COMMENT ON COLUMN package_versions.package_version_id IS 'package version id'; +COMMENT ON COLUMN package_versions.version IS 'package version'; +COMMENT ON COLUMN package_versions.abbreviated_dist_id IS 'abbreviated manifest dist id'; +COMMENT ON COLUMN package_versions.manifest_dist_id IS 'manifest dist id'; +COMMENT ON COLUMN package_versions.tar_dist_id IS 'tar dist id'; +COMMENT ON COLUMN package_versions.readme_dist_id IS 'readme dist id'; +COMMENT ON COLUMN package_versions.publish_time IS 'publish time'; +COMMENT ON COLUMN package_versions.padding_version IS 'token name'; +COMMENT ON COLUMN package_versions.is_pre_release IS '是否是先行版本'; + + +CREATE TABLE packages ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_id varchar(24) NOT NULL, + is_private boolean NOT NULL DEFAULT false, + name varchar(214) NOT NULL, + scope varchar(214) NOT NULL, + description varchar(10240) DEFAULT NULL, + abbreviateds_dist_id varchar(24) DEFAULT NULL, + manifests_dist_id varchar(24) DEFAULT NULL, + registry_id varchar(24) DEFAULT NULL +); + +CREATE UNIQUE INDEX packages_uk_package_id ON packages (package_id); +CREATE UNIQUE INDEX packages_uk_scope_name ON packages (scope, name); + +COMMENT ON TABLE packages IS 'package info'; +COMMENT ON COLUMN packages.id IS 'primary key'; +COMMENT ON COLUMN packages.gmt_create IS 'create time'; +COMMENT ON COLUMN packages.gmt_modified IS 'modified time'; +COMMENT ON COLUMN packages.package_id IS 'package id'; +COMMENT ON COLUMN packages.is_private IS 'private pkg or not, 1: true, other: false'; +COMMENT ON COLUMN packages.name IS 'package name'; +COMMENT ON COLUMN packages.scope IS 'package name, empty string meaning no scope'; +COMMENT ON COLUMN packages.description IS 'package description'; +COMMENT ON COLUMN packages.abbreviateds_dist_id IS 'all abbreviated manifests dist id'; +COMMENT ON COLUMN packages.manifests_dist_id IS 'all full manifests dist id'; +COMMENT ON COLUMN packages.registry_id IS 'source registry'; + + +CREATE TABLE proxy_caches ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + fullname varchar(214) NOT NULL DEFAULT '', + version varchar(214) DEFAULT NULL, + file_type varchar(30) NOT NULL DEFAULT '', + file_path varchar(512) NOT NULL DEFAULT '' +); + +CREATE UNIQUE INDEX proxy_caches_uk_package_version_path_name ON proxy_caches (file_path); +CREATE UNIQUE INDEX proxy_caches_ux_package_version_file_name ON proxy_caches (fullname, file_type, version); + +COMMENT ON TABLE proxy_caches IS 'proxy mode cached files index'; +COMMENT ON COLUMN proxy_caches.id IS 'primary key'; +COMMENT ON COLUMN proxy_caches.gmt_create IS 'create time'; +COMMENT ON COLUMN proxy_caches.gmt_modified IS 'modify time'; +COMMENT ON COLUMN proxy_caches.fullname IS '@scope/package name'; +COMMENT ON COLUMN proxy_caches.version IS 'package version'; +COMMENT ON COLUMN proxy_caches.file_type IS 'file type'; +COMMENT ON COLUMN proxy_caches.file_path IS 'nfs file path'; + + +CREATE TABLE registries ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + registry_id varchar(24) NOT NULL, + name varchar(256) DEFAULT NULL, + host varchar(4096) DEFAULT NULL, + change_stream varchar(4096) DEFAULT NULL, + type varchar(256) DEFAULT NULL, + user_prefix varchar(256) DEFAULT NULL, + auth_token varchar(256) DEFAULT NULL +); + +CREATE UNIQUE INDEX registries_uk_name ON registries (name); + +COMMENT ON TABLE registries IS 'registry info'; +COMMENT ON COLUMN registries.id IS 'primary key'; +COMMENT ON COLUMN registries.gmt_create IS 'create time'; +COMMENT ON COLUMN registries.gmt_modified IS 'modified time'; +COMMENT ON COLUMN registries.registry_id IS 'registry id'; +COMMENT ON COLUMN registries.name IS 'registry name'; +COMMENT ON COLUMN registries.host IS 'registry host'; +COMMENT ON COLUMN registries.change_stream IS 'change stream url'; +COMMENT ON COLUMN registries.type IS 'registry type cnpmjsorg/cnpmcore/npm'; +COMMENT ON COLUMN registries.user_prefix IS 'user prefix'; +COMMENT ON COLUMN registries.auth_token IS 'registry auth token'; + + +CREATE TABLE scopes ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + scope_id varchar(24) NOT NULL, + name varchar(214) DEFAULT NULL, + registry_id varchar(24) NOT NULL +); + +CREATE UNIQUE INDEX scopes_uk_name ON scopes (name); + +COMMENT ON TABLE scopes IS 'scope info'; +COMMENT ON COLUMN scopes.id IS 'primary key'; +COMMENT ON COLUMN scopes.gmt_create IS 'create time'; +COMMENT ON COLUMN scopes.gmt_modified IS 'modified time'; +COMMENT ON COLUMN scopes.scope_id IS 'scope id'; +COMMENT ON COLUMN scopes.name IS 'scope name'; +COMMENT ON COLUMN scopes.registry_id IS 'registry id'; + + +CREATE TABLE tasks ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + task_id varchar(24) NOT NULL, + type varchar(20) NOT NULL, + state varchar(20) NOT NULL, + target_name varchar(214) NOT NULL, + author_id varchar(24) NOT NULL, + author_ip varchar(100) NOT NULL, + data json DEFAULT NULL, + log_path varchar(512) NOT NULL, + log_store_position varchar(10) NOT NULL, + attempts integer DEFAULT 0, + error text, + biz_id varchar(100) DEFAULT NULL +); + +CREATE UNIQUE INDEX tasks_uk_task_id ON tasks (task_id); +CREATE UNIQUE INDEX tasks_uk_biz_id ON tasks (biz_id); +CREATE INDEX tasks_idx_type_state_target_name ON tasks (target_name, type, state); +CREATE INDEX tasks_idx_type_state_gmt_modified ON tasks (type, state, gmt_modified); +CREATE INDEX tasks_idx_gmt_modified ON tasks (gmt_modified); + +COMMENT ON TABLE tasks IS 'task info'; +COMMENT ON COLUMN tasks.id IS 'primary key'; +COMMENT ON COLUMN tasks.gmt_create IS 'create time'; +COMMENT ON COLUMN tasks.gmt_modified IS 'modified time'; +COMMENT ON COLUMN tasks.task_id IS 'task id'; +COMMENT ON COLUMN tasks.type IS 'task type'; +COMMENT ON COLUMN tasks.state IS 'task state'; +COMMENT ON COLUMN tasks.target_name IS 'target name, like package name / user name'; +COMMENT ON COLUMN tasks.author_id IS 'create task user id'; +COMMENT ON COLUMN tasks.author_ip IS 'create task user request ip'; +COMMENT ON COLUMN tasks.data IS 'task params'; +COMMENT ON COLUMN tasks.log_path IS 'access path'; +COMMENT ON COLUMN tasks.log_store_position IS 'cloud store disk position'; +COMMENT ON COLUMN tasks.attempts IS 'task execute attempts times'; +COMMENT ON COLUMN tasks.error IS 'error description'; +COMMENT ON COLUMN tasks.biz_id IS 'unique biz id to keep task unique'; + + +CREATE TABLE token_packages ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + token_id varchar(24) NOT NULL, + package_id varchar(24) NOT NULL +); + +CREATE UNIQUE INDEX token_packages_uk_token_id_package_id ON token_packages (token_id, package_id); +CREATE INDEX token_packages_idx_token_id ON token_packages (token_id); +CREATE INDEX token_packages_idx_package_id ON token_packages (package_id); + +COMMENT ON TABLE token_packages IS 'token allowed packages'; +COMMENT ON COLUMN token_packages.id IS 'primary key'; +COMMENT ON COLUMN token_packages.gmt_create IS 'create time'; +COMMENT ON COLUMN token_packages.gmt_modified IS 'modified time'; +COMMENT ON COLUMN token_packages.token_id IS 'token id'; +COMMENT ON COLUMN token_packages.package_id IS 'package id'; + + +CREATE TABLE tokens ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + token_id varchar(24) NOT NULL, + token_mark varchar(20) NOT NULL, + token_key varchar(200) NOT NULL, + is_readonly boolean NOT NULL DEFAULT false, + is_automation boolean NOT NULL DEFAULT false, + cidr_whitelist json NOT NULL, + user_id varchar(24) NOT NULL, + name varchar(255) DEFAULT NULL, + type varchar(255) DEFAULT NULL, + description varchar(255) DEFAULT NULL, + allowed_scopes text, + expired_at timestamp(3) DEFAULT NULL, + last_used_at timestamp(3) DEFAULT NULL +); + +CREATE UNIQUE INDEX tokens_uk_token_id ON tokens (token_id); +CREATE UNIQUE INDEX tokens_uk_token_key ON tokens (token_key); +CREATE UNIQUE INDEX tokens_uk_user_id_name ON tokens (user_id, name); +CREATE INDEX tokens_idx_user_id ON tokens (user_id); + +COMMENT ON TABLE tokens IS 'token info'; +COMMENT ON COLUMN tokens.id IS 'primary key'; +COMMENT ON COLUMN tokens.gmt_create IS 'create time'; +COMMENT ON COLUMN tokens.gmt_modified IS 'modified time'; +COMMENT ON COLUMN tokens.token_id IS 'token id'; +COMMENT ON COLUMN tokens.token_mark IS 'token mark value'; +COMMENT ON COLUMN tokens.token_key IS 'token value sha512 hex'; +COMMENT ON COLUMN tokens.is_readonly IS 'readonly token or not, 1: true, other: false'; +COMMENT ON COLUMN tokens.is_automation IS 'automation token or not, 1: true, other: false'; +COMMENT ON COLUMN tokens.cidr_whitelist IS 'ip list, ["127.0.0.1"]'; +COMMENT ON COLUMN tokens.user_id IS 'user id'; +COMMENT ON COLUMN tokens.name IS 'token name'; +COMMENT ON COLUMN tokens.type IS 'token type, granular or legacy'; +COMMENT ON COLUMN tokens.description IS 'token description'; +COMMENT ON COLUMN tokens.allowed_scopes IS 'scope allowed list'; +COMMENT ON COLUMN tokens.expired_at IS 'token expiration time'; +COMMENT ON COLUMN tokens.last_used_at IS 'token last used time'; + + +CREATE TABLE total ( + id BIGSERIAL PRIMARY KEY, + total_id varchar(24) NOT NULL, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + package_count bigint NOT NULL DEFAULT 0, + package_file_size bigint NOT NULL DEFAULT 0, + package_version_count bigint NOT NULL DEFAULT 0, + package_version_delete_count bigint NOT NULL DEFAULT 0, + private_package_count bigint NOT NULL DEFAULT 0, + private_package_file_size bigint NOT NULL DEFAULT 0, + private_package_version_count bigint NOT NULL DEFAULT 0, + private_package_version_delete_count bigint NOT NULL DEFAULT 0, + change_stream_seq varchar(100) DEFAULT NULL +); + +CREATE UNIQUE INDEX total_uk_total_id ON total (total_id); + +COMMENT ON TABLE total IS 'total info'; +COMMENT ON COLUMN total.id IS 'primary key'; +COMMENT ON COLUMN total.total_id IS 'total id, should set it to "global"'; +COMMENT ON COLUMN total.gmt_create IS 'create time'; +COMMENT ON COLUMN total.gmt_modified IS 'modified time'; +COMMENT ON COLUMN total.package_count IS 'package count'; +COMMENT ON COLUMN total.package_file_size IS 'package all files total size'; +COMMENT ON COLUMN total.package_version_count IS 'package version count'; +COMMENT ON COLUMN total.package_version_delete_count IS 'package version delete count'; +COMMENT ON COLUMN total.private_package_count IS 'private package count'; +COMMENT ON COLUMN total.private_package_file_size IS 'private package all files total size'; +COMMENT ON COLUMN total.private_package_version_count IS 'private package version count'; +COMMENT ON COLUMN total.private_package_version_delete_count IS 'private package version delete count'; +COMMENT ON COLUMN total.change_stream_seq IS 'npm change stream sync data seq id'; + + +CREATE TABLE users ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + user_id varchar(24) NOT NULL, + name varchar(100) NOT NULL, + email varchar(400) NOT NULL, + password_salt varchar(100) NOT NULL, + password_integrity varchar(512) NOT NULL, + ip varchar(100) NOT NULL, + is_private boolean NOT NULL DEFAULT true, + scopes json DEFAULT NULL +); + +CREATE UNIQUE INDEX users_uk_user_id ON users (user_id); +CREATE UNIQUE INDEX users_uk_name ON users (name); + +COMMENT ON TABLE users IS 'user info'; +COMMENT ON COLUMN users.id IS 'primary key'; +COMMENT ON COLUMN users.gmt_create IS 'create time'; +COMMENT ON COLUMN users.gmt_modified IS 'modified time'; +COMMENT ON COLUMN users.user_id IS 'user id'; +COMMENT ON COLUMN users.name IS 'user name'; +COMMENT ON COLUMN users.email IS 'user email'; +COMMENT ON COLUMN users.password_salt IS 'password salt'; +COMMENT ON COLUMN users.password_integrity IS 'password integrity'; +COMMENT ON COLUMN users.ip IS 'user login request ip'; +COMMENT ON COLUMN users.is_private IS 'private user or not, 1: true, other: false'; +COMMENT ON COLUMN users.scopes IS 'white scope list, ["@cnpm", "@foo"]'; + + +CREATE TABLE webauthn_credentials ( + id BIGSERIAL PRIMARY KEY, + gmt_create timestamp(3) NOT NULL, + gmt_modified timestamp(3) NOT NULL, + wanc_id varchar(24) NOT NULL, + user_id varchar(24) NOT NULL, + credential_id varchar(200) NOT NULL, + public_key varchar(512) NOT NULL, + browser_type varchar(20) DEFAULT NULL +); + +CREATE UNIQUE INDEX webauthn_credentials_uk_wanc_id ON webauthn_credentials (wanc_id); +CREATE INDEX webauthn_credentials_idx_user_id ON webauthn_credentials (user_id); + +COMMENT ON TABLE webauthn_credentials IS 'webauthn credential info'; +COMMENT ON COLUMN webauthn_credentials.id IS 'primary key'; +COMMENT ON COLUMN webauthn_credentials.gmt_create IS 'create time'; +COMMENT ON COLUMN webauthn_credentials.gmt_modified IS 'modified time'; +COMMENT ON COLUMN webauthn_credentials.wanc_id IS 'webauthn credential id'; +COMMENT ON COLUMN webauthn_credentials.user_id IS 'user id'; +COMMENT ON COLUMN webauthn_credentials.credential_id IS 'webauthn credential id'; +COMMENT ON COLUMN webauthn_credentials.public_key IS 'webauthn credential publick key'; +COMMENT ON COLUMN webauthn_credentials.browser_type IS 'user browser name'; diff --git a/test/TestUtil.ts b/test/TestUtil.ts index 32ae1870..1cbd41ad 100644 --- a/test/TestUtil.ts +++ b/test/TestUtil.ts @@ -5,11 +5,13 @@ import { tmpdir } from 'os'; import { mkdtempSync } from 'fs'; import { Readable } from 'stream'; import mysql from 'mysql2'; +import pg from 'pg'; import path from 'path'; import crypto from 'crypto'; import { cleanUserPrefix, getScopeAndName } from '../app/common/PackageUtil'; import semver from 'semver'; import { PackageJSONType } from '../app/repository/PackageRepository'; +import { database, DATABASE_TYPE } from '../config/database'; type PackageOptions = { name?: string; @@ -44,20 +46,14 @@ export class TestUtil { private static _app; private static ua = 'npm/7.0.0 cnpmcore-unittest/1.0.0'; - static getMySqlConfig() { + static getDatabaseConfig() { return { - host: process.env.MYSQL_HOST || '127.0.0.1', - port: process.env.MYSQL_PORT || 3306, - user: process.env.MYSQL_USER || 'root', - password: process.env.MYSQL_PASSWORD, + ...database, + database: database.name ?? 'cnpmcore_unittest', multipleStatements: true, }; } - static getDatabase() { - return process.env.MYSQL_DATABASE || 'cnpmcore_unittest'; - } - // 不同的 npm 版本 cli 命令不同 // 通过 coffee 运行时获取对应版本号 static async getNpmVersion() { @@ -65,26 +61,17 @@ export class TestUtil { return semver.clean(res.stdout); } - // 获取当前所有 sql 脚本内容 - // 目前统一放置在 ../sql 文件夹中 - // 默认根据版本号排序,确保向后兼容 - static async getTableSqls(): Promise { - const dirents = await fs.readdir(path.join(__dirname, '../sql')); - let versions = dirents.filter(t => path.extname(t) === '.sql').map(t => path.basename(t, '.sql')); - versions = semver.sort(versions); - const sqls = await Promise.all(versions.map(version => { - return fs.readFile(path.join(__dirname, '../sql', `${version}.sql`), 'utf8'); - })); - return sqls.join('\n'); - } - static async query(sql: string): Promise { const conn = this.getConnection(); return new Promise((resolve, reject) => { - conn.query(sql, (err: Error, rows: any[]) => { + conn.query(sql, (err: Error, rows: any) => { if (err) { return reject(err); } + if (rows.rows) { + // pg: { rows } + return resolve(rows.rows); + } return resolve(rows); }); }); @@ -92,11 +79,15 @@ export class TestUtil { static getConnection() { if (!this.connection) { - const config: any = this.getMySqlConfig(); + const config = this.getDatabaseConfig(); if (process.env.CI) { - console.log('[TestUtil] connection to mysql: %j', config); + console.log('[TestUtil] connection to database: %j', config); + } + if (config.type === DATABASE_TYPE.MySQL) { + this.connection = mysql.createConnection(config as any); + } else if (config.type === DATABASE_TYPE.PostgreSQL) { + this.connection = new pg.Client(config as any); } - this.connection = mysql.createConnection(config); this.connection.connect(); } return this.connection; @@ -111,18 +102,26 @@ export class TestUtil { static async getTableNames() { if (!this.tables) { - const database = this.getDatabase(); - const sql = `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${database}';`; - const rows = await this.query(sql); - this.tables = rows.map(row => row.TABLE_NAME); + const config = this.getDatabaseConfig(); + if (config.type === DATABASE_TYPE.MySQL) { + const sql = ` + SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${config.database}';`; + const rows = await this.query(sql); + this.tables = rows.map(row => row.TABLE_NAME); + } else if (config.type === DATABASE_TYPE.PostgreSQL) { + const sql = 'SELECT * FROM pg_catalog.pg_tables where schemaname = \'public\';'; + const rows = await this.query(sql); + this.tables = rows.map(row => row.tablename); + } } return this.tables; } static async truncateDatabase() { - const database = this.getDatabase(); const tables = await this.getTableNames(); - await Promise.all(tables.map((table: string) => this.query(`TRUNCATE TABLE ${database}.${table};`))); + await Promise.all(tables.map(async (table: string) => { + await this.query(`TRUNCATE TABLE ${table};`); + })); } static get app() { diff --git a/test/port/controller/PackageVersionFileController/listFiles.test.ts b/test/port/controller/PackageVersionFileController/listFiles.test.ts index a3b475d3..ed4ec5ba 100644 --- a/test/port/controller/PackageVersionFileController/listFiles.test.ts +++ b/test/port/controller/PackageVersionFileController/listFiles.test.ts @@ -4,6 +4,7 @@ import { app, mock } from 'egg-mock/bootstrap'; import { TestUtil } from '../../../../test/TestUtil'; import { PackageVersionFileService } from '../../../../app/core/service/PackageVersionFileService'; import { calculateIntegrity } from '../../../../app/common/PackageUtil'; +import { database, DATABASE_TYPE } from '../../../../config/database'; describe('test/port/controller/PackageVersionFileController/listFiles.test.ts', () => { let publisher; @@ -151,7 +152,7 @@ describe('test/port/controller/PackageVersionFileController/listFiles.test.ts', }); }); - it('should return the current directory\'s files and directories instead all sub items', async () => { + it('should return the current directory files and directories instead all sub items', async () => { mock(app.config.cnpmcore, 'allowPublishNonScopePackage', true); const tarball = await TestUtil.readFixturesFile('unpkg.com/openapi-7.3.3.tgz'); const { integrity } = await calculateIntegrity(tarball); @@ -184,139 +185,143 @@ describe('test/port/controller/PackageVersionFileController/listFiles.test.ts', file.lastModified = '2024-05-18T16:00:18.307Z'; } // console.log(JSON.stringify(res.body, null, 2)); - assert.deepEqual(res.body, { - path: '/', - type: 'directory', - files: [ - { - path: '/LICENSE', - type: 'file', - contentType: 'text/plain', - integrity: 'sha512-OJCAthMtPqrngGSNaZg5DYzHGQhWG84JV44nxUKqGp8xIuAfZAxbAb7nMATCOqTp8gZv5e4MogcsJCBXiyjXHw==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 11357, - }, - { - path: '/index.html', - type: 'file', - contentType: 'text/html', - integrity: 'sha512-L4Vxx8DW1PtZfPut4uwP9DSK9+DbFbKDWWGp4KK5TRKGTHSjYoMExqY50WiTKs/bGu1Ecpneiu3dnYlRZ/sDdw==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 1437, - }, - { - path: '/package.json', - type: 'file', - contentType: 'application/json', - integrity: 'sha512-ke5ybpErJgl+Mul1XCSMvly0uYAt8/5mWa5/yYykxfMCE0OBpzgWoFHC+/RM9AQfNgic3bW/ssHXDUUPZiEKkg==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 2852, - }, - { - path: '/CHANGES.md', - type: 'file', - contentType: 'text/markdown', - integrity: 'sha512-xxD+0Mdep4Pprq0JsudGLCKtSfHBeIqJVoGqM0qK1b2B/0sXjSQYinxgAwjK8rKSD0jNSo3R5aK8VbgOXLtbjw==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 12346, - }, - { - path: '/README.md', - type: 'file', - contentType: 'text/markdown', - integrity: 'sha512-Nnj8b9SsDDobga1LsV7FVE46YrxkdZf5MOMboVHICw56tPHnQ0v1lXvXkWz7k12kTFWbA0z42daaW7WE+AQWfw==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 4409, - }, - { - path: '/.npmcheckrc.yaml', - type: 'file', - contentType: 'text/yaml', - integrity: 'sha512-EYTJJ5StGM9DUpAbF8XHV4Z02rlmzN9O6k93fu1YXpf1wDBtmFYG64xaTXk2UfB8x0BCotga+Upm1yOgJVIZTQ==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 105, - }, - { - path: '/.redocly.lint-ignore.yaml', - type: 'file', - contentType: 'text/yaml', - integrity: 'sha512-tyPeiIaOGIXb3PNFb2ELAZawxGHSdPZ7IoLdl+tEcDARVFlq6B9yJVAzL5R8L26iCBbvPtlfNGnYkHj4H/5ZMA==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 644, - }, - { - path: '/index.yaml', - type: 'file', - contentType: 'text/yaml', - integrity: 'sha512-KW7xaZW5F8NOGt72kc9WvLcvkFDmXbm65JdWPM2pYfy9HMX0/6obJD5jhzQSX5ZU8ww0HMlXGXkRviFnDr88ZA==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 21379, - }, - { - path: '/.eslintrc.yml', - type: 'file', - contentType: 'text/yaml', - integrity: 'sha512-3q0aghG4dBd7pgE4UrbtVn52cfg3BqOPkuNcCSwHZKMSFnKZxWr+sH7/OgnBDaifVsXGK7AN8q7sX0Eds6Ditw==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 149, - }, - { - path: '/oauth2', - type: 'directory', - files: [], - }, - { - path: '/_util', - type: 'directory', - files: [], - }, - { - path: '/resource', - type: 'directory', - files: [], - }, - { - path: '/parameters', - type: 'directory', - files: [], - }, - { - path: '/id', - type: 'directory', - files: [], - }, - { - path: '/location', - type: 'directory', - files: [], - }, - { - path: '/string', - type: 'directory', - files: [], - }, - { - path: '/money', - type: 'directory', - files: [], - }, - { - path: '/time', - type: 'directory', - files: [], - }, - { - path: '/human', - type: 'directory', - files: [], - }, - { - path: '/health', - type: 'directory', - files: [], - }, - ], - }); + if (database.type === DATABASE_TYPE.PostgreSQL) { + assert.equal(res.body.files.length, 20); + } else { + assert.deepEqual(res.body, { + path: '/', + type: 'directory', + files: [ + { + path: '/LICENSE', + type: 'file', + contentType: 'text/plain', + integrity: 'sha512-OJCAthMtPqrngGSNaZg5DYzHGQhWG84JV44nxUKqGp8xIuAfZAxbAb7nMATCOqTp8gZv5e4MogcsJCBXiyjXHw==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 11357, + }, + { + path: '/index.html', + type: 'file', + contentType: 'text/html', + integrity: 'sha512-L4Vxx8DW1PtZfPut4uwP9DSK9+DbFbKDWWGp4KK5TRKGTHSjYoMExqY50WiTKs/bGu1Ecpneiu3dnYlRZ/sDdw==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 1437, + }, + { + path: '/package.json', + type: 'file', + contentType: 'application/json', + integrity: 'sha512-ke5ybpErJgl+Mul1XCSMvly0uYAt8/5mWa5/yYykxfMCE0OBpzgWoFHC+/RM9AQfNgic3bW/ssHXDUUPZiEKkg==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 2852, + }, + { + path: '/CHANGES.md', + type: 'file', + contentType: 'text/markdown', + integrity: 'sha512-xxD+0Mdep4Pprq0JsudGLCKtSfHBeIqJVoGqM0qK1b2B/0sXjSQYinxgAwjK8rKSD0jNSo3R5aK8VbgOXLtbjw==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 12346, + }, + { + path: '/README.md', + type: 'file', + contentType: 'text/markdown', + integrity: 'sha512-Nnj8b9SsDDobga1LsV7FVE46YrxkdZf5MOMboVHICw56tPHnQ0v1lXvXkWz7k12kTFWbA0z42daaW7WE+AQWfw==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 4409, + }, + { + path: '/.npmcheckrc.yaml', + type: 'file', + contentType: 'text/yaml', + integrity: 'sha512-EYTJJ5StGM9DUpAbF8XHV4Z02rlmzN9O6k93fu1YXpf1wDBtmFYG64xaTXk2UfB8x0BCotga+Upm1yOgJVIZTQ==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 105, + }, + { + path: '/.redocly.lint-ignore.yaml', + type: 'file', + contentType: 'text/yaml', + integrity: 'sha512-tyPeiIaOGIXb3PNFb2ELAZawxGHSdPZ7IoLdl+tEcDARVFlq6B9yJVAzL5R8L26iCBbvPtlfNGnYkHj4H/5ZMA==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 644, + }, + { + path: '/index.yaml', + type: 'file', + contentType: 'text/yaml', + integrity: 'sha512-KW7xaZW5F8NOGt72kc9WvLcvkFDmXbm65JdWPM2pYfy9HMX0/6obJD5jhzQSX5ZU8ww0HMlXGXkRviFnDr88ZA==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 21379, + }, + { + path: '/.eslintrc.yml', + type: 'file', + contentType: 'text/yaml', + integrity: 'sha512-3q0aghG4dBd7pgE4UrbtVn52cfg3BqOPkuNcCSwHZKMSFnKZxWr+sH7/OgnBDaifVsXGK7AN8q7sX0Eds6Ditw==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 149, + }, + { + path: '/oauth2', + type: 'directory', + files: [], + }, + { + path: '/_util', + type: 'directory', + files: [], + }, + { + path: '/resource', + type: 'directory', + files: [], + }, + { + path: '/parameters', + type: 'directory', + files: [], + }, + { + path: '/id', + type: 'directory', + files: [], + }, + { + path: '/location', + type: 'directory', + files: [], + }, + { + path: '/string', + type: 'directory', + files: [], + }, + { + path: '/money', + type: 'directory', + files: [], + }, + { + path: '/time', + type: 'directory', + files: [], + }, + { + path: '/human', + type: 'directory', + files: [], + }, + { + path: '/health', + type: 'directory', + files: [], + }, + ], + }); + } res = await app.httpRequest() .get(`/${pkg.name}/1.0.0/files/id/?meta`); @@ -326,83 +331,87 @@ describe('test/port/controller/PackageVersionFileController/listFiles.test.ts', file.lastModified = '2024-05-18T16:00:18.307Z'; } // console.log(JSON.stringify(res.body, null, 2)); - assert.deepEqual(res.body, { - path: '/id', - type: 'directory', - files: [ - { - path: '/id/AccountId.d.ts', - type: 'file', - contentType: 'text/plain', - integrity: 'sha512-xj1/RCRAp72pukals97C98DG0b38Gl2xNrUwOi2SRj+EnJKIfQX8WisDpCOSKLFq5j++sGbL0/4wCttrPvi37w==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 787, - }, - { - path: '/id/AccountId.js', - type: 'file', - contentType: 'application/javascript', - integrity: 'sha512-kFa+SXSMGbCh2DiuSGmlCS8OCBSE4VRGlq/A2IyY3QxL794soFq4zO3F+UEx4ANUG33urAa4LG4IY2OiUc2Mng==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 1343, - }, - { - path: '/id/AccountId.yaml', - type: 'file', - contentType: 'text/yaml', - integrity: 'sha512-R6WB9dXEaNpvqIAH6OdRQ77gSEBlq1GeH2jv2tv1wQEVOmzQtErHlpj+ukvZUwzqf9wTXIPxKjeUhqk6VbfBkA==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 571, - }, - { - path: '/id/Mode.js', - type: 'file', - contentType: 'application/javascript', - integrity: 'sha512-jfMuIff4LW/ZQ8el9iCww8c9gw+12UK7eZn+6TMDAlStfLhlu8u7jcCSWSEG1zBTty9DIHn4Nbp+dMDjRUnVWQ==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 3357, - }, - { - path: '/id/mode.yaml', - type: 'file', - contentType: 'text/yaml', - integrity: 'sha512-er9S1Da52G8fxwfgxhNbcXPdYz9bzABM7VifDXhgVGX+hwtu8tve9y2aZhPAHcJOy3dClMDQ1eYLAHp7k8TMNQ==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 1222, - }, - { - path: '/id/UUID.js', - type: 'file', - contentType: 'application/javascript', - integrity: 'sha512-bo/JyxOZeRRjbN0OR8vNRz3cTY2GcJfRmRnp3QTGXE5iuKYjrpjYzj+vEXopZV1QYPdZaXUK671EoysPE59pQQ==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 992, - }, - { - path: '/id/UUID.yaml', - type: 'file', - contentType: 'text/yaml', - integrity: 'sha512-Gjr0LNqWQcO5/oaCyMm9oZWpc/D9K6Qe37sGuYv4kbq0I8teZL92xbR81L+2VShkhLSXdg2Qw5WRjwCkSWyfoA==', - lastModified: '2024-05-18T16:00:18.307Z', - size: 659, - }, - { - path: '/id/legalPerson', - type: 'directory', - files: [], - }, - { - path: '/id/naturalPerson', - type: 'directory', - files: [], - }, - { - path: '/id/sigedis', - type: 'directory', - files: [], - }, - ], - }); + if (database.type === DATABASE_TYPE.PostgreSQL) { + assert.equal(res.body.files.length, 10); + } else { + assert.deepEqual(res.body, { + path: '/id', + type: 'directory', + files: [ + { + path: '/id/AccountId.d.ts', + type: 'file', + contentType: 'text/plain', + integrity: 'sha512-xj1/RCRAp72pukals97C98DG0b38Gl2xNrUwOi2SRj+EnJKIfQX8WisDpCOSKLFq5j++sGbL0/4wCttrPvi37w==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 787, + }, + { + path: '/id/AccountId.js', + type: 'file', + contentType: 'application/javascript', + integrity: 'sha512-kFa+SXSMGbCh2DiuSGmlCS8OCBSE4VRGlq/A2IyY3QxL794soFq4zO3F+UEx4ANUG33urAa4LG4IY2OiUc2Mng==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 1343, + }, + { + path: '/id/AccountId.yaml', + type: 'file', + contentType: 'text/yaml', + integrity: 'sha512-R6WB9dXEaNpvqIAH6OdRQ77gSEBlq1GeH2jv2tv1wQEVOmzQtErHlpj+ukvZUwzqf9wTXIPxKjeUhqk6VbfBkA==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 571, + }, + { + path: '/id/Mode.js', + type: 'file', + contentType: 'application/javascript', + integrity: 'sha512-jfMuIff4LW/ZQ8el9iCww8c9gw+12UK7eZn+6TMDAlStfLhlu8u7jcCSWSEG1zBTty9DIHn4Nbp+dMDjRUnVWQ==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 3357, + }, + { + path: '/id/mode.yaml', + type: 'file', + contentType: 'text/yaml', + integrity: 'sha512-er9S1Da52G8fxwfgxhNbcXPdYz9bzABM7VifDXhgVGX+hwtu8tve9y2aZhPAHcJOy3dClMDQ1eYLAHp7k8TMNQ==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 1222, + }, + { + path: '/id/UUID.js', + type: 'file', + contentType: 'application/javascript', + integrity: 'sha512-bo/JyxOZeRRjbN0OR8vNRz3cTY2GcJfRmRnp3QTGXE5iuKYjrpjYzj+vEXopZV1QYPdZaXUK671EoysPE59pQQ==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 992, + }, + { + path: '/id/UUID.yaml', + type: 'file', + contentType: 'text/yaml', + integrity: 'sha512-Gjr0LNqWQcO5/oaCyMm9oZWpc/D9K6Qe37sGuYv4kbq0I8teZL92xbR81L+2VShkhLSXdg2Qw5WRjwCkSWyfoA==', + lastModified: '2024-05-18T16:00:18.307Z', + size: 659, + }, + { + path: '/id/legalPerson', + type: 'directory', + files: [], + }, + { + path: '/id/naturalPerson', + type: 'directory', + files: [], + }, + { + path: '/id/sigedis', + type: 'directory', + files: [], + }, + ], + }); + } res = await app.httpRequest() .get(`/${pkg.name}/1.0.0/files/id/legalPerson/?meta`); diff --git a/test/port/controller/TokenController/createToken.test.ts b/test/port/controller/TokenController/createToken.test.ts index 0285458a..c8511660 100644 --- a/test/port/controller/TokenController/createToken.test.ts +++ b/test/port/controller/TokenController/createToken.test.ts @@ -232,7 +232,7 @@ describe('test/port/controller/TokenController/createToken.test.ts', () => { expires: 30, }); - assert.match(res.body.error, /ER_DUP_ENTRY/); + assert.match(res.body.error, /ER_DUP_ENTRY|duplicate key value violates unique constraint/); }); }); diff --git a/test/repository/ChangeRepository.test.ts b/test/repository/ChangeRepository.test.ts index e6dda944..58fb3972 100644 --- a/test/repository/ChangeRepository.test.ts +++ b/test/repository/ChangeRepository.test.ts @@ -30,8 +30,10 @@ describe('test/repository/ChangeRepository.test.ts', () => { it('should list from header', async () => { const changes = await changeRepository.query(0, 5); const ids = changes.map(t => t.id); + // pg truncate 后,id 不会重置 + const firstId = Number(ids[0]) - 1; assert.deepStrictEqual(ids, [ - 1, 2, 3, 4, 5, + firstId + 1, firstId + 2, firstId + 3, firstId + 4, firstId + 5, ]); }); });