@proteinjs/db-file 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +20 -0
- package/.prettierignore +4 -0
- package/.prettierrc +8 -0
- package/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/dist/generated/index.d.ts +10 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/index.js +42 -0
- package/dist/generated/index.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/src/DbFileStorageDriver.d.ts +14 -0
- package/dist/src/DbFileStorageDriver.d.ts.map +1 -0
- package/dist/src/DbFileStorageDriver.js +143 -0
- package/dist/src/DbFileStorageDriver.js.map +1 -0
- package/dist/src/FileStorage.d.ts +70 -0
- package/dist/src/FileStorage.d.ts.map +1 -0
- package/dist/src/FileStorage.js +210 -0
- package/dist/src/FileStorage.js.map +1 -0
- package/dist/src/FileStorageDriver.d.ts +9 -0
- package/dist/src/FileStorageDriver.d.ts.map +1 -0
- package/dist/src/FileStorageDriver.js +3 -0
- package/dist/src/FileStorageDriver.js.map +1 -0
- package/dist/src/routes/getFile.d.ts +3 -0
- package/dist/src/routes/getFile.d.ts.map +1 -0
- package/dist/src/routes/getFile.js +86 -0
- package/dist/src/routes/getFile.js.map +1 -0
- package/dist/src/routes/getFileRoute.d.ts +5 -0
- package/dist/src/routes/getFileRoute.d.ts.map +1 -0
- package/dist/src/routes/getFileRoute.js +5 -0
- package/dist/src/routes/getFileRoute.js.map +1 -0
- package/dist/src/services/FileStorageService.d.ts +13 -0
- package/dist/src/services/FileStorageService.d.ts.map +1 -0
- package/dist/src/services/FileStorageService.js +6 -0
- package/dist/src/services/FileStorageService.js.map +1 -0
- package/dist/src/tables/FileDataTable.d.ts +23 -0
- package/dist/src/tables/FileDataTable.d.ts.map +1 -0
- package/dist/src/tables/FileDataTable.js +45 -0
- package/dist/src/tables/FileDataTable.js.map +1 -0
- package/dist/src/tables/FileTable.d.ts +26 -0
- package/dist/src/tables/FileTable.d.ts.map +1 -0
- package/dist/src/tables/FileTable.js +51 -0
- package/dist/src/tables/FileTable.js.map +1 -0
- package/dist/src/tables/tables.d.ts +8 -0
- package/dist/src/tables/tables.d.ts.map +1 -0
- package/dist/src/tables/tables.js +10 -0
- package/dist/src/tables/tables.js.map +1 -0
- package/generated/index.ts +35 -0
- package/index.ts +14 -0
- package/jest.config.js +9 -0
- package/package.json +48 -0
- package/src/DbFileStorageDriver.ts +67 -0
- package/src/FileStorage.ts +128 -0
- package/src/FileStorageDriver.ts +9 -0
- package/src/routes/getFile.ts +33 -0
- package/src/routes/getFileRoute.ts +1 -0
- package/src/services/FileStorageService.ts +14 -0
- package/src/tables/FileDataTable.ts +26 -0
- package/src/tables/FileTable.ts +32 -0
- package/src/tables/tables.ts +8 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Load Dependency Source Graphs */
|
|
2
|
+
|
|
3
|
+
import '@proteinjs/db';
|
|
4
|
+
import '@proteinjs/reflection';
|
|
5
|
+
import '@proteinjs/server-api';
|
|
6
|
+
import '@proteinjs/service';
|
|
7
|
+
import '@proteinjs/user';
|
|
8
|
+
import '@proteinjs/util';
|
|
9
|
+
import 'moment';
|
|
10
|
+
|
|
11
|
+
/** Generate Source Graph */
|
|
12
|
+
|
|
13
|
+
const sourceGraph =
|
|
14
|
+
'{"options":{"directed":true,"multigraph":false,"compound":false},"nodes":[{"v":"@proteinjs/db-file/DefaultFileStorageDriverFactory","value":{"packageName":"@proteinjs/db-file","name":"DefaultFileStorageDriverFactory","filePath":"/home/runner/work/db/db/packages/file/src/FileStorage.ts","qualifiedName":"@proteinjs/db-file/DefaultFileStorageDriverFactory","properties":[],"methods":[{"name":"getDriver","returnType":{"packageName":"@proteinjs/db-file","name":"FileStorageDriver","filePath":null,"qualifiedName":"@proteinjs/db-file/FileStorageDriver","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":true,"isStatic":false,"visibility":"public","parameters":[]}],"typeParameters":[],"directParents":[{"packageName":"@proteinjs/reflection","name":"Loadable","filePath":null,"qualifiedName":"@proteinjs/reflection/Loadable","properties":[],"methods":[],"typeParameters":[],"directParents":[]}],"sourceType":3}},{"v":"@proteinjs/reflection/Loadable"},{"v":"@proteinjs/db-file/FileStorage","value":{"packageName":"@proteinjs/db-file","name":"FileStorage","filePath":"/home/runner/work/db/db/packages/file/src/FileStorage.ts","qualifiedName":"@proteinjs/db-file/FileStorage","isAbstract":false,"isStatic":false,"visibility":"public","properties":[{"name":"defaultDriver","type":{"packageName":"@proteinjs/db-file","name":"FileStorageDriver","filePath":null,"qualifiedName":"@proteinjs/db-file/FileStorageDriver","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":true,"visibility":"private"},{"name":"driver","type":{"packageName":"@proteinjs/db-file","name":"FileStorageDriver","filePath":null,"qualifiedName":"@proteinjs/db-file/FileStorageDriver","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"private"},{"name":"logger","type":{"packageName":"@proteinjs/util","name":"Logger","filePath":null,"qualifiedName":"@proteinjs/util/Logger","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"private"},{"name":"serviceMetadata","type":null,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"}],"methods":[{"name":"getDefaultDriver","returnType":{"packageName":"@proteinjs/db-file","name":"FileStorageDriver","filePath":null,"qualifiedName":"@proteinjs/db-file/FileStorageDriver","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"private","parameters":[]},{"name":"createFile","returnType":{"packageName":"","name":"Promise<File>","filePath":null,"qualifiedName":"/Promise<File>","typeParameters":null,"directParents":null},"isAsync":true,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[{"name":"fileMetaData","type":{"packageName":"","name":"Omit<File, keyof ScopedRecord>","filePath":null,"qualifiedName":"/Omit<File, keyof ScopedRecord>","typeParameters":null,"directParents":null}},{"name":"fileData","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]},{"name":"getFile","returnType":{"packageName":"","name":"Promise<File>","filePath":null,"qualifiedName":"/Promise<File>","typeParameters":null,"directParents":null},"isAsync":true,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[{"name":"fileId","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]},{"name":"getFileData","returnType":{"packageName":"","name":"Promise<string>","filePath":null,"qualifiedName":"/Promise<string>","typeParameters":null,"directParents":null},"isAsync":true,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[{"name":"fileId","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]},{"name":"updateFileData","returnType":{"packageName":"","name":"Promise<void>","filePath":null,"qualifiedName":"/Promise<void>","typeParameters":null,"directParents":null},"isAsync":true,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[{"name":"fileId","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}},{"name":"data","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]},{"name":"updateFile","returnType":{"packageName":"","name":"Promise<void>","filePath":null,"qualifiedName":"/Promise<void>","typeParameters":null,"directParents":null},"isAsync":true,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[{"name":"file","type":{"packageName":"","name":"Omit<File, keyof ScopedRecord>","filePath":null,"qualifiedName":"/Omit<File, keyof ScopedRecord>","typeParameters":null,"directParents":null}}]},{"name":"deleteFile","returnType":{"packageName":"","name":"Promise<void>","filePath":null,"qualifiedName":"/Promise<void>","typeParameters":null,"directParents":null},"isAsync":true,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public","parameters":[{"name":"fileId","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]}],"typeParameters":[],"directParentInterfaces":[{"packageName":"@proteinjs/db-file","name":"FileStorageService","filePath":null,"qualifiedName":"@proteinjs/db-file/FileStorageService","properties":[],"methods":[],"typeParameters":[],"directParents":[]}],"directParentClasses":[],"sourceType":2}},{"v":"@proteinjs/db-file/FileStorageService","value":{"packageName":"@proteinjs/db-file","name":"FileStorageService","filePath":"/home/runner/work/db/db/packages/file/src/services/FileStorageService.ts","qualifiedName":"@proteinjs/db-file/FileStorageService","properties":[],"methods":[{"name":"createFile","returnType":{"packageName":"","name":"Promise<File>","filePath":null,"qualifiedName":"/Promise<File>","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":true,"isStatic":false,"visibility":"public","parameters":[{"name":"fileMetaData","type":{"packageName":"","name":"Omit<File, keyof ScopedRecord>","filePath":null,"qualifiedName":"/Omit<File, keyof ScopedRecord>","typeParameters":null,"directParents":null}},{"name":"fileData","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]},{"name":"getFile","returnType":{"packageName":"","name":"Promise<File>","filePath":null,"qualifiedName":"/Promise<File>","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":true,"isStatic":false,"visibility":"public","parameters":[{"name":"fileId","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]},{"name":"getFileData","returnType":{"packageName":"","name":"Promise<string>","filePath":null,"qualifiedName":"/Promise<string>","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":true,"isStatic":false,"visibility":"public","parameters":[{"name":"fileId","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]},{"name":"updateFileData","returnType":{"packageName":"","name":"Promise<void>","filePath":null,"qualifiedName":"/Promise<void>","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":true,"isStatic":false,"visibility":"public","parameters":[{"name":"fileId","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}},{"name":"data","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]},{"name":"updateFile","returnType":{"packageName":"","name":"Promise<void>","filePath":null,"qualifiedName":"/Promise<void>","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":true,"isStatic":false,"visibility":"public","parameters":[{"name":"file","type":{"packageName":"","name":"Omit<File, keyof ScopedRecord>","filePath":null,"qualifiedName":"/Omit<File, keyof ScopedRecord>","typeParameters":null,"directParents":null}}]},{"name":"deleteFile","returnType":{"packageName":"","name":"Promise<void>","filePath":null,"qualifiedName":"/Promise<void>","typeParameters":null,"directParents":null},"isAsync":false,"isOptional":false,"isAbstract":true,"isStatic":false,"visibility":"public","parameters":[{"name":"fileId","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null}}]}],"typeParameters":[],"directParents":[{"packageName":"@proteinjs/service","name":"Service","filePath":null,"qualifiedName":"@proteinjs/service/Service","properties":[],"methods":[],"typeParameters":[],"directParents":[]}],"sourceType":3}},{"v":"@proteinjs/db-file/getFile","value":{"packageName":"@proteinjs/db-file","name":"getFile","filePath":"/home/runner/work/db/db/packages/file/src/routes/getFile.ts","qualifiedName":"@proteinjs/db-file/getFile","type":{"packageName":"@proteinjs/server-api","name":"Route","filePath":null,"qualifiedName":"@proteinjs/server-api/Route","typeParameters":[],"directParents":[{"packageName":"@proteinjs/server-api","name":"Route","filePath":null,"qualifiedName":"@proteinjs/server-api/Route","typeParameters":[],"directParents":null}]},"isExported":true,"isConst":true,"sourceType":0}},{"v":"@proteinjs/server-api/Route"},{"v":"@proteinjs/service/Service"},{"v":"@proteinjs/db-file/FileData","value":{"packageName":"@proteinjs/db-file","name":"FileData","filePath":"/home/runner/work/db/db/packages/file/src/tables/FileDataTable.ts","qualifiedName":"@proteinjs/db-file/FileData","properties":[{"name":"file","type":{"packageName":"","name":"Reference<File>","filePath":null,"qualifiedName":"/Reference<File>","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"},{"name":"order","type":{"packageName":"","name":"number","filePath":null,"qualifiedName":"/number","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"},{"name":"data","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"}],"methods":[],"typeParameters":[],"directParents":[{"packageName":"@proteinjs/user","name":"ScopedRecord","filePath":null,"qualifiedName":"@proteinjs/user/ScopedRecord","properties":[],"methods":[],"typeParameters":[],"directParents":[]}],"sourceType":3}},{"v":"@proteinjs/user/ScopedRecord"},{"v":"@proteinjs/db-file/FileDataTable","value":{"packageName":"@proteinjs/db-file","name":"FileDataTable","filePath":"/home/runner/work/db/db/packages/file/src/tables/FileDataTable.ts","qualifiedName":"@proteinjs/db-file/FileDataTable","isAbstract":false,"isStatic":false,"visibility":"public","properties":[{"name":"name","type":null,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"},{"name":"auth","type":{"packageName":"","name":"Table<FileData>[\'auth\']","filePath":null,"qualifiedName":"/Table<FileData>[\'auth\']","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"},{"name":"columns","type":null,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"}],"methods":[],"typeParameters":[],"directParentInterfaces":[],"directParentClasses":[{"packageName":"@proteinjs/db","name":"Table","filePath":null,"qualifiedName":"@proteinjs/db/Table","isAbstract":false,"isStatic":false,"visibility":"public","properties":[],"methods":[],"typeParameters":["@proteinjs/db-file/FileData"],"directParentInterfaces":[],"directParentClasses":[]}],"sourceType":2}},{"v":"@proteinjs/db/Table"},{"v":"@proteinjs/db-file/File","value":{"packageName":"@proteinjs/db-file","name":"File","filePath":"/home/runner/work/db/db/packages/file/src/tables/FileTable.ts","qualifiedName":"@proteinjs/db-file/File","properties":[{"name":"name","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"},{"name":"type","type":{"packageName":"","name":"string","filePath":null,"qualifiedName":"/string","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"},{"name":"size","type":{"packageName":"","name":"number","filePath":null,"qualifiedName":"/number","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"}],"methods":[],"typeParameters":[],"directParents":[{"packageName":"@proteinjs/user","name":"ScopedRecord","filePath":null,"qualifiedName":"@proteinjs/user/ScopedRecord","properties":[],"methods":[],"typeParameters":[],"directParents":[]}],"sourceType":3}},{"v":"@proteinjs/db-file/FileTable","value":{"packageName":"@proteinjs/db-file","name":"FileTable","filePath":"/home/runner/work/db/db/packages/file/src/tables/FileTable.ts","qualifiedName":"@proteinjs/db-file/FileTable","isAbstract":false,"isStatic":false,"visibility":"public","properties":[{"name":"name","type":null,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"},{"name":"auth","type":{"packageName":"","name":"Table<File>[\'auth\']","filePath":null,"qualifiedName":"/Table<File>[\'auth\']","typeParameters":null,"directParents":null},"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"},{"name":"columns","type":null,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"},{"name":"cascadeDeleteReferences","type":null,"isOptional":false,"isAbstract":false,"isStatic":false,"visibility":"public"}],"methods":[],"typeParameters":[],"directParentInterfaces":[],"directParentClasses":[{"packageName":"@proteinjs/db","name":"Table","filePath":null,"qualifiedName":"@proteinjs/db/Table","isAbstract":false,"isStatic":false,"visibility":"public","properties":[],"methods":[],"typeParameters":["@proteinjs/db-file/File"],"directParentInterfaces":[],"directParentClasses":[]}],"sourceType":2}}],"edges":[{"v":"@proteinjs/db-file/DefaultFileStorageDriverFactory","w":"@proteinjs/reflection/Loadable","value":"extends interface"},{"v":"@proteinjs/db-file/FileStorage","w":"@proteinjs/db-file/FileStorageService","value":"implements interface"},{"v":"@proteinjs/db-file/getFile","w":"@proteinjs/server-api/Route","value":"has type"},{"v":"@proteinjs/db-file/FileStorageService","w":"@proteinjs/service/Service","value":"extends interface"},{"v":"@proteinjs/db-file/FileData","w":"@proteinjs/user/ScopedRecord","value":"extends interface"},{"v":"@proteinjs/db-file/FileDataTable","w":"@proteinjs/db/Table","value":"extends class"},{"v":"@proteinjs/db-file/File","w":"@proteinjs/user/ScopedRecord","value":"extends interface"},{"v":"@proteinjs/db-file/FileTable","w":"@proteinjs/db/Table","value":"extends class"}]}';
|
|
15
|
+
|
|
16
|
+
/** Generate Source Links */
|
|
17
|
+
|
|
18
|
+
import { FileStorage } from '../src/FileStorage';
|
|
19
|
+
import { getFile } from '../src/routes/getFile';
|
|
20
|
+
import { FileDataTable } from '../src/tables/FileDataTable';
|
|
21
|
+
import { FileTable } from '../src/tables/FileTable';
|
|
22
|
+
|
|
23
|
+
const sourceLinks = {
|
|
24
|
+
'@proteinjs/db-file/FileStorage': FileStorage,
|
|
25
|
+
'@proteinjs/db-file/getFile': getFile,
|
|
26
|
+
'@proteinjs/db-file/FileDataTable': FileDataTable,
|
|
27
|
+
'@proteinjs/db-file/FileTable': FileTable,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** Load Source Graph and Links */
|
|
31
|
+
|
|
32
|
+
import { SourceRepository } from '@proteinjs/reflection';
|
|
33
|
+
SourceRepository.merge(sourceGraph, sourceLinks);
|
|
34
|
+
|
|
35
|
+
export * from '../index';
|
package/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import moment from 'moment';
|
|
2
|
+
|
|
3
|
+
export * from './src/FileStorage';
|
|
4
|
+
|
|
5
|
+
export * from './src/tables/tables';
|
|
6
|
+
export * from './src/tables/FileTable';
|
|
7
|
+
export * from './src/tables/FileDataTable';
|
|
8
|
+
|
|
9
|
+
export * from './src/services/FileStorageService';
|
|
10
|
+
|
|
11
|
+
export * from './src/routes/getFileRoute';
|
|
12
|
+
|
|
13
|
+
export * from './src/FileStorageDriver';
|
|
14
|
+
export * from './src/DbFileStorageDriver';
|
package/jest.config.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@proteinjs/db-file",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "File storage in the db",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/proteinjs/db.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/proteinjs/db/issues"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/proteinjs/db#readme",
|
|
16
|
+
"author": "Brent Bahry",
|
|
17
|
+
"license": "ISC",
|
|
18
|
+
"scripts": {
|
|
19
|
+
"clean": "rm -rf dist/ node_modules/ generated/",
|
|
20
|
+
"build": "reflection-build && tsc",
|
|
21
|
+
"watch": "reflection-watch"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@proteinjs/db": "^1.3.0",
|
|
25
|
+
"@proteinjs/reflection": "1.1.5",
|
|
26
|
+
"@proteinjs/server-api": "1.3.0",
|
|
27
|
+
"@proteinjs/service": "1.0.18",
|
|
28
|
+
"@proteinjs/user": "1.0.24",
|
|
29
|
+
"@proteinjs/util": "1.1.2",
|
|
30
|
+
"moment": "2.29.4"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@proteinjs/reflection-build": "1.0.19",
|
|
34
|
+
"@types/jest": "29.5.5",
|
|
35
|
+
"@types/node": "14.0.27",
|
|
36
|
+
"@typescript-eslint/eslint-plugin": "7.8.0",
|
|
37
|
+
"@typescript-eslint/parser": "7.8.0",
|
|
38
|
+
"eslint": "8.57.0",
|
|
39
|
+
"eslint-config-prettier": "9.1.0",
|
|
40
|
+
"eslint-plugin-prettier": "5.1.3",
|
|
41
|
+
"jest": "29.7.0",
|
|
42
|
+
"ts-jest": "29.1.1",
|
|
43
|
+
"typescript": "5.2.2"
|
|
44
|
+
},
|
|
45
|
+
"main": "./dist/generated/index.js",
|
|
46
|
+
"types": "./dist/generated/index.d.ts",
|
|
47
|
+
"gitHead": "bac0422554df77dee36aad99af215a191ed59bde"
|
|
48
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { getScopedDb } from '@proteinjs/user';
|
|
2
|
+
import { QueryBuilderFactory, Reference } from '@proteinjs/db';
|
|
3
|
+
import { File } from './tables/FileTable';
|
|
4
|
+
import { tables } from './tables/tables';
|
|
5
|
+
import { FileStorageDriver } from './FileStorageDriver';
|
|
6
|
+
|
|
7
|
+
export class DbFileStorageDriver implements FileStorageDriver {
|
|
8
|
+
private chunkSize = 1048576; // Max length of data written to `FileData.data` (1mb)
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param chunkSize the size, in bytes, to be stored in each `FileDataTable` record; default is 1mb
|
|
12
|
+
*/
|
|
13
|
+
constructor(chunkSize?: number) {
|
|
14
|
+
if (chunkSize != undefined) {
|
|
15
|
+
this.chunkSize = chunkSize;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async createFile(file: File, fileData: string): Promise<void> {
|
|
20
|
+
const db = getScopedDb();
|
|
21
|
+
const chunks = this.splitIntoChunks(fileData);
|
|
22
|
+
for (let index = 0; index < chunks.length; index++) {
|
|
23
|
+
const chunk = chunks[index];
|
|
24
|
+
await db.insert(tables.FileData, {
|
|
25
|
+
file: new Reference(tables.FileData.name, file.id),
|
|
26
|
+
order: index,
|
|
27
|
+
data: chunk,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private splitIntoChunks(data: string): string[] {
|
|
33
|
+
const chunks = [];
|
|
34
|
+
for (let i = 0; i < data.length; i += this.chunkSize) {
|
|
35
|
+
chunks.push(data.substring(i, i + this.chunkSize));
|
|
36
|
+
}
|
|
37
|
+
return chunks;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async getFileData(fileId: string): Promise<string> {
|
|
41
|
+
const db = getScopedDb();
|
|
42
|
+
const qb = new QueryBuilderFactory()
|
|
43
|
+
.getQueryBuilder(tables.FileData, { file: fileId })
|
|
44
|
+
.sort([{ field: 'order', desc: false }]);
|
|
45
|
+
const fileDataRecords = await db.query(tables.FileData, qb);
|
|
46
|
+
return fileDataRecords.map((record) => record.data).join('');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async updateFileData(fileId: string, data: string): Promise<void> {
|
|
50
|
+
const db = getScopedDb();
|
|
51
|
+
|
|
52
|
+
// Delete existing data
|
|
53
|
+
const deleteQuery = new QueryBuilderFactory().getQueryBuilder(tables.FileData, { file: fileId });
|
|
54
|
+
await db.delete(tables.FileData, deleteQuery);
|
|
55
|
+
|
|
56
|
+
// Split new data into chunks and insert
|
|
57
|
+
const chunks = this.splitIntoChunks(data);
|
|
58
|
+
for (let index = 0; index < chunks.length; index++) {
|
|
59
|
+
const chunk = chunks[index];
|
|
60
|
+
await db.insert(tables.FileData, {
|
|
61
|
+
file: new Reference(tables.FileData.name, fileId),
|
|
62
|
+
order: index,
|
|
63
|
+
data: chunk,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { ScopedRecord, getScopedDb } from '@proteinjs/user';
|
|
2
|
+
import { File } from './tables/FileTable';
|
|
3
|
+
import { tables } from './tables/tables';
|
|
4
|
+
import { FileStorageService, getFileStorageService } from './services/FileStorageService';
|
|
5
|
+
import { FileStorageDriver } from './FileStorageDriver';
|
|
6
|
+
import { Loadable, SourceRepository } from '@proteinjs/reflection';
|
|
7
|
+
import { Logger } from '@proteinjs/util';
|
|
8
|
+
import { DbFileStorageDriver } from './DbFileStorageDriver';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A convenience factory function so code using this is portable (can be used in server or browser).
|
|
12
|
+
* @returns an instance of the `FileStorageService` when called from the browser, and an instance of `FileStorage` otherwise
|
|
13
|
+
* */
|
|
14
|
+
export const getFileStorage = () =>
|
|
15
|
+
typeof self === 'undefined' ? new FileStorage() : (getFileStorageService() as FileStorage);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A convenience factory to provide a default `FileStorageDriver`
|
|
19
|
+
*/
|
|
20
|
+
export interface DefaultFileStorageDriverFactory extends Loadable {
|
|
21
|
+
getDriver(): FileStorageDriver;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A simple api for file storage.
|
|
26
|
+
* File metadata is stored in the `FileTable`.
|
|
27
|
+
* File data is stored by the `FileStorageDriver`.
|
|
28
|
+
*/
|
|
29
|
+
export class FileStorage implements FileStorageService {
|
|
30
|
+
private static defaultDriver: FileStorageDriver;
|
|
31
|
+
private driver: FileStorageDriver;
|
|
32
|
+
private logger: Logger = new Logger(this.constructor.name);
|
|
33
|
+
|
|
34
|
+
public serviceMetadata = {
|
|
35
|
+
auth: {
|
|
36
|
+
allUsers: true,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
constructor(driver?: FileStorageDriver) {
|
|
41
|
+
this.driver = driver ? driver : this.getDefaultDriver();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private getDefaultDriver(): FileStorageDriver {
|
|
45
|
+
if (!FileStorage.defaultDriver) {
|
|
46
|
+
const defaultDriverFactory = SourceRepository.get().object<DefaultFileStorageDriverFactory>(
|
|
47
|
+
'@proteinjs/db-file/DefaultFileStorageDriverFactory'
|
|
48
|
+
);
|
|
49
|
+
if (defaultDriverFactory) {
|
|
50
|
+
FileStorage.defaultDriver = defaultDriverFactory.getDriver();
|
|
51
|
+
} else {
|
|
52
|
+
this.logger.info(`Defaulting to DbFileStorageDriver since no FileStorageDriver was provided`);
|
|
53
|
+
FileStorage.defaultDriver = new DbFileStorageDriver();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return FileStorage.defaultDriver;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Creates a new file record and its associated data chunks.
|
|
62
|
+
* @param fileMetaData - The file metadata (name, type, size).
|
|
63
|
+
* @param fileData - The file data as a string.
|
|
64
|
+
* @returns The created file record.
|
|
65
|
+
*/
|
|
66
|
+
async createFile(fileMetaData: Omit<File, keyof ScopedRecord>, fileData: string): Promise<File> {
|
|
67
|
+
const db = getScopedDb();
|
|
68
|
+
const file = await db.insert(tables.File, fileMetaData);
|
|
69
|
+
await this.driver.createFile(file, fileData);
|
|
70
|
+
return file;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Retrieves the metadata of a given file.
|
|
75
|
+
* @param fileId - The `id` of the file.
|
|
76
|
+
* @returns The file metadata.
|
|
77
|
+
*/
|
|
78
|
+
async getFile(fileId: string): Promise<File> {
|
|
79
|
+
const db = getScopedDb();
|
|
80
|
+
const file = await db.get(tables.File, { id: fileId });
|
|
81
|
+
return file;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Retrieves the data chunks associated with a given file.
|
|
86
|
+
* @param fileId - The `id` of the file.
|
|
87
|
+
* @returns The file data as a single string.
|
|
88
|
+
*/
|
|
89
|
+
async getFileData(fileId: string): Promise<string> {
|
|
90
|
+
return await this.driver.getFileData(fileId);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Updates the data chunks associated with a given file.
|
|
95
|
+
* @param fileId - The `id` of the file.
|
|
96
|
+
* @param data - The new data string to replace the existing data.
|
|
97
|
+
*/
|
|
98
|
+
async updateFileData(fileId: string, data: string): Promise<void> {
|
|
99
|
+
await this.driver.updateFileData(fileId, data);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Updates the metadata of a given file.
|
|
104
|
+
* @param file - The updated file to persist.
|
|
105
|
+
*/
|
|
106
|
+
async updateFile(file: Omit<File, keyof ScopedRecord>): Promise<void> {
|
|
107
|
+
const db = getScopedDb();
|
|
108
|
+
await db.update(tables.File, file);
|
|
109
|
+
|
|
110
|
+
if (this.driver.updateFile) {
|
|
111
|
+
await this.driver.updateFile(file as File);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Deletes a file and its data.
|
|
117
|
+
* The file data is deleted by a cascade delete rule defined on the `FileTable`
|
|
118
|
+
* @param fileId - The `id` of the file to delete.
|
|
119
|
+
*/
|
|
120
|
+
async deleteFile(fileId: string): Promise<void> {
|
|
121
|
+
const db = getScopedDb();
|
|
122
|
+
if (this.driver.deleteFile) {
|
|
123
|
+
await this.driver.deleteFile(fileId);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
await db.delete(tables.File, { id: fileId });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { File } from './tables/FileTable';
|
|
2
|
+
|
|
3
|
+
export interface FileStorageDriver {
|
|
4
|
+
createFile(file: File, fileData: string): Promise<void>;
|
|
5
|
+
getFileData(fileId: string): Promise<string>;
|
|
6
|
+
updateFileData(fileId: string, data: string): Promise<void>;
|
|
7
|
+
updateFile?(file: File): Promise<void>;
|
|
8
|
+
deleteFile?(fileId: string): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Route } from '@proteinjs/server-api';
|
|
2
|
+
import { getFileStorage } from '../FileStorage';
|
|
3
|
+
import { UserAuth } from '@proteinjs/user';
|
|
4
|
+
|
|
5
|
+
export const getFile: Route = {
|
|
6
|
+
path: '/file/:id',
|
|
7
|
+
method: 'get',
|
|
8
|
+
onRequest: async (request, response): Promise<void> => {
|
|
9
|
+
if (!UserAuth.isLoggedIn()) {
|
|
10
|
+
response.status(401).send('User not logged in');
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const fileId = request.params.id;
|
|
15
|
+
const fileStorage = getFileStorage();
|
|
16
|
+
try {
|
|
17
|
+
const file = await fileStorage.getFile(fileId);
|
|
18
|
+
const fileDataBase64 = await fileStorage.getFileData(fileId);
|
|
19
|
+
if (!file || !fileDataBase64) {
|
|
20
|
+
response.status(404).send('File not found');
|
|
21
|
+
} else {
|
|
22
|
+
const safeFilename = encodeURIComponent(file.name);
|
|
23
|
+
const fileData = file.type.startsWith('image/') ? Buffer.from(fileDataBase64, 'base64') : fileDataBase64;
|
|
24
|
+
response.setHeader('Content-Disposition', `inline; filename="${safeFilename}"`);
|
|
25
|
+
response.setHeader('Content-Type', file.type);
|
|
26
|
+
response.send(fileData);
|
|
27
|
+
}
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error(`Error fetching file (${fileId}):`, error);
|
|
30
|
+
response.status(500).send('Internal Server Error');
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const getFileRoute = { path: (fileId: string) => `/file/${fileId}`, method: 'get' };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Service, serviceFactory } from '@proteinjs/service';
|
|
2
|
+
import { ScopedRecord } from '@proteinjs/user';
|
|
3
|
+
import { File } from '../tables/FileTable';
|
|
4
|
+
|
|
5
|
+
export const getFileStorageService = serviceFactory<FileStorageService>('@proteinjs/db-file/FileStorageService');
|
|
6
|
+
|
|
7
|
+
export interface FileStorageService extends Service {
|
|
8
|
+
createFile(fileMetaData: Omit<File, keyof ScopedRecord>, fileData: string): Promise<File>;
|
|
9
|
+
getFile(fileId: string): Promise<File>;
|
|
10
|
+
getFileData(fileId: string): Promise<string>;
|
|
11
|
+
updateFileData(fileId: string, data: string): Promise<void>;
|
|
12
|
+
updateFile(file: Omit<File, keyof ScopedRecord>): Promise<void>;
|
|
13
|
+
deleteFile(fileId: string): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Table, StringColumn, IntegerColumn, ReferenceColumn, Reference } from '@proteinjs/db';
|
|
2
|
+
import { ScopedRecord, withScopedRecordColumns } from '@proteinjs/user';
|
|
3
|
+
import { File, FileTable } from './FileTable';
|
|
4
|
+
|
|
5
|
+
export interface FileData extends ScopedRecord {
|
|
6
|
+
file: Reference<File>;
|
|
7
|
+
order: number;
|
|
8
|
+
data: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class FileDataTable extends Table<FileData> {
|
|
12
|
+
public name = 'file_data';
|
|
13
|
+
public auth: Table<FileData>['auth'] = {
|
|
14
|
+
db: {
|
|
15
|
+
all: 'authenticated',
|
|
16
|
+
},
|
|
17
|
+
service: {
|
|
18
|
+
all: 'authenticated',
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
public columns = withScopedRecordColumns<FileData>({
|
|
22
|
+
file: new ReferenceColumn<File>('file', new FileTable().name, false),
|
|
23
|
+
order: new IntegerColumn('order'),
|
|
24
|
+
data: new StringColumn('data', {}, 'MAX'),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Table, StringColumn, IntegerColumn } from '@proteinjs/db';
|
|
2
|
+
import { ScopedRecord, withScopedRecordColumns } from '@proteinjs/user';
|
|
3
|
+
import { FileDataTable } from './FileDataTable';
|
|
4
|
+
|
|
5
|
+
export interface File extends ScopedRecord {
|
|
6
|
+
name: string;
|
|
7
|
+
type: string;
|
|
8
|
+
size: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class FileTable extends Table<File> {
|
|
12
|
+
public name = 'file';
|
|
13
|
+
public auth: Table<File>['auth'] = {
|
|
14
|
+
db: {
|
|
15
|
+
all: 'authenticated',
|
|
16
|
+
},
|
|
17
|
+
service: {
|
|
18
|
+
all: 'authenticated',
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
public columns = withScopedRecordColumns<File>({
|
|
22
|
+
name: new StringColumn('name'),
|
|
23
|
+
type: new StringColumn('type'),
|
|
24
|
+
size: new IntegerColumn('size'),
|
|
25
|
+
});
|
|
26
|
+
public cascadeDeleteReferences = () => [
|
|
27
|
+
{
|
|
28
|
+
table: new FileDataTable().name,
|
|
29
|
+
referenceColumn: new FileDataTable().columns.file.name,
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Table } from '@proteinjs/db';
|
|
2
|
+
import { FileTable, File } from './FileTable';
|
|
3
|
+
import { FileDataTable, FileData } from './FileDataTable';
|
|
4
|
+
|
|
5
|
+
export const tables = {
|
|
6
|
+
File: new FileTable() as Table<File>,
|
|
7
|
+
FileData: new FileDataTable() as Table<FileData>,
|
|
8
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"rootDir": "./",
|
|
4
|
+
"target": "es5",
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationMap": true,
|
|
8
|
+
"sourceMap": true,
|
|
9
|
+
"outDir": "./dist/",
|
|
10
|
+
"strict": true,
|
|
11
|
+
"noImplicitAny": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"typeRoots": ["./node_modules/@types"],
|
|
17
|
+
"types": ["node", "jest"]
|
|
18
|
+
}
|
|
19
|
+
}
|