Compare commits
21 Commits
roburst-lo
...
feat/inlin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
023d2195f9 | ||
|
|
c482bdfae7 | ||
|
|
0dadfc52dd | ||
|
|
df4a27e8a7 | ||
|
|
1f9813a28e | ||
|
|
bbfff45058 | ||
|
|
87dd09d103 | ||
|
|
dd94ad17aa | ||
|
|
a87c2e82cd | ||
|
|
a11ab4c3f7 | ||
|
|
ebf2f9fd7b | ||
|
|
683af67344 | ||
|
|
d149d6fa3f | ||
|
|
8c5269c002 | ||
|
|
cf91d9bdfc | ||
|
|
5579554532 | ||
|
|
7e35e6985e | ||
|
|
56756baea2 | ||
|
|
d5923241b5 | ||
|
|
cc471806fe | ||
|
|
4ce9bce414 |
6
.github/package-lock.json
generated
vendored
6
.github/package-lock.json
generated
vendored
@@ -9,9 +9,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
||||||
"integrity": "sha512-5xGWRa90Sp2+x1dQtNpIpeOQpTDBs9cZDmA/qs2vDNN2i18PdapqY7CmBeyLlMuGqXJRIOPaCaVZTLNQRWUH/A==",
|
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
uses: github/codeql-action/autobuild@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
@@ -76,6 +76,6 @@ jobs:
|
|||||||
# ./location_of_script_within_repo/buildscript.sh
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
|
||||||
with:
|
with:
|
||||||
category: '/language:${{matrix.language}}'
|
category: '/language:${{matrix.language}}'
|
||||||
|
|||||||
26
.github/workflows/static_analysis.yml
vendored
26
.github/workflows/static_analysis.yml
vendored
@@ -42,6 +42,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./mobile
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
@@ -56,27 +59,23 @@ jobs:
|
|||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: dart pub get
|
run: dart pub get
|
||||||
working-directory: ./mobile
|
|
||||||
|
|
||||||
- name: Install DCM
|
- name: Install DCM
|
||||||
run: |
|
# TODO: Move to upstream after https://github.com/CQLabs/setup-dcm/pull/235 merges
|
||||||
sudo apt-get update
|
uses: bo0tzz/setup-dcm@b4952ab813659c03513b57bd78bfe3f634171f8a
|
||||||
wget -qO- https://dcm.dev/pgp-key.public | sudo gpg --dearmor -o /usr/share/keyrings/dcm.gpg
|
with:
|
||||||
echo 'deb [signed-by=/usr/share/keyrings/dcm.gpg arch=amd64] https://dcm.dev/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
sudo apt-get update
|
version: auto
|
||||||
sudo apt-get install dcm
|
working-directory: ./mobile
|
||||||
|
|
||||||
- name: Generate translation file
|
- name: Generate translation file
|
||||||
run: make translation
|
run: make translation
|
||||||
working-directory: ./mobile
|
|
||||||
|
|
||||||
- name: Run Build Runner
|
- name: Run Build Runner
|
||||||
run: make build
|
run: make build
|
||||||
working-directory: ./mobile
|
|
||||||
|
|
||||||
- name: Generate platform API
|
- name: Generate platform API
|
||||||
run: make pigeon
|
run: make pigeon
|
||||||
working-directory: ./mobile
|
|
||||||
|
|
||||||
- name: Find file changes
|
- name: Find file changes
|
||||||
uses: tj-actions/verify-changed-files@a1c6acee9df209257a246f2cc6ae8cb6581c1edf # v20.0.4
|
uses: tj-actions/verify-changed-files@a1c6acee9df209257a246f2cc6ae8cb6581c1edf # v20.0.4
|
||||||
@@ -98,19 +97,16 @@ jobs:
|
|||||||
|
|
||||||
- name: Run dart analyze
|
- name: Run dart analyze
|
||||||
run: dart analyze --fatal-infos
|
run: dart analyze --fatal-infos
|
||||||
working-directory: ./mobile
|
|
||||||
|
|
||||||
- name: Run dart format
|
- name: Run dart format
|
||||||
run: dart format lib/ --set-exit-if-changed
|
run: dart format lib/ --set-exit-if-changed
|
||||||
working-directory: ./mobile
|
|
||||||
|
|
||||||
- name: Run dart custom_lint
|
- name: Run dart custom_lint
|
||||||
run: dart run custom_lint
|
run: dart run custom_lint
|
||||||
working-directory: ./mobile
|
|
||||||
|
|
||||||
|
# TODO: Use https://github.com/CQLabs/dcm-action
|
||||||
- name: Run DCM
|
- name: Run DCM
|
||||||
run: dcm analyze lib --fatal-style --fatal-warnings
|
run: dcm analyze lib --fatal-style --fatal-warnings
|
||||||
working-directory: ./mobile
|
|
||||||
|
|
||||||
zizmor:
|
zizmor:
|
||||||
name: zizmor
|
name: zizmor
|
||||||
@@ -134,7 +130,7 @@ jobs:
|
|||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Upload SARIF file
|
- name: Upload SARIF file
|
||||||
uses: github/codeql-action/upload-sarif@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
uses: github/codeql-action/upload-sarif@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
category: zizmor
|
category: zizmor
|
||||||
|
|||||||
162
cli/package-lock.json
generated
162
cli/package-lock.json
generated
@@ -16,7 +16,7 @@
|
|||||||
"micromatch": "^4.0.8"
|
"micromatch": "^4.0.8"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"immich": "dist/index.js"
|
"immich": "bin/immich"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.1.0",
|
"@eslint/eslintrc": "^3.1.0",
|
||||||
@@ -607,9 +607,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-array": {
|
"node_modules/@eslint/config-array": {
|
||||||
"version": "0.20.1",
|
"version": "0.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz",
|
||||||
"integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
|
"integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -622,9 +622,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-helpers": {
|
"node_modules/@eslint/config-helpers": {
|
||||||
"version": "0.2.1",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz",
|
||||||
"integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==",
|
"integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -682,9 +682,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.29.0",
|
"version": "9.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.1.tgz",
|
||||||
"integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
|
"integrity": "sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1365,17 +1365,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.1.tgz",
|
||||||
"integrity": "sha512-ijItUYaiWuce0N1SoSMrEd0b6b6lYkYt99pqCPfybd+HKVXtEvYhICfLdwp42MhiI5mp0oq7PKEL+g1cNiz/Eg==",
|
"integrity": "sha512-9XNTlo7P7RJxbVeICaIIIEipqxLKguyh+3UbXuT2XQuFp6d8VOeDEGuz5IiX0dgZo8CiI6aOFLg4e8cF71SFVg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "8.35.0",
|
"@typescript-eslint/scope-manager": "8.35.1",
|
||||||
"@typescript-eslint/type-utils": "8.35.0",
|
"@typescript-eslint/type-utils": "8.35.1",
|
||||||
"@typescript-eslint/utils": "8.35.0",
|
"@typescript-eslint/utils": "8.35.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.35.0",
|
"@typescript-eslint/visitor-keys": "8.35.1",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^7.0.0",
|
"ignore": "^7.0.0",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -1389,7 +1389,7 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@typescript-eslint/parser": "^8.35.0",
|
"@typescript-eslint/parser": "^8.35.1",
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0",
|
||||||
"typescript": ">=4.8.4 <5.9.0"
|
"typescript": ">=4.8.4 <5.9.0"
|
||||||
}
|
}
|
||||||
@@ -1405,16 +1405,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.35.1.tgz",
|
||||||
"integrity": "sha512-6sMvZePQrnZH2/cJkwRpkT7DxoAWh+g6+GFRK6bV3YQo7ogi3SX5rgF6099r5Q53Ma5qeT7LGmOmuIutF4t3lA==",
|
"integrity": "sha512-3MyiDfrfLeK06bi/g9DqJxP5pV74LNv4rFTyvGDmT3x2p1yp1lOd+qYZfiRPIOf/oON+WRZR5wxxuF85qOar+w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.35.0",
|
"@typescript-eslint/scope-manager": "8.35.1",
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.35.0",
|
"@typescript-eslint/typescript-estree": "8.35.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.35.0",
|
"@typescript-eslint/visitor-keys": "8.35.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1430,14 +1430,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/project-service": {
|
"node_modules/@typescript-eslint/project-service": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.35.1.tgz",
|
||||||
"integrity": "sha512-41xatqRwWZuhUMF/aZm2fcUsOFKNcG28xqRSS6ZVr9BVJtGExosLAm5A1OxTjRMagx8nJqva+P5zNIGt8RIgbQ==",
|
"integrity": "sha512-VYxn/5LOpVxADAuP3NrnxxHYfzVtQzLKeldIhDhzC8UHaiQvYlXvKuVho1qLduFbJjjy5U5bkGwa3rUGUb1Q6Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.35.0",
|
"@typescript-eslint/tsconfig-utils": "^8.35.1",
|
||||||
"@typescript-eslint/types": "^8.35.0",
|
"@typescript-eslint/types": "^8.35.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1452,14 +1452,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.35.1.tgz",
|
||||||
"integrity": "sha512-+AgL5+mcoLxl1vGjwNfiWq5fLDZM1TmTPYs2UkyHfFhgERxBbqHlNjRzhThJqz+ktBqTChRYY6zwbMwy0591AA==",
|
"integrity": "sha512-s/Bpd4i7ht2934nG+UoSPlYXd08KYz3bmjLEb7Ye1UVob0d1ENiT3lY8bsCmik4RqfSbPw9xJJHbugpPpP5JUg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.35.0"
|
"@typescript-eslint/visitor-keys": "8.35.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -1470,9 +1470,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.1.tgz",
|
||||||
"integrity": "sha512-04k/7247kZzFraweuEirmvUj+W3bJLI9fX6fbo1Qm2YykuBvEhRTPl8tcxlYO8kZZW+HIXfkZNoasVb8EV4jpA==",
|
"integrity": "sha512-K5/U9VmT9dTHoNowWZpz+/TObS3xqC5h0xAIjXPw+MNcKV9qg6eSatEnmeAwkjHijhACH0/N7bkhKvbt1+DXWQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1487,14 +1487,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.35.1.tgz",
|
||||||
"integrity": "sha512-ceNNttjfmSEoM9PW87bWLDEIaLAyR+E6BoYJQ5PfaDau37UGca9Nyq3lBk8Bw2ad0AKvYabz6wxc7DMTO2jnNA==",
|
"integrity": "sha512-HOrUBlfVRz5W2LIKpXzZoy6VTZzMu2n8q9C2V/cFngIC5U1nStJgv0tMV4sZPzdf4wQm9/ToWUFPMN9Vq9VJQQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "8.35.0",
|
"@typescript-eslint/typescript-estree": "8.35.1",
|
||||||
"@typescript-eslint/utils": "8.35.0",
|
"@typescript-eslint/utils": "8.35.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^2.1.0"
|
"ts-api-utils": "^2.1.0"
|
||||||
},
|
},
|
||||||
@@ -1511,9 +1511,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.1.tgz",
|
||||||
"integrity": "sha512-0mYH3emanku0vHw2aRLNGqe7EXh9WHEhi7kZzscrMDf6IIRUQ5Jk4wp1QrledE/36KtdZrVfKnE32eZCf/vaVQ==",
|
"integrity": "sha512-q/O04vVnKHfrrhNAscndAn1tuQhIkwqnaW+eu5waD5IPts2eX1dgJxgqcPx5BX109/qAz7IG6VrEPTOYKCNfRQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1525,16 +1525,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.35.1.tgz",
|
||||||
"integrity": "sha512-F+BhnaBemgu1Qf8oHrxyw14wq6vbL8xwWKKMwTMwYIRmFFY/1n/9T/jpbobZL8vp7QyEUcC6xGrnAO4ua8Kp7w==",
|
"integrity": "sha512-Vvpuvj4tBxIka7cPs6Y1uvM7gJgdF5Uu9F+mBJBPY4MhvjrjWGK4H0lVgLJd/8PWZ23FTqsaJaLEkBCFUk8Y9g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.35.0",
|
"@typescript-eslint/project-service": "8.35.1",
|
||||||
"@typescript-eslint/tsconfig-utils": "8.35.0",
|
"@typescript-eslint/tsconfig-utils": "8.35.1",
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.35.0",
|
"@typescript-eslint/visitor-keys": "8.35.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@@ -1580,16 +1580,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.1.tgz",
|
||||||
"integrity": "sha512-nqoMu7WWM7ki5tPgLVsmPM8CkqtoPUG6xXGeefM5t4x3XumOEKMoUZPdi+7F+/EotukN4R9OWdmDxN80fqoZeg==",
|
"integrity": "sha512-lhnwatFmOFcazAsUm3ZnZFpXSxiwoa1Lj50HphnDe1Et01NF4+hrdXONSUHIcbVu2eFb1bAf+5yjXkGVkXBKAQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.7.0",
|
"@eslint-community/eslint-utils": "^4.7.0",
|
||||||
"@typescript-eslint/scope-manager": "8.35.0",
|
"@typescript-eslint/scope-manager": "8.35.1",
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.35.0"
|
"@typescript-eslint/typescript-estree": "8.35.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -1604,13 +1604,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.35.1.tgz",
|
||||||
"integrity": "sha512-zTh2+1Y8ZpmeQaQVIc/ZZxsx8UzgKJyNg1PTvjzC7WMhPSVS8bfDX34k1SrwOf016qd5RU3az2UxUNue3IfQ5g==",
|
"integrity": "sha512-VRwixir4zBWCSTP/ljEo091lbpypz57PoeAQ9imjG+vbeof9LplljsL1mos4ccG6H9IjfrVGM359RozUnuFhpw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"eslint-visitor-keys": "^4.2.1"
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2305,19 +2305,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.29.0",
|
"version": "9.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.1.tgz",
|
||||||
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
|
"integrity": "sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
"@eslint/config-array": "^0.20.1",
|
"@eslint/config-array": "^0.21.0",
|
||||||
"@eslint/config-helpers": "^0.2.1",
|
"@eslint/config-helpers": "^0.3.0",
|
||||||
"@eslint/core": "^0.14.0",
|
"@eslint/core": "^0.14.0",
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@eslint/js": "9.29.0",
|
"@eslint/js": "9.30.1",
|
||||||
"@eslint/plugin-kit": "^0.3.1",
|
"@eslint/plugin-kit": "^0.3.1",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
@@ -2822,9 +2822,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/globals": {
|
"node_modules/globals": {
|
||||||
"version": "16.2.0",
|
"version": "16.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz",
|
||||||
"integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==",
|
"integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3505,9 +3505,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
||||||
"integrity": "sha512-5xGWRa90Sp2+x1dQtNpIpeOQpTDBs9cZDmA/qs2vDNN2i18PdapqY7CmBeyLlMuGqXJRIOPaCaVZTLNQRWUH/A==",
|
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -4125,15 +4125,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript-eslint": {
|
"node_modules/typescript-eslint": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.35.1.tgz",
|
||||||
"integrity": "sha512-uEnz70b7kBz6eg/j0Czy6K5NivaYopgxRjsnAJ2Fx5oTLo3wefTHIbL7AkQr1+7tJCRVpTs/wiM8JR/11Loq9A==",
|
"integrity": "sha512-xslJjFzhOmHYQzSB/QTeASAHbjmxOGEP6Coh93TXmUBFQoJ1VU35UHIDmG06Jd6taf3wqqC1ntBnCMeymy5Ovw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "8.35.0",
|
"@typescript-eslint/eslint-plugin": "8.35.1",
|
||||||
"@typescript-eslint/parser": "8.35.0",
|
"@typescript-eslint/parser": "8.35.1",
|
||||||
"@typescript-eslint/utils": "8.35.0"
|
"@typescript-eslint/utils": "8.35.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ Once you have a new OAuth client application configured, Immich can be configure
|
|||||||
| Scope | string | openid email profile | Full list of scopes to send with the request (space delimited) |
|
| Scope | string | openid email profile | Full list of scopes to send with the request (space delimited) |
|
||||||
| Signing Algorithm | string | RS256 | The algorithm used to sign the id token (examples: RS256, HS256) |
|
| Signing Algorithm | string | RS256 | The algorithm used to sign the id token (examples: RS256, HS256) |
|
||||||
| Storage Label Claim | string | preferred_username | Claim mapping for the user's storage label**¹** |
|
| Storage Label Claim | string | preferred_username | Claim mapping for the user's storage label**¹** |
|
||||||
|
| Role Claim | string | immich_role | Claim mapping for the user's role. (should return "user" or "admin")**¹** |
|
||||||
| Storage Quota Claim | string | immich_quota | Claim mapping for the user's storage**¹** |
|
| Storage Quota Claim | string | immich_quota | Claim mapping for the user's storage**¹** |
|
||||||
| Default Storage Quota (GiB) | number | 0 | Default quota for user without storage quota claim (Enter 0 for unlimited quota) |
|
| Default Storage Quota (GiB) | number | 0 | Default quota for user without storage quota claim (Enter 0 for unlimited quota) |
|
||||||
| Button Text | string | Login with OAuth | Text for the OAuth button on the web |
|
| Button Text | string | Login with OAuth | Text for the OAuth button on the web |
|
||||||
|
|||||||
6
docs/package-lock.json
generated
6
docs/package-lock.json
generated
@@ -16459,9 +16459,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
||||||
"integrity": "sha512-5xGWRa90Sp2+x1dQtNpIpeOQpTDBs9cZDmA/qs2vDNN2i18PdapqY7CmBeyLlMuGqXJRIOPaCaVZTLNQRWUH/A==",
|
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ services:
|
|||||||
- 2285:2285
|
- 2285:2285
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:6.2-alpine@sha256:3211c33a618c457e5d241922c975dbc4f446d0bdb2dc75694f5573ef8e2d01fa
|
image: redis:6.2-alpine@sha256:03fd052257735b41cd19f3d8ae9782926bf9b704fb6a9dc5e29f9ccfbe8827f0
|
||||||
|
|
||||||
database:
|
database:
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:3aef84a0a4fabbda17ef115c3019ba0c914ec73e9f6e59203674322d858b8eea
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:3aef84a0a4fabbda17ef115c3019ba0c914ec73e9f6e59203674322d858b8eea
|
||||||
|
|||||||
342
e2e/package-lock.json
generated
342
e2e/package-lock.json
generated
@@ -56,7 +56,7 @@
|
|||||||
"micromatch": "^4.0.8"
|
"micromatch": "^4.0.8"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"immich": "dist/index.js"
|
"immich": "bin/immich"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.1.0",
|
"@eslint/eslintrc": "^3.1.0",
|
||||||
@@ -658,9 +658,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-array": {
|
"node_modules/@eslint/config-array": {
|
||||||
"version": "0.20.1",
|
"version": "0.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz",
|
||||||
"integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
|
"integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -673,9 +673,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-helpers": {
|
"node_modules/@eslint/config-helpers": {
|
||||||
"version": "0.2.3",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz",
|
||||||
"integrity": "sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==",
|
"integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -733,9 +733,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.29.0",
|
"version": "9.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.1.tgz",
|
||||||
"integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
|
"integrity": "sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1509,13 +1509,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@playwright/test": {
|
"node_modules/@playwright/test": {
|
||||||
"version": "1.53.1",
|
"version": "1.53.2",
|
||||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.1.tgz",
|
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.2.tgz",
|
||||||
"integrity": "sha512-Z4c23LHV0muZ8hfv4jw6HngPJkbbtZxTkxPNIg7cJcTc9C28N/p2q7g3JZS2SiKBBHJ3uM1dgDye66bB7LEk5w==",
|
"integrity": "sha512-tEB2U5z74ebBeyfGNZ3Jfg29AnW+5HlWhvHtb/Mqco9pFdZU1ZLNdVb2UtB5CvmiilNr2ZfVH/qMmAROG/XTzw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright": "1.53.1"
|
"playwright": "1.53.2"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
@@ -2028,66 +2028,6 @@
|
|||||||
"pg-types": "^2.2.0"
|
"pg-types": "^2.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/pg/node_modules/pg-types": {
|
|
||||||
"version": "2.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
|
|
||||||
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"pg-int8": "1.0.1",
|
|
||||||
"postgres-array": "~2.0.0",
|
|
||||||
"postgres-bytea": "~1.0.0",
|
|
||||||
"postgres-date": "~1.0.4",
|
|
||||||
"postgres-interval": "^1.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/pg/node_modules/postgres-array": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/pg/node_modules/postgres-bytea": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/pg/node_modules/postgres-date": {
|
|
||||||
"version": "1.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
|
|
||||||
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/pg/node_modules/postgres-interval": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
|
|
||||||
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"xtend": "^4.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/pngjs": {
|
"node_modules/@types/pngjs": {
|
||||||
"version": "6.0.5",
|
"version": "6.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/pngjs/-/pngjs-6.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/pngjs/-/pngjs-6.0.5.tgz",
|
||||||
@@ -2160,17 +2100,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.1.tgz",
|
||||||
"integrity": "sha512-ijItUYaiWuce0N1SoSMrEd0b6b6lYkYt99pqCPfybd+HKVXtEvYhICfLdwp42MhiI5mp0oq7PKEL+g1cNiz/Eg==",
|
"integrity": "sha512-9XNTlo7P7RJxbVeICaIIIEipqxLKguyh+3UbXuT2XQuFp6d8VOeDEGuz5IiX0dgZo8CiI6aOFLg4e8cF71SFVg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "8.35.0",
|
"@typescript-eslint/scope-manager": "8.35.1",
|
||||||
"@typescript-eslint/type-utils": "8.35.0",
|
"@typescript-eslint/type-utils": "8.35.1",
|
||||||
"@typescript-eslint/utils": "8.35.0",
|
"@typescript-eslint/utils": "8.35.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.35.0",
|
"@typescript-eslint/visitor-keys": "8.35.1",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^7.0.0",
|
"ignore": "^7.0.0",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -2184,7 +2124,7 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@typescript-eslint/parser": "^8.35.0",
|
"@typescript-eslint/parser": "^8.35.1",
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0",
|
||||||
"typescript": ">=4.8.4 <5.9.0"
|
"typescript": ">=4.8.4 <5.9.0"
|
||||||
}
|
}
|
||||||
@@ -2200,16 +2140,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.35.1.tgz",
|
||||||
"integrity": "sha512-6sMvZePQrnZH2/cJkwRpkT7DxoAWh+g6+GFRK6bV3YQo7ogi3SX5rgF6099r5Q53Ma5qeT7LGmOmuIutF4t3lA==",
|
"integrity": "sha512-3MyiDfrfLeK06bi/g9DqJxP5pV74LNv4rFTyvGDmT3x2p1yp1lOd+qYZfiRPIOf/oON+WRZR5wxxuF85qOar+w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.35.0",
|
"@typescript-eslint/scope-manager": "8.35.1",
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.35.0",
|
"@typescript-eslint/typescript-estree": "8.35.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.35.0",
|
"@typescript-eslint/visitor-keys": "8.35.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2225,14 +2165,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/project-service": {
|
"node_modules/@typescript-eslint/project-service": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.35.1.tgz",
|
||||||
"integrity": "sha512-41xatqRwWZuhUMF/aZm2fcUsOFKNcG28xqRSS6ZVr9BVJtGExosLAm5A1OxTjRMagx8nJqva+P5zNIGt8RIgbQ==",
|
"integrity": "sha512-VYxn/5LOpVxADAuP3NrnxxHYfzVtQzLKeldIhDhzC8UHaiQvYlXvKuVho1qLduFbJjjy5U5bkGwa3rUGUb1Q6Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.35.0",
|
"@typescript-eslint/tsconfig-utils": "^8.35.1",
|
||||||
"@typescript-eslint/types": "^8.35.0",
|
"@typescript-eslint/types": "^8.35.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2247,14 +2187,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.35.1.tgz",
|
||||||
"integrity": "sha512-+AgL5+mcoLxl1vGjwNfiWq5fLDZM1TmTPYs2UkyHfFhgERxBbqHlNjRzhThJqz+ktBqTChRYY6zwbMwy0591AA==",
|
"integrity": "sha512-s/Bpd4i7ht2934nG+UoSPlYXd08KYz3bmjLEb7Ye1UVob0d1ENiT3lY8bsCmik4RqfSbPw9xJJHbugpPpP5JUg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.35.0"
|
"@typescript-eslint/visitor-keys": "8.35.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -2265,9 +2205,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.1.tgz",
|
||||||
"integrity": "sha512-04k/7247kZzFraweuEirmvUj+W3bJLI9fX6fbo1Qm2YykuBvEhRTPl8tcxlYO8kZZW+HIXfkZNoasVb8EV4jpA==",
|
"integrity": "sha512-K5/U9VmT9dTHoNowWZpz+/TObS3xqC5h0xAIjXPw+MNcKV9qg6eSatEnmeAwkjHijhACH0/N7bkhKvbt1+DXWQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2282,14 +2222,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.35.1.tgz",
|
||||||
"integrity": "sha512-ceNNttjfmSEoM9PW87bWLDEIaLAyR+E6BoYJQ5PfaDau37UGca9Nyq3lBk8Bw2ad0AKvYabz6wxc7DMTO2jnNA==",
|
"integrity": "sha512-HOrUBlfVRz5W2LIKpXzZoy6VTZzMu2n8q9C2V/cFngIC5U1nStJgv0tMV4sZPzdf4wQm9/ToWUFPMN9Vq9VJQQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "8.35.0",
|
"@typescript-eslint/typescript-estree": "8.35.1",
|
||||||
"@typescript-eslint/utils": "8.35.0",
|
"@typescript-eslint/utils": "8.35.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^2.1.0"
|
"ts-api-utils": "^2.1.0"
|
||||||
},
|
},
|
||||||
@@ -2306,9 +2246,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.1.tgz",
|
||||||
"integrity": "sha512-0mYH3emanku0vHw2aRLNGqe7EXh9WHEhi7kZzscrMDf6IIRUQ5Jk4wp1QrledE/36KtdZrVfKnE32eZCf/vaVQ==",
|
"integrity": "sha512-q/O04vVnKHfrrhNAscndAn1tuQhIkwqnaW+eu5waD5IPts2eX1dgJxgqcPx5BX109/qAz7IG6VrEPTOYKCNfRQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2320,16 +2260,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.35.1.tgz",
|
||||||
"integrity": "sha512-F+BhnaBemgu1Qf8oHrxyw14wq6vbL8xwWKKMwTMwYIRmFFY/1n/9T/jpbobZL8vp7QyEUcC6xGrnAO4ua8Kp7w==",
|
"integrity": "sha512-Vvpuvj4tBxIka7cPs6Y1uvM7gJgdF5Uu9F+mBJBPY4MhvjrjWGK4H0lVgLJd/8PWZ23FTqsaJaLEkBCFUk8Y9g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.35.0",
|
"@typescript-eslint/project-service": "8.35.1",
|
||||||
"@typescript-eslint/tsconfig-utils": "8.35.0",
|
"@typescript-eslint/tsconfig-utils": "8.35.1",
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.35.0",
|
"@typescript-eslint/visitor-keys": "8.35.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@@ -2375,16 +2315,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.1.tgz",
|
||||||
"integrity": "sha512-nqoMu7WWM7ki5tPgLVsmPM8CkqtoPUG6xXGeefM5t4x3XumOEKMoUZPdi+7F+/EotukN4R9OWdmDxN80fqoZeg==",
|
"integrity": "sha512-lhnwatFmOFcazAsUm3ZnZFpXSxiwoa1Lj50HphnDe1Et01NF4+hrdXONSUHIcbVu2eFb1bAf+5yjXkGVkXBKAQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.7.0",
|
"@eslint-community/eslint-utils": "^4.7.0",
|
||||||
"@typescript-eslint/scope-manager": "8.35.0",
|
"@typescript-eslint/scope-manager": "8.35.1",
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.35.0"
|
"@typescript-eslint/typescript-estree": "8.35.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -2399,13 +2339,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.35.1.tgz",
|
||||||
"integrity": "sha512-zTh2+1Y8ZpmeQaQVIc/ZZxsx8UzgKJyNg1PTvjzC7WMhPSVS8bfDX34k1SrwOf016qd5RU3az2UxUNue3IfQ5g==",
|
"integrity": "sha512-VRwixir4zBWCSTP/ljEo091lbpypz57PoeAQ9imjG+vbeof9LplljsL1mos4ccG6H9IjfrVGM359RozUnuFhpw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"eslint-visitor-keys": "^4.2.1"
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3498,19 +3438,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.29.0",
|
"version": "9.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.1.tgz",
|
||||||
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
|
"integrity": "sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
"@eslint/config-array": "^0.20.1",
|
"@eslint/config-array": "^0.21.0",
|
||||||
"@eslint/config-helpers": "^0.2.1",
|
"@eslint/config-helpers": "^0.3.0",
|
||||||
"@eslint/core": "^0.14.0",
|
"@eslint/core": "^0.14.0",
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@eslint/js": "9.29.0",
|
"@eslint/js": "9.30.1",
|
||||||
"@eslint/plugin-kit": "^0.3.1",
|
"@eslint/plugin-kit": "^0.3.1",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
@@ -4279,9 +4219,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/globals": {
|
"node_modules/globals": {
|
||||||
"version": "16.2.0",
|
"version": "16.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz",
|
||||||
"integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==",
|
"integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -5430,15 +5370,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg": {
|
"node_modules/pg": {
|
||||||
"version": "8.16.2",
|
"version": "8.16.3",
|
||||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.2.tgz",
|
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
|
||||||
"integrity": "sha512-OtLWF0mKLmpxelOt9BqVq83QV6bTfsS0XLegIeAKqKjurRnRKie1Dc1iL89MugmSLhftxw6NNCyZhm1yQFLMEQ==",
|
"integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pg-connection-string": "^2.9.1",
|
"pg-connection-string": "^2.9.1",
|
||||||
"pg-pool": "^3.10.1",
|
"pg-pool": "^3.10.1",
|
||||||
"pg-protocol": "^1.10.2",
|
"pg-protocol": "^1.10.3",
|
||||||
"pg-types": "2.2.0",
|
"pg-types": "2.2.0",
|
||||||
"pgpass": "1.0.5"
|
"pgpass": "1.0.5"
|
||||||
},
|
},
|
||||||
@@ -5446,7 +5386,7 @@
|
|||||||
"node": ">= 16.0.0"
|
"node": ">= 16.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"pg-cloudflare": "^1.2.6"
|
"pg-cloudflare": "^1.2.7"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"pg-native": ">=3.0.1"
|
"pg-native": ">=3.0.1"
|
||||||
@@ -5499,7 +5439,7 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/pg/node_modules/pg-types": {
|
"node_modules/pg-types": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
|
||||||
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
|
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
|
||||||
@@ -5516,49 +5456,6 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg/node_modules/postgres-array": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/pg/node_modules/postgres-bytea": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/pg/node_modules/postgres-date": {
|
|
||||||
"version": "1.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
|
|
||||||
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/pg/node_modules/postgres-interval": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
|
|
||||||
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"xtend": "^4.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/pgpass": {
|
"node_modules/pgpass": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
|
||||||
@@ -5590,13 +5487,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright": {
|
"node_modules/playwright": {
|
||||||
"version": "1.53.1",
|
"version": "1.53.2",
|
||||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.1.tgz",
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.2.tgz",
|
||||||
"integrity": "sha512-LJ13YLr/ocweuwxyGf1XNFWIU4M2zUSo149Qbp+A4cpwDjsxRPj7k6H25LBrEHiEwxvRbD8HdwvQmRMSvquhYw==",
|
"integrity": "sha512-6K/qQxVFuVQhRQhFsVZ9fGeatxirtrpPgxzBYWyZLEXJzqYwuL4fuNmfOfD5et1tJE4GScKyPNeLhZeRwuTU3A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.53.1"
|
"playwright-core": "1.53.2"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
@@ -5609,9 +5506,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright-core": {
|
"node_modules/playwright-core": {
|
||||||
"version": "1.53.1",
|
"version": "1.53.2",
|
||||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.1.tgz",
|
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.2.tgz",
|
||||||
"integrity": "sha512-Z46Oq7tLAyT0lGoFx4DOuB1IA9D1TPj0QkYxpPVUnGDqHHvDpCftu1J2hM2PiWsNMoZh8+LQaarAWcDfPBc6zg==",
|
"integrity": "sha512-ox/OytMy+2w1jcYEYlOo1Hhp8hZkLCximMTUTMBXjGUA1KoFfiSZ+DU+3a739jsPY0yoKH2TFy9S2fsJas8yAw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -5689,6 +5586,49 @@
|
|||||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/postgres-array": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postgres-bytea": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postgres-date": {
|
||||||
|
"version": "1.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
|
||||||
|
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postgres-interval": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"xtend": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prelude-ls": {
|
"node_modules/prelude-ls": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||||
@@ -5700,9 +5640,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
||||||
"integrity": "sha512-5xGWRa90Sp2+x1dQtNpIpeOQpTDBs9cZDmA/qs2vDNN2i18PdapqY7CmBeyLlMuGqXJRIOPaCaVZTLNQRWUH/A==",
|
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -6837,15 +6777,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript-eslint": {
|
"node_modules/typescript-eslint": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.35.1.tgz",
|
||||||
"integrity": "sha512-uEnz70b7kBz6eg/j0Czy6K5NivaYopgxRjsnAJ2Fx5oTLo3wefTHIbL7AkQr1+7tJCRVpTs/wiM8JR/11Loq9A==",
|
"integrity": "sha512-xslJjFzhOmHYQzSB/QTeASAHbjmxOGEP6Coh93TXmUBFQoJ1VU35UHIDmG06Jd6taf3wqqC1ntBnCMeymy5Ovw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "8.35.0",
|
"@typescript-eslint/eslint-plugin": "8.35.1",
|
||||||
"@typescript-eslint/parser": "8.35.0",
|
"@typescript-eslint/parser": "8.35.1",
|
||||||
"@typescript-eslint/utils": "8.35.0"
|
"@typescript-eslint/utils": "8.35.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
|||||||
@@ -227,6 +227,21 @@ describe(`/oauth`, () => {
|
|||||||
expect(user.storageLabel).toBe('user-username');
|
expect(user.storageLabel).toBe('user-username');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should set the admin status from a role claim', async () => {
|
||||||
|
const callbackParams = await loginWithOAuth(OAuthUser.WITH_ROLE);
|
||||||
|
const { status, body } = await request(app).post('/oauth/callback').send(callbackParams);
|
||||||
|
expect(status).toBe(201);
|
||||||
|
expect(body).toMatchObject({
|
||||||
|
accessToken: expect.any(String),
|
||||||
|
userId: expect.any(String),
|
||||||
|
userEmail: 'oauth-with-role@immich.app',
|
||||||
|
isAdmin: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const user = await getMyUser({ headers: asBearerAuth(body.accessToken) });
|
||||||
|
expect(user.isAdmin).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it('should work with RS256 signed tokens', async () => {
|
it('should work with RS256 signed tokens', async () => {
|
||||||
await setupOAuth(admin.accessToken, {
|
await setupOAuth(admin.accessToken, {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export enum OAuthUser {
|
|||||||
NO_NAME = 'no-name',
|
NO_NAME = 'no-name',
|
||||||
WITH_QUOTA = 'with-quota',
|
WITH_QUOTA = 'with-quota',
|
||||||
WITH_USERNAME = 'with-username',
|
WITH_USERNAME = 'with-username',
|
||||||
|
WITH_ROLE = 'with-role',
|
||||||
}
|
}
|
||||||
|
|
||||||
const claims = [
|
const claims = [
|
||||||
@@ -34,6 +35,12 @@ const claims = [
|
|||||||
preferred_username: 'user-quota',
|
preferred_username: 'user-quota',
|
||||||
immich_quota: 25,
|
immich_quota: 25,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
sub: OAuthUser.WITH_ROLE,
|
||||||
|
email: 'oauth-with-role@immich.app',
|
||||||
|
email_verified: true,
|
||||||
|
immich_role: 'admin',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const withDefaultClaims = (sub: string) => ({
|
const withDefaultClaims = (sub: string) => ({
|
||||||
@@ -64,7 +71,15 @@ const setup = async () => {
|
|||||||
claims: {
|
claims: {
|
||||||
openid: ['sub'],
|
openid: ['sub'],
|
||||||
email: ['email', 'email_verified'],
|
email: ['email', 'email_verified'],
|
||||||
profile: ['name', 'given_name', 'family_name', 'preferred_username', 'immich_quota', 'immich_username'],
|
profile: [
|
||||||
|
'name',
|
||||||
|
'given_name',
|
||||||
|
'family_name',
|
||||||
|
'preferred_username',
|
||||||
|
'immich_quota',
|
||||||
|
'immich_username',
|
||||||
|
'immich_role',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
features: {
|
features: {
|
||||||
jwtUserinfo: {
|
jwtUserinfo: {
|
||||||
|
|||||||
@@ -196,6 +196,8 @@
|
|||||||
"oauth_mobile_redirect_uri": "Mobile redirect URI",
|
"oauth_mobile_redirect_uri": "Mobile redirect URI",
|
||||||
"oauth_mobile_redirect_uri_override": "Mobile redirect URI override",
|
"oauth_mobile_redirect_uri_override": "Mobile redirect URI override",
|
||||||
"oauth_mobile_redirect_uri_override_description": "Enable when OAuth provider does not allow a mobile URI, like ''{callback}''",
|
"oauth_mobile_redirect_uri_override_description": "Enable when OAuth provider does not allow a mobile URI, like ''{callback}''",
|
||||||
|
"oauth_role_claim": "Role Claim",
|
||||||
|
"oauth_role_claim_description": "Automatically grant admin access based on the presence of this claim. The claim may have either 'user' or 'admin'.",
|
||||||
"oauth_settings": "OAuth",
|
"oauth_settings": "OAuth",
|
||||||
"oauth_settings_description": "Manage OAuth login settings",
|
"oauth_settings_description": "Manage OAuth login settings",
|
||||||
"oauth_settings_more_details": "For more details about this feature, refer to the <link>docs</link>.",
|
"oauth_settings_more_details": "For more details about this feature, refer to the <link>docs</link>.",
|
||||||
|
|||||||
1332
mobile/drift_schemas/main/drift_schema_v1.json
generated
1332
mobile/drift_schemas/main/drift_schema_v1.json
generated
File diff suppressed because one or more lines are too long
@@ -18,7 +18,7 @@ const String kSecuredPinCode = "secured_pin_code";
|
|||||||
|
|
||||||
// Timeline constants
|
// Timeline constants
|
||||||
const int kTimelineNoneSegmentSize = 120;
|
const int kTimelineNoneSegmentSize = 120;
|
||||||
const int kTimelineAssetLoadBatchSize = 256;
|
const int kTimelineAssetLoadBatchSize = 1024;
|
||||||
const int kTimelineAssetLoadOppositeSize = 64;
|
const int kTimelineAssetLoadOppositeSize = 64;
|
||||||
|
|
||||||
// Widget keys
|
// Widget keys
|
||||||
|
|||||||
84
mobile/lib/domain/models/stack.model.dart
Normal file
84
mobile/lib/domain/models/stack.model.dart
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
// Model for a stack stored in the server
|
||||||
|
class Stack {
|
||||||
|
final String id;
|
||||||
|
final DateTime createdAt;
|
||||||
|
final DateTime updatedAt;
|
||||||
|
final String ownerId;
|
||||||
|
final String primaryAssetId;
|
||||||
|
|
||||||
|
const Stack({
|
||||||
|
required this.id,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
required this.ownerId,
|
||||||
|
required this.primaryAssetId,
|
||||||
|
});
|
||||||
|
|
||||||
|
Stack copyWith({
|
||||||
|
String? id,
|
||||||
|
DateTime? createdAt,
|
||||||
|
DateTime? updatedAt,
|
||||||
|
String? ownerId,
|
||||||
|
String? primaryAssetId,
|
||||||
|
}) {
|
||||||
|
return Stack(
|
||||||
|
id: id ?? this.id,
|
||||||
|
createdAt: createdAt ?? this.createdAt,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
|
ownerId: ownerId ?? this.ownerId,
|
||||||
|
primaryAssetId: primaryAssetId ?? this.primaryAssetId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return <String, dynamic>{
|
||||||
|
'id': id,
|
||||||
|
'createdAt': createdAt.millisecondsSinceEpoch,
|
||||||
|
'updatedAt': updatedAt.millisecondsSinceEpoch,
|
||||||
|
'ownerId': ownerId,
|
||||||
|
'primaryAssetId': primaryAssetId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
factory Stack.fromMap(Map<String, dynamic> map) {
|
||||||
|
return Stack(
|
||||||
|
id: map['id'] as String,
|
||||||
|
createdAt: DateTime.fromMillisecondsSinceEpoch(map['createdAt'] as int),
|
||||||
|
updatedAt: DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] as int),
|
||||||
|
ownerId: map['ownerId'] as String,
|
||||||
|
primaryAssetId: map['primaryAssetId'] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String toJson() => json.encode(toMap());
|
||||||
|
|
||||||
|
factory Stack.fromJson(String source) =>
|
||||||
|
Stack.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Stack(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, ownerId: $ownerId, primaryAssetId: $primaryAssetId)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(covariant Stack other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
|
||||||
|
return other.id == id &&
|
||||||
|
other.createdAt == createdAt &&
|
||||||
|
other.updatedAt == updatedAt &&
|
||||||
|
other.ownerId == ownerId &&
|
||||||
|
other.primaryAssetId == primaryAssetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return id.hashCode ^
|
||||||
|
createdAt.hashCode ^
|
||||||
|
updatedAt.hashCode ^
|
||||||
|
ownerId.hashCode ^
|
||||||
|
primaryAssetId.hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -154,6 +154,25 @@ class SyncStreamService {
|
|||||||
return _syncStreamRepository.updateMemoryAssetsV1(data.cast());
|
return _syncStreamRepository.updateMemoryAssetsV1(data.cast());
|
||||||
case SyncEntityType.memoryToAssetDeleteV1:
|
case SyncEntityType.memoryToAssetDeleteV1:
|
||||||
return _syncStreamRepository.deleteMemoryAssetsV1(data.cast());
|
return _syncStreamRepository.deleteMemoryAssetsV1(data.cast());
|
||||||
|
case SyncEntityType.stackV1:
|
||||||
|
return _syncStreamRepository.updateStacksV1(data.cast());
|
||||||
|
case SyncEntityType.stackDeleteV1:
|
||||||
|
return _syncStreamRepository.deleteStacksV1(data.cast());
|
||||||
|
case SyncEntityType.partnerStackV1:
|
||||||
|
return _syncStreamRepository.updateStacksV1(
|
||||||
|
data.cast(),
|
||||||
|
debugLabel: 'partner',
|
||||||
|
);
|
||||||
|
case SyncEntityType.partnerStackBackfillV1:
|
||||||
|
return _syncStreamRepository.updateStacksV1(
|
||||||
|
data.cast(),
|
||||||
|
debugLabel: 'partner backfill',
|
||||||
|
);
|
||||||
|
case SyncEntityType.partnerStackDeleteV1:
|
||||||
|
return _syncStreamRepository.deleteStacksV1(
|
||||||
|
data.cast(),
|
||||||
|
debugLabel: 'partner',
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
_logger.warning("Unknown sync data type: $type");
|
_logger.warning("Unknown sync data type: $type");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,16 +42,66 @@ class TimelineFactory {
|
|||||||
|
|
||||||
TimelineService localAlbum({required String albumId}) => TimelineService(
|
TimelineService localAlbum({required String albumId}) => TimelineService(
|
||||||
assetSource: (offset, count) => _timelineRepository
|
assetSource: (offset, count) => _timelineRepository
|
||||||
.getLocalBucketAssets(albumId, offset: offset, count: count),
|
.getLocalAlbumBucketAssets(albumId, offset: offset, count: count),
|
||||||
bucketSource: () =>
|
bucketSource: () => _timelineRepository.watchLocalAlbumBucket(
|
||||||
_timelineRepository.watchLocalBucket(albumId, groupBy: groupBy),
|
albumId,
|
||||||
|
groupBy: groupBy,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
TimelineService remoteAlbum({required String albumId}) => TimelineService(
|
TimelineService remoteAlbum({required String albumId}) => TimelineService(
|
||||||
assetSource: (offset, count) => _timelineRepository
|
assetSource: (offset, count) => _timelineRepository
|
||||||
.getRemoteBucketAssets(albumId, offset: offset, count: count),
|
.getRemoteAlbumBucketAssets(albumId, offset: offset, count: count),
|
||||||
|
bucketSource: () => _timelineRepository.watchRemoteAlbumBucket(
|
||||||
|
albumId,
|
||||||
|
groupBy: groupBy,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
TimelineService remoteAssets(List<String> timelineUsers) => TimelineService(
|
||||||
|
assetSource: (offset, count) => _timelineRepository
|
||||||
|
.getRemoteBucketAssets(timelineUsers, offset: offset, count: count),
|
||||||
|
bucketSource: () => _timelineRepository.watchRemoteBucket(
|
||||||
|
timelineUsers,
|
||||||
|
groupBy: GroupAssetsBy.month,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
TimelineService favorite(String userId) => TimelineService(
|
||||||
|
assetSource: (offset, count) => _timelineRepository
|
||||||
|
.getFavoriteBucketAssets(userId, offset: offset, count: count),
|
||||||
bucketSource: () =>
|
bucketSource: () =>
|
||||||
_timelineRepository.watchRemoteBucket(albumId, groupBy: groupBy),
|
_timelineRepository.watchFavoriteBucket(userId, groupBy: groupBy),
|
||||||
|
);
|
||||||
|
|
||||||
|
TimelineService trash(String userId) => TimelineService(
|
||||||
|
assetSource: (offset, count) => _timelineRepository
|
||||||
|
.getTrashBucketAssets(userId, offset: offset, count: count),
|
||||||
|
bucketSource: () =>
|
||||||
|
_timelineRepository.watchTrashBucket(userId, groupBy: groupBy),
|
||||||
|
);
|
||||||
|
|
||||||
|
TimelineService archive(String userId) => TimelineService(
|
||||||
|
assetSource: (offset, count) => _timelineRepository
|
||||||
|
.getArchiveBucketAssets(userId, offset: offset, count: count),
|
||||||
|
bucketSource: () =>
|
||||||
|
_timelineRepository.watchArchiveBucket(userId, groupBy: groupBy),
|
||||||
|
);
|
||||||
|
|
||||||
|
TimelineService lockedFolder(String userId) => TimelineService(
|
||||||
|
assetSource: (offset, count) => _timelineRepository
|
||||||
|
.getLockedFolderBucketAssets(userId, offset: offset, count: count),
|
||||||
|
bucketSource: () => _timelineRepository.watchLockedFolderBucket(
|
||||||
|
userId,
|
||||||
|
groupBy: groupBy,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
TimelineService video(String userId) => TimelineService(
|
||||||
|
assetSource: (offset, count) => _timelineRepository
|
||||||
|
.getVideoBucketAssets(userId, offset: offset, count: count),
|
||||||
|
bucketSource: () =>
|
||||||
|
_timelineRepository.watchVideoBucket(userId, groupBy: groupBy),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
58
mobile/lib/infrastructure/entities/asset_triggers.drift
Normal file
58
mobile/lib/infrastructure/entities/asset_triggers.drift
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import 'remote_asset.entity.dart';
|
||||||
|
import 'local_asset.entity.dart';
|
||||||
|
|
||||||
|
-- TRIGGERS ON local_asset_entity
|
||||||
|
|
||||||
|
-- Find and update the remote_id in local_asset_entity and local_id in remote_asset_entity when checksum is set
|
||||||
|
CREATE TRIGGER IF NOT EXISTS tr_local_asset_update_checksum_set_ids
|
||||||
|
AFTER UPDATE OF checksum ON local_asset_entity
|
||||||
|
FOR EACH ROW
|
||||||
|
WHEN NEW.checksum IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
UPDATE local_asset_entity
|
||||||
|
SET remote_id = (SELECT id FROM remote_asset_entity WHERE checksum = NEW.checksum LIMIT 1)
|
||||||
|
WHERE id = NEW.id;
|
||||||
|
|
||||||
|
UPDATE remote_asset_entity
|
||||||
|
SET local_id = (SELECT id FROM local_asset_entity WHERE checksum = NEW.checksum ORDER BY id ASC LIMIT 1)
|
||||||
|
WHERE checksum = NEW.checksum;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- When a local asset is updated, relink remote assets that had a checksum match
|
||||||
|
CREATE TRIGGER IF NOT EXISTS tr_local_asset_update_old_checksum_set_remote_asset_local_id
|
||||||
|
AFTER UPDATE OF checksum ON local_asset_entity
|
||||||
|
FOR EACH ROW
|
||||||
|
WHEN OLD.checksum IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
UPDATE remote_asset_entity
|
||||||
|
SET local_id = (SELECT id FROM local_asset_entity WHERE checksum = OLD.checksum ORDER BY id ASC LIMIT 1)
|
||||||
|
WHERE checksum = OLD.checksum;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- remote_asset_entity.checksum is a 1..* relationship with local_asset_entity.checksum.
|
||||||
|
-- When a local asset is deleted, update remote assets that had a checksum match
|
||||||
|
-- to ensure their local_id is set to the first matching local asset or NULL
|
||||||
|
CREATE TRIGGER IF NOT EXISTS tr_local_asset_delete_update_remote_asset_local_id
|
||||||
|
AFTER DELETE ON local_asset_entity
|
||||||
|
FOR EACH ROW
|
||||||
|
WHEN OLD.checksum IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
UPDATE remote_asset_entity
|
||||||
|
SET local_id = (SELECT id FROM local_asset_entity WHERE checksum = OLD.checksum ORDER BY id ASC LIMIT 1)
|
||||||
|
WHERE checksum = OLD.checksum;
|
||||||
|
END;
|
||||||
|
|
||||||
|
|
||||||
|
-- TRIGGERS ON remote_asset_entity
|
||||||
|
|
||||||
|
-- Find and update local_id in remote_asset_entity when a new remote asset is inserted
|
||||||
|
CREATE TRIGGER IF NOT EXISTS tr_remote_asset_insert_set_local_id
|
||||||
|
AFTER INSERT ON remote_asset_entity
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE remote_asset_entity
|
||||||
|
SET local_id = (SELECT id FROM local_asset_entity WHERE checksum = NEW.checksum ORDER BY id ASC LIMIT 1)
|
||||||
|
WHERE id = NEW.id;
|
||||||
|
|
||||||
|
UPDATE local_asset_entity SET remote_id = NEW.id WHERE checksum = NEW.checksum;
|
||||||
|
END;
|
||||||
16
mobile/lib/infrastructure/entities/asset_triggers.drift.dart
generated
Normal file
16
mobile/lib/infrastructure/entities/asset_triggers.drift.dart
generated
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// dart format width=80
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
import 'package:drift/drift.dart' as i0;
|
||||||
|
|
||||||
|
i0.Trigger get trLocalAssetUpdateChecksumSetIds => i0.Trigger(
|
||||||
|
'CREATE TRIGGER IF NOT EXISTS tr_local_asset_update_checksum_set_ids AFTER UPDATE OF checksum ON local_asset_entity WHEN NEW.checksum IS NOT NULL BEGIN UPDATE local_asset_entity SET remote_id = (SELECT id FROM remote_asset_entity WHERE checksum = NEW.checksum LIMIT 1) WHERE id = NEW.id;UPDATE remote_asset_entity SET local_id = (SELECT id FROM local_asset_entity WHERE checksum = NEW.checksum ORDER BY id ASC LIMIT 1) WHERE checksum = NEW.checksum;END',
|
||||||
|
'tr_local_asset_update_checksum_set_ids');
|
||||||
|
i0.Trigger get trLocalAssetUpdateOldChecksumSetRemoteAssetLocalId => i0.Trigger(
|
||||||
|
'CREATE TRIGGER IF NOT EXISTS tr_local_asset_update_old_checksum_set_remote_asset_local_id AFTER UPDATE OF checksum ON local_asset_entity WHEN OLD.checksum IS NOT NULL BEGIN UPDATE remote_asset_entity SET local_id = (SELECT id FROM local_asset_entity WHERE checksum = OLD.checksum ORDER BY id ASC LIMIT 1) WHERE checksum = OLD.checksum;END',
|
||||||
|
'tr_local_asset_update_old_checksum_set_remote_asset_local_id');
|
||||||
|
i0.Trigger get trLocalAssetDeleteUpdateRemoteAssetLocalId => i0.Trigger(
|
||||||
|
'CREATE TRIGGER IF NOT EXISTS tr_local_asset_delete_update_remote_asset_local_id AFTER DELETE ON local_asset_entity WHEN OLD.checksum IS NOT NULL BEGIN UPDATE remote_asset_entity SET local_id = (SELECT id FROM local_asset_entity WHERE checksum = OLD.checksum ORDER BY id ASC LIMIT 1) WHERE checksum = OLD.checksum;END',
|
||||||
|
'tr_local_asset_delete_update_remote_asset_local_id');
|
||||||
|
i0.Trigger get trRemoteAssetInsertSetLocalId => i0.Trigger(
|
||||||
|
'CREATE TRIGGER IF NOT EXISTS tr_remote_asset_insert_set_local_id AFTER INSERT ON remote_asset_entity BEGIN UPDATE remote_asset_entity SET local_id = (SELECT id FROM local_asset_entity WHERE checksum = NEW.checksum ORDER BY id ASC LIMIT 1) WHERE id = NEW.id;UPDATE local_asset_entity SET remote_id = NEW.id WHERE checksum = NEW.checksum;END',
|
||||||
|
'tr_remote_asset_insert_set_local_id');
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/utils/asset.mixin.dart';
|
import 'package:immich_mobile/infrastructure/utils/asset.mixin.dart';
|
||||||
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
||||||
|
|
||||||
@@ -9,6 +10,11 @@ class LocalAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin {
|
|||||||
const LocalAssetEntity();
|
const LocalAssetEntity();
|
||||||
|
|
||||||
TextColumn get id => text()();
|
TextColumn get id => text()();
|
||||||
|
|
||||||
|
TextColumn get remoteId => text()
|
||||||
|
.nullable()
|
||||||
|
.references(RemoteAssetEntity, #id, onDelete: KeyAction.setNull)();
|
||||||
|
|
||||||
TextColumn get checksum => text().nullable()();
|
TextColumn get checksum => text().nullable()();
|
||||||
|
|
||||||
// Only used during backup to mirror the favorite status of the asset in the server
|
// Only used during backup to mirror the favorite status of the asset in the server
|
||||||
@@ -30,6 +36,6 @@ extension LocalAssetEntityDataDomainEx on LocalAssetEntityData {
|
|||||||
isFavorite: isFavorite,
|
isFavorite: isFavorite,
|
||||||
height: height,
|
height: height,
|
||||||
width: width,
|
width: width,
|
||||||
remoteId: null,
|
remoteId: remoteId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart' as i2;
|
|||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart'
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart'
|
||||||
as i3;
|
as i3;
|
||||||
import 'package:drift/src/runtime/query_builder/query_builder.dart' as i4;
|
import 'package:drift/src/runtime/query_builder/query_builder.dart' as i4;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'
|
||||||
|
as i5;
|
||||||
|
import 'package:drift/internal/modular.dart' as i6;
|
||||||
|
|
||||||
typedef $$LocalAssetEntityTableCreateCompanionBuilder
|
typedef $$LocalAssetEntityTableCreateCompanionBuilder
|
||||||
= i1.LocalAssetEntityCompanion Function({
|
= i1.LocalAssetEntityCompanion Function({
|
||||||
@@ -18,6 +21,7 @@ typedef $$LocalAssetEntityTableCreateCompanionBuilder
|
|||||||
i0.Value<int?> height,
|
i0.Value<int?> height,
|
||||||
i0.Value<int?> durationInSeconds,
|
i0.Value<int?> durationInSeconds,
|
||||||
required String id,
|
required String id,
|
||||||
|
i0.Value<String?> remoteId,
|
||||||
i0.Value<String?> checksum,
|
i0.Value<String?> checksum,
|
||||||
i0.Value<bool> isFavorite,
|
i0.Value<bool> isFavorite,
|
||||||
});
|
});
|
||||||
@@ -31,10 +35,43 @@ typedef $$LocalAssetEntityTableUpdateCompanionBuilder
|
|||||||
i0.Value<int?> height,
|
i0.Value<int?> height,
|
||||||
i0.Value<int?> durationInSeconds,
|
i0.Value<int?> durationInSeconds,
|
||||||
i0.Value<String> id,
|
i0.Value<String> id,
|
||||||
|
i0.Value<String?> remoteId,
|
||||||
i0.Value<String?> checksum,
|
i0.Value<String?> checksum,
|
||||||
i0.Value<bool> isFavorite,
|
i0.Value<bool> isFavorite,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final class $$LocalAssetEntityTableReferences extends i0.BaseReferences<
|
||||||
|
i0.GeneratedDatabase, i1.$LocalAssetEntityTable, i1.LocalAssetEntityData> {
|
||||||
|
$$LocalAssetEntityTableReferences(
|
||||||
|
super.$_db, super.$_table, super.$_typedResult);
|
||||||
|
|
||||||
|
static i5.$RemoteAssetEntityTable _remoteIdTable(i0.GeneratedDatabase db) =>
|
||||||
|
i6.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||||
|
.createAlias(i0.$_aliasNameGenerator(
|
||||||
|
i6.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i1.$LocalAssetEntityTable>('local_asset_entity')
|
||||||
|
.remoteId,
|
||||||
|
i6.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||||
|
.id));
|
||||||
|
|
||||||
|
i5.$$RemoteAssetEntityTableProcessedTableManager? get remoteId {
|
||||||
|
final $_column = $_itemColumn<String>('remote_id');
|
||||||
|
if ($_column == null) return null;
|
||||||
|
final manager = i5
|
||||||
|
.$$RemoteAssetEntityTableTableManager(
|
||||||
|
$_db,
|
||||||
|
i6.ReadDatabaseContainer($_db)
|
||||||
|
.resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity'))
|
||||||
|
.filter((f) => f.id.sqlEquals($_column));
|
||||||
|
final item = $_typedResult.readTableOrNull(_remoteIdTable($_db));
|
||||||
|
if (item == null) return manager;
|
||||||
|
return i0.ProcessedTableManager(
|
||||||
|
manager.$state.copyWith(prefetchedData: [item]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class $$LocalAssetEntityTableFilterComposer
|
class $$LocalAssetEntityTableFilterComposer
|
||||||
extends i0.Composer<i0.GeneratedDatabase, i1.$LocalAssetEntityTable> {
|
extends i0.Composer<i0.GeneratedDatabase, i1.$LocalAssetEntityTable> {
|
||||||
$$LocalAssetEntityTableFilterComposer({
|
$$LocalAssetEntityTableFilterComposer({
|
||||||
@@ -76,6 +113,28 @@ class $$LocalAssetEntityTableFilterComposer
|
|||||||
|
|
||||||
i0.ColumnFilters<bool> get isFavorite => $composableBuilder(
|
i0.ColumnFilters<bool> get isFavorite => $composableBuilder(
|
||||||
column: $table.isFavorite, builder: (column) => i0.ColumnFilters(column));
|
column: $table.isFavorite, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i5.$$RemoteAssetEntityTableFilterComposer get remoteId {
|
||||||
|
final i5.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.remoteId,
|
||||||
|
referencedTable: i6.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i5.$$RemoteAssetEntityTableFilterComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i6.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$LocalAssetEntityTableOrderingComposer
|
class $$LocalAssetEntityTableOrderingComposer
|
||||||
@@ -120,6 +179,30 @@ class $$LocalAssetEntityTableOrderingComposer
|
|||||||
i0.ColumnOrderings<bool> get isFavorite => $composableBuilder(
|
i0.ColumnOrderings<bool> get isFavorite => $composableBuilder(
|
||||||
column: $table.isFavorite,
|
column: $table.isFavorite,
|
||||||
builder: (column) => i0.ColumnOrderings(column));
|
builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i5.$$RemoteAssetEntityTableOrderingComposer get remoteId {
|
||||||
|
final i5.$$RemoteAssetEntityTableOrderingComposer composer =
|
||||||
|
$composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.remoteId,
|
||||||
|
referencedTable: i6.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i5.$$RemoteAssetEntityTableOrderingComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i6.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$RemoteAssetEntityTable>(
|
||||||
|
'remote_asset_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$LocalAssetEntityTableAnnotationComposer
|
class $$LocalAssetEntityTableAnnotationComposer
|
||||||
@@ -160,6 +243,30 @@ class $$LocalAssetEntityTableAnnotationComposer
|
|||||||
|
|
||||||
i0.GeneratedColumn<bool> get isFavorite => $composableBuilder(
|
i0.GeneratedColumn<bool> get isFavorite => $composableBuilder(
|
||||||
column: $table.isFavorite, builder: (column) => column);
|
column: $table.isFavorite, builder: (column) => column);
|
||||||
|
|
||||||
|
i5.$$RemoteAssetEntityTableAnnotationComposer get remoteId {
|
||||||
|
final i5.$$RemoteAssetEntityTableAnnotationComposer composer =
|
||||||
|
$composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.remoteId,
|
||||||
|
referencedTable: i6.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i5.$$RemoteAssetEntityTableAnnotationComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i6.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i5.$RemoteAssetEntityTable>(
|
||||||
|
'remote_asset_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
|
class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
|
||||||
@@ -171,13 +278,9 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
|
|||||||
i1.$$LocalAssetEntityTableAnnotationComposer,
|
i1.$$LocalAssetEntityTableAnnotationComposer,
|
||||||
$$LocalAssetEntityTableCreateCompanionBuilder,
|
$$LocalAssetEntityTableCreateCompanionBuilder,
|
||||||
$$LocalAssetEntityTableUpdateCompanionBuilder,
|
$$LocalAssetEntityTableUpdateCompanionBuilder,
|
||||||
(
|
(i1.LocalAssetEntityData, i1.$$LocalAssetEntityTableReferences),
|
||||||
i1.LocalAssetEntityData,
|
|
||||||
i0.BaseReferences<i0.GeneratedDatabase, i1.$LocalAssetEntityTable,
|
|
||||||
i1.LocalAssetEntityData>
|
|
||||||
),
|
|
||||||
i1.LocalAssetEntityData,
|
i1.LocalAssetEntityData,
|
||||||
i0.PrefetchHooks Function()> {
|
i0.PrefetchHooks Function({bool remoteId})> {
|
||||||
$$LocalAssetEntityTableTableManager(
|
$$LocalAssetEntityTableTableManager(
|
||||||
i0.GeneratedDatabase db, i1.$LocalAssetEntityTable table)
|
i0.GeneratedDatabase db, i1.$LocalAssetEntityTable table)
|
||||||
: super(i0.TableManagerState(
|
: super(i0.TableManagerState(
|
||||||
@@ -199,6 +302,7 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
|
|||||||
i0.Value<int?> height = const i0.Value.absent(),
|
i0.Value<int?> height = const i0.Value.absent(),
|
||||||
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||||
i0.Value<String> id = const i0.Value.absent(),
|
i0.Value<String> id = const i0.Value.absent(),
|
||||||
|
i0.Value<String?> remoteId = const i0.Value.absent(),
|
||||||
i0.Value<String?> checksum = const i0.Value.absent(),
|
i0.Value<String?> checksum = const i0.Value.absent(),
|
||||||
i0.Value<bool> isFavorite = const i0.Value.absent(),
|
i0.Value<bool> isFavorite = const i0.Value.absent(),
|
||||||
}) =>
|
}) =>
|
||||||
@@ -211,6 +315,7 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
|
|||||||
height: height,
|
height: height,
|
||||||
durationInSeconds: durationInSeconds,
|
durationInSeconds: durationInSeconds,
|
||||||
id: id,
|
id: id,
|
||||||
|
remoteId: remoteId,
|
||||||
checksum: checksum,
|
checksum: checksum,
|
||||||
isFavorite: isFavorite,
|
isFavorite: isFavorite,
|
||||||
),
|
),
|
||||||
@@ -223,6 +328,7 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
|
|||||||
i0.Value<int?> height = const i0.Value.absent(),
|
i0.Value<int?> height = const i0.Value.absent(),
|
||||||
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||||
required String id,
|
required String id,
|
||||||
|
i0.Value<String?> remoteId = const i0.Value.absent(),
|
||||||
i0.Value<String?> checksum = const i0.Value.absent(),
|
i0.Value<String?> checksum = const i0.Value.absent(),
|
||||||
i0.Value<bool> isFavorite = const i0.Value.absent(),
|
i0.Value<bool> isFavorite = const i0.Value.absent(),
|
||||||
}) =>
|
}) =>
|
||||||
@@ -235,13 +341,52 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
|
|||||||
height: height,
|
height: height,
|
||||||
durationInSeconds: durationInSeconds,
|
durationInSeconds: durationInSeconds,
|
||||||
id: id,
|
id: id,
|
||||||
|
remoteId: remoteId,
|
||||||
checksum: checksum,
|
checksum: checksum,
|
||||||
isFavorite: isFavorite,
|
isFavorite: isFavorite,
|
||||||
),
|
),
|
||||||
withReferenceMapper: (p0) => p0
|
withReferenceMapper: (p0) => p0
|
||||||
.map((e) => (e.readTable(table), i0.BaseReferences(db, table, e)))
|
.map((e) => (
|
||||||
|
e.readTable(table),
|
||||||
|
i1.$$LocalAssetEntityTableReferences(db, table, e)
|
||||||
|
))
|
||||||
.toList(),
|
.toList(),
|
||||||
prefetchHooksCallback: null,
|
prefetchHooksCallback: ({remoteId = false}) {
|
||||||
|
return i0.PrefetchHooks(
|
||||||
|
db: db,
|
||||||
|
explicitlyWatchedTables: [],
|
||||||
|
addJoins: <
|
||||||
|
T extends i0.TableManagerState<
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic>>(state) {
|
||||||
|
if (remoteId) {
|
||||||
|
state = state.withJoin(
|
||||||
|
currentTable: table,
|
||||||
|
currentColumn: table.remoteId,
|
||||||
|
referencedTable:
|
||||||
|
i1.$$LocalAssetEntityTableReferences._remoteIdTable(db),
|
||||||
|
referencedColumn: i1.$$LocalAssetEntityTableReferences
|
||||||
|
._remoteIdTable(db)
|
||||||
|
.id,
|
||||||
|
) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
},
|
||||||
|
getPrefetchedDataCallback: (items) async {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,13 +399,9 @@ typedef $$LocalAssetEntityTableProcessedTableManager = i0.ProcessedTableManager<
|
|||||||
i1.$$LocalAssetEntityTableAnnotationComposer,
|
i1.$$LocalAssetEntityTableAnnotationComposer,
|
||||||
$$LocalAssetEntityTableCreateCompanionBuilder,
|
$$LocalAssetEntityTableCreateCompanionBuilder,
|
||||||
$$LocalAssetEntityTableUpdateCompanionBuilder,
|
$$LocalAssetEntityTableUpdateCompanionBuilder,
|
||||||
(
|
(i1.LocalAssetEntityData, i1.$$LocalAssetEntityTableReferences),
|
||||||
i1.LocalAssetEntityData,
|
|
||||||
i0.BaseReferences<i0.GeneratedDatabase, i1.$LocalAssetEntityTable,
|
|
||||||
i1.LocalAssetEntityData>
|
|
||||||
),
|
|
||||||
i1.LocalAssetEntityData,
|
i1.LocalAssetEntityData,
|
||||||
i0.PrefetchHooks Function()>;
|
i0.PrefetchHooks Function({bool remoteId})>;
|
||||||
i0.Index get idxLocalAssetChecksum => i0.Index('idx_local_asset_checksum',
|
i0.Index get idxLocalAssetChecksum => i0.Index('idx_local_asset_checksum',
|
||||||
'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)');
|
'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)');
|
||||||
|
|
||||||
@@ -321,6 +462,15 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
|
|||||||
late final i0.GeneratedColumn<String> id = i0.GeneratedColumn<String>(
|
late final i0.GeneratedColumn<String> id = i0.GeneratedColumn<String>(
|
||||||
'id', aliasedName, false,
|
'id', aliasedName, false,
|
||||||
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||||
|
static const i0.VerificationMeta _remoteIdMeta =
|
||||||
|
const i0.VerificationMeta('remoteId');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> remoteId = i0.GeneratedColumn<String>(
|
||||||
|
'remote_id', aliasedName, true,
|
||||||
|
type: i0.DriftSqlType.string,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||||
|
'REFERENCES remote_asset_entity (id) ON DELETE SET NULL'));
|
||||||
static const i0.VerificationMeta _checksumMeta =
|
static const i0.VerificationMeta _checksumMeta =
|
||||||
const i0.VerificationMeta('checksum');
|
const i0.VerificationMeta('checksum');
|
||||||
@override
|
@override
|
||||||
@@ -347,6 +497,7 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
|
|||||||
height,
|
height,
|
||||||
durationInSeconds,
|
durationInSeconds,
|
||||||
id,
|
id,
|
||||||
|
remoteId,
|
||||||
checksum,
|
checksum,
|
||||||
isFavorite
|
isFavorite
|
||||||
];
|
];
|
||||||
@@ -394,6 +545,10 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
|
|||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
context.missing(_idMeta);
|
context.missing(_idMeta);
|
||||||
}
|
}
|
||||||
|
if (data.containsKey('remote_id')) {
|
||||||
|
context.handle(_remoteIdMeta,
|
||||||
|
remoteId.isAcceptableOrUnknown(data['remote_id']!, _remoteIdMeta));
|
||||||
|
}
|
||||||
if (data.containsKey('checksum')) {
|
if (data.containsKey('checksum')) {
|
||||||
context.handle(_checksumMeta,
|
context.handle(_checksumMeta,
|
||||||
checksum.isAcceptableOrUnknown(data['checksum']!, _checksumMeta));
|
checksum.isAcceptableOrUnknown(data['checksum']!, _checksumMeta));
|
||||||
@@ -431,6 +586,8 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
|
|||||||
i0.DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']),
|
i0.DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']),
|
||||||
id: attachedDatabase.typeMapping
|
id: attachedDatabase.typeMapping
|
||||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!,
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!,
|
||||||
|
remoteId: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}remote_id']),
|
||||||
checksum: attachedDatabase.typeMapping
|
checksum: attachedDatabase.typeMapping
|
||||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}checksum']),
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}checksum']),
|
||||||
isFavorite: attachedDatabase.typeMapping
|
isFavorite: attachedDatabase.typeMapping
|
||||||
@@ -461,6 +618,7 @@ class LocalAssetEntityData extends i0.DataClass
|
|||||||
final int? height;
|
final int? height;
|
||||||
final int? durationInSeconds;
|
final int? durationInSeconds;
|
||||||
final String id;
|
final String id;
|
||||||
|
final String? remoteId;
|
||||||
final String? checksum;
|
final String? checksum;
|
||||||
final bool isFavorite;
|
final bool isFavorite;
|
||||||
const LocalAssetEntityData(
|
const LocalAssetEntityData(
|
||||||
@@ -472,6 +630,7 @@ class LocalAssetEntityData extends i0.DataClass
|
|||||||
this.height,
|
this.height,
|
||||||
this.durationInSeconds,
|
this.durationInSeconds,
|
||||||
required this.id,
|
required this.id,
|
||||||
|
this.remoteId,
|
||||||
this.checksum,
|
this.checksum,
|
||||||
required this.isFavorite});
|
required this.isFavorite});
|
||||||
@override
|
@override
|
||||||
@@ -494,6 +653,9 @@ class LocalAssetEntityData extends i0.DataClass
|
|||||||
map['duration_in_seconds'] = i0.Variable<int>(durationInSeconds);
|
map['duration_in_seconds'] = i0.Variable<int>(durationInSeconds);
|
||||||
}
|
}
|
||||||
map['id'] = i0.Variable<String>(id);
|
map['id'] = i0.Variable<String>(id);
|
||||||
|
if (!nullToAbsent || remoteId != null) {
|
||||||
|
map['remote_id'] = i0.Variable<String>(remoteId);
|
||||||
|
}
|
||||||
if (!nullToAbsent || checksum != null) {
|
if (!nullToAbsent || checksum != null) {
|
||||||
map['checksum'] = i0.Variable<String>(checksum);
|
map['checksum'] = i0.Variable<String>(checksum);
|
||||||
}
|
}
|
||||||
@@ -514,6 +676,7 @@ class LocalAssetEntityData extends i0.DataClass
|
|||||||
height: serializer.fromJson<int?>(json['height']),
|
height: serializer.fromJson<int?>(json['height']),
|
||||||
durationInSeconds: serializer.fromJson<int?>(json['durationInSeconds']),
|
durationInSeconds: serializer.fromJson<int?>(json['durationInSeconds']),
|
||||||
id: serializer.fromJson<String>(json['id']),
|
id: serializer.fromJson<String>(json['id']),
|
||||||
|
remoteId: serializer.fromJson<String?>(json['remoteId']),
|
||||||
checksum: serializer.fromJson<String?>(json['checksum']),
|
checksum: serializer.fromJson<String?>(json['checksum']),
|
||||||
isFavorite: serializer.fromJson<bool>(json['isFavorite']),
|
isFavorite: serializer.fromJson<bool>(json['isFavorite']),
|
||||||
);
|
);
|
||||||
@@ -531,6 +694,7 @@ class LocalAssetEntityData extends i0.DataClass
|
|||||||
'height': serializer.toJson<int?>(height),
|
'height': serializer.toJson<int?>(height),
|
||||||
'durationInSeconds': serializer.toJson<int?>(durationInSeconds),
|
'durationInSeconds': serializer.toJson<int?>(durationInSeconds),
|
||||||
'id': serializer.toJson<String>(id),
|
'id': serializer.toJson<String>(id),
|
||||||
|
'remoteId': serializer.toJson<String?>(remoteId),
|
||||||
'checksum': serializer.toJson<String?>(checksum),
|
'checksum': serializer.toJson<String?>(checksum),
|
||||||
'isFavorite': serializer.toJson<bool>(isFavorite),
|
'isFavorite': serializer.toJson<bool>(isFavorite),
|
||||||
};
|
};
|
||||||
@@ -545,6 +709,7 @@ class LocalAssetEntityData extends i0.DataClass
|
|||||||
i0.Value<int?> height = const i0.Value.absent(),
|
i0.Value<int?> height = const i0.Value.absent(),
|
||||||
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||||
String? id,
|
String? id,
|
||||||
|
i0.Value<String?> remoteId = const i0.Value.absent(),
|
||||||
i0.Value<String?> checksum = const i0.Value.absent(),
|
i0.Value<String?> checksum = const i0.Value.absent(),
|
||||||
bool? isFavorite}) =>
|
bool? isFavorite}) =>
|
||||||
i1.LocalAssetEntityData(
|
i1.LocalAssetEntityData(
|
||||||
@@ -558,6 +723,7 @@ class LocalAssetEntityData extends i0.DataClass
|
|||||||
? durationInSeconds.value
|
? durationInSeconds.value
|
||||||
: this.durationInSeconds,
|
: this.durationInSeconds,
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
|
remoteId: remoteId.present ? remoteId.value : this.remoteId,
|
||||||
checksum: checksum.present ? checksum.value : this.checksum,
|
checksum: checksum.present ? checksum.value : this.checksum,
|
||||||
isFavorite: isFavorite ?? this.isFavorite,
|
isFavorite: isFavorite ?? this.isFavorite,
|
||||||
);
|
);
|
||||||
@@ -573,6 +739,7 @@ class LocalAssetEntityData extends i0.DataClass
|
|||||||
? data.durationInSeconds.value
|
? data.durationInSeconds.value
|
||||||
: this.durationInSeconds,
|
: this.durationInSeconds,
|
||||||
id: data.id.present ? data.id.value : this.id,
|
id: data.id.present ? data.id.value : this.id,
|
||||||
|
remoteId: data.remoteId.present ? data.remoteId.value : this.remoteId,
|
||||||
checksum: data.checksum.present ? data.checksum.value : this.checksum,
|
checksum: data.checksum.present ? data.checksum.value : this.checksum,
|
||||||
isFavorite:
|
isFavorite:
|
||||||
data.isFavorite.present ? data.isFavorite.value : this.isFavorite,
|
data.isFavorite.present ? data.isFavorite.value : this.isFavorite,
|
||||||
@@ -590,6 +757,7 @@ class LocalAssetEntityData extends i0.DataClass
|
|||||||
..write('height: $height, ')
|
..write('height: $height, ')
|
||||||
..write('durationInSeconds: $durationInSeconds, ')
|
..write('durationInSeconds: $durationInSeconds, ')
|
||||||
..write('id: $id, ')
|
..write('id: $id, ')
|
||||||
|
..write('remoteId: $remoteId, ')
|
||||||
..write('checksum: $checksum, ')
|
..write('checksum: $checksum, ')
|
||||||
..write('isFavorite: $isFavorite')
|
..write('isFavorite: $isFavorite')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
@@ -598,7 +766,7 @@ class LocalAssetEntityData extends i0.DataClass
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(name, type, createdAt, updatedAt, width,
|
int get hashCode => Object.hash(name, type, createdAt, updatedAt, width,
|
||||||
height, durationInSeconds, id, checksum, isFavorite);
|
height, durationInSeconds, id, remoteId, checksum, isFavorite);
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
@@ -611,6 +779,7 @@ class LocalAssetEntityData extends i0.DataClass
|
|||||||
other.height == this.height &&
|
other.height == this.height &&
|
||||||
other.durationInSeconds == this.durationInSeconds &&
|
other.durationInSeconds == this.durationInSeconds &&
|
||||||
other.id == this.id &&
|
other.id == this.id &&
|
||||||
|
other.remoteId == this.remoteId &&
|
||||||
other.checksum == this.checksum &&
|
other.checksum == this.checksum &&
|
||||||
other.isFavorite == this.isFavorite);
|
other.isFavorite == this.isFavorite);
|
||||||
}
|
}
|
||||||
@@ -625,6 +794,7 @@ class LocalAssetEntityCompanion
|
|||||||
final i0.Value<int?> height;
|
final i0.Value<int?> height;
|
||||||
final i0.Value<int?> durationInSeconds;
|
final i0.Value<int?> durationInSeconds;
|
||||||
final i0.Value<String> id;
|
final i0.Value<String> id;
|
||||||
|
final i0.Value<String?> remoteId;
|
||||||
final i0.Value<String?> checksum;
|
final i0.Value<String?> checksum;
|
||||||
final i0.Value<bool> isFavorite;
|
final i0.Value<bool> isFavorite;
|
||||||
const LocalAssetEntityCompanion({
|
const LocalAssetEntityCompanion({
|
||||||
@@ -636,6 +806,7 @@ class LocalAssetEntityCompanion
|
|||||||
this.height = const i0.Value.absent(),
|
this.height = const i0.Value.absent(),
|
||||||
this.durationInSeconds = const i0.Value.absent(),
|
this.durationInSeconds = const i0.Value.absent(),
|
||||||
this.id = const i0.Value.absent(),
|
this.id = const i0.Value.absent(),
|
||||||
|
this.remoteId = const i0.Value.absent(),
|
||||||
this.checksum = const i0.Value.absent(),
|
this.checksum = const i0.Value.absent(),
|
||||||
this.isFavorite = const i0.Value.absent(),
|
this.isFavorite = const i0.Value.absent(),
|
||||||
});
|
});
|
||||||
@@ -648,6 +819,7 @@ class LocalAssetEntityCompanion
|
|||||||
this.height = const i0.Value.absent(),
|
this.height = const i0.Value.absent(),
|
||||||
this.durationInSeconds = const i0.Value.absent(),
|
this.durationInSeconds = const i0.Value.absent(),
|
||||||
required String id,
|
required String id,
|
||||||
|
this.remoteId = const i0.Value.absent(),
|
||||||
this.checksum = const i0.Value.absent(),
|
this.checksum = const i0.Value.absent(),
|
||||||
this.isFavorite = const i0.Value.absent(),
|
this.isFavorite = const i0.Value.absent(),
|
||||||
}) : name = i0.Value(name),
|
}) : name = i0.Value(name),
|
||||||
@@ -662,6 +834,7 @@ class LocalAssetEntityCompanion
|
|||||||
i0.Expression<int>? height,
|
i0.Expression<int>? height,
|
||||||
i0.Expression<int>? durationInSeconds,
|
i0.Expression<int>? durationInSeconds,
|
||||||
i0.Expression<String>? id,
|
i0.Expression<String>? id,
|
||||||
|
i0.Expression<String>? remoteId,
|
||||||
i0.Expression<String>? checksum,
|
i0.Expression<String>? checksum,
|
||||||
i0.Expression<bool>? isFavorite,
|
i0.Expression<bool>? isFavorite,
|
||||||
}) {
|
}) {
|
||||||
@@ -674,6 +847,7 @@ class LocalAssetEntityCompanion
|
|||||||
if (height != null) 'height': height,
|
if (height != null) 'height': height,
|
||||||
if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds,
|
if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds,
|
||||||
if (id != null) 'id': id,
|
if (id != null) 'id': id,
|
||||||
|
if (remoteId != null) 'remote_id': remoteId,
|
||||||
if (checksum != null) 'checksum': checksum,
|
if (checksum != null) 'checksum': checksum,
|
||||||
if (isFavorite != null) 'is_favorite': isFavorite,
|
if (isFavorite != null) 'is_favorite': isFavorite,
|
||||||
});
|
});
|
||||||
@@ -688,6 +862,7 @@ class LocalAssetEntityCompanion
|
|||||||
i0.Value<int?>? height,
|
i0.Value<int?>? height,
|
||||||
i0.Value<int?>? durationInSeconds,
|
i0.Value<int?>? durationInSeconds,
|
||||||
i0.Value<String>? id,
|
i0.Value<String>? id,
|
||||||
|
i0.Value<String?>? remoteId,
|
||||||
i0.Value<String?>? checksum,
|
i0.Value<String?>? checksum,
|
||||||
i0.Value<bool>? isFavorite}) {
|
i0.Value<bool>? isFavorite}) {
|
||||||
return i1.LocalAssetEntityCompanion(
|
return i1.LocalAssetEntityCompanion(
|
||||||
@@ -699,6 +874,7 @@ class LocalAssetEntityCompanion
|
|||||||
height: height ?? this.height,
|
height: height ?? this.height,
|
||||||
durationInSeconds: durationInSeconds ?? this.durationInSeconds,
|
durationInSeconds: durationInSeconds ?? this.durationInSeconds,
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
|
remoteId: remoteId ?? this.remoteId,
|
||||||
checksum: checksum ?? this.checksum,
|
checksum: checksum ?? this.checksum,
|
||||||
isFavorite: isFavorite ?? this.isFavorite,
|
isFavorite: isFavorite ?? this.isFavorite,
|
||||||
);
|
);
|
||||||
@@ -732,6 +908,9 @@ class LocalAssetEntityCompanion
|
|||||||
if (id.present) {
|
if (id.present) {
|
||||||
map['id'] = i0.Variable<String>(id.value);
|
map['id'] = i0.Variable<String>(id.value);
|
||||||
}
|
}
|
||||||
|
if (remoteId.present) {
|
||||||
|
map['remote_id'] = i0.Variable<String>(remoteId.value);
|
||||||
|
}
|
||||||
if (checksum.present) {
|
if (checksum.present) {
|
||||||
map['checksum'] = i0.Variable<String>(checksum.value);
|
map['checksum'] = i0.Variable<String>(checksum.value);
|
||||||
}
|
}
|
||||||
@@ -752,6 +931,7 @@ class LocalAssetEntityCompanion
|
|||||||
..write('height: $height, ')
|
..write('height: $height, ')
|
||||||
..write('durationInSeconds: $durationInSeconds, ')
|
..write('durationInSeconds: $durationInSeconds, ')
|
||||||
..write('id: $id, ')
|
..write('id: $id, ')
|
||||||
|
..write('remoteId: $remoteId, ')
|
||||||
..write('checksum: $checksum, ')
|
..write('checksum: $checksum, ')
|
||||||
..write('isFavorite: $isFavorite')
|
..write('isFavorite: $isFavorite')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ mergedAsset: SELECT * FROM
|
|||||||
(
|
(
|
||||||
SELECT
|
SELECT
|
||||||
rae.id as remote_id,
|
rae.id as remote_id,
|
||||||
lae.id as local_id,
|
rae.local_id as local_id,
|
||||||
rae.name,
|
rae.name,
|
||||||
rae."type",
|
rae."type",
|
||||||
rae.created_at,
|
rae.created_at,
|
||||||
@@ -19,13 +19,11 @@ mergedAsset: SELECT * FROM
|
|||||||
rae.owner_id
|
rae.owner_id
|
||||||
FROM
|
FROM
|
||||||
remote_asset_entity rae
|
remote_asset_entity rae
|
||||||
LEFT JOIN
|
|
||||||
local_asset_entity lae ON rae.checksum = lae.checksum
|
|
||||||
WHERE
|
WHERE
|
||||||
rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id in ?
|
rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id in ?
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT
|
SELECT
|
||||||
NULL as remote_id,
|
lae.remote_id as remote_id,
|
||||||
lae.id as local_id,
|
lae.id as local_id,
|
||||||
lae.name,
|
lae.name,
|
||||||
lae."type",
|
lae."type",
|
||||||
@@ -40,10 +38,8 @@ mergedAsset: SELECT * FROM
|
|||||||
NULL as owner_id
|
NULL as owner_id
|
||||||
FROM
|
FROM
|
||||||
local_asset_entity lae
|
local_asset_entity lae
|
||||||
LEFT JOIN
|
|
||||||
remote_asset_entity rae ON rae.checksum = lae.checksum
|
|
||||||
WHERE
|
WHERE
|
||||||
rae.id IS NULL
|
lae.remote_id IS NULL
|
||||||
)
|
)
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
LIMIT $limit;
|
LIMIT $limit;
|
||||||
@@ -62,8 +58,6 @@ FROM
|
|||||||
rae.created_at
|
rae.created_at
|
||||||
FROM
|
FROM
|
||||||
remote_asset_entity rae
|
remote_asset_entity rae
|
||||||
LEFT JOIN
|
|
||||||
local_asset_entity lae ON rae.checksum = lae.checksum
|
|
||||||
WHERE
|
WHERE
|
||||||
rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id in ?
|
rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id in ?
|
||||||
UNION ALL
|
UNION ALL
|
||||||
@@ -72,10 +66,8 @@ FROM
|
|||||||
lae.created_at
|
lae.created_at
|
||||||
FROM
|
FROM
|
||||||
local_asset_entity lae
|
local_asset_entity lae
|
||||||
LEFT JOIN
|
|
||||||
remote_asset_entity rae ON rae.checksum = lae.checksum
|
|
||||||
WHERE
|
WHERE
|
||||||
rae.id IS NULL
|
lae.remote_id IS NULL
|
||||||
)
|
)
|
||||||
GROUP BY bucket_date
|
GROUP BY bucket_date
|
||||||
ORDER BY bucket_date DESC;
|
ORDER BY bucket_date DESC;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class MergedAssetDrift extends i1.ModularAccessor {
|
|||||||
final generatedlimit = $write(limit, startIndex: $arrayStartIndex);
|
final generatedlimit = $write(limit, startIndex: $arrayStartIndex);
|
||||||
$arrayStartIndex += generatedlimit.amountOfVariables;
|
$arrayStartIndex += generatedlimit.amountOfVariables;
|
||||||
return customSelect(
|
return customSelect(
|
||||||
'SELECT * FROM (SELECT rae.id AS remote_id, lae.id AS local_id, rae.name, rae.type, rae.created_at, rae.updated_at, rae.width, rae.height, rae.duration_in_seconds, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id FROM remote_asset_entity AS rae LEFT JOIN local_asset_entity AS lae ON rae.checksum = lae.checksum WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar1) UNION ALL SELECT NULL AS remote_id, lae.id AS local_id, lae.name, lae.type, lae.created_at, lae.updated_at, lae.width, lae.height, lae.duration_in_seconds, lae.is_favorite, NULL AS thumb_hash, lae.checksum, NULL AS owner_id FROM local_asset_entity AS lae LEFT JOIN remote_asset_entity AS rae ON rae.checksum = lae.checksum WHERE rae.id IS NULL) ORDER BY created_at DESC ${generatedlimit.sql}',
|
'SELECT * FROM (SELECT rae.id AS remote_id, rae.local_id AS local_id, rae.name, rae.type, rae.created_at, rae.updated_at, rae.width, rae.height, rae.duration_in_seconds, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id FROM remote_asset_entity AS rae WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar1) UNION ALL SELECT lae.remote_id AS remote_id, lae.id AS local_id, lae.name, lae.type, lae.created_at, lae.updated_at, lae.width, lae.height, lae.duration_in_seconds, lae.is_favorite, NULL AS thumb_hash, lae.checksum, NULL AS owner_id FROM local_asset_entity AS lae WHERE lae.remote_id IS NULL) ORDER BY created_at DESC ${generatedlimit.sql}',
|
||||||
variables: [
|
variables: [
|
||||||
for (var $ in var1) i0.Variable<String>($),
|
for (var $ in var1) i0.Variable<String>($),
|
||||||
...generatedlimit.introducedVariables
|
...generatedlimit.introducedVariables
|
||||||
@@ -51,7 +51,7 @@ class MergedAssetDrift extends i1.ModularAccessor {
|
|||||||
final expandedvar2 = $expandVar($arrayStartIndex, var2.length);
|
final expandedvar2 = $expandVar($arrayStartIndex, var2.length);
|
||||||
$arrayStartIndex += var2.length;
|
$arrayStartIndex += var2.length;
|
||||||
return customSelect(
|
return customSelect(
|
||||||
'SELECT COUNT(*) AS asset_count, CASE WHEN ?1 = 0 THEN STRFTIME(\'%Y-%m-%d\', created_at, \'localtime\') WHEN ?1 = 1 THEN STRFTIME(\'%Y-%m\', created_at, \'localtime\') END AS bucket_date FROM (SELECT rae.name, rae.created_at FROM remote_asset_entity AS rae LEFT JOIN local_asset_entity AS lae ON rae.checksum = lae.checksum WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar2) UNION ALL SELECT lae.name, lae.created_at FROM local_asset_entity AS lae LEFT JOIN remote_asset_entity AS rae ON rae.checksum = lae.checksum WHERE rae.id IS NULL) GROUP BY bucket_date ORDER BY bucket_date DESC',
|
'SELECT COUNT(*) AS asset_count, CASE WHEN ?1 = 0 THEN STRFTIME(\'%Y-%m-%d\', created_at, \'localtime\') WHEN ?1 = 1 THEN STRFTIME(\'%Y-%m\', created_at, \'localtime\') END AS bucket_date FROM (SELECT rae.name, rae.created_at FROM remote_asset_entity AS rae WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar2) UNION ALL SELECT lae.name, lae.created_at FROM local_asset_entity AS lae WHERE lae.remote_id IS NULL) GROUP BY bucket_date ORDER BY bucket_date DESC',
|
||||||
variables: [
|
variables: [
|
||||||
i0.Variable<int>(groupBy),
|
i0.Variable<int>(groupBy),
|
||||||
for (var $ in var2) i0.Variable<String>($)
|
for (var $ in var2) i0.Variable<String>($)
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ class RemoteAssetEntity extends Table
|
|||||||
|
|
||||||
TextColumn get id => text()();
|
TextColumn get id => text()();
|
||||||
|
|
||||||
|
TextColumn get localId => text().nullable()();
|
||||||
|
|
||||||
TextColumn get checksum => text()();
|
TextColumn get checksum => text()();
|
||||||
|
|
||||||
BoolColumn get isFavorite => boolean().withDefault(const Constant(false))();
|
BoolColumn get isFavorite => boolean().withDefault(const Constant(false))();
|
||||||
@@ -51,6 +53,6 @@ extension RemoteAssetEntityDataDomainEx on RemoteAssetEntityData {
|
|||||||
width: width,
|
width: width,
|
||||||
thumbHash: thumbHash,
|
thumbHash: thumbHash,
|
||||||
visibility: visibility,
|
visibility: visibility,
|
||||||
localId: null,
|
localId: localId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ typedef $$RemoteAssetEntityTableCreateCompanionBuilder
|
|||||||
i0.Value<int?> height,
|
i0.Value<int?> height,
|
||||||
i0.Value<int?> durationInSeconds,
|
i0.Value<int?> durationInSeconds,
|
||||||
required String id,
|
required String id,
|
||||||
|
i0.Value<String?> localId,
|
||||||
required String checksum,
|
required String checksum,
|
||||||
i0.Value<bool> isFavorite,
|
i0.Value<bool> isFavorite,
|
||||||
required String ownerId,
|
required String ownerId,
|
||||||
@@ -39,6 +40,7 @@ typedef $$RemoteAssetEntityTableUpdateCompanionBuilder
|
|||||||
i0.Value<int?> height,
|
i0.Value<int?> height,
|
||||||
i0.Value<int?> durationInSeconds,
|
i0.Value<int?> durationInSeconds,
|
||||||
i0.Value<String> id,
|
i0.Value<String> id,
|
||||||
|
i0.Value<String?> localId,
|
||||||
i0.Value<String> checksum,
|
i0.Value<String> checksum,
|
||||||
i0.Value<bool> isFavorite,
|
i0.Value<bool> isFavorite,
|
||||||
i0.Value<String> ownerId,
|
i0.Value<String> ownerId,
|
||||||
@@ -118,6 +120,9 @@ class $$RemoteAssetEntityTableFilterComposer
|
|||||||
i0.ColumnFilters<String> get id => $composableBuilder(
|
i0.ColumnFilters<String> get id => $composableBuilder(
|
||||||
column: $table.id, builder: (column) => i0.ColumnFilters(column));
|
column: $table.id, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i0.ColumnFilters<String> get localId => $composableBuilder(
|
||||||
|
column: $table.localId, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
i0.ColumnFilters<String> get checksum => $composableBuilder(
|
i0.ColumnFilters<String> get checksum => $composableBuilder(
|
||||||
column: $table.checksum, builder: (column) => i0.ColumnFilters(column));
|
column: $table.checksum, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
@@ -198,6 +203,9 @@ class $$RemoteAssetEntityTableOrderingComposer
|
|||||||
i0.ColumnOrderings<String> get id => $composableBuilder(
|
i0.ColumnOrderings<String> get id => $composableBuilder(
|
||||||
column: $table.id, builder: (column) => i0.ColumnOrderings(column));
|
column: $table.id, builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i0.ColumnOrderings<String> get localId => $composableBuilder(
|
||||||
|
column: $table.localId, builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
i0.ColumnOrderings<String> get checksum => $composableBuilder(
|
i0.ColumnOrderings<String> get checksum => $composableBuilder(
|
||||||
column: $table.checksum, builder: (column) => i0.ColumnOrderings(column));
|
column: $table.checksum, builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
@@ -277,6 +285,9 @@ class $$RemoteAssetEntityTableAnnotationComposer
|
|||||||
i0.GeneratedColumn<String> get id =>
|
i0.GeneratedColumn<String> get id =>
|
||||||
$composableBuilder(column: $table.id, builder: (column) => column);
|
$composableBuilder(column: $table.id, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumn<String> get localId =>
|
||||||
|
$composableBuilder(column: $table.localId, builder: (column) => column);
|
||||||
|
|
||||||
i0.GeneratedColumn<String> get checksum =>
|
i0.GeneratedColumn<String> get checksum =>
|
||||||
$composableBuilder(column: $table.checksum, builder: (column) => column);
|
$composableBuilder(column: $table.checksum, builder: (column) => column);
|
||||||
|
|
||||||
@@ -352,6 +363,7 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager<
|
|||||||
i0.Value<int?> height = const i0.Value.absent(),
|
i0.Value<int?> height = const i0.Value.absent(),
|
||||||
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||||
i0.Value<String> id = const i0.Value.absent(),
|
i0.Value<String> id = const i0.Value.absent(),
|
||||||
|
i0.Value<String?> localId = const i0.Value.absent(),
|
||||||
i0.Value<String> checksum = const i0.Value.absent(),
|
i0.Value<String> checksum = const i0.Value.absent(),
|
||||||
i0.Value<bool> isFavorite = const i0.Value.absent(),
|
i0.Value<bool> isFavorite = const i0.Value.absent(),
|
||||||
i0.Value<String> ownerId = const i0.Value.absent(),
|
i0.Value<String> ownerId = const i0.Value.absent(),
|
||||||
@@ -369,6 +381,7 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager<
|
|||||||
height: height,
|
height: height,
|
||||||
durationInSeconds: durationInSeconds,
|
durationInSeconds: durationInSeconds,
|
||||||
id: id,
|
id: id,
|
||||||
|
localId: localId,
|
||||||
checksum: checksum,
|
checksum: checksum,
|
||||||
isFavorite: isFavorite,
|
isFavorite: isFavorite,
|
||||||
ownerId: ownerId,
|
ownerId: ownerId,
|
||||||
@@ -386,6 +399,7 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager<
|
|||||||
i0.Value<int?> height = const i0.Value.absent(),
|
i0.Value<int?> height = const i0.Value.absent(),
|
||||||
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||||
required String id,
|
required String id,
|
||||||
|
i0.Value<String?> localId = const i0.Value.absent(),
|
||||||
required String checksum,
|
required String checksum,
|
||||||
i0.Value<bool> isFavorite = const i0.Value.absent(),
|
i0.Value<bool> isFavorite = const i0.Value.absent(),
|
||||||
required String ownerId,
|
required String ownerId,
|
||||||
@@ -403,6 +417,7 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager<
|
|||||||
height: height,
|
height: height,
|
||||||
durationInSeconds: durationInSeconds,
|
durationInSeconds: durationInSeconds,
|
||||||
id: id,
|
id: id,
|
||||||
|
localId: localId,
|
||||||
checksum: checksum,
|
checksum: checksum,
|
||||||
isFavorite: isFavorite,
|
isFavorite: isFavorite,
|
||||||
ownerId: ownerId,
|
ownerId: ownerId,
|
||||||
@@ -530,6 +545,12 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity
|
|||||||
late final i0.GeneratedColumn<String> id = i0.GeneratedColumn<String>(
|
late final i0.GeneratedColumn<String> id = i0.GeneratedColumn<String>(
|
||||||
'id', aliasedName, false,
|
'id', aliasedName, false,
|
||||||
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||||
|
static const i0.VerificationMeta _localIdMeta =
|
||||||
|
const i0.VerificationMeta('localId');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> localId = i0.GeneratedColumn<String>(
|
||||||
|
'local_id', aliasedName, true,
|
||||||
|
type: i0.DriftSqlType.string, requiredDuringInsert: false);
|
||||||
static const i0.VerificationMeta _checksumMeta =
|
static const i0.VerificationMeta _checksumMeta =
|
||||||
const i0.VerificationMeta('checksum');
|
const i0.VerificationMeta('checksum');
|
||||||
@override
|
@override
|
||||||
@@ -589,6 +610,7 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity
|
|||||||
height,
|
height,
|
||||||
durationInSeconds,
|
durationInSeconds,
|
||||||
id,
|
id,
|
||||||
|
localId,
|
||||||
checksum,
|
checksum,
|
||||||
isFavorite,
|
isFavorite,
|
||||||
ownerId,
|
ownerId,
|
||||||
@@ -641,6 +663,10 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity
|
|||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
context.missing(_idMeta);
|
context.missing(_idMeta);
|
||||||
}
|
}
|
||||||
|
if (data.containsKey('local_id')) {
|
||||||
|
context.handle(_localIdMeta,
|
||||||
|
localId.isAcceptableOrUnknown(data['local_id']!, _localIdMeta));
|
||||||
|
}
|
||||||
if (data.containsKey('checksum')) {
|
if (data.containsKey('checksum')) {
|
||||||
context.handle(_checksumMeta,
|
context.handle(_checksumMeta,
|
||||||
checksum.isAcceptableOrUnknown(data['checksum']!, _checksumMeta));
|
checksum.isAcceptableOrUnknown(data['checksum']!, _checksumMeta));
|
||||||
@@ -700,6 +726,8 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity
|
|||||||
i0.DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']),
|
i0.DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']),
|
||||||
id: attachedDatabase.typeMapping
|
id: attachedDatabase.typeMapping
|
||||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!,
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!,
|
||||||
|
localId: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}local_id']),
|
||||||
checksum: attachedDatabase.typeMapping
|
checksum: attachedDatabase.typeMapping
|
||||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}checksum'])!,
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}checksum'])!,
|
||||||
isFavorite: attachedDatabase.typeMapping
|
isFavorite: attachedDatabase.typeMapping
|
||||||
@@ -744,6 +772,7 @@ class RemoteAssetEntityData extends i0.DataClass
|
|||||||
final int? height;
|
final int? height;
|
||||||
final int? durationInSeconds;
|
final int? durationInSeconds;
|
||||||
final String id;
|
final String id;
|
||||||
|
final String? localId;
|
||||||
final String checksum;
|
final String checksum;
|
||||||
final bool isFavorite;
|
final bool isFavorite;
|
||||||
final String ownerId;
|
final String ownerId;
|
||||||
@@ -760,6 +789,7 @@ class RemoteAssetEntityData extends i0.DataClass
|
|||||||
this.height,
|
this.height,
|
||||||
this.durationInSeconds,
|
this.durationInSeconds,
|
||||||
required this.id,
|
required this.id,
|
||||||
|
this.localId,
|
||||||
required this.checksum,
|
required this.checksum,
|
||||||
required this.isFavorite,
|
required this.isFavorite,
|
||||||
required this.ownerId,
|
required this.ownerId,
|
||||||
@@ -787,6 +817,9 @@ class RemoteAssetEntityData extends i0.DataClass
|
|||||||
map['duration_in_seconds'] = i0.Variable<int>(durationInSeconds);
|
map['duration_in_seconds'] = i0.Variable<int>(durationInSeconds);
|
||||||
}
|
}
|
||||||
map['id'] = i0.Variable<String>(id);
|
map['id'] = i0.Variable<String>(id);
|
||||||
|
if (!nullToAbsent || localId != null) {
|
||||||
|
map['local_id'] = i0.Variable<String>(localId);
|
||||||
|
}
|
||||||
map['checksum'] = i0.Variable<String>(checksum);
|
map['checksum'] = i0.Variable<String>(checksum);
|
||||||
map['is_favorite'] = i0.Variable<bool>(isFavorite);
|
map['is_favorite'] = i0.Variable<bool>(isFavorite);
|
||||||
map['owner_id'] = i0.Variable<String>(ownerId);
|
map['owner_id'] = i0.Variable<String>(ownerId);
|
||||||
@@ -819,6 +852,7 @@ class RemoteAssetEntityData extends i0.DataClass
|
|||||||
height: serializer.fromJson<int?>(json['height']),
|
height: serializer.fromJson<int?>(json['height']),
|
||||||
durationInSeconds: serializer.fromJson<int?>(json['durationInSeconds']),
|
durationInSeconds: serializer.fromJson<int?>(json['durationInSeconds']),
|
||||||
id: serializer.fromJson<String>(json['id']),
|
id: serializer.fromJson<String>(json['id']),
|
||||||
|
localId: serializer.fromJson<String?>(json['localId']),
|
||||||
checksum: serializer.fromJson<String>(json['checksum']),
|
checksum: serializer.fromJson<String>(json['checksum']),
|
||||||
isFavorite: serializer.fromJson<bool>(json['isFavorite']),
|
isFavorite: serializer.fromJson<bool>(json['isFavorite']),
|
||||||
ownerId: serializer.fromJson<String>(json['ownerId']),
|
ownerId: serializer.fromJson<String>(json['ownerId']),
|
||||||
@@ -842,6 +876,7 @@ class RemoteAssetEntityData extends i0.DataClass
|
|||||||
'height': serializer.toJson<int?>(height),
|
'height': serializer.toJson<int?>(height),
|
||||||
'durationInSeconds': serializer.toJson<int?>(durationInSeconds),
|
'durationInSeconds': serializer.toJson<int?>(durationInSeconds),
|
||||||
'id': serializer.toJson<String>(id),
|
'id': serializer.toJson<String>(id),
|
||||||
|
'localId': serializer.toJson<String?>(localId),
|
||||||
'checksum': serializer.toJson<String>(checksum),
|
'checksum': serializer.toJson<String>(checksum),
|
||||||
'isFavorite': serializer.toJson<bool>(isFavorite),
|
'isFavorite': serializer.toJson<bool>(isFavorite),
|
||||||
'ownerId': serializer.toJson<String>(ownerId),
|
'ownerId': serializer.toJson<String>(ownerId),
|
||||||
@@ -862,6 +897,7 @@ class RemoteAssetEntityData extends i0.DataClass
|
|||||||
i0.Value<int?> height = const i0.Value.absent(),
|
i0.Value<int?> height = const i0.Value.absent(),
|
||||||
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||||
String? id,
|
String? id,
|
||||||
|
i0.Value<String?> localId = const i0.Value.absent(),
|
||||||
String? checksum,
|
String? checksum,
|
||||||
bool? isFavorite,
|
bool? isFavorite,
|
||||||
String? ownerId,
|
String? ownerId,
|
||||||
@@ -880,6 +916,7 @@ class RemoteAssetEntityData extends i0.DataClass
|
|||||||
? durationInSeconds.value
|
? durationInSeconds.value
|
||||||
: this.durationInSeconds,
|
: this.durationInSeconds,
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
|
localId: localId.present ? localId.value : this.localId,
|
||||||
checksum: checksum ?? this.checksum,
|
checksum: checksum ?? this.checksum,
|
||||||
isFavorite: isFavorite ?? this.isFavorite,
|
isFavorite: isFavorite ?? this.isFavorite,
|
||||||
ownerId: ownerId ?? this.ownerId,
|
ownerId: ownerId ?? this.ownerId,
|
||||||
@@ -901,6 +938,7 @@ class RemoteAssetEntityData extends i0.DataClass
|
|||||||
? data.durationInSeconds.value
|
? data.durationInSeconds.value
|
||||||
: this.durationInSeconds,
|
: this.durationInSeconds,
|
||||||
id: data.id.present ? data.id.value : this.id,
|
id: data.id.present ? data.id.value : this.id,
|
||||||
|
localId: data.localId.present ? data.localId.value : this.localId,
|
||||||
checksum: data.checksum.present ? data.checksum.value : this.checksum,
|
checksum: data.checksum.present ? data.checksum.value : this.checksum,
|
||||||
isFavorite:
|
isFavorite:
|
||||||
data.isFavorite.present ? data.isFavorite.value : this.isFavorite,
|
data.isFavorite.present ? data.isFavorite.value : this.isFavorite,
|
||||||
@@ -926,6 +964,7 @@ class RemoteAssetEntityData extends i0.DataClass
|
|||||||
..write('height: $height, ')
|
..write('height: $height, ')
|
||||||
..write('durationInSeconds: $durationInSeconds, ')
|
..write('durationInSeconds: $durationInSeconds, ')
|
||||||
..write('id: $id, ')
|
..write('id: $id, ')
|
||||||
|
..write('localId: $localId, ')
|
||||||
..write('checksum: $checksum, ')
|
..write('checksum: $checksum, ')
|
||||||
..write('isFavorite: $isFavorite, ')
|
..write('isFavorite: $isFavorite, ')
|
||||||
..write('ownerId: $ownerId, ')
|
..write('ownerId: $ownerId, ')
|
||||||
@@ -947,6 +986,7 @@ class RemoteAssetEntityData extends i0.DataClass
|
|||||||
height,
|
height,
|
||||||
durationInSeconds,
|
durationInSeconds,
|
||||||
id,
|
id,
|
||||||
|
localId,
|
||||||
checksum,
|
checksum,
|
||||||
isFavorite,
|
isFavorite,
|
||||||
ownerId,
|
ownerId,
|
||||||
@@ -966,6 +1006,7 @@ class RemoteAssetEntityData extends i0.DataClass
|
|||||||
other.height == this.height &&
|
other.height == this.height &&
|
||||||
other.durationInSeconds == this.durationInSeconds &&
|
other.durationInSeconds == this.durationInSeconds &&
|
||||||
other.id == this.id &&
|
other.id == this.id &&
|
||||||
|
other.localId == this.localId &&
|
||||||
other.checksum == this.checksum &&
|
other.checksum == this.checksum &&
|
||||||
other.isFavorite == this.isFavorite &&
|
other.isFavorite == this.isFavorite &&
|
||||||
other.ownerId == this.ownerId &&
|
other.ownerId == this.ownerId &&
|
||||||
@@ -985,6 +1026,7 @@ class RemoteAssetEntityCompanion
|
|||||||
final i0.Value<int?> height;
|
final i0.Value<int?> height;
|
||||||
final i0.Value<int?> durationInSeconds;
|
final i0.Value<int?> durationInSeconds;
|
||||||
final i0.Value<String> id;
|
final i0.Value<String> id;
|
||||||
|
final i0.Value<String?> localId;
|
||||||
final i0.Value<String> checksum;
|
final i0.Value<String> checksum;
|
||||||
final i0.Value<bool> isFavorite;
|
final i0.Value<bool> isFavorite;
|
||||||
final i0.Value<String> ownerId;
|
final i0.Value<String> ownerId;
|
||||||
@@ -1001,6 +1043,7 @@ class RemoteAssetEntityCompanion
|
|||||||
this.height = const i0.Value.absent(),
|
this.height = const i0.Value.absent(),
|
||||||
this.durationInSeconds = const i0.Value.absent(),
|
this.durationInSeconds = const i0.Value.absent(),
|
||||||
this.id = const i0.Value.absent(),
|
this.id = const i0.Value.absent(),
|
||||||
|
this.localId = const i0.Value.absent(),
|
||||||
this.checksum = const i0.Value.absent(),
|
this.checksum = const i0.Value.absent(),
|
||||||
this.isFavorite = const i0.Value.absent(),
|
this.isFavorite = const i0.Value.absent(),
|
||||||
this.ownerId = const i0.Value.absent(),
|
this.ownerId = const i0.Value.absent(),
|
||||||
@@ -1018,6 +1061,7 @@ class RemoteAssetEntityCompanion
|
|||||||
this.height = const i0.Value.absent(),
|
this.height = const i0.Value.absent(),
|
||||||
this.durationInSeconds = const i0.Value.absent(),
|
this.durationInSeconds = const i0.Value.absent(),
|
||||||
required String id,
|
required String id,
|
||||||
|
this.localId = const i0.Value.absent(),
|
||||||
required String checksum,
|
required String checksum,
|
||||||
this.isFavorite = const i0.Value.absent(),
|
this.isFavorite = const i0.Value.absent(),
|
||||||
required String ownerId,
|
required String ownerId,
|
||||||
@@ -1040,6 +1084,7 @@ class RemoteAssetEntityCompanion
|
|||||||
i0.Expression<int>? height,
|
i0.Expression<int>? height,
|
||||||
i0.Expression<int>? durationInSeconds,
|
i0.Expression<int>? durationInSeconds,
|
||||||
i0.Expression<String>? id,
|
i0.Expression<String>? id,
|
||||||
|
i0.Expression<String>? localId,
|
||||||
i0.Expression<String>? checksum,
|
i0.Expression<String>? checksum,
|
||||||
i0.Expression<bool>? isFavorite,
|
i0.Expression<bool>? isFavorite,
|
||||||
i0.Expression<String>? ownerId,
|
i0.Expression<String>? ownerId,
|
||||||
@@ -1057,6 +1102,7 @@ class RemoteAssetEntityCompanion
|
|||||||
if (height != null) 'height': height,
|
if (height != null) 'height': height,
|
||||||
if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds,
|
if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds,
|
||||||
if (id != null) 'id': id,
|
if (id != null) 'id': id,
|
||||||
|
if (localId != null) 'local_id': localId,
|
||||||
if (checksum != null) 'checksum': checksum,
|
if (checksum != null) 'checksum': checksum,
|
||||||
if (isFavorite != null) 'is_favorite': isFavorite,
|
if (isFavorite != null) 'is_favorite': isFavorite,
|
||||||
if (ownerId != null) 'owner_id': ownerId,
|
if (ownerId != null) 'owner_id': ownerId,
|
||||||
@@ -1076,6 +1122,7 @@ class RemoteAssetEntityCompanion
|
|||||||
i0.Value<int?>? height,
|
i0.Value<int?>? height,
|
||||||
i0.Value<int?>? durationInSeconds,
|
i0.Value<int?>? durationInSeconds,
|
||||||
i0.Value<String>? id,
|
i0.Value<String>? id,
|
||||||
|
i0.Value<String?>? localId,
|
||||||
i0.Value<String>? checksum,
|
i0.Value<String>? checksum,
|
||||||
i0.Value<bool>? isFavorite,
|
i0.Value<bool>? isFavorite,
|
||||||
i0.Value<String>? ownerId,
|
i0.Value<String>? ownerId,
|
||||||
@@ -1092,6 +1139,7 @@ class RemoteAssetEntityCompanion
|
|||||||
height: height ?? this.height,
|
height: height ?? this.height,
|
||||||
durationInSeconds: durationInSeconds ?? this.durationInSeconds,
|
durationInSeconds: durationInSeconds ?? this.durationInSeconds,
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
|
localId: localId ?? this.localId,
|
||||||
checksum: checksum ?? this.checksum,
|
checksum: checksum ?? this.checksum,
|
||||||
isFavorite: isFavorite ?? this.isFavorite,
|
isFavorite: isFavorite ?? this.isFavorite,
|
||||||
ownerId: ownerId ?? this.ownerId,
|
ownerId: ownerId ?? this.ownerId,
|
||||||
@@ -1130,6 +1178,9 @@ class RemoteAssetEntityCompanion
|
|||||||
if (id.present) {
|
if (id.present) {
|
||||||
map['id'] = i0.Variable<String>(id.value);
|
map['id'] = i0.Variable<String>(id.value);
|
||||||
}
|
}
|
||||||
|
if (localId.present) {
|
||||||
|
map['local_id'] = i0.Variable<String>(localId.value);
|
||||||
|
}
|
||||||
if (checksum.present) {
|
if (checksum.present) {
|
||||||
map['checksum'] = i0.Variable<String>(checksum.value);
|
map['checksum'] = i0.Variable<String>(checksum.value);
|
||||||
}
|
}
|
||||||
@@ -1167,6 +1218,7 @@ class RemoteAssetEntityCompanion
|
|||||||
..write('height: $height, ')
|
..write('height: $height, ')
|
||||||
..write('durationInSeconds: $durationInSeconds, ')
|
..write('durationInSeconds: $durationInSeconds, ')
|
||||||
..write('id: $id, ')
|
..write('id: $id, ')
|
||||||
|
..write('localId: $localId, ')
|
||||||
..write('checksum: $checksum, ')
|
..write('checksum: $checksum, ')
|
||||||
..write('isFavorite: $isFavorite, ')
|
..write('isFavorite: $isFavorite, ')
|
||||||
..write('ownerId: $ownerId, ')
|
..write('ownerId: $ownerId, ')
|
||||||
|
|||||||
22
mobile/lib/infrastructure/entities/stack.entity.dart
Normal file
22
mobile/lib/infrastructure/entities/stack.entity.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
||||||
|
|
||||||
|
class StackEntity extends Table with DriftDefaultsMixin {
|
||||||
|
const StackEntity();
|
||||||
|
|
||||||
|
TextColumn get id => text()();
|
||||||
|
|
||||||
|
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||||
|
|
||||||
|
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
|
||||||
|
|
||||||
|
TextColumn get ownerId =>
|
||||||
|
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
|
||||||
|
|
||||||
|
TextColumn get primaryAssetId => text().references(RemoteAssetEntity, #id)();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<Column> get primaryKey => {id};
|
||||||
|
}
|
||||||
706
mobile/lib/infrastructure/entities/stack.entity.drift.dart
generated
Normal file
706
mobile/lib/infrastructure/entities/stack.entity.drift.dart
generated
Normal file
@@ -0,0 +1,706 @@
|
|||||||
|
// dart format width=80
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
import 'package:drift/drift.dart' as i0;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart'
|
||||||
|
as i1;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/stack.entity.dart' as i2;
|
||||||
|
import 'package:drift/src/runtime/query_builder/query_builder.dart' as i3;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart'
|
||||||
|
as i4;
|
||||||
|
import 'package:drift/internal/modular.dart' as i5;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'
|
||||||
|
as i6;
|
||||||
|
|
||||||
|
typedef $$StackEntityTableCreateCompanionBuilder = i1.StackEntityCompanion
|
||||||
|
Function({
|
||||||
|
required String id,
|
||||||
|
i0.Value<DateTime> createdAt,
|
||||||
|
i0.Value<DateTime> updatedAt,
|
||||||
|
required String ownerId,
|
||||||
|
required String primaryAssetId,
|
||||||
|
});
|
||||||
|
typedef $$StackEntityTableUpdateCompanionBuilder = i1.StackEntityCompanion
|
||||||
|
Function({
|
||||||
|
i0.Value<String> id,
|
||||||
|
i0.Value<DateTime> createdAt,
|
||||||
|
i0.Value<DateTime> updatedAt,
|
||||||
|
i0.Value<String> ownerId,
|
||||||
|
i0.Value<String> primaryAssetId,
|
||||||
|
});
|
||||||
|
|
||||||
|
final class $$StackEntityTableReferences extends i0.BaseReferences<
|
||||||
|
i0.GeneratedDatabase, i1.$StackEntityTable, i1.StackEntityData> {
|
||||||
|
$$StackEntityTableReferences(super.$_db, super.$_table, super.$_typedResult);
|
||||||
|
|
||||||
|
static i4.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) =>
|
||||||
|
i5.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i4.$UserEntityTable>('user_entity')
|
||||||
|
.createAlias(i0.$_aliasNameGenerator(
|
||||||
|
i5.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i1.$StackEntityTable>('stack_entity')
|
||||||
|
.ownerId,
|
||||||
|
i5.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i4.$UserEntityTable>('user_entity')
|
||||||
|
.id));
|
||||||
|
|
||||||
|
i4.$$UserEntityTableProcessedTableManager get ownerId {
|
||||||
|
final $_column = $_itemColumn<String>('owner_id')!;
|
||||||
|
|
||||||
|
final manager = i4
|
||||||
|
.$$UserEntityTableTableManager(
|
||||||
|
$_db,
|
||||||
|
i5.ReadDatabaseContainer($_db)
|
||||||
|
.resultSet<i4.$UserEntityTable>('user_entity'))
|
||||||
|
.filter((f) => f.id.sqlEquals($_column));
|
||||||
|
final item = $_typedResult.readTableOrNull(_ownerIdTable($_db));
|
||||||
|
if (item == null) return manager;
|
||||||
|
return i0.ProcessedTableManager(
|
||||||
|
manager.$state.copyWith(prefetchedData: [item]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static i6.$RemoteAssetEntityTable _primaryAssetIdTable(
|
||||||
|
i0.GeneratedDatabase db) =>
|
||||||
|
i5.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i6.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||||
|
.createAlias(i0.$_aliasNameGenerator(
|
||||||
|
i5.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i1.$StackEntityTable>('stack_entity')
|
||||||
|
.primaryAssetId,
|
||||||
|
i5.ReadDatabaseContainer(db)
|
||||||
|
.resultSet<i6.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||||
|
.id));
|
||||||
|
|
||||||
|
i6.$$RemoteAssetEntityTableProcessedTableManager get primaryAssetId {
|
||||||
|
final $_column = $_itemColumn<String>('primary_asset_id')!;
|
||||||
|
|
||||||
|
final manager = i6
|
||||||
|
.$$RemoteAssetEntityTableTableManager(
|
||||||
|
$_db,
|
||||||
|
i5.ReadDatabaseContainer($_db)
|
||||||
|
.resultSet<i6.$RemoteAssetEntityTable>('remote_asset_entity'))
|
||||||
|
.filter((f) => f.id.sqlEquals($_column));
|
||||||
|
final item = $_typedResult.readTableOrNull(_primaryAssetIdTable($_db));
|
||||||
|
if (item == null) return manager;
|
||||||
|
return i0.ProcessedTableManager(
|
||||||
|
manager.$state.copyWith(prefetchedData: [item]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$StackEntityTableFilterComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$StackEntityTable> {
|
||||||
|
$$StackEntityTableFilterComposer({
|
||||||
|
required super.$db,
|
||||||
|
required super.$table,
|
||||||
|
super.joinBuilder,
|
||||||
|
super.$addJoinBuilderToRootComposer,
|
||||||
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
|
});
|
||||||
|
i0.ColumnFilters<String> get id => $composableBuilder(
|
||||||
|
column: $table.id, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i0.ColumnFilters<DateTime> get createdAt => $composableBuilder(
|
||||||
|
column: $table.createdAt, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i0.ColumnFilters<DateTime> get updatedAt => $composableBuilder(
|
||||||
|
column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column));
|
||||||
|
|
||||||
|
i4.$$UserEntityTableFilterComposer get ownerId {
|
||||||
|
final i4.$$UserEntityTableFilterComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.ownerId,
|
||||||
|
referencedTable: i5.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i4.$UserEntityTable>('user_entity'),
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i4.$$UserEntityTableFilterComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i5.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i4.$UserEntityTable>('user_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
|
||||||
|
i6.$$RemoteAssetEntityTableFilterComposer get primaryAssetId {
|
||||||
|
final i6.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.primaryAssetId,
|
||||||
|
referencedTable: i5.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i6.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i6.$$RemoteAssetEntityTableFilterComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i5.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i6.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$StackEntityTableOrderingComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$StackEntityTable> {
|
||||||
|
$$StackEntityTableOrderingComposer({
|
||||||
|
required super.$db,
|
||||||
|
required super.$table,
|
||||||
|
super.joinBuilder,
|
||||||
|
super.$addJoinBuilderToRootComposer,
|
||||||
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
|
});
|
||||||
|
i0.ColumnOrderings<String> get id => $composableBuilder(
|
||||||
|
column: $table.id, builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i0.ColumnOrderings<DateTime> get createdAt => $composableBuilder(
|
||||||
|
column: $table.createdAt,
|
||||||
|
builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i0.ColumnOrderings<DateTime> get updatedAt => $composableBuilder(
|
||||||
|
column: $table.updatedAt,
|
||||||
|
builder: (column) => i0.ColumnOrderings(column));
|
||||||
|
|
||||||
|
i4.$$UserEntityTableOrderingComposer get ownerId {
|
||||||
|
final i4.$$UserEntityTableOrderingComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.ownerId,
|
||||||
|
referencedTable: i5.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i4.$UserEntityTable>('user_entity'),
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i4.$$UserEntityTableOrderingComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i5.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i4.$UserEntityTable>('user_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
|
||||||
|
i6.$$RemoteAssetEntityTableOrderingComposer get primaryAssetId {
|
||||||
|
final i6.$$RemoteAssetEntityTableOrderingComposer composer =
|
||||||
|
$composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.primaryAssetId,
|
||||||
|
referencedTable: i5.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i6.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i6.$$RemoteAssetEntityTableOrderingComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i5.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i6.$RemoteAssetEntityTable>(
|
||||||
|
'remote_asset_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$StackEntityTableAnnotationComposer
|
||||||
|
extends i0.Composer<i0.GeneratedDatabase, i1.$StackEntityTable> {
|
||||||
|
$$StackEntityTableAnnotationComposer({
|
||||||
|
required super.$db,
|
||||||
|
required super.$table,
|
||||||
|
super.joinBuilder,
|
||||||
|
super.$addJoinBuilderToRootComposer,
|
||||||
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
|
});
|
||||||
|
i0.GeneratedColumn<String> get id =>
|
||||||
|
$composableBuilder(column: $table.id, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumn<DateTime> get createdAt =>
|
||||||
|
$composableBuilder(column: $table.createdAt, builder: (column) => column);
|
||||||
|
|
||||||
|
i0.GeneratedColumn<DateTime> get updatedAt =>
|
||||||
|
$composableBuilder(column: $table.updatedAt, builder: (column) => column);
|
||||||
|
|
||||||
|
i4.$$UserEntityTableAnnotationComposer get ownerId {
|
||||||
|
final i4.$$UserEntityTableAnnotationComposer composer = $composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.ownerId,
|
||||||
|
referencedTable: i5.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i4.$UserEntityTable>('user_entity'),
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i4.$$UserEntityTableAnnotationComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i5.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i4.$UserEntityTable>('user_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
|
||||||
|
i6.$$RemoteAssetEntityTableAnnotationComposer get primaryAssetId {
|
||||||
|
final i6.$$RemoteAssetEntityTableAnnotationComposer composer =
|
||||||
|
$composerBuilder(
|
||||||
|
composer: this,
|
||||||
|
getCurrentColumn: (t) => t.primaryAssetId,
|
||||||
|
referencedTable: i5.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i6.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||||
|
getReferencedColumn: (t) => t.id,
|
||||||
|
builder: (joinBuilder,
|
||||||
|
{$addJoinBuilderToRootComposer,
|
||||||
|
$removeJoinBuilderFromRootComposer}) =>
|
||||||
|
i6.$$RemoteAssetEntityTableAnnotationComposer(
|
||||||
|
$db: $db,
|
||||||
|
$table: i5.ReadDatabaseContainer($db)
|
||||||
|
.resultSet<i6.$RemoteAssetEntityTable>(
|
||||||
|
'remote_asset_entity'),
|
||||||
|
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||||
|
joinBuilder: joinBuilder,
|
||||||
|
$removeJoinBuilderFromRootComposer:
|
||||||
|
$removeJoinBuilderFromRootComposer,
|
||||||
|
));
|
||||||
|
return composer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$StackEntityTableTableManager extends i0.RootTableManager<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$StackEntityTable,
|
||||||
|
i1.StackEntityData,
|
||||||
|
i1.$$StackEntityTableFilterComposer,
|
||||||
|
i1.$$StackEntityTableOrderingComposer,
|
||||||
|
i1.$$StackEntityTableAnnotationComposer,
|
||||||
|
$$StackEntityTableCreateCompanionBuilder,
|
||||||
|
$$StackEntityTableUpdateCompanionBuilder,
|
||||||
|
(i1.StackEntityData, i1.$$StackEntityTableReferences),
|
||||||
|
i1.StackEntityData,
|
||||||
|
i0.PrefetchHooks Function({bool ownerId, bool primaryAssetId})> {
|
||||||
|
$$StackEntityTableTableManager(
|
||||||
|
i0.GeneratedDatabase db, i1.$StackEntityTable table)
|
||||||
|
: super(i0.TableManagerState(
|
||||||
|
db: db,
|
||||||
|
table: table,
|
||||||
|
createFilteringComposer: () =>
|
||||||
|
i1.$$StackEntityTableFilterComposer($db: db, $table: table),
|
||||||
|
createOrderingComposer: () =>
|
||||||
|
i1.$$StackEntityTableOrderingComposer($db: db, $table: table),
|
||||||
|
createComputedFieldComposer: () =>
|
||||||
|
i1.$$StackEntityTableAnnotationComposer($db: db, $table: table),
|
||||||
|
updateCompanionCallback: ({
|
||||||
|
i0.Value<String> id = const i0.Value.absent(),
|
||||||
|
i0.Value<DateTime> createdAt = const i0.Value.absent(),
|
||||||
|
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||||
|
i0.Value<String> ownerId = const i0.Value.absent(),
|
||||||
|
i0.Value<String> primaryAssetId = const i0.Value.absent(),
|
||||||
|
}) =>
|
||||||
|
i1.StackEntityCompanion(
|
||||||
|
id: id,
|
||||||
|
createdAt: createdAt,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
ownerId: ownerId,
|
||||||
|
primaryAssetId: primaryAssetId,
|
||||||
|
),
|
||||||
|
createCompanionCallback: ({
|
||||||
|
required String id,
|
||||||
|
i0.Value<DateTime> createdAt = const i0.Value.absent(),
|
||||||
|
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||||
|
required String ownerId,
|
||||||
|
required String primaryAssetId,
|
||||||
|
}) =>
|
||||||
|
i1.StackEntityCompanion.insert(
|
||||||
|
id: id,
|
||||||
|
createdAt: createdAt,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
ownerId: ownerId,
|
||||||
|
primaryAssetId: primaryAssetId,
|
||||||
|
),
|
||||||
|
withReferenceMapper: (p0) => p0
|
||||||
|
.map((e) => (
|
||||||
|
e.readTable(table),
|
||||||
|
i1.$$StackEntityTableReferences(db, table, e)
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
prefetchHooksCallback: ({ownerId = false, primaryAssetId = false}) {
|
||||||
|
return i0.PrefetchHooks(
|
||||||
|
db: db,
|
||||||
|
explicitlyWatchedTables: [],
|
||||||
|
addJoins: <
|
||||||
|
T extends i0.TableManagerState<
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic,
|
||||||
|
dynamic>>(state) {
|
||||||
|
if (ownerId) {
|
||||||
|
state = state.withJoin(
|
||||||
|
currentTable: table,
|
||||||
|
currentColumn: table.ownerId,
|
||||||
|
referencedTable:
|
||||||
|
i1.$$StackEntityTableReferences._ownerIdTable(db),
|
||||||
|
referencedColumn:
|
||||||
|
i1.$$StackEntityTableReferences._ownerIdTable(db).id,
|
||||||
|
) as T;
|
||||||
|
}
|
||||||
|
if (primaryAssetId) {
|
||||||
|
state = state.withJoin(
|
||||||
|
currentTable: table,
|
||||||
|
currentColumn: table.primaryAssetId,
|
||||||
|
referencedTable: i1.$$StackEntityTableReferences
|
||||||
|
._primaryAssetIdTable(db),
|
||||||
|
referencedColumn: i1.$$StackEntityTableReferences
|
||||||
|
._primaryAssetIdTable(db)
|
||||||
|
.id,
|
||||||
|
) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
},
|
||||||
|
getPrefetchedDataCallback: (items) async {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef $$StackEntityTableProcessedTableManager = i0.ProcessedTableManager<
|
||||||
|
i0.GeneratedDatabase,
|
||||||
|
i1.$StackEntityTable,
|
||||||
|
i1.StackEntityData,
|
||||||
|
i1.$$StackEntityTableFilterComposer,
|
||||||
|
i1.$$StackEntityTableOrderingComposer,
|
||||||
|
i1.$$StackEntityTableAnnotationComposer,
|
||||||
|
$$StackEntityTableCreateCompanionBuilder,
|
||||||
|
$$StackEntityTableUpdateCompanionBuilder,
|
||||||
|
(i1.StackEntityData, i1.$$StackEntityTableReferences),
|
||||||
|
i1.StackEntityData,
|
||||||
|
i0.PrefetchHooks Function({bool ownerId, bool primaryAssetId})>;
|
||||||
|
|
||||||
|
class $StackEntityTable extends i2.StackEntity
|
||||||
|
with i0.TableInfo<$StackEntityTable, i1.StackEntityData> {
|
||||||
|
@override
|
||||||
|
final i0.GeneratedDatabase attachedDatabase;
|
||||||
|
final String? _alias;
|
||||||
|
$StackEntityTable(this.attachedDatabase, [this._alias]);
|
||||||
|
static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> id = i0.GeneratedColumn<String>(
|
||||||
|
'id', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||||
|
static const i0.VerificationMeta _createdAtMeta =
|
||||||
|
const i0.VerificationMeta('createdAt');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<DateTime> createdAt =
|
||||||
|
i0.GeneratedColumn<DateTime>('created_at', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.dateTime,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultValue: i3.currentDateAndTime);
|
||||||
|
static const i0.VerificationMeta _updatedAtMeta =
|
||||||
|
const i0.VerificationMeta('updatedAt');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<DateTime> updatedAt =
|
||||||
|
i0.GeneratedColumn<DateTime>('updated_at', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.dateTime,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultValue: i3.currentDateAndTime);
|
||||||
|
static const i0.VerificationMeta _ownerIdMeta =
|
||||||
|
const i0.VerificationMeta('ownerId');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> ownerId = i0.GeneratedColumn<String>(
|
||||||
|
'owner_id', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.string,
|
||||||
|
requiredDuringInsert: true,
|
||||||
|
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||||
|
'REFERENCES user_entity (id) ON DELETE CASCADE'));
|
||||||
|
static const i0.VerificationMeta _primaryAssetIdMeta =
|
||||||
|
const i0.VerificationMeta('primaryAssetId');
|
||||||
|
@override
|
||||||
|
late final i0.GeneratedColumn<String> primaryAssetId =
|
||||||
|
i0.GeneratedColumn<String>(
|
||||||
|
'primary_asset_id', aliasedName, false,
|
||||||
|
type: i0.DriftSqlType.string,
|
||||||
|
requiredDuringInsert: true,
|
||||||
|
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||||
|
'REFERENCES remote_asset_entity (id)'));
|
||||||
|
@override
|
||||||
|
List<i0.GeneratedColumn> get $columns =>
|
||||||
|
[id, createdAt, updatedAt, ownerId, primaryAssetId];
|
||||||
|
@override
|
||||||
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
|
@override
|
||||||
|
String get actualTableName => $name;
|
||||||
|
static const String $name = 'stack_entity';
|
||||||
|
@override
|
||||||
|
i0.VerificationContext validateIntegrity(
|
||||||
|
i0.Insertable<i1.StackEntityData> instance,
|
||||||
|
{bool isInserting = false}) {
|
||||||
|
final context = i0.VerificationContext();
|
||||||
|
final data = instance.toColumns(true);
|
||||||
|
if (data.containsKey('id')) {
|
||||||
|
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
|
||||||
|
} else if (isInserting) {
|
||||||
|
context.missing(_idMeta);
|
||||||
|
}
|
||||||
|
if (data.containsKey('created_at')) {
|
||||||
|
context.handle(_createdAtMeta,
|
||||||
|
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('updated_at')) {
|
||||||
|
context.handle(_updatedAtMeta,
|
||||||
|
updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('owner_id')) {
|
||||||
|
context.handle(_ownerIdMeta,
|
||||||
|
ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta));
|
||||||
|
} else if (isInserting) {
|
||||||
|
context.missing(_ownerIdMeta);
|
||||||
|
}
|
||||||
|
if (data.containsKey('primary_asset_id')) {
|
||||||
|
context.handle(
|
||||||
|
_primaryAssetIdMeta,
|
||||||
|
primaryAssetId.isAcceptableOrUnknown(
|
||||||
|
data['primary_asset_id']!, _primaryAssetIdMeta));
|
||||||
|
} else if (isInserting) {
|
||||||
|
context.missing(_primaryAssetIdMeta);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<i0.GeneratedColumn> get $primaryKey => {id};
|
||||||
|
@override
|
||||||
|
i1.StackEntityData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||||
|
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||||
|
return i1.StackEntityData(
|
||||||
|
id: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!,
|
||||||
|
createdAt: attachedDatabase.typeMapping.read(
|
||||||
|
i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
|
||||||
|
updatedAt: attachedDatabase.typeMapping.read(
|
||||||
|
i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!,
|
||||||
|
ownerId: attachedDatabase.typeMapping
|
||||||
|
.read(i0.DriftSqlType.string, data['${effectivePrefix}owner_id'])!,
|
||||||
|
primaryAssetId: attachedDatabase.typeMapping.read(
|
||||||
|
i0.DriftSqlType.string, data['${effectivePrefix}primary_asset_id'])!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
$StackEntityTable createAlias(String alias) {
|
||||||
|
return $StackEntityTable(attachedDatabase, alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get withoutRowId => true;
|
||||||
|
@override
|
||||||
|
bool get isStrict => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class StackEntityData extends i0.DataClass
|
||||||
|
implements i0.Insertable<i1.StackEntityData> {
|
||||||
|
final String id;
|
||||||
|
final DateTime createdAt;
|
||||||
|
final DateTime updatedAt;
|
||||||
|
final String ownerId;
|
||||||
|
final String primaryAssetId;
|
||||||
|
const StackEntityData(
|
||||||
|
{required this.id,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
required this.ownerId,
|
||||||
|
required this.primaryAssetId});
|
||||||
|
@override
|
||||||
|
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, i0.Expression>{};
|
||||||
|
map['id'] = i0.Variable<String>(id);
|
||||||
|
map['created_at'] = i0.Variable<DateTime>(createdAt);
|
||||||
|
map['updated_at'] = i0.Variable<DateTime>(updatedAt);
|
||||||
|
map['owner_id'] = i0.Variable<String>(ownerId);
|
||||||
|
map['primary_asset_id'] = i0.Variable<String>(primaryAssetId);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
factory StackEntityData.fromJson(Map<String, dynamic> json,
|
||||||
|
{i0.ValueSerializer? serializer}) {
|
||||||
|
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||||
|
return StackEntityData(
|
||||||
|
id: serializer.fromJson<String>(json['id']),
|
||||||
|
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
|
||||||
|
updatedAt: serializer.fromJson<DateTime>(json['updatedAt']),
|
||||||
|
ownerId: serializer.fromJson<String>(json['ownerId']),
|
||||||
|
primaryAssetId: serializer.fromJson<String>(json['primaryAssetId']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||||
|
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||||
|
return <String, dynamic>{
|
||||||
|
'id': serializer.toJson<String>(id),
|
||||||
|
'createdAt': serializer.toJson<DateTime>(createdAt),
|
||||||
|
'updatedAt': serializer.toJson<DateTime>(updatedAt),
|
||||||
|
'ownerId': serializer.toJson<String>(ownerId),
|
||||||
|
'primaryAssetId': serializer.toJson<String>(primaryAssetId),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.StackEntityData copyWith(
|
||||||
|
{String? id,
|
||||||
|
DateTime? createdAt,
|
||||||
|
DateTime? updatedAt,
|
||||||
|
String? ownerId,
|
||||||
|
String? primaryAssetId}) =>
|
||||||
|
i1.StackEntityData(
|
||||||
|
id: id ?? this.id,
|
||||||
|
createdAt: createdAt ?? this.createdAt,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
|
ownerId: ownerId ?? this.ownerId,
|
||||||
|
primaryAssetId: primaryAssetId ?? this.primaryAssetId,
|
||||||
|
);
|
||||||
|
StackEntityData copyWithCompanion(i1.StackEntityCompanion data) {
|
||||||
|
return StackEntityData(
|
||||||
|
id: data.id.present ? data.id.value : this.id,
|
||||||
|
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
||||||
|
updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt,
|
||||||
|
ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId,
|
||||||
|
primaryAssetId: data.primaryAssetId.present
|
||||||
|
? data.primaryAssetId.value
|
||||||
|
: this.primaryAssetId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('StackEntityData(')
|
||||||
|
..write('id: $id, ')
|
||||||
|
..write('createdAt: $createdAt, ')
|
||||||
|
..write('updatedAt: $updatedAt, ')
|
||||||
|
..write('ownerId: $ownerId, ')
|
||||||
|
..write('primaryAssetId: $primaryAssetId')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
Object.hash(id, createdAt, updatedAt, ownerId, primaryAssetId);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
(other is i1.StackEntityData &&
|
||||||
|
other.id == this.id &&
|
||||||
|
other.createdAt == this.createdAt &&
|
||||||
|
other.updatedAt == this.updatedAt &&
|
||||||
|
other.ownerId == this.ownerId &&
|
||||||
|
other.primaryAssetId == this.primaryAssetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
class StackEntityCompanion extends i0.UpdateCompanion<i1.StackEntityData> {
|
||||||
|
final i0.Value<String> id;
|
||||||
|
final i0.Value<DateTime> createdAt;
|
||||||
|
final i0.Value<DateTime> updatedAt;
|
||||||
|
final i0.Value<String> ownerId;
|
||||||
|
final i0.Value<String> primaryAssetId;
|
||||||
|
const StackEntityCompanion({
|
||||||
|
this.id = const i0.Value.absent(),
|
||||||
|
this.createdAt = const i0.Value.absent(),
|
||||||
|
this.updatedAt = const i0.Value.absent(),
|
||||||
|
this.ownerId = const i0.Value.absent(),
|
||||||
|
this.primaryAssetId = const i0.Value.absent(),
|
||||||
|
});
|
||||||
|
StackEntityCompanion.insert({
|
||||||
|
required String id,
|
||||||
|
this.createdAt = const i0.Value.absent(),
|
||||||
|
this.updatedAt = const i0.Value.absent(),
|
||||||
|
required String ownerId,
|
||||||
|
required String primaryAssetId,
|
||||||
|
}) : id = i0.Value(id),
|
||||||
|
ownerId = i0.Value(ownerId),
|
||||||
|
primaryAssetId = i0.Value(primaryAssetId);
|
||||||
|
static i0.Insertable<i1.StackEntityData> custom({
|
||||||
|
i0.Expression<String>? id,
|
||||||
|
i0.Expression<DateTime>? createdAt,
|
||||||
|
i0.Expression<DateTime>? updatedAt,
|
||||||
|
i0.Expression<String>? ownerId,
|
||||||
|
i0.Expression<String>? primaryAssetId,
|
||||||
|
}) {
|
||||||
|
return i0.RawValuesInsertable({
|
||||||
|
if (id != null) 'id': id,
|
||||||
|
if (createdAt != null) 'created_at': createdAt,
|
||||||
|
if (updatedAt != null) 'updated_at': updatedAt,
|
||||||
|
if (ownerId != null) 'owner_id': ownerId,
|
||||||
|
if (primaryAssetId != null) 'primary_asset_id': primaryAssetId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.StackEntityCompanion copyWith(
|
||||||
|
{i0.Value<String>? id,
|
||||||
|
i0.Value<DateTime>? createdAt,
|
||||||
|
i0.Value<DateTime>? updatedAt,
|
||||||
|
i0.Value<String>? ownerId,
|
||||||
|
i0.Value<String>? primaryAssetId}) {
|
||||||
|
return i1.StackEntityCompanion(
|
||||||
|
id: id ?? this.id,
|
||||||
|
createdAt: createdAt ?? this.createdAt,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
|
ownerId: ownerId ?? this.ownerId,
|
||||||
|
primaryAssetId: primaryAssetId ?? this.primaryAssetId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, i0.Expression>{};
|
||||||
|
if (id.present) {
|
||||||
|
map['id'] = i0.Variable<String>(id.value);
|
||||||
|
}
|
||||||
|
if (createdAt.present) {
|
||||||
|
map['created_at'] = i0.Variable<DateTime>(createdAt.value);
|
||||||
|
}
|
||||||
|
if (updatedAt.present) {
|
||||||
|
map['updated_at'] = i0.Variable<DateTime>(updatedAt.value);
|
||||||
|
}
|
||||||
|
if (ownerId.present) {
|
||||||
|
map['owner_id'] = i0.Variable<String>(ownerId.value);
|
||||||
|
}
|
||||||
|
if (primaryAssetId.present) {
|
||||||
|
map['primary_asset_id'] = i0.Variable<String>(primaryAssetId.value);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('StackEntityCompanion(')
|
||||||
|
..write('id: $id, ')
|
||||||
|
..write('createdAt: $createdAt, ')
|
||||||
|
..write('updatedAt: $updatedAt, ')
|
||||||
|
..write('ownerId: $ownerId, ')
|
||||||
|
..write('primaryAssetId: $primaryAssetId')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import 'package:immich_mobile/infrastructure/entities/remote_album.entity.dart';
|
|||||||
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/stack.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
@@ -50,9 +51,11 @@ class IsarDatabaseRepository implements IDatabaseRepository {
|
|||||||
RemoteAlbumUserEntity,
|
RemoteAlbumUserEntity,
|
||||||
MemoryEntity,
|
MemoryEntity,
|
||||||
MemoryAssetEntity,
|
MemoryAssetEntity,
|
||||||
|
StackEntity,
|
||||||
],
|
],
|
||||||
include: {
|
include: {
|
||||||
'package:immich_mobile/infrastructure/entities/merged_asset.drift',
|
'package:immich_mobile/infrastructure/entities/merged_asset.drift',
|
||||||
|
'package:immich_mobile/infrastructure/entities/asset_triggers.drift',
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
class Drift extends $Drift implements IDatabaseRepository {
|
class Drift extends $Drift implements IDatabaseRepository {
|
||||||
|
|||||||
@@ -7,29 +7,33 @@ import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.
|
|||||||
as i2;
|
as i2;
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'
|
||||||
as i3;
|
as i3;
|
||||||
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/asset_triggers.drift.dart'
|
||||||
as i4;
|
as i4;
|
||||||
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart'
|
||||||
as i5;
|
as i5;
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart'
|
||||||
as i6;
|
as i6;
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart'
|
||||||
as i7;
|
as i7;
|
||||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart'
|
||||||
as i8;
|
as i8;
|
||||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart'
|
||||||
as i9;
|
as i9;
|
||||||
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart'
|
||||||
as i10;
|
as i10;
|
||||||
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart'
|
||||||
as i11;
|
as i11;
|
||||||
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart'
|
||||||
as i12;
|
as i12;
|
||||||
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart'
|
||||||
as i13;
|
as i13;
|
||||||
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart'
|
import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart'
|
||||||
as i14;
|
as i14;
|
||||||
import 'package:drift/internal/modular.dart' as i15;
|
import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart'
|
||||||
|
as i15;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart'
|
||||||
|
as i16;
|
||||||
|
import 'package:drift/internal/modular.dart' as i17;
|
||||||
|
|
||||||
abstract class $Drift extends i0.GeneratedDatabase {
|
abstract class $Drift extends i0.GeneratedDatabase {
|
||||||
$Drift(i0.QueryExecutor e) : super(e);
|
$Drift(i0.QueryExecutor e) : super(e);
|
||||||
@@ -39,27 +43,28 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
|||||||
i2.$RemoteAssetEntityTable(this);
|
i2.$RemoteAssetEntityTable(this);
|
||||||
late final i3.$LocalAssetEntityTable localAssetEntity =
|
late final i3.$LocalAssetEntityTable localAssetEntity =
|
||||||
i3.$LocalAssetEntityTable(this);
|
i3.$LocalAssetEntityTable(this);
|
||||||
late final i4.$UserMetadataEntityTable userMetadataEntity =
|
late final i5.$UserMetadataEntityTable userMetadataEntity =
|
||||||
i4.$UserMetadataEntityTable(this);
|
i5.$UserMetadataEntityTable(this);
|
||||||
late final i5.$PartnerEntityTable partnerEntity =
|
late final i6.$PartnerEntityTable partnerEntity =
|
||||||
i5.$PartnerEntityTable(this);
|
i6.$PartnerEntityTable(this);
|
||||||
late final i6.$LocalAlbumEntityTable localAlbumEntity =
|
late final i7.$LocalAlbumEntityTable localAlbumEntity =
|
||||||
i6.$LocalAlbumEntityTable(this);
|
i7.$LocalAlbumEntityTable(this);
|
||||||
late final i7.$LocalAlbumAssetEntityTable localAlbumAssetEntity =
|
late final i8.$LocalAlbumAssetEntityTable localAlbumAssetEntity =
|
||||||
i7.$LocalAlbumAssetEntityTable(this);
|
i8.$LocalAlbumAssetEntityTable(this);
|
||||||
late final i8.$RemoteExifEntityTable remoteExifEntity =
|
late final i9.$RemoteExifEntityTable remoteExifEntity =
|
||||||
i8.$RemoteExifEntityTable(this);
|
i9.$RemoteExifEntityTable(this);
|
||||||
late final i9.$RemoteAlbumEntityTable remoteAlbumEntity =
|
late final i10.$RemoteAlbumEntityTable remoteAlbumEntity =
|
||||||
i9.$RemoteAlbumEntityTable(this);
|
i10.$RemoteAlbumEntityTable(this);
|
||||||
late final i10.$RemoteAlbumAssetEntityTable remoteAlbumAssetEntity =
|
late final i11.$RemoteAlbumAssetEntityTable remoteAlbumAssetEntity =
|
||||||
i10.$RemoteAlbumAssetEntityTable(this);
|
i11.$RemoteAlbumAssetEntityTable(this);
|
||||||
late final i11.$RemoteAlbumUserEntityTable remoteAlbumUserEntity =
|
late final i12.$RemoteAlbumUserEntityTable remoteAlbumUserEntity =
|
||||||
i11.$RemoteAlbumUserEntityTable(this);
|
i12.$RemoteAlbumUserEntityTable(this);
|
||||||
late final i12.$MemoryEntityTable memoryEntity = i12.$MemoryEntityTable(this);
|
late final i13.$MemoryEntityTable memoryEntity = i13.$MemoryEntityTable(this);
|
||||||
late final i13.$MemoryAssetEntityTable memoryAssetEntity =
|
late final i14.$MemoryAssetEntityTable memoryAssetEntity =
|
||||||
i13.$MemoryAssetEntityTable(this);
|
i14.$MemoryAssetEntityTable(this);
|
||||||
i14.MergedAssetDrift get mergedAssetDrift => i15.ReadDatabaseContainer(this)
|
late final i15.$StackEntityTable stackEntity = i15.$StackEntityTable(this);
|
||||||
.accessor<i14.MergedAssetDrift>(i14.MergedAssetDrift.new);
|
i16.MergedAssetDrift get mergedAssetDrift => i17.ReadDatabaseContainer(this)
|
||||||
|
.accessor<i16.MergedAssetDrift>(i16.MergedAssetDrift.new);
|
||||||
@override
|
@override
|
||||||
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
|
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
|
||||||
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
|
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
|
||||||
@@ -68,6 +73,10 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
|||||||
userEntity,
|
userEntity,
|
||||||
remoteAssetEntity,
|
remoteAssetEntity,
|
||||||
localAssetEntity,
|
localAssetEntity,
|
||||||
|
i4.trLocalAssetUpdateChecksumSetIds,
|
||||||
|
i4.trLocalAssetUpdateOldChecksumSetRemoteAssetLocalId,
|
||||||
|
i4.trLocalAssetDeleteUpdateRemoteAssetLocalId,
|
||||||
|
i4.trRemoteAssetInsertSetLocalId,
|
||||||
i3.idxLocalAssetChecksum,
|
i3.idxLocalAssetChecksum,
|
||||||
i2.uQRemoteAssetOwnerChecksum,
|
i2.uQRemoteAssetOwnerChecksum,
|
||||||
i2.idxRemoteAssetChecksum,
|
i2.idxRemoteAssetChecksum,
|
||||||
@@ -80,7 +89,8 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
|||||||
remoteAlbumAssetEntity,
|
remoteAlbumAssetEntity,
|
||||||
remoteAlbumUserEntity,
|
remoteAlbumUserEntity,
|
||||||
memoryEntity,
|
memoryEntity,
|
||||||
memoryAssetEntity
|
memoryAssetEntity,
|
||||||
|
stackEntity
|
||||||
];
|
];
|
||||||
@override
|
@override
|
||||||
i0.StreamQueryUpdateRules get streamUpdateRules =>
|
i0.StreamQueryUpdateRules get streamUpdateRules =>
|
||||||
@@ -93,6 +103,43 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
|||||||
i0.TableUpdate('remote_asset_entity', kind: i0.UpdateKind.delete),
|
i0.TableUpdate('remote_asset_entity', kind: i0.UpdateKind.delete),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
i0.WritePropagation(
|
||||||
|
on: i0.TableUpdateQuery.onTableName('remote_asset_entity',
|
||||||
|
limitUpdateKind: i0.UpdateKind.delete),
|
||||||
|
result: [
|
||||||
|
i0.TableUpdate('local_asset_entity', kind: i0.UpdateKind.update),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
i0.WritePropagation(
|
||||||
|
on: i0.TableUpdateQuery.onTableName('local_asset_entity',
|
||||||
|
limitUpdateKind: i0.UpdateKind.update),
|
||||||
|
result: [
|
||||||
|
i0.TableUpdate('local_asset_entity', kind: i0.UpdateKind.update),
|
||||||
|
i0.TableUpdate('remote_asset_entity', kind: i0.UpdateKind.update),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
i0.WritePropagation(
|
||||||
|
on: i0.TableUpdateQuery.onTableName('local_asset_entity',
|
||||||
|
limitUpdateKind: i0.UpdateKind.update),
|
||||||
|
result: [
|
||||||
|
i0.TableUpdate('remote_asset_entity', kind: i0.UpdateKind.update),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
i0.WritePropagation(
|
||||||
|
on: i0.TableUpdateQuery.onTableName('local_asset_entity',
|
||||||
|
limitUpdateKind: i0.UpdateKind.delete),
|
||||||
|
result: [
|
||||||
|
i0.TableUpdate('remote_asset_entity', kind: i0.UpdateKind.update),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
i0.WritePropagation(
|
||||||
|
on: i0.TableUpdateQuery.onTableName('remote_asset_entity',
|
||||||
|
limitUpdateKind: i0.UpdateKind.insert),
|
||||||
|
result: [
|
||||||
|
i0.TableUpdate('remote_asset_entity', kind: i0.UpdateKind.update),
|
||||||
|
i0.TableUpdate('local_asset_entity', kind: i0.UpdateKind.update),
|
||||||
|
],
|
||||||
|
),
|
||||||
i0.WritePropagation(
|
i0.WritePropagation(
|
||||||
on: i0.TableUpdateQuery.onTableName('user_entity',
|
on: i0.TableUpdateQuery.onTableName('user_entity',
|
||||||
limitUpdateKind: i0.UpdateKind.delete),
|
limitUpdateKind: i0.UpdateKind.delete),
|
||||||
@@ -205,6 +252,13 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
|||||||
i0.TableUpdate('memory_asset_entity', kind: i0.UpdateKind.delete),
|
i0.TableUpdate('memory_asset_entity', kind: i0.UpdateKind.delete),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
i0.WritePropagation(
|
||||||
|
on: i0.TableUpdateQuery.onTableName('user_entity',
|
||||||
|
limitUpdateKind: i0.UpdateKind.delete),
|
||||||
|
result: [
|
||||||
|
i0.TableUpdate('stack_entity', kind: i0.UpdateKind.delete),
|
||||||
|
],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
@@ -221,25 +275,27 @@ class $DriftManager {
|
|||||||
i2.$$RemoteAssetEntityTableTableManager(_db, _db.remoteAssetEntity);
|
i2.$$RemoteAssetEntityTableTableManager(_db, _db.remoteAssetEntity);
|
||||||
i3.$$LocalAssetEntityTableTableManager get localAssetEntity =>
|
i3.$$LocalAssetEntityTableTableManager get localAssetEntity =>
|
||||||
i3.$$LocalAssetEntityTableTableManager(_db, _db.localAssetEntity);
|
i3.$$LocalAssetEntityTableTableManager(_db, _db.localAssetEntity);
|
||||||
i4.$$UserMetadataEntityTableTableManager get userMetadataEntity =>
|
i5.$$UserMetadataEntityTableTableManager get userMetadataEntity =>
|
||||||
i4.$$UserMetadataEntityTableTableManager(_db, _db.userMetadataEntity);
|
i5.$$UserMetadataEntityTableTableManager(_db, _db.userMetadataEntity);
|
||||||
i5.$$PartnerEntityTableTableManager get partnerEntity =>
|
i6.$$PartnerEntityTableTableManager get partnerEntity =>
|
||||||
i5.$$PartnerEntityTableTableManager(_db, _db.partnerEntity);
|
i6.$$PartnerEntityTableTableManager(_db, _db.partnerEntity);
|
||||||
i6.$$LocalAlbumEntityTableTableManager get localAlbumEntity =>
|
i7.$$LocalAlbumEntityTableTableManager get localAlbumEntity =>
|
||||||
i6.$$LocalAlbumEntityTableTableManager(_db, _db.localAlbumEntity);
|
i7.$$LocalAlbumEntityTableTableManager(_db, _db.localAlbumEntity);
|
||||||
i7.$$LocalAlbumAssetEntityTableTableManager get localAlbumAssetEntity => i7
|
i8.$$LocalAlbumAssetEntityTableTableManager get localAlbumAssetEntity => i8
|
||||||
.$$LocalAlbumAssetEntityTableTableManager(_db, _db.localAlbumAssetEntity);
|
.$$LocalAlbumAssetEntityTableTableManager(_db, _db.localAlbumAssetEntity);
|
||||||
i8.$$RemoteExifEntityTableTableManager get remoteExifEntity =>
|
i9.$$RemoteExifEntityTableTableManager get remoteExifEntity =>
|
||||||
i8.$$RemoteExifEntityTableTableManager(_db, _db.remoteExifEntity);
|
i9.$$RemoteExifEntityTableTableManager(_db, _db.remoteExifEntity);
|
||||||
i9.$$RemoteAlbumEntityTableTableManager get remoteAlbumEntity =>
|
i10.$$RemoteAlbumEntityTableTableManager get remoteAlbumEntity =>
|
||||||
i9.$$RemoteAlbumEntityTableTableManager(_db, _db.remoteAlbumEntity);
|
i10.$$RemoteAlbumEntityTableTableManager(_db, _db.remoteAlbumEntity);
|
||||||
i10.$$RemoteAlbumAssetEntityTableTableManager get remoteAlbumAssetEntity =>
|
i11.$$RemoteAlbumAssetEntityTableTableManager get remoteAlbumAssetEntity =>
|
||||||
i10.$$RemoteAlbumAssetEntityTableTableManager(
|
i11.$$RemoteAlbumAssetEntityTableTableManager(
|
||||||
_db, _db.remoteAlbumAssetEntity);
|
_db, _db.remoteAlbumAssetEntity);
|
||||||
i11.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i11
|
i12.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i12
|
||||||
.$$RemoteAlbumUserEntityTableTableManager(_db, _db.remoteAlbumUserEntity);
|
.$$RemoteAlbumUserEntityTableTableManager(_db, _db.remoteAlbumUserEntity);
|
||||||
i12.$$MemoryEntityTableTableManager get memoryEntity =>
|
i13.$$MemoryEntityTableTableManager get memoryEntity =>
|
||||||
i12.$$MemoryEntityTableTableManager(_db, _db.memoryEntity);
|
i13.$$MemoryEntityTableTableManager(_db, _db.memoryEntity);
|
||||||
i13.$$MemoryAssetEntityTableTableManager get memoryAssetEntity =>
|
i14.$$MemoryAssetEntityTableTableManager get memoryAssetEntity =>
|
||||||
i13.$$MemoryAssetEntityTableTableManager(_db, _db.memoryAssetEntity);
|
i14.$$MemoryAssetEntityTableTableManager(_db, _db.memoryAssetEntity);
|
||||||
|
i15.$$StackEntityTableTableManager get stackEntity =>
|
||||||
|
i15.$$StackEntityTableTableManager(_db, _db.stackEntity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -282,6 +282,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
durationInSeconds: Value(asset.durationInSeconds),
|
durationInSeconds: Value(asset.durationInSeconds),
|
||||||
id: asset.id,
|
id: asset.id,
|
||||||
checksum: const Value(null),
|
checksum: const Value(null),
|
||||||
|
remoteId: const Value(null),
|
||||||
);
|
);
|
||||||
batch.insert<$LocalAssetEntityTable, LocalAssetEntityData>(
|
batch.insert<$LocalAssetEntityTable, LocalAssetEntityData>(
|
||||||
_db.localAssetEntity,
|
_db.localAssetEntity,
|
||||||
|
|||||||
@@ -9,23 +9,10 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
|||||||
const DriftLocalAssetRepository(this._db) : super(_db);
|
const DriftLocalAssetRepository(this._db) : super(_db);
|
||||||
|
|
||||||
Stream<LocalAsset?> watchAsset(String id) {
|
Stream<LocalAsset?> watchAsset(String id) {
|
||||||
final query = _db.localAssetEntity
|
final query = _db.localAssetEntity.select()
|
||||||
.select()
|
..where((row) => row.id.equals(id));
|
||||||
.addColumns([_db.localAssetEntity.id]).join([
|
|
||||||
leftOuterJoin(
|
|
||||||
_db.remoteAssetEntity,
|
|
||||||
_db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum),
|
|
||||||
useColumns: false,
|
|
||||||
),
|
|
||||||
])
|
|
||||||
..where(_db.localAssetEntity.id.equals(id));
|
|
||||||
|
|
||||||
return query.map((row) {
|
return query.map((row) => row.toDto()).watchSingleOrNull();
|
||||||
final asset = row.readTable(_db.localAssetEntity).toDto();
|
|
||||||
return asset.copyWith(
|
|
||||||
remoteId: row.read(_db.remoteAssetEntity.id),
|
|
||||||
);
|
|
||||||
}).watchSingleOrNull();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateHashes(Iterable<LocalAsset> hashes) {
|
Future<void> updateHashes(Iterable<LocalAsset> hashes) {
|
||||||
|
|||||||
@@ -13,24 +13,27 @@ class RemoteAssetRepository extends DriftDatabaseRepository {
|
|||||||
final Drift _db;
|
final Drift _db;
|
||||||
const RemoteAssetRepository(this._db) : super(_db);
|
const RemoteAssetRepository(this._db) : super(_db);
|
||||||
|
|
||||||
Stream<RemoteAsset?> watchAsset(String id) {
|
/// For testing purposes
|
||||||
final query = _db.remoteAssetEntity
|
Future<List<RemoteAsset>> getSome(String userId) {
|
||||||
.select()
|
final query = _db.remoteAssetEntity.select()
|
||||||
.addColumns([_db.localAssetEntity.id]).join([
|
..where(
|
||||||
leftOuterJoin(
|
(row) =>
|
||||||
_db.localAssetEntity,
|
_db.remoteAssetEntity.ownerId.equals(userId) &
|
||||||
_db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum),
|
_db.remoteAssetEntity.deletedAt.isNull() &
|
||||||
useColumns: false,
|
_db.remoteAssetEntity.visibility
|
||||||
),
|
.equalsValue(AssetVisibility.timeline),
|
||||||
])
|
)
|
||||||
..where(_db.remoteAssetEntity.id.equals(id));
|
..orderBy([(row) => OrderingTerm.desc(row.createdAt)])
|
||||||
|
..limit(10);
|
||||||
|
|
||||||
return query.map((row) {
|
return query.map((row) => row.toDto()).get();
|
||||||
final asset = row.readTable(_db.remoteAssetEntity).toDto();
|
}
|
||||||
return asset.copyWith(
|
|
||||||
localId: row.read(_db.localAssetEntity.id),
|
Stream<RemoteAsset?> watchAsset(String id) {
|
||||||
);
|
final query = _db.remoteAssetEntity.select()
|
||||||
}).watchSingleOrNull();
|
..where((row) => row.id.equals(id));
|
||||||
|
|
||||||
|
return query.map((row) => row.toDto()).watchSingleOrNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ExifInfo?> getExif(String id) {
|
Future<ExifInfo?> getExif(String id) {
|
||||||
|
|||||||
30
mobile/lib/infrastructure/repositories/stack.repository.dart
Normal file
30
mobile/lib/infrastructure/repositories/stack.repository.dart
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/stack.model.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
|
|
||||||
|
class DriftStackRepository extends DriftDatabaseRepository {
|
||||||
|
final Drift _db;
|
||||||
|
const DriftStackRepository(this._db) : super(_db);
|
||||||
|
|
||||||
|
Future<List<Stack>> getAll(String userId) {
|
||||||
|
final query = _db.stackEntity.select()
|
||||||
|
..where((e) => e.ownerId.equals(userId));
|
||||||
|
|
||||||
|
return query.map((stack) {
|
||||||
|
return stack.toDto();
|
||||||
|
}).get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on StackEntityData {
|
||||||
|
Stack toDto() {
|
||||||
|
return Stack(
|
||||||
|
id: id,
|
||||||
|
createdAt: createdAt,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
ownerId: ownerId,
|
||||||
|
primaryAssetId: primaryAssetId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,6 +54,8 @@ class SyncApiRepository {
|
|||||||
SyncRequestType.albumToAssetsV1,
|
SyncRequestType.albumToAssetsV1,
|
||||||
SyncRequestType.memoriesV1,
|
SyncRequestType.memoriesV1,
|
||||||
SyncRequestType.memoryToAssetsV1,
|
SyncRequestType.memoryToAssetsV1,
|
||||||
|
SyncRequestType.stacksV1,
|
||||||
|
SyncRequestType.partnerStacksV1,
|
||||||
],
|
],
|
||||||
).toJson(),
|
).toJson(),
|
||||||
);
|
);
|
||||||
@@ -163,6 +165,11 @@ const _kResponseMap = <SyncEntityType, Function(Object)>{
|
|||||||
SyncEntityType.memoryDeleteV1: SyncMemoryDeleteV1.fromJson,
|
SyncEntityType.memoryDeleteV1: SyncMemoryDeleteV1.fromJson,
|
||||||
SyncEntityType.memoryToAssetV1: SyncMemoryAssetV1.fromJson,
|
SyncEntityType.memoryToAssetV1: SyncMemoryAssetV1.fromJson,
|
||||||
SyncEntityType.memoryToAssetDeleteV1: SyncMemoryAssetDeleteV1.fromJson,
|
SyncEntityType.memoryToAssetDeleteV1: SyncMemoryAssetDeleteV1.fromJson,
|
||||||
|
SyncEntityType.stackV1: SyncStackV1.fromJson,
|
||||||
|
SyncEntityType.stackDeleteV1: SyncStackDeleteV1.fromJson,
|
||||||
|
SyncEntityType.partnerStackV1: SyncStackV1.fromJson,
|
||||||
|
SyncEntityType.partnerStackBackfillV1: SyncStackV1.fromJson,
|
||||||
|
SyncEntityType.partnerStackDeleteV1: SyncStackDeleteV1.fromJson,
|
||||||
};
|
};
|
||||||
|
|
||||||
class _SyncAckV1 {
|
class _SyncAckV1 {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.
|
|||||||
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
@@ -69,8 +70,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe('Error: SyncPartnerDeleteV1', error, stackTrace);
|
_logger.severe('Error: SyncPartnerDeleteV1', error, stack);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,8 +93,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe('Error: SyncPartnerV1', error, stackTrace);
|
_logger.severe('Error: SyncPartnerV1', error, stack);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,10 +105,10 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
await _db.remoteAssetEntity.deleteWhere(
|
await _db.remoteAssetEntity.deleteWhere(
|
||||||
(row) => row.id.isIn(data.map((error) => error.assetId)),
|
(row) => row.id.isIn(data.map((e) => e.assetId)),
|
||||||
);
|
);
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe('Error: deleteAssetsV1 - $debugLabel', error, stackTrace);
|
_logger.severe('Error: deleteAssetsV1 - $debugLabel', error, stack);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,8 +143,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe('Error: updateAssetsV1 - $debugLabel', error, stackTrace);
|
_logger.severe('Error: updateAssetsV1 - $debugLabel', error, stack);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,11 +187,11 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe(
|
_logger.severe(
|
||||||
'Error: updateAssetsExifV1 - $debugLabel',
|
'Error: updateAssetsExifV1 - $debugLabel',
|
||||||
error,
|
error,
|
||||||
stackTrace,
|
stack,
|
||||||
);
|
);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
@@ -201,8 +202,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
await _db.remoteAlbumEntity.deleteWhere(
|
await _db.remoteAlbumEntity.deleteWhere(
|
||||||
(row) => row.id.isIn(data.map((e) => e.albumId)),
|
(row) => row.id.isIn(data.map((e) => e.albumId)),
|
||||||
);
|
);
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe('Error: deleteAlbumsV1', error, stackTrace);
|
_logger.severe('Error: deleteAlbumsV1', error, stack);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,8 +230,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe('Error: updateAlbumsV1', error, stackTrace);
|
_logger.severe('Error: updateAlbumsV1', error, stack);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,8 +249,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe('Error: deleteAlbumUsersV1', error, stackTrace);
|
_logger.severe('Error: deleteAlbumUsersV1', error, stack);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,11 +276,11 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe(
|
_logger.severe(
|
||||||
'Error: updateAlbumUsersV1 - $debugLabel',
|
'Error: updateAlbumUsersV1 - $debugLabel',
|
||||||
error,
|
error,
|
||||||
stackTrace,
|
stack,
|
||||||
);
|
);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
@@ -300,8 +301,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe('Error: deleteAlbumToAssetsV1', error, stackTrace);
|
_logger.severe('Error: deleteAlbumToAssetsV1', error, stack);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,11 +326,11 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe(
|
_logger.severe(
|
||||||
'Error: updateAlbumToAssetsV1 - $debugLabel',
|
'Error: updateAlbumToAssetsV1 - $debugLabel',
|
||||||
error,
|
error,
|
||||||
stackTrace,
|
stack,
|
||||||
);
|
);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
@@ -359,8 +360,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe('Error: updateMemoriesV1', error, stackTrace);
|
_logger.severe('Error: updateMemoriesV1', error, stack);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -370,8 +371,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
await _db.memoryEntity.deleteWhere(
|
await _db.memoryEntity.deleteWhere(
|
||||||
(row) => row.id.isIn(data.map((e) => e.memoryId)),
|
(row) => row.id.isIn(data.map((e) => e.memoryId)),
|
||||||
);
|
);
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe('Error: deleteMemoriesV1', error, stackTrace);
|
_logger.severe('Error: deleteMemoriesV1', error, stack);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -392,8 +393,8 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe('Error: updateMemoryAssetsV1', error, stackTrace);
|
_logger.severe('Error: updateMemoryAssetsV1', error, stack);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -413,8 +414,49 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stack) {
|
||||||
_logger.severe('Error: deleteMemoryAssetsV1', error, stackTrace);
|
_logger.severe('Error: deleteMemoryAssetsV1', error, stack);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateStacksV1(
|
||||||
|
Iterable<SyncStackV1> data, {
|
||||||
|
String debugLabel = 'user',
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
await _db.batch((batch) {
|
||||||
|
for (final stack in data) {
|
||||||
|
final companion = StackEntityCompanion(
|
||||||
|
createdAt: Value(stack.createdAt),
|
||||||
|
updatedAt: Value(stack.updatedAt),
|
||||||
|
ownerId: Value(stack.ownerId),
|
||||||
|
primaryAssetId: Value(stack.primaryAssetId),
|
||||||
|
);
|
||||||
|
|
||||||
|
batch.insert(
|
||||||
|
_db.stackEntity,
|
||||||
|
companion.copyWith(id: Value(stack.id)),
|
||||||
|
onConflict: DoUpdate((_) => companion),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error, stack) {
|
||||||
|
_logger.severe('Error: updateStacksV1 - $debugLabel', error, stack);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteStacksV1(
|
||||||
|
Iterable<SyncStackDeleteV1> data, {
|
||||||
|
String debugLabel = 'user',
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
await _db.stackEntity.deleteWhere(
|
||||||
|
(row) => row.id.isIn(data.map((e) => e.stackId)),
|
||||||
|
);
|
||||||
|
} catch (error, stack) {
|
||||||
|
_logger.severe('Error: deleteStacksV1 - $debugLabel', error, stack);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -467,7 +509,7 @@ extension on String {
|
|||||||
Duration? toDuration() {
|
Duration? toDuration() {
|
||||||
try {
|
try {
|
||||||
final parts = split(':')
|
final parts = split(':')
|
||||||
.map((error) => double.parse(error).toInt())
|
.map((e) => double.parse(e).toInt())
|
||||||
.toList(growable: false);
|
.toList(growable: false);
|
||||||
|
|
||||||
return Duration(hours: parts[0], minutes: parts[1], seconds: parts[2]);
|
return Duration(hours: parts[0], minutes: parts[1], seconds: parts[2]);
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
).get();
|
).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<List<Bucket>> watchLocalBucket(
|
Stream<List<Bucket>> watchLocalAlbumBucket(
|
||||||
String albumId, {
|
String albumId, {
|
||||||
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
}) {
|
}) {
|
||||||
@@ -137,7 +137,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
}).watch();
|
}).watch();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<BaseAsset>> getLocalBucketAssets(
|
Future<List<BaseAsset>> getLocalAlbumBucketAssets(
|
||||||
String albumId, {
|
String albumId, {
|
||||||
required int offset,
|
required int offset,
|
||||||
required int count,
|
required int count,
|
||||||
@@ -158,7 +158,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<List<Bucket>> watchRemoteBucket(
|
Stream<List<Bucket>> watchRemoteAlbumBucket(
|
||||||
String albumId, {
|
String albumId, {
|
||||||
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
}) {
|
}) {
|
||||||
@@ -192,7 +192,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
}).watch();
|
}).watch();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<BaseAsset>> getRemoteBucketAssets(
|
Future<List<BaseAsset>> getRemoteAlbumBucketAssets(
|
||||||
String albumId, {
|
String albumId, {
|
||||||
required int offset,
|
required int offset,
|
||||||
required int count,
|
required int count,
|
||||||
@@ -213,6 +213,317 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
.map((row) => row.readTable(_db.remoteAssetEntity).toDto())
|
.map((row) => row.readTable(_db.remoteAssetEntity).toDto())
|
||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Stream<List<Bucket>> watchFavoriteBucket(
|
||||||
|
String userId, {
|
||||||
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
|
}) {
|
||||||
|
if (groupBy == GroupAssetsBy.none) {
|
||||||
|
return _db.remoteAssetEntity
|
||||||
|
.count(
|
||||||
|
where: (row) =>
|
||||||
|
row.isFavorite.equals(true) & row.ownerId.equals(userId),
|
||||||
|
)
|
||||||
|
.map(_generateBuckets)
|
||||||
|
.watchSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
final assetCountExp = _db.remoteAssetEntity.id.count();
|
||||||
|
final dateExp = _db.remoteAssetEntity.createdAt.dateFmt(groupBy);
|
||||||
|
|
||||||
|
final query = _db.remoteAssetEntity.selectOnly()
|
||||||
|
..addColumns([assetCountExp, dateExp])
|
||||||
|
..where(
|
||||||
|
_db.remoteAssetEntity.ownerId.equals(userId) &
|
||||||
|
_db.remoteAssetEntity.isFavorite.equals(true),
|
||||||
|
)
|
||||||
|
..groupBy([dateExp])
|
||||||
|
..orderBy([OrderingTerm.desc(dateExp)]);
|
||||||
|
|
||||||
|
return query.map((row) {
|
||||||
|
final timeline = row.read(dateExp)!.dateFmt(groupBy);
|
||||||
|
final assetCount = row.read(assetCountExp)!;
|
||||||
|
return TimeBucket(date: timeline, assetCount: assetCount);
|
||||||
|
}).watch();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<BaseAsset>> getFavoriteBucketAssets(
|
||||||
|
String userId, {
|
||||||
|
required int offset,
|
||||||
|
required int count,
|
||||||
|
}) {
|
||||||
|
final query = _db.remoteAssetEntity.select()
|
||||||
|
..where(
|
||||||
|
(row) => row.isFavorite.equals(true) & row.ownerId.equals(userId),
|
||||||
|
)
|
||||||
|
..orderBy([(row) => OrderingTerm.desc(row.createdAt)])
|
||||||
|
..limit(count, offset: offset);
|
||||||
|
|
||||||
|
return query.map((row) => row.toDto()).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<List<Bucket>> watchTrashBucket(
|
||||||
|
String userId, {
|
||||||
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
|
}) {
|
||||||
|
if (groupBy == GroupAssetsBy.none) {
|
||||||
|
return _db.remoteAssetEntity
|
||||||
|
.count(
|
||||||
|
where: (row) =>
|
||||||
|
row.deletedAt.isNotNull() & row.ownerId.equals(userId),
|
||||||
|
)
|
||||||
|
.map(_generateBuckets)
|
||||||
|
.watchSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
final assetCountExp = _db.remoteAssetEntity.id.count();
|
||||||
|
final dateExp = _db.remoteAssetEntity.createdAt.dateFmt(groupBy);
|
||||||
|
|
||||||
|
final query = _db.remoteAssetEntity.selectOnly()
|
||||||
|
..addColumns([assetCountExp, dateExp])
|
||||||
|
..where(
|
||||||
|
_db.remoteAssetEntity.ownerId.equals(userId) &
|
||||||
|
_db.remoteAssetEntity.deletedAt.isNotNull(),
|
||||||
|
)
|
||||||
|
..groupBy([dateExp])
|
||||||
|
..orderBy([OrderingTerm.desc(dateExp)]);
|
||||||
|
|
||||||
|
return query.map((row) {
|
||||||
|
final timeline = row.read(dateExp)!.dateFmt(groupBy);
|
||||||
|
final assetCount = row.read(assetCountExp)!;
|
||||||
|
return TimeBucket(date: timeline, assetCount: assetCount);
|
||||||
|
}).watch();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<BaseAsset>> getTrashBucketAssets(
|
||||||
|
String userId, {
|
||||||
|
required int offset,
|
||||||
|
required int count,
|
||||||
|
}) {
|
||||||
|
final query = _db.remoteAssetEntity.select()
|
||||||
|
..where(
|
||||||
|
(row) => row.deletedAt.isNotNull() & row.ownerId.equals(userId),
|
||||||
|
)
|
||||||
|
..orderBy([(row) => OrderingTerm.desc(row.createdAt)])
|
||||||
|
..limit(count, offset: offset);
|
||||||
|
|
||||||
|
return query.map((row) => row.toDto()).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<List<Bucket>> watchArchiveBucket(
|
||||||
|
String userId, {
|
||||||
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
|
}) {
|
||||||
|
if (groupBy == GroupAssetsBy.none) {
|
||||||
|
return _db.remoteAssetEntity
|
||||||
|
.count(
|
||||||
|
where: (row) =>
|
||||||
|
row.visibility.equalsValue(AssetVisibility.archive) &
|
||||||
|
row.ownerId.equals(userId),
|
||||||
|
)
|
||||||
|
.map(_generateBuckets)
|
||||||
|
.watchSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
final assetCountExp = _db.remoteAssetEntity.id.count();
|
||||||
|
final dateExp = _db.remoteAssetEntity.createdAt.dateFmt(groupBy);
|
||||||
|
|
||||||
|
final query = _db.remoteAssetEntity.selectOnly()
|
||||||
|
..addColumns([assetCountExp, dateExp])
|
||||||
|
..where(
|
||||||
|
_db.remoteAssetEntity.ownerId.equals(userId) &
|
||||||
|
_db.remoteAssetEntity.visibility
|
||||||
|
.equalsValue(AssetVisibility.archive),
|
||||||
|
)
|
||||||
|
..groupBy([dateExp])
|
||||||
|
..orderBy([OrderingTerm.desc(dateExp)]);
|
||||||
|
|
||||||
|
return query.map((row) {
|
||||||
|
final timeline = row.read(dateExp)!.dateFmt(groupBy);
|
||||||
|
final assetCount = row.read(assetCountExp)!;
|
||||||
|
return TimeBucket(date: timeline, assetCount: assetCount);
|
||||||
|
}).watch();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<BaseAsset>> getArchiveBucketAssets(
|
||||||
|
String userId, {
|
||||||
|
required int offset,
|
||||||
|
required int count,
|
||||||
|
}) {
|
||||||
|
final query = _db.remoteAssetEntity.select()
|
||||||
|
..where(
|
||||||
|
(row) =>
|
||||||
|
row.ownerId.equals(userId) &
|
||||||
|
row.visibility.equalsValue(AssetVisibility.archive),
|
||||||
|
)
|
||||||
|
..orderBy([(row) => OrderingTerm.desc(row.createdAt)])
|
||||||
|
..limit(count, offset: offset);
|
||||||
|
|
||||||
|
return query.map((row) => row.toDto()).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<List<Bucket>> watchLockedFolderBucket(
|
||||||
|
String userId, {
|
||||||
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
|
}) {
|
||||||
|
if (groupBy == GroupAssetsBy.none) {
|
||||||
|
return _db.remoteAssetEntity
|
||||||
|
.count(
|
||||||
|
where: (row) =>
|
||||||
|
row.visibility.equalsValue(AssetVisibility.locked) &
|
||||||
|
row.ownerId.equals(userId),
|
||||||
|
)
|
||||||
|
.map(_generateBuckets)
|
||||||
|
.watchSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
final assetCountExp = _db.remoteAssetEntity.id.count();
|
||||||
|
final dateExp = _db.remoteAssetEntity.createdAt.dateFmt(groupBy);
|
||||||
|
|
||||||
|
final query = _db.remoteAssetEntity.selectOnly()
|
||||||
|
..addColumns([assetCountExp, dateExp])
|
||||||
|
..where(
|
||||||
|
_db.remoteAssetEntity.ownerId.equals(userId) &
|
||||||
|
_db.remoteAssetEntity.visibility
|
||||||
|
.equalsValue(AssetVisibility.locked),
|
||||||
|
)
|
||||||
|
..groupBy([dateExp])
|
||||||
|
..orderBy([OrderingTerm.desc(dateExp)]);
|
||||||
|
|
||||||
|
return query.map((row) {
|
||||||
|
final timeline = row.read(dateExp)!.dateFmt(groupBy);
|
||||||
|
final assetCount = row.read(assetCountExp)!;
|
||||||
|
return TimeBucket(date: timeline, assetCount: assetCount);
|
||||||
|
}).watch();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<BaseAsset>> getLockedFolderBucketAssets(
|
||||||
|
String userId, {
|
||||||
|
required int offset,
|
||||||
|
required int count,
|
||||||
|
}) {
|
||||||
|
final query = _db.remoteAssetEntity.select()
|
||||||
|
..where(
|
||||||
|
(row) =>
|
||||||
|
row.visibility.equalsValue(AssetVisibility.locked) &
|
||||||
|
row.ownerId.equals(userId),
|
||||||
|
)
|
||||||
|
..orderBy([(row) => OrderingTerm.desc(row.createdAt)])
|
||||||
|
..limit(count, offset: offset);
|
||||||
|
|
||||||
|
return query.map((row) => row.toDto()).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<List<Bucket>> watchVideoBucket(
|
||||||
|
String userId, {
|
||||||
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
|
}) {
|
||||||
|
if (groupBy == GroupAssetsBy.none) {
|
||||||
|
return _db.remoteAssetEntity
|
||||||
|
.count(
|
||||||
|
where: (row) =>
|
||||||
|
row.type.equalsValue(AssetType.video) &
|
||||||
|
row.visibility.equalsValue(AssetVisibility.timeline) &
|
||||||
|
row.ownerId.equals(userId),
|
||||||
|
)
|
||||||
|
.map(_generateBuckets)
|
||||||
|
.watchSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
final assetCountExp = _db.remoteAssetEntity.id.count();
|
||||||
|
final dateExp = _db.remoteAssetEntity.createdAt.dateFmt(groupBy);
|
||||||
|
|
||||||
|
final query = _db.remoteAssetEntity.selectOnly()
|
||||||
|
..addColumns([assetCountExp, dateExp])
|
||||||
|
..where(
|
||||||
|
_db.remoteAssetEntity.ownerId.equals(userId) &
|
||||||
|
_db.remoteAssetEntity.type.equalsValue(AssetType.video) &
|
||||||
|
_db.remoteAssetEntity.visibility
|
||||||
|
.equalsValue(AssetVisibility.timeline),
|
||||||
|
)
|
||||||
|
..groupBy([dateExp])
|
||||||
|
..orderBy([OrderingTerm.desc(dateExp)]);
|
||||||
|
|
||||||
|
return query.map((row) {
|
||||||
|
final timeline = row.read(dateExp)!.dateFmt(groupBy);
|
||||||
|
final assetCount = row.read(assetCountExp)!;
|
||||||
|
return TimeBucket(date: timeline, assetCount: assetCount);
|
||||||
|
}).watch();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<BaseAsset>> getVideoBucketAssets(
|
||||||
|
String userId, {
|
||||||
|
required int offset,
|
||||||
|
required int count,
|
||||||
|
}) {
|
||||||
|
final query = _db.remoteAssetEntity.select()
|
||||||
|
..where(
|
||||||
|
(row) =>
|
||||||
|
_db.remoteAssetEntity.type.equalsValue(AssetType.video) &
|
||||||
|
_db.remoteAssetEntity.visibility
|
||||||
|
.equalsValue(AssetVisibility.timeline) &
|
||||||
|
_db.remoteAssetEntity.ownerId.equals(userId),
|
||||||
|
)
|
||||||
|
..orderBy([(row) => OrderingTerm.desc(row.createdAt)])
|
||||||
|
..limit(count, offset: offset);
|
||||||
|
|
||||||
|
return query.map((row) => row.toDto()).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<List<Bucket>> watchRemoteBucket(
|
||||||
|
List<String> userIds, {
|
||||||
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
|
}) {
|
||||||
|
if (groupBy == GroupAssetsBy.none) {
|
||||||
|
return _db.remoteAssetEntity
|
||||||
|
.count(
|
||||||
|
where: (row) =>
|
||||||
|
row.deletedAt.isNull() &
|
||||||
|
row.visibility.equalsValue(AssetVisibility.timeline) &
|
||||||
|
row.ownerId.isIn(userIds),
|
||||||
|
)
|
||||||
|
.map(_generateBuckets)
|
||||||
|
.watchSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
final assetCountExp = _db.remoteAssetEntity.id.count();
|
||||||
|
final dateExp = _db.remoteAssetEntity.createdAt.dateFmt(groupBy);
|
||||||
|
|
||||||
|
final query = _db.remoteAssetEntity.selectOnly()
|
||||||
|
..addColumns([assetCountExp, dateExp])
|
||||||
|
..where(
|
||||||
|
_db.remoteAssetEntity.deletedAt.isNull() &
|
||||||
|
_db.remoteAssetEntity.visibility
|
||||||
|
.equalsValue(AssetVisibility.timeline) &
|
||||||
|
_db.remoteAssetEntity.ownerId.isIn(userIds),
|
||||||
|
)
|
||||||
|
..groupBy([dateExp])
|
||||||
|
..orderBy([OrderingTerm.desc(dateExp)]);
|
||||||
|
|
||||||
|
return query.map((row) {
|
||||||
|
final timeline = row.read(dateExp)!.dateFmt(groupBy);
|
||||||
|
final assetCount = row.read(assetCountExp)!;
|
||||||
|
return TimeBucket(date: timeline, assetCount: assetCount);
|
||||||
|
}).watch();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<BaseAsset>> getRemoteBucketAssets(
|
||||||
|
List<String> userIds, {
|
||||||
|
required int offset,
|
||||||
|
required int count,
|
||||||
|
}) {
|
||||||
|
final query = _db.remoteAssetEntity.select()
|
||||||
|
..where(
|
||||||
|
(row) =>
|
||||||
|
row.deletedAt.isNull() &
|
||||||
|
row.visibility.equalsValue(AssetVisibility.timeline) &
|
||||||
|
row.ownerId.isIn(userIds),
|
||||||
|
)
|
||||||
|
..orderBy([(t) => OrderingTerm.desc(t.createdAt)])
|
||||||
|
..limit(count, offset: offset);
|
||||||
|
|
||||||
|
return query.map((row) => row.toDto()).get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension on Expression<DateTime> {
|
extension on Expression<DateTime> {
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class TabShellPage extends ConsumerWidget {
|
|||||||
const MainTimelineRoute(),
|
const MainTimelineRoute(),
|
||||||
SearchRoute(),
|
SearchRoute(),
|
||||||
const DriftAlbumsRoute(),
|
const DriftAlbumsRoute(),
|
||||||
const LibraryRoute(),
|
const DriftLibraryRoute(),
|
||||||
],
|
],
|
||||||
duration: const Duration(milliseconds: 600),
|
duration: const Duration(milliseconds: 600),
|
||||||
transitionBuilder: (context, child, animation) => FadeTransition(
|
transitionBuilder: (context, child, animation) => FadeTransition(
|
||||||
|
|||||||
33
mobile/lib/presentation/pages/dev/drift_archive.page.dart
Normal file
33
mobile/lib/presentation/pages/dev/drift_archive.page.dart
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class DriftArchivePage extends StatelessWidget {
|
||||||
|
const DriftArchivePage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
timelineServiceProvider.overrideWith(
|
||||||
|
(ref) {
|
||||||
|
final user = ref.watch(currentUserProvider);
|
||||||
|
if (user == null) {
|
||||||
|
throw Exception('User must be logged in to access archive');
|
||||||
|
}
|
||||||
|
|
||||||
|
final timelineService =
|
||||||
|
ref.watch(timelineFactoryProvider).archive(user.id);
|
||||||
|
ref.onDispose(timelineService.dispose);
|
||||||
|
return timelineService;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: const Timeline(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
mobile/lib/presentation/pages/dev/drift_favorite.page.dart
Normal file
33
mobile/lib/presentation/pages/dev/drift_favorite.page.dart
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class DriftFavoritePage extends StatelessWidget {
|
||||||
|
const DriftFavoritePage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
timelineServiceProvider.overrideWith(
|
||||||
|
(ref) {
|
||||||
|
final user = ref.watch(currentUserProvider);
|
||||||
|
if (user == null) {
|
||||||
|
throw Exception('User must be logged in to access favorite');
|
||||||
|
}
|
||||||
|
|
||||||
|
final timelineService =
|
||||||
|
ref.watch(timelineFactoryProvider).favorite(user.id);
|
||||||
|
ref.onDispose(timelineService.dispose);
|
||||||
|
return timelineService;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: const Timeline(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class DriftLockedFolderPage extends StatelessWidget {
|
||||||
|
const DriftLockedFolderPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
timelineServiceProvider.overrideWith(
|
||||||
|
(ref) {
|
||||||
|
final user = ref.watch(currentUserProvider);
|
||||||
|
if (user == null) {
|
||||||
|
throw Exception('User must be logged in to access locked folder');
|
||||||
|
}
|
||||||
|
|
||||||
|
final timelineService =
|
||||||
|
ref.watch(timelineFactoryProvider).lockedFolder(user.id);
|
||||||
|
ref.onDispose(timelineService.dispose);
|
||||||
|
return timelineService;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: const Timeline(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
mobile/lib/presentation/pages/dev/drift_trash.page.dart
Normal file
33
mobile/lib/presentation/pages/dev/drift_trash.page.dart
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class DriftTrashPage extends StatelessWidget {
|
||||||
|
const DriftTrashPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
timelineServiceProvider.overrideWith(
|
||||||
|
(ref) {
|
||||||
|
final user = ref.watch(currentUserProvider);
|
||||||
|
if (user == null) {
|
||||||
|
throw Exception('User must be logged in to access trash');
|
||||||
|
}
|
||||||
|
|
||||||
|
final timelineService =
|
||||||
|
ref.watch(timelineFactoryProvider).trash(user.id);
|
||||||
|
ref.onDispose(timelineService.dispose);
|
||||||
|
return timelineService;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: const Timeline(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
mobile/lib/presentation/pages/dev/drift_video.page.dart
Normal file
33
mobile/lib/presentation/pages/dev/drift_video.page.dart
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class DriftVideoPage extends StatelessWidget {
|
||||||
|
const DriftVideoPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
timelineServiceProvider.overrideWith(
|
||||||
|
(ref) {
|
||||||
|
final user = ref.watch(currentUserProvider);
|
||||||
|
if (user == null) {
|
||||||
|
throw Exception('User must be logged in to video');
|
||||||
|
}
|
||||||
|
|
||||||
|
final timelineService =
|
||||||
|
ref.watch(timelineFactoryProvider).video(user.id);
|
||||||
|
ref.onDispose(timelineService.dispose);
|
||||||
|
return timelineService;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: const Timeline(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,15 +5,43 @@ import 'package:drift/drift.dart' hide Column;
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
||||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
|
|
||||||
final _features = [
|
final _features = [
|
||||||
|
_Feature(
|
||||||
|
name: 'Selection Mode Timeline',
|
||||||
|
icon: Icons.developer_mode_rounded,
|
||||||
|
onTap: (ctx, ref) async {
|
||||||
|
final user = ref.watch(currentUserProvider);
|
||||||
|
if (user == null) {
|
||||||
|
return Future.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
final assets =
|
||||||
|
await ref.read(remoteAssetRepositoryProvider).getSome(user.id);
|
||||||
|
|
||||||
|
final selectedAssets = await ctx.pushRoute<Set<BaseAsset>>(
|
||||||
|
DriftAssetSelectionTimelineRoute(
|
||||||
|
lockedSelectionAssets: assets.toSet(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
DLog.log(
|
||||||
|
"Selected ${selectedAssets?.length ?? 0} assets",
|
||||||
|
);
|
||||||
|
|
||||||
|
return Future.value();
|
||||||
|
},
|
||||||
|
),
|
||||||
_Feature(
|
_Feature(
|
||||||
name: 'Sync Local',
|
name: 'Sync Local',
|
||||||
icon: Icons.photo_album_rounded,
|
icon: Icons.photo_album_rounded,
|
||||||
@@ -66,6 +94,9 @@ final _features = [
|
|||||||
await db.remoteAlbumEntity.deleteAll();
|
await db.remoteAlbumEntity.deleteAll();
|
||||||
await db.remoteAlbumUserEntity.deleteAll();
|
await db.remoteAlbumUserEntity.deleteAll();
|
||||||
await db.remoteAlbumAssetEntity.deleteAll();
|
await db.remoteAlbumAssetEntity.deleteAll();
|
||||||
|
await db.memoryEntity.deleteAll();
|
||||||
|
await db.memoryAssetEntity.deleteAll();
|
||||||
|
await db.stackEntity.deleteAll();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
_Feature(
|
_Feature(
|
||||||
@@ -96,6 +127,11 @@ final _features = [
|
|||||||
icon: Icons.timeline_rounded,
|
icon: Icons.timeline_rounded,
|
||||||
onTap: (ctx, _) => ctx.pushRoute(const TabShellRoute()),
|
onTap: (ctx, _) => ctx.pushRoute(const TabShellRoute()),
|
||||||
),
|
),
|
||||||
|
_Feature(
|
||||||
|
name: 'Video',
|
||||||
|
icon: Icons.video_collection_outlined,
|
||||||
|
onTap: (ctx, _) => ctx.pushRoute(const DriftVideoRoute()),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
|
|||||||
@@ -162,6 +162,10 @@ final _remoteStats = [
|
|||||||
name: 'Memories Assets',
|
name: 'Memories Assets',
|
||||||
load: (db) => db.managers.memoryAssetEntity.count(),
|
load: (db) => db.managers.memoryAssetEntity.count(),
|
||||||
),
|
),
|
||||||
|
_Stat(
|
||||||
|
name: 'Stacks',
|
||||||
|
load: (db) => db.managers.stackEntity.count(),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class DriftAssetSelectionTimelinePage extends ConsumerWidget {
|
||||||
|
final Set<BaseAsset> lockedSelectionAssets;
|
||||||
|
const DriftAssetSelectionTimelinePage({
|
||||||
|
super.key,
|
||||||
|
this.lockedSelectionAssets = const {},
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
multiSelectProvider.overrideWith(
|
||||||
|
() => MultiSelectNotifier(
|
||||||
|
MultiSelectState(
|
||||||
|
selectedAssets: {},
|
||||||
|
lockedSelectionAssets: lockedSelectionAssets,
|
||||||
|
forceEnable: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
timelineServiceProvider.overrideWith(
|
||||||
|
(ref) {
|
||||||
|
final timelineUsers =
|
||||||
|
ref.watch(timelineUsersProvider).valueOrNull ?? [];
|
||||||
|
final timelineService =
|
||||||
|
ref.watch(timelineFactoryProvider).remoteAssets(timelineUsers);
|
||||||
|
ref.onDispose(timelineService.dispose);
|
||||||
|
return timelineService;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: const Timeline(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
501
mobile/lib/presentation/pages/drift_library.page.dart
Normal file
501
mobile/lib/presentation/pages/drift_library.page.dart
Normal file
@@ -0,0 +1,501 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
|
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/providers/album/album.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/partner.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/search/people.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
|
import 'package:immich_mobile/utils/image_url_builder.dart';
|
||||||
|
import 'package:immich_mobile/widgets/album/album_thumbnail_card.dart';
|
||||||
|
import 'package:immich_mobile/widgets/common/immich_sliver_app_bar.dart';
|
||||||
|
import 'package:immich_mobile/widgets/common/user_avatar.dart';
|
||||||
|
import 'package:immich_mobile/widgets/map/map_thumbnail.dart';
|
||||||
|
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class DriftLibraryPage extends ConsumerWidget {
|
||||||
|
const DriftLibraryPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return const Scaffold(
|
||||||
|
body: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
ImmichSliverAppBar(),
|
||||||
|
_ActionButtonGrid(),
|
||||||
|
_CollectionCards(),
|
||||||
|
_QuickAccessButtonList(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ActionButtonGrid extends ConsumerWidget {
|
||||||
|
const _ActionButtonGrid();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final isTrashEnable = ref.watch(
|
||||||
|
serverInfoProvider.select((state) => state.serverFeatures.trash),
|
||||||
|
);
|
||||||
|
|
||||||
|
return SliverPadding(
|
||||||
|
padding: const EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 12),
|
||||||
|
sliver: SliverToBoxAdapter(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
_ActionButton(
|
||||||
|
icon: Icons.favorite_outline_rounded,
|
||||||
|
onTap: () => context.pushRoute(const DriftFavoriteRoute()),
|
||||||
|
label: 'favorites'.t(context: context),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
_ActionButton(
|
||||||
|
icon: Icons.archive_outlined,
|
||||||
|
onTap: () => context.pushRoute(const DriftArchiveRoute()),
|
||||||
|
label: 'archived'.t(context: context),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
_ActionButton(
|
||||||
|
icon: Icons.link_outlined,
|
||||||
|
onTap: () => context.pushRoute(const SharedLinkRoute()),
|
||||||
|
label: 'shared_links'.t(context: context),
|
||||||
|
),
|
||||||
|
isTrashEnable
|
||||||
|
? const SizedBox(width: 8)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
isTrashEnable
|
||||||
|
? _ActionButton(
|
||||||
|
icon: Icons.delete_outline_rounded,
|
||||||
|
onTap: () => context.pushRoute(const DriftTrashRoute()),
|
||||||
|
label: 'trash'.t(context: context),
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ActionButton extends StatelessWidget {
|
||||||
|
const _ActionButton({
|
||||||
|
required this.icon,
|
||||||
|
required this.onTap,
|
||||||
|
required this.label,
|
||||||
|
});
|
||||||
|
|
||||||
|
final IconData icon;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final String label;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Expanded(
|
||||||
|
child: FilledButton.icon(
|
||||||
|
onPressed: onTap,
|
||||||
|
label: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 4.0),
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
color: context.colorScheme.onSurface,
|
||||||
|
fontSize: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
style: FilledButton.styleFrom(
|
||||||
|
elevation: 0,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
|
||||||
|
backgroundColor: context.colorScheme.surfaceContainerLow,
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(25)),
|
||||||
|
side: BorderSide(
|
||||||
|
color: context.colorScheme.onSurface.withAlpha(10),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
icon: Icon(
|
||||||
|
icon,
|
||||||
|
color: context.primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CollectionCards extends StatelessWidget {
|
||||||
|
const _CollectionCards();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const SliverPadding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
sliver: SliverToBoxAdapter(
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
runSpacing: 8,
|
||||||
|
children: [
|
||||||
|
_PeopleCollectionCard(),
|
||||||
|
_PlacesCollectionCard(),
|
||||||
|
_LocalAlbumsCollectionCard(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PeopleCollectionCard extends ConsumerWidget {
|
||||||
|
const _PeopleCollectionCard();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final people = ref.watch(getAllPeopleProvider);
|
||||||
|
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
final isTablet = constraints.maxWidth > 600;
|
||||||
|
final widthFactor = isTablet ? 0.25 : 0.5;
|
||||||
|
final size = context.width * widthFactor - 20.0;
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => context.pushRoute(const PeopleCollectionRoute()),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: size,
|
||||||
|
width: size,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: const BorderRadius.all(
|
||||||
|
Radius.circular(20),
|
||||||
|
),
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: [
|
||||||
|
context.colorScheme.primary.withAlpha(30),
|
||||||
|
context.colorScheme.primary.withAlpha(25),
|
||||||
|
],
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: people.widgetWhen(
|
||||||
|
onLoading: () => const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
onData: (people) {
|
||||||
|
return GridView.count(
|
||||||
|
crossAxisCount: 2,
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
crossAxisSpacing: 8,
|
||||||
|
mainAxisSpacing: 8,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
children: people.take(4).map((person) {
|
||||||
|
return CircleAvatar(
|
||||||
|
backgroundImage: NetworkImage(
|
||||||
|
getFaceThumbnailUrl(person.id),
|
||||||
|
headers: ApiService.getRequestHeaders(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'people'.t(context: context),
|
||||||
|
style: context.textTheme.titleSmall?.copyWith(
|
||||||
|
color: context.colorScheme.onSurface,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PlacesCollectionCard extends StatelessWidget {
|
||||||
|
const _PlacesCollectionCard();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
final isTablet = constraints.maxWidth > 600;
|
||||||
|
final widthFactor = isTablet ? 0.25 : 0.5;
|
||||||
|
final size = context.width * widthFactor - 20.0;
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => context.pushRoute(
|
||||||
|
PlacesCollectionRoute(
|
||||||
|
currentLocation: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: size,
|
||||||
|
width: size,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||||
|
color:
|
||||||
|
context.colorScheme.secondaryContainer.withAlpha(100),
|
||||||
|
),
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: MapThumbnail(
|
||||||
|
zoom: 8,
|
||||||
|
centre: const LatLng(
|
||||||
|
21.44950,
|
||||||
|
-157.91959,
|
||||||
|
),
|
||||||
|
showAttribution: false,
|
||||||
|
themeMode: context.isDarkTheme
|
||||||
|
? ThemeMode.dark
|
||||||
|
: ThemeMode.light,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'places'.t(),
|
||||||
|
style: context.textTheme.titleSmall?.copyWith(
|
||||||
|
color: context.colorScheme.onSurface,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LocalAlbumsCollectionCard extends ConsumerWidget {
|
||||||
|
const _LocalAlbumsCollectionCard();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
// TODO: Migrate to the drift after local album page
|
||||||
|
final albums = ref.watch(localAlbumsProvider);
|
||||||
|
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
final isTablet = constraints.maxWidth > 600;
|
||||||
|
final widthFactor = isTablet ? 0.25 : 0.5;
|
||||||
|
final size = context.width * widthFactor - 20.0;
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => context.pushRoute(
|
||||||
|
const LocalAlbumsRoute(),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: size,
|
||||||
|
width: size,
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: [
|
||||||
|
context.colorScheme.primary.withAlpha(30),
|
||||||
|
context.colorScheme.primary.withAlpha(25),
|
||||||
|
],
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: GridView.count(
|
||||||
|
crossAxisCount: 2,
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
crossAxisSpacing: 8,
|
||||||
|
mainAxisSpacing: 8,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
children: albums.take(4).map((album) {
|
||||||
|
return AlbumThumbnailCard(
|
||||||
|
album: album,
|
||||||
|
showTitle: false,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'on_this_device'.t(context: context),
|
||||||
|
style: context.textTheme.titleSmall?.copyWith(
|
||||||
|
color: context.colorScheme.onSurface,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _QuickAccessButtonList extends ConsumerWidget {
|
||||||
|
const _QuickAccessButtonList();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final partners = ref.watch(partnerSharedWithProvider);
|
||||||
|
|
||||||
|
return SliverPadding(
|
||||||
|
padding: const EdgeInsets.only(left: 16, top: 12, right: 16, bottom: 32),
|
||||||
|
sliver: SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: context.colorScheme.onSurface.withAlpha(10),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
borderRadius: const BorderRadius.all(
|
||||||
|
Radius.circular(20),
|
||||||
|
),
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: [
|
||||||
|
context.colorScheme.primary.withAlpha(10),
|
||||||
|
context.colorScheme.primary.withAlpha(15),
|
||||||
|
context.colorScheme.primary.withAlpha(20),
|
||||||
|
],
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: ListView(
|
||||||
|
shrinkWrap: true,
|
||||||
|
padding: const EdgeInsets.all(0),
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: const Radius.circular(20),
|
||||||
|
topRight: const Radius.circular(20),
|
||||||
|
bottomLeft: Radius.circular(partners.isEmpty ? 20 : 0),
|
||||||
|
bottomRight: Radius.circular(partners.isEmpty ? 20 : 0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
leading: const Icon(
|
||||||
|
Icons.folder_outlined,
|
||||||
|
size: 26,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'folders'.t(context: context),
|
||||||
|
style: context.textTheme.titleSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () => context.pushRoute(FolderRoute()),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(
|
||||||
|
Icons.lock_outline_rounded,
|
||||||
|
size: 26,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'locked_folder'.t(context: context),
|
||||||
|
style: context.textTheme.titleSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// TODO: PIN code is needed
|
||||||
|
onTap: () => context.pushRoute(const DriftLockedFolderRoute()),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(
|
||||||
|
Icons.group_outlined,
|
||||||
|
size: 26,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'partners'.t(context: context),
|
||||||
|
style: context.textTheme.titleSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () => context.pushRoute(const PartnerRoute()),
|
||||||
|
),
|
||||||
|
_PartnerList(partners: partners),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PartnerList extends StatelessWidget {
|
||||||
|
const _PartnerList({required this.partners});
|
||||||
|
|
||||||
|
final List<UserDto> partners;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListView.builder(
|
||||||
|
padding: const EdgeInsets.all(0),
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: partners.length,
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final partner = partners[index];
|
||||||
|
final isLastItem = index == partners.length - 1;
|
||||||
|
return ListTile(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(isLastItem ? 20 : 0),
|
||||||
|
bottomRight: Radius.circular(isLastItem ? 20 : 0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsets.only(
|
||||||
|
left: 12.0,
|
||||||
|
right: 18.0,
|
||||||
|
),
|
||||||
|
leading: userAvatar(context, partner, radius: 16),
|
||||||
|
title: const Text(
|
||||||
|
"partner_list_user_photos",
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
).t(context: context, args: {'user': partner.name}),
|
||||||
|
onTap: () => context.pushRoute(PartnerDetailRoute(partner: partner)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
import 'dart:convert' hide Codec;
|
|
||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:thumbhash/thumbhash.dart';
|
|
||||||
|
|
||||||
class ThumbHashProvider extends ImageProvider<ThumbHashProvider> {
|
|
||||||
final String thumbHash;
|
|
||||||
|
|
||||||
const ThumbHashProvider({
|
|
||||||
required this.thumbHash,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<ThumbHashProvider> obtainKey(ImageConfiguration configuration) {
|
|
||||||
return SynchronousFuture(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
ImageStreamCompleter loadImage(
|
|
||||||
ThumbHashProvider key,
|
|
||||||
ImageDecoderCallback decode,
|
|
||||||
) {
|
|
||||||
return MultiFrameImageStreamCompleter(
|
|
||||||
codec: _loadCodec(key, decode),
|
|
||||||
scale: 1.0,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Codec> _loadCodec(
|
|
||||||
ThumbHashProvider key,
|
|
||||||
ImageDecoderCallback decode,
|
|
||||||
) async {
|
|
||||||
final image = thumbHashToRGBA(base64Decode(key.thumbHash));
|
|
||||||
return decode(await ImmutableBuffer.fromUint8List(rgbaToBmp(image)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
if (identical(this, other)) return true;
|
|
||||||
if (other is ThumbHashProvider) {
|
|
||||||
return thumbHash == other.thumbHash;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => thumbHash.hashCode;
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
|
import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/images/thumb_hash_provider.dart';
|
import 'package:immich_mobile/widgets/common/thumbhash.dart';
|
||||||
import 'package:immich_mobile/widgets/asset_grid/thumbnail_placeholder.dart';
|
|
||||||
import 'package:immich_mobile/widgets/common/fade_in_placeholder_image.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:octo_image/octo_image.dart';
|
import 'package:octo_image/octo_image.dart';
|
||||||
|
|
||||||
@@ -56,13 +54,7 @@ OctoPlaceholderBuilder _blurHashPlaceholderBuilder(
|
|||||||
String? thumbHash, {
|
String? thumbHash, {
|
||||||
BoxFit? fit,
|
BoxFit? fit,
|
||||||
}) {
|
}) {
|
||||||
return (context) => thumbHash == null
|
return (context) => Thumbhash(blurhash: thumbHash, fit: fit ?? BoxFit.cover);
|
||||||
? const ThumbnailPlaceholder()
|
|
||||||
: FadeInPlaceholderImage(
|
|
||||||
placeholder: const ThumbnailPlaceholder(),
|
|
||||||
image: ThumbHashProvider(thumbHash: thumbHash),
|
|
||||||
fit: fit ?? BoxFit.cover,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OctoErrorBuilder _blurHashErrorBuilder(
|
OctoErrorBuilder _blurHashErrorBuilder(
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class ThumbnailTile extends ConsumerWidget {
|
|||||||
this.size = const Size.square(256),
|
this.size = const Size.square(256),
|
||||||
this.fit = BoxFit.cover,
|
this.fit = BoxFit.cover,
|
||||||
this.showStorageIndicator = true,
|
this.showStorageIndicator = true,
|
||||||
this.canDeselect = true,
|
this.lockSelection = false,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -20,15 +20,13 @@ class ThumbnailTile extends ConsumerWidget {
|
|||||||
final Size size;
|
final Size size;
|
||||||
final BoxFit fit;
|
final BoxFit fit;
|
||||||
final bool showStorageIndicator;
|
final bool showStorageIndicator;
|
||||||
|
final bool lockSelection;
|
||||||
/// If we are allowed to deselect this image
|
|
||||||
final bool canDeselect;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final assetContainerColor = context.isDarkTheme
|
final assetContainerColor = context.isDarkTheme
|
||||||
? context.primaryColor.darken(amount: 0.6)
|
? context.primaryColor.darken(amount: 0.4)
|
||||||
: context.primaryColor.lighten(amount: 0.8);
|
: context.primaryColor.lighten(amount: 0.75);
|
||||||
|
|
||||||
final isSelected = ref.watch(
|
final isSelected = ref.watch(
|
||||||
multiSelectProvider.select(
|
multiSelectProvider.select(
|
||||||
@@ -36,24 +34,29 @@ class ThumbnailTile extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final borderStyle = lockSelection
|
||||||
|
? BoxDecoration(
|
||||||
|
color: context.colorScheme.surfaceContainerHighest,
|
||||||
|
border: Border.all(
|
||||||
|
color: context.colorScheme.surfaceContainerHighest,
|
||||||
|
width: 6,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: isSelected
|
||||||
|
? BoxDecoration(
|
||||||
|
color: assetContainerColor,
|
||||||
|
border: Border.all(color: assetContainerColor, width: 6),
|
||||||
|
)
|
||||||
|
: const BoxDecoration();
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
AnimatedContainer(
|
AnimatedContainer(
|
||||||
duration: Durations.short4,
|
duration: Durations.short4,
|
||||||
curve: Curves.decelerate,
|
curve: Curves.decelerate,
|
||||||
decoration: BoxDecoration(
|
decoration: borderStyle,
|
||||||
color: isSelected
|
|
||||||
? (canDeselect ? assetContainerColor : Colors.grey)
|
|
||||||
: null,
|
|
||||||
border: isSelected
|
|
||||||
? Border.all(
|
|
||||||
color: canDeselect ? assetContainerColor : Colors.grey,
|
|
||||||
width: 8,
|
|
||||||
)
|
|
||||||
: const Border(),
|
|
||||||
),
|
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: isSelected
|
borderRadius: isSelected || lockSelection
|
||||||
? const BorderRadius.all(Radius.circular(15.0))
|
? const BorderRadius.all(Radius.circular(15.0))
|
||||||
: BorderRadius.zero,
|
: BorderRadius.zero,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
@@ -102,14 +105,17 @@ class ThumbnailTile extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (isSelected)
|
if (isSelected || lockSelection)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(3.0),
|
padding: const EdgeInsets.all(3.0),
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.topLeft,
|
alignment: Alignment.topLeft,
|
||||||
child: _SelectionIndicator(
|
child: _SelectionIndicator(
|
||||||
isSelected: isSelected,
|
isSelected: isSelected,
|
||||||
color: assetContainerColor,
|
isLocked: lockSelection,
|
||||||
|
color: lockSelection
|
||||||
|
? context.colorScheme.surfaceContainerHighest
|
||||||
|
: assetContainerColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -120,15 +126,29 @@ class ThumbnailTile extends ConsumerWidget {
|
|||||||
|
|
||||||
class _SelectionIndicator extends StatelessWidget {
|
class _SelectionIndicator extends StatelessWidget {
|
||||||
final bool isSelected;
|
final bool isSelected;
|
||||||
|
final bool isLocked;
|
||||||
final Color? color;
|
final Color? color;
|
||||||
|
|
||||||
const _SelectionIndicator({
|
const _SelectionIndicator({
|
||||||
required this.isSelected,
|
required this.isSelected,
|
||||||
|
required this.isLocked,
|
||||||
this.color,
|
this.color,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (isSelected) {
|
if (isLocked) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: color,
|
||||||
|
),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.check_circle_rounded,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (isSelected) {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
|||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/images/full_image.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/images/full_image.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
|
import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
|
||||||
import 'package:immich_mobile/utils/hooks/blurhash_hook.dart';
|
import 'package:immich_mobile/widgets/common/thumbhash.dart';
|
||||||
|
|
||||||
class DriftMemoryCard extends StatelessWidget {
|
class DriftMemoryCard extends StatelessWidget {
|
||||||
final RemoteAsset asset;
|
final RemoteAsset asset;
|
||||||
@@ -117,43 +117,29 @@ class _BlurredBackdrop extends HookWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final blurhash = useDriftBlurHashRef(asset).value;
|
final blurhash = asset.thumbHash;
|
||||||
if (blurhash != null) {
|
if (blurhash != null) {
|
||||||
// Use a nice cheap blur hash image decoration
|
// Use a nice cheap blur hash image decoration
|
||||||
return Container(
|
return Thumbhash(blurhash: blurhash, fit: BoxFit.cover);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to using a more expensive image filtered
|
||||||
|
// Since the ImmichImage is already precached, we can
|
||||||
|
// safely use that as the image provider
|
||||||
|
return ImageFiltered(
|
||||||
|
imageFilter: ImageFilter.blur(sigmaX: 30, sigmaY: 30),
|
||||||
|
child: DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
image: MemoryImage(
|
image: getFullImageProvider(
|
||||||
blurhash,
|
asset,
|
||||||
|
size: Size(context.width, context.height),
|
||||||
),
|
),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Container(
|
child: const ColoredBox(color: Color.fromRGBO(0, 0, 0, 0.2)),
|
||||||
color: Colors.black.withValues(alpha: 0.2),
|
),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Fall back to using a more expensive image filtered
|
|
||||||
// Since the ImmichImage is already precached, we can
|
|
||||||
// safely use that as the image provider
|
|
||||||
return ImageFiltered(
|
|
||||||
imageFilter: ImageFilter.blur(sigmaX: 30, sigmaY: 30),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
image: DecorationImage(
|
|
||||||
image: getFullImageProvider(
|
|
||||||
asset,
|
|
||||||
size: Size(context.width, context.height),
|
|
||||||
),
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
color: Colors.black.withValues(alpha: 0.2),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,22 +166,22 @@ class _AssetTileWidget extends ConsumerWidget {
|
|||||||
BaseAsset asset,
|
BaseAsset asset,
|
||||||
) {
|
) {
|
||||||
final multiSelectState = ref.read(multiSelectProvider);
|
final multiSelectState = ref.read(multiSelectProvider);
|
||||||
if (!multiSelectState.isEnabled) {
|
|
||||||
|
if (multiSelectState.forceEnable || multiSelectState.isEnabled) {
|
||||||
|
ref.read(multiSelectProvider.notifier).toggleAssetSelection(asset);
|
||||||
|
} else {
|
||||||
ctx.pushRoute(
|
ctx.pushRoute(
|
||||||
AssetViewerRoute(
|
AssetViewerRoute(
|
||||||
initialIndex: assetIndex,
|
initialIndex: assetIndex,
|
||||||
timelineService: ref.read(timelineServiceProvider),
|
timelineService: ref.read(timelineServiceProvider),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ref.read(multiSelectProvider.notifier).toggleAssetSelection(asset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleOnLongPress(WidgetRef ref, BaseAsset asset) {
|
void _handleOnLongPress(WidgetRef ref, BaseAsset asset) {
|
||||||
final multiSelectState = ref.read(multiSelectProvider);
|
final multiSelectState = ref.read(multiSelectProvider);
|
||||||
if (multiSelectState.isEnabled) {
|
if (multiSelectState.isEnabled || multiSelectState.forceEnable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,13 +189,35 @@ class _AssetTileWidget extends ConsumerWidget {
|
|||||||
ref.read(multiSelectProvider.notifier).toggleAssetSelection(asset);
|
ref.read(multiSelectProvider.notifier).toggleAssetSelection(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _getLockSelectionStatus(WidgetRef ref) {
|
||||||
|
final lockSelectionAssets = ref.read(
|
||||||
|
multiSelectProvider.select(
|
||||||
|
(state) => state.lockedSelectionAssets,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (lockSelectionAssets.isEmpty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lockSelectionAssets.contains(asset);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final lockSelection = _getLockSelectionStatus(ref);
|
||||||
|
|
||||||
return RepaintBoundary(
|
return RepaintBoundary(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => _handleOnTap(context, ref, assetIndex, asset),
|
onTap: () => lockSelection
|
||||||
onLongPress: () => _handleOnLongPress(ref, asset),
|
? null
|
||||||
child: ThumbnailTile(asset),
|
: _handleOnTap(context, ref, assetIndex, asset),
|
||||||
|
onLongPress: () =>
|
||||||
|
lockSelection ? null : _handleOnLongPress(ref, asset),
|
||||||
|
child: ThumbnailTile(
|
||||||
|
asset,
|
||||||
|
lockSelection: lockSelection,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -354,22 +354,24 @@ class ScrubberState extends ConsumerState<Scrubber>
|
|||||||
isDragging: _isDragging,
|
isDragging: _isDragging,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PositionedDirectional(
|
if (_scrollController.hasClients &&
|
||||||
top: _thumbTopOffset + widget.topPadding,
|
_scrollController.position.maxScrollExtent > 0)
|
||||||
end: 0,
|
PositionedDirectional(
|
||||||
child: RepaintBoundary(
|
top: _thumbTopOffset + widget.topPadding,
|
||||||
child: GestureDetector(
|
end: 0,
|
||||||
onVerticalDragStart: _onDragStart,
|
child: RepaintBoundary(
|
||||||
onVerticalDragUpdate: _onDragUpdate,
|
child: GestureDetector(
|
||||||
onVerticalDragEnd: _onDragEnd,
|
onVerticalDragStart: _onDragStart,
|
||||||
child: _Scrubber(
|
onVerticalDragUpdate: _onDragUpdate,
|
||||||
thumbAnimation: _thumbAnimation,
|
onVerticalDragEnd: _onDragEnd,
|
||||||
labelAnimation: _labelAnimation,
|
child: _Scrubber(
|
||||||
label: label,
|
thumbAnimation: _thumbAnimation,
|
||||||
|
labelAnimation: _labelAnimation,
|
||||||
|
label: label,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -18,9 +18,14 @@ import 'package:immich_mobile/providers/infrastructure/setting.provider.dart';
|
|||||||
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_sliver_app_bar.dart';
|
import 'package:immich_mobile/widgets/common/immich_sliver_app_bar.dart';
|
||||||
|
import 'package:immich_mobile/widgets/common/selection_sliver_app_bar.dart';
|
||||||
|
|
||||||
class Timeline extends StatelessWidget {
|
class Timeline extends StatelessWidget {
|
||||||
const Timeline({super.key, this.topSliverWidget, this.topSliverWidgetHeight});
|
const Timeline({
|
||||||
|
super.key,
|
||||||
|
this.topSliverWidget,
|
||||||
|
this.topSliverWidgetHeight,
|
||||||
|
});
|
||||||
|
|
||||||
final Widget? topSliverWidget;
|
final Widget? topSliverWidget;
|
||||||
final double? topSliverWidgetHeight;
|
final double? topSliverWidgetHeight;
|
||||||
@@ -52,7 +57,10 @@ class Timeline extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _SliverTimeline extends ConsumerStatefulWidget {
|
class _SliverTimeline extends ConsumerStatefulWidget {
|
||||||
const _SliverTimeline({this.topSliverWidget, this.topSliverWidgetHeight});
|
const _SliverTimeline({
|
||||||
|
this.topSliverWidget,
|
||||||
|
this.topSliverWidgetHeight,
|
||||||
|
});
|
||||||
|
|
||||||
final Widget? topSliverWidget;
|
final Widget? topSliverWidget;
|
||||||
final double? topSliverWidgetHeight;
|
final double? topSliverWidgetHeight;
|
||||||
@@ -84,6 +92,10 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
|
|||||||
final asyncSegments = ref.watch(timelineSegmentProvider);
|
final asyncSegments = ref.watch(timelineSegmentProvider);
|
||||||
final maxHeight =
|
final maxHeight =
|
||||||
ref.watch(timelineArgsProvider.select((args) => args.maxHeight));
|
ref.watch(timelineArgsProvider.select((args) => args.maxHeight));
|
||||||
|
final isSelectionMode = ref.watch(
|
||||||
|
multiSelectProvider.select((s) => s.forceEnable),
|
||||||
|
);
|
||||||
|
|
||||||
return asyncSegments.widgetWhen(
|
return asyncSegments.widgetWhen(
|
||||||
onData: (segments) {
|
onData: (segments) {
|
||||||
final childCount = (segments.lastOrNull?.lastIndex ?? -1) + 1;
|
final childCount = (segments.lastOrNull?.lastIndex ?? -1) + 1;
|
||||||
@@ -105,11 +117,14 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
|
|||||||
primary: true,
|
primary: true,
|
||||||
cacheExtent: maxHeight * 2,
|
cacheExtent: maxHeight * 2,
|
||||||
slivers: [
|
slivers: [
|
||||||
const ImmichSliverAppBar(
|
if (isSelectionMode)
|
||||||
floating: true,
|
const SelectionSliverAppBar()
|
||||||
pinned: false,
|
else
|
||||||
snap: false,
|
const ImmichSliverAppBar(
|
||||||
),
|
floating: true,
|
||||||
|
pinned: false,
|
||||||
|
snap: false,
|
||||||
|
),
|
||||||
if (widget.topSliverWidget != null) widget.topSliverWidget!,
|
if (widget.topSliverWidget != null) widget.topSliverWidget!,
|
||||||
_SliverSegmentedList(
|
_SliverSegmentedList(
|
||||||
segments: segments,
|
segments: segments,
|
||||||
@@ -134,40 +149,42 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Consumer(
|
if (!isSelectionMode) ...[
|
||||||
builder: (_, consumerRef, child) {
|
Consumer(
|
||||||
final isMultiSelectEnabled = consumerRef.watch(
|
builder: (_, consumerRef, child) {
|
||||||
multiSelectProvider.select(
|
final isMultiSelectEnabled = consumerRef.watch(
|
||||||
(s) => s.isEnabled,
|
multiSelectProvider.select(
|
||||||
),
|
(s) => s.isEnabled,
|
||||||
);
|
),
|
||||||
|
);
|
||||||
|
|
||||||
if (isMultiSelectEnabled) {
|
if (isMultiSelectEnabled) {
|
||||||
return child!;
|
return child!;
|
||||||
}
|
}
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
},
|
},
|
||||||
child: const Positioned(
|
child: const Positioned(
|
||||||
top: 60,
|
top: 60,
|
||||||
left: 25,
|
left: 25,
|
||||||
child: _MultiSelectStatusButton(),
|
child: _MultiSelectStatusButton(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
Consumer(
|
||||||
Consumer(
|
builder: (_, consumerRef, child) {
|
||||||
builder: (_, consumerRef, child) {
|
final isMultiSelectEnabled = consumerRef.watch(
|
||||||
final isMultiSelectEnabled = consumerRef.watch(
|
multiSelectProvider.select(
|
||||||
multiSelectProvider.select(
|
(s) => s.isEnabled,
|
||||||
(s) => s.isEnabled,
|
),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
|
|
||||||
if (isMultiSelectEnabled) {
|
if (isMultiSelectEnabled) {
|
||||||
return child!;
|
return child!;
|
||||||
}
|
}
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
},
|
},
|
||||||
child: const HomeBottomAppBar(),
|
child: const HomeBottomAppBar(),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
7
mobile/lib/providers/stack.provider.dart
Normal file
7
mobile/lib/providers/stack.provider.dart
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/repositories/stack.repository.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||||
|
|
||||||
|
final driftStackProvider = Provider<DriftStackRepository>(
|
||||||
|
(ref) => DriftStackRepository(ref.watch(driftProvider)),
|
||||||
|
);
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
@@ -12,8 +13,14 @@ final multiSelectProvider =
|
|||||||
|
|
||||||
class MultiSelectState {
|
class MultiSelectState {
|
||||||
final Set<BaseAsset> selectedAssets;
|
final Set<BaseAsset> selectedAssets;
|
||||||
|
final Set<BaseAsset> lockedSelectionAssets;
|
||||||
|
final bool forceEnable;
|
||||||
|
|
||||||
const MultiSelectState({required this.selectedAssets});
|
const MultiSelectState({
|
||||||
|
required this.selectedAssets,
|
||||||
|
required this.lockedSelectionAssets,
|
||||||
|
this.forceEnable = false,
|
||||||
|
});
|
||||||
|
|
||||||
bool get isEnabled => selectedAssets.isNotEmpty;
|
bool get isEnabled => selectedAssets.isNotEmpty;
|
||||||
bool get hasRemote => selectedAssets.any(
|
bool get hasRemote => selectedAssets.any(
|
||||||
@@ -25,33 +32,54 @@ class MultiSelectState {
|
|||||||
(asset) => asset.storage == AssetState.local,
|
(asset) => asset.storage == AssetState.local,
|
||||||
);
|
);
|
||||||
|
|
||||||
MultiSelectState copyWith({Set<BaseAsset>? selectedAssets}) {
|
MultiSelectState copyWith({
|
||||||
|
Set<BaseAsset>? selectedAssets,
|
||||||
|
Set<BaseAsset>? lockedSelectionAssets,
|
||||||
|
bool? forceEnable,
|
||||||
|
}) {
|
||||||
return MultiSelectState(
|
return MultiSelectState(
|
||||||
selectedAssets: selectedAssets ?? this.selectedAssets,
|
selectedAssets: selectedAssets ?? this.selectedAssets,
|
||||||
|
lockedSelectionAssets:
|
||||||
|
lockedSelectionAssets ?? this.lockedSelectionAssets,
|
||||||
|
forceEnable: forceEnable ?? this.forceEnable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'MultiSelectState(selectedAssets: $selectedAssets)';
|
String toString() =>
|
||||||
|
'MultiSelectState(selectedAssets: $selectedAssets, lockedSelectionAssets: $lockedSelectionAssets, forceEnable: $forceEnable)';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(covariant MultiSelectState other) {
|
bool operator ==(covariant MultiSelectState other) {
|
||||||
if (identical(this, other)) return true;
|
if (identical(this, other)) return true;
|
||||||
final listEquals = const DeepCollectionEquality().equals;
|
final setEquals = const DeepCollectionEquality().equals;
|
||||||
|
|
||||||
return listEquals(other.selectedAssets, selectedAssets);
|
return setEquals(other.selectedAssets, selectedAssets) &&
|
||||||
|
setEquals(other.lockedSelectionAssets, lockedSelectionAssets) &&
|
||||||
|
other.forceEnable == forceEnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => selectedAssets.hashCode;
|
int get hashCode =>
|
||||||
|
selectedAssets.hashCode ^
|
||||||
|
lockedSelectionAssets.hashCode ^
|
||||||
|
forceEnable.hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
||||||
|
MultiSelectNotifier([this._defaultState]);
|
||||||
|
final MultiSelectState? _defaultState;
|
||||||
|
|
||||||
TimelineService get _timelineService => ref.read(timelineServiceProvider);
|
TimelineService get _timelineService => ref.read(timelineServiceProvider);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MultiSelectState build() {
|
MultiSelectState build() {
|
||||||
return const MultiSelectState(selectedAssets: {});
|
return _defaultState ??
|
||||||
|
const MultiSelectState(
|
||||||
|
selectedAssets: {},
|
||||||
|
lockedSelectionAssets: {},
|
||||||
|
forceEnable: false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void selectAsset(BaseAsset asset) {
|
void selectAsset(BaseAsset asset) {
|
||||||
@@ -83,7 +111,11 @@ class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
state = const MultiSelectState(selectedAssets: {});
|
state = const MultiSelectState(
|
||||||
|
selectedAssets: {},
|
||||||
|
lockedSelectionAssets: {},
|
||||||
|
forceEnable: false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bucket bulk operations
|
/// Bucket bulk operations
|
||||||
@@ -131,6 +163,12 @@ class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
|||||||
|
|
||||||
state = state.copyWith(selectedAssets: selectedAssets);
|
state = state.copyWith(selectedAssets: selectedAssets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setLockedSelectionAssets(Set<BaseAsset> assets) {
|
||||||
|
state = state.copyWith(
|
||||||
|
lockedSelectionAssets: assets,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final bucketSelectionProvider = Provider.family<bool, List<BaseAsset>>(
|
final bucketSelectionProvider = Provider.family<bool, List<BaseAsset>>(
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ class AuthRepository extends DatabaseRepository {
|
|||||||
_drift.remoteAlbumEntity.deleteAll(),
|
_drift.remoteAlbumEntity.deleteAll(),
|
||||||
_drift.remoteAlbumAssetEntity.deleteAll(),
|
_drift.remoteAlbumAssetEntity.deleteAll(),
|
||||||
_drift.remoteAlbumUserEntity.deleteAll(),
|
_drift.remoteAlbumUserEntity.deleteAll(),
|
||||||
|
_drift.memoryEntity.deleteAll(),
|
||||||
|
_drift.memoryAssetEntity.deleteAll(),
|
||||||
|
_drift.stackEntity.deleteAll(),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/log.model.dart';
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/memory.model.dart';
|
import 'package:immich_mobile/domain/models/memory.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
@@ -66,12 +67,19 @@ import 'package:immich_mobile/pages/search/person_result.page.dart';
|
|||||||
import 'package:immich_mobile/pages/search/recently_taken.page.dart';
|
import 'package:immich_mobile/pages/search/recently_taken.page.dart';
|
||||||
import 'package:immich_mobile/pages/search/search.page.dart';
|
import 'package:immich_mobile/pages/search/search.page.dart';
|
||||||
import 'package:immich_mobile/pages/share_intent/share_intent.page.dart';
|
import 'package:immich_mobile/pages/share_intent/share_intent.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/pages/dev/drift_favorite.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/pages/dev/drift_video.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/pages/dev/drift_trash.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/pages/dev/drift_archive.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/pages/dev/drift_locked_folder.page.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/dev/feat_in_development.page.dart';
|
import 'package:immich_mobile/presentation/pages/dev/feat_in_development.page.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/dev/local_timeline.page.dart';
|
import 'package:immich_mobile/presentation/pages/dev/local_timeline.page.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/dev/main_timeline.page.dart';
|
import 'package:immich_mobile/presentation/pages/dev/main_timeline.page.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/dev/media_stat.page.dart';
|
import 'package:immich_mobile/presentation/pages/dev/media_stat.page.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/dev/remote_timeline.page.dart';
|
import 'package:immich_mobile/presentation/pages/dev/remote_timeline.page.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/drift_album.page.dart';
|
import 'package:immich_mobile/presentation/pages/drift_album.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/pages/drift_library.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/pages/drift_asset_selection_timeline.page.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/drift_memory.page.dart';
|
import 'package:immich_mobile/presentation/pages/drift_memory.page.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.page.dart';
|
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.page.dart';
|
||||||
import 'package:immich_mobile/providers/api.provider.dart';
|
import 'package:immich_mobile/providers/api.provider.dart';
|
||||||
@@ -174,7 +182,7 @@ class AppRouter extends RootStackRouter {
|
|||||||
maintainState: false,
|
maintainState: false,
|
||||||
),
|
),
|
||||||
AutoRoute(
|
AutoRoute(
|
||||||
page: LibraryRoute.page,
|
page: DriftLibraryRoute.page,
|
||||||
guards: [_authGuard, _duplicateGuard],
|
guards: [_authGuard, _duplicateGuard],
|
||||||
),
|
),
|
||||||
AutoRoute(
|
AutoRoute(
|
||||||
@@ -392,6 +400,34 @@ class AppRouter extends RootStackRouter {
|
|||||||
page: DriftMemoryRoute.page,
|
page: DriftMemoryRoute.page,
|
||||||
guards: [_authGuard, _duplicateGuard],
|
guards: [_authGuard, _duplicateGuard],
|
||||||
),
|
),
|
||||||
|
AutoRoute(
|
||||||
|
page: DriftFavoriteRoute.page,
|
||||||
|
guards: [_authGuard, _duplicateGuard],
|
||||||
|
),
|
||||||
|
AutoRoute(
|
||||||
|
page: DriftTrashRoute.page,
|
||||||
|
guards: [_authGuard, _duplicateGuard],
|
||||||
|
),
|
||||||
|
AutoRoute(
|
||||||
|
page: DriftArchiveRoute.page,
|
||||||
|
guards: [_authGuard, _duplicateGuard],
|
||||||
|
),
|
||||||
|
AutoRoute(
|
||||||
|
page: DriftLockedFolderRoute.page,
|
||||||
|
guards: [_authGuard, _duplicateGuard],
|
||||||
|
),
|
||||||
|
AutoRoute(
|
||||||
|
page: DriftVideoRoute.page,
|
||||||
|
guards: [_authGuard, _duplicateGuard],
|
||||||
|
),
|
||||||
|
AutoRoute(
|
||||||
|
page: DriftLibraryRoute.page,
|
||||||
|
guards: [_authGuard, _duplicateGuard],
|
||||||
|
),
|
||||||
|
AutoRoute(
|
||||||
|
page: DriftAssetSelectionTimelineRoute.page,
|
||||||
|
guards: [_authGuard, _duplicateGuard],
|
||||||
|
),
|
||||||
|
|
||||||
// required to handle all deeplinks in deep_link.service.dart
|
// required to handle all deeplinks in deep_link.service.dart
|
||||||
// auto_route_library#1722
|
// auto_route_library#1722
|
||||||
|
|||||||
@@ -618,6 +618,119 @@ class DriftAlbumsRoute extends PageRouteInfo<void> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// generated route for
|
||||||
|
/// [DriftArchivePage]
|
||||||
|
class DriftArchiveRoute extends PageRouteInfo<void> {
|
||||||
|
const DriftArchiveRoute({List<PageRouteInfo>? children})
|
||||||
|
: super(DriftArchiveRoute.name, initialChildren: children);
|
||||||
|
|
||||||
|
static const String name = 'DriftArchiveRoute';
|
||||||
|
|
||||||
|
static PageInfo page = PageInfo(
|
||||||
|
name,
|
||||||
|
builder: (data) {
|
||||||
|
return const DriftArchivePage();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generated route for
|
||||||
|
/// [DriftAssetSelectionTimelinePage]
|
||||||
|
class DriftAssetSelectionTimelineRoute
|
||||||
|
extends PageRouteInfo<DriftAssetSelectionTimelineRouteArgs> {
|
||||||
|
DriftAssetSelectionTimelineRoute({
|
||||||
|
Key? key,
|
||||||
|
Set<BaseAsset> lockedSelectionAssets = const {},
|
||||||
|
List<PageRouteInfo>? children,
|
||||||
|
}) : super(
|
||||||
|
DriftAssetSelectionTimelineRoute.name,
|
||||||
|
args: DriftAssetSelectionTimelineRouteArgs(
|
||||||
|
key: key,
|
||||||
|
lockedSelectionAssets: lockedSelectionAssets,
|
||||||
|
),
|
||||||
|
initialChildren: children,
|
||||||
|
);
|
||||||
|
|
||||||
|
static const String name = 'DriftAssetSelectionTimelineRoute';
|
||||||
|
|
||||||
|
static PageInfo page = PageInfo(
|
||||||
|
name,
|
||||||
|
builder: (data) {
|
||||||
|
final args = data.argsAs<DriftAssetSelectionTimelineRouteArgs>(
|
||||||
|
orElse: () => const DriftAssetSelectionTimelineRouteArgs(),
|
||||||
|
);
|
||||||
|
return DriftAssetSelectionTimelinePage(
|
||||||
|
key: args.key,
|
||||||
|
lockedSelectionAssets: args.lockedSelectionAssets,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DriftAssetSelectionTimelineRouteArgs {
|
||||||
|
const DriftAssetSelectionTimelineRouteArgs({
|
||||||
|
this.key,
|
||||||
|
this.lockedSelectionAssets = const {},
|
||||||
|
});
|
||||||
|
|
||||||
|
final Key? key;
|
||||||
|
|
||||||
|
final Set<BaseAsset> lockedSelectionAssets;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'DriftAssetSelectionTimelineRouteArgs{key: $key, lockedSelectionAssets: $lockedSelectionAssets}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generated route for
|
||||||
|
/// [DriftFavoritePage]
|
||||||
|
class DriftFavoriteRoute extends PageRouteInfo<void> {
|
||||||
|
const DriftFavoriteRoute({List<PageRouteInfo>? children})
|
||||||
|
: super(DriftFavoriteRoute.name, initialChildren: children);
|
||||||
|
|
||||||
|
static const String name = 'DriftFavoriteRoute';
|
||||||
|
|
||||||
|
static PageInfo page = PageInfo(
|
||||||
|
name,
|
||||||
|
builder: (data) {
|
||||||
|
return const DriftFavoritePage();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generated route for
|
||||||
|
/// [DriftLibraryPage]
|
||||||
|
class DriftLibraryRoute extends PageRouteInfo<void> {
|
||||||
|
const DriftLibraryRoute({List<PageRouteInfo>? children})
|
||||||
|
: super(DriftLibraryRoute.name, initialChildren: children);
|
||||||
|
|
||||||
|
static const String name = 'DriftLibraryRoute';
|
||||||
|
|
||||||
|
static PageInfo page = PageInfo(
|
||||||
|
name,
|
||||||
|
builder: (data) {
|
||||||
|
return const DriftLibraryPage();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generated route for
|
||||||
|
/// [DriftLockedFolderPage]
|
||||||
|
class DriftLockedFolderRoute extends PageRouteInfo<void> {
|
||||||
|
const DriftLockedFolderRoute({List<PageRouteInfo>? children})
|
||||||
|
: super(DriftLockedFolderRoute.name, initialChildren: children);
|
||||||
|
|
||||||
|
static const String name = 'DriftLockedFolderRoute';
|
||||||
|
|
||||||
|
static PageInfo page = PageInfo(
|
||||||
|
name,
|
||||||
|
builder: (data) {
|
||||||
|
return const DriftLockedFolderPage();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// generated route for
|
/// generated route for
|
||||||
/// [DriftMemoryPage]
|
/// [DriftMemoryPage]
|
||||||
class DriftMemoryRoute extends PageRouteInfo<DriftMemoryRouteArgs> {
|
class DriftMemoryRoute extends PageRouteInfo<DriftMemoryRouteArgs> {
|
||||||
@@ -670,6 +783,38 @@ class DriftMemoryRouteArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// generated route for
|
||||||
|
/// [DriftTrashPage]
|
||||||
|
class DriftTrashRoute extends PageRouteInfo<void> {
|
||||||
|
const DriftTrashRoute({List<PageRouteInfo>? children})
|
||||||
|
: super(DriftTrashRoute.name, initialChildren: children);
|
||||||
|
|
||||||
|
static const String name = 'DriftTrashRoute';
|
||||||
|
|
||||||
|
static PageInfo page = PageInfo(
|
||||||
|
name,
|
||||||
|
builder: (data) {
|
||||||
|
return const DriftTrashPage();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generated route for
|
||||||
|
/// [DriftVideoPage]
|
||||||
|
class DriftVideoRoute extends PageRouteInfo<void> {
|
||||||
|
const DriftVideoRoute({List<PageRouteInfo>? children})
|
||||||
|
: super(DriftVideoRoute.name, initialChildren: children);
|
||||||
|
|
||||||
|
static const String name = 'DriftVideoRoute';
|
||||||
|
|
||||||
|
static PageInfo page = PageInfo(
|
||||||
|
name,
|
||||||
|
builder: (data) {
|
||||||
|
return const DriftVideoPage();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// generated route for
|
/// generated route for
|
||||||
/// [EditImagePage]
|
/// [EditImagePage]
|
||||||
class EditImageRoute extends PageRouteInfo<EditImageRouteArgs> {
|
class EditImageRoute extends PageRouteInfo<EditImageRouteArgs> {
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:typed_data';
|
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
|
||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
|
||||||
import 'package:thumbhash/thumbhash.dart' as thumbhash;
|
|
||||||
|
|
||||||
ObjectRef<Uint8List?> useBlurHashRef(Asset? asset) {
|
|
||||||
if (asset?.thumbhash == null) {
|
|
||||||
return useRef(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
final rbga = thumbhash.thumbHashToRGBA(
|
|
||||||
base64Decode(asset!.thumbhash!),
|
|
||||||
);
|
|
||||||
|
|
||||||
return useRef(thumbhash.rgbaToBmp(rbga));
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectRef<Uint8List?> useDriftBlurHashRef(RemoteAsset? asset) {
|
|
||||||
if (asset?.thumbHash == null) {
|
|
||||||
return useRef(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
final rbga = thumbhash.thumbHashToRGBA(
|
|
||||||
base64Decode(asset!.thumbHash!),
|
|
||||||
);
|
|
||||||
|
|
||||||
return useRef(thumbhash.rgbaToBmp(rbga));
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:immich_mobile/widgets/common/transparent_image.dart';
|
|
||||||
|
|
||||||
class FadeInPlaceholderImage extends StatelessWidget {
|
|
||||||
final Widget placeholder;
|
|
||||||
final ImageProvider image;
|
|
||||||
final Duration duration;
|
|
||||||
final BoxFit fit;
|
|
||||||
|
|
||||||
const FadeInPlaceholderImage({
|
|
||||||
super.key,
|
|
||||||
required this.placeholder,
|
|
||||||
required this.image,
|
|
||||||
this.duration = const Duration(milliseconds: 100),
|
|
||||||
this.fit = BoxFit.cover,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SizedBox.expand(
|
|
||||||
child: Stack(
|
|
||||||
fit: StackFit.expand,
|
|
||||||
children: [
|
|
||||||
placeholder,
|
|
||||||
FadeInImage(
|
|
||||||
fadeInDuration: duration,
|
|
||||||
image: image,
|
|
||||||
fit: fit,
|
|
||||||
placeholder: MemoryImage(kTransparentImage),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/providers/image/immich_local_thumbnail_provider.dart';
|
import 'package:immich_mobile/providers/image/immich_local_thumbnail_provider.dart';
|
||||||
import 'package:immich_mobile/providers/image/immich_remote_thumbnail_provider.dart';
|
import 'package:immich_mobile/providers/image/immich_remote_thumbnail_provider.dart';
|
||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
import 'package:immich_mobile/utils/hooks/blurhash_hook.dart';
|
|
||||||
import 'package:immich_mobile/utils/thumbnail_utils.dart';
|
import 'package:immich_mobile/utils/thumbnail_utils.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_image.dart';
|
import 'package:immich_mobile/widgets/common/immich_image.dart';
|
||||||
import 'package:immich_mobile/widgets/common/thumbhash_placeholder.dart';
|
import 'package:immich_mobile/widgets/common/thumbhash_placeholder.dart';
|
||||||
@@ -64,7 +61,6 @@ class ImmichThumbnail extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
Uint8List? blurhash = useBlurHashRef(asset).value;
|
|
||||||
final userId = ref.watch(currentUserProvider)?.id;
|
final userId = ref.watch(currentUserProvider)?.id;
|
||||||
|
|
||||||
if (asset == null) {
|
if (asset == null) {
|
||||||
@@ -82,7 +78,7 @@ class ImmichThumbnail extends HookConsumerWidget {
|
|||||||
asset!.exifInfo,
|
asset!.exifInfo,
|
||||||
asset!.fileCreatedAt,
|
asset!.fileCreatedAt,
|
||||||
asset!.type,
|
asset!.type,
|
||||||
[],
|
const [],
|
||||||
);
|
);
|
||||||
|
|
||||||
final thumbnailProviderInstance = ImmichThumbnail.imageProvider(
|
final thumbnailProviderInstance = ImmichThumbnail.imageProvider(
|
||||||
@@ -94,7 +90,7 @@ class ImmichThumbnail extends HookConsumerWidget {
|
|||||||
thumbnailProviderInstance.evict();
|
thumbnailProviderInstance.evict();
|
||||||
|
|
||||||
final originalErrorWidgetBuilder =
|
final originalErrorWidgetBuilder =
|
||||||
blurHashErrorBuilder(blurhash, fit: fit);
|
blurHashErrorBuilder(asset?.thumbhash, fit: fit);
|
||||||
return originalErrorWidgetBuilder(ctx, error, stackTrace);
|
return originalErrorWidgetBuilder(ctx, error, stackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +101,8 @@ class ImmichThumbnail extends HookConsumerWidget {
|
|||||||
fadeInDuration: Duration.zero,
|
fadeInDuration: Duration.zero,
|
||||||
fadeOutDuration: const Duration(milliseconds: 100),
|
fadeOutDuration: const Duration(milliseconds: 100),
|
||||||
octoSet: OctoSet(
|
octoSet: OctoSet(
|
||||||
placeholderBuilder: blurHashPlaceholderBuilder(blurhash, fit: fit),
|
placeholderBuilder:
|
||||||
|
blurHashPlaceholderBuilder(asset?.thumbhash, fit: fit),
|
||||||
errorBuilder: customErrorBuilder,
|
errorBuilder: customErrorBuilder,
|
||||||
),
|
),
|
||||||
image: thumbnailProviderInstance,
|
image: thumbnailProviderInstance,
|
||||||
|
|||||||
77
mobile/lib/widgets/common/selection_sliver_app_bar.dart
Normal file
77
mobile/lib/widgets/common/selection_sliver_app_bar.dart
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
|
|
||||||
|
class SelectionSliverAppBar extends ConsumerStatefulWidget {
|
||||||
|
const SelectionSliverAppBar({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<SelectionSliverAppBar> createState() =>
|
||||||
|
_SelectionSliverAppBarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SelectionSliverAppBarState extends ConsumerState<SelectionSliverAppBar> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final selection = ref.watch(
|
||||||
|
multiSelectProvider.select((s) => s.selectedAssets),
|
||||||
|
);
|
||||||
|
|
||||||
|
final toExclude = ref.watch(
|
||||||
|
multiSelectProvider.select((s) => s.lockedSelectionAssets),
|
||||||
|
);
|
||||||
|
|
||||||
|
final filteredAssets = selection.where((asset) {
|
||||||
|
return !toExclude.contains(asset);
|
||||||
|
}).toSet();
|
||||||
|
|
||||||
|
onDone(Set<BaseAsset> selected) {
|
||||||
|
ref.read(multiSelectProvider.notifier).reset();
|
||||||
|
context.maybePop<Set<BaseAsset>>(selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SliverAppBar(
|
||||||
|
floating: true,
|
||||||
|
pinned: true,
|
||||||
|
snap: false,
|
||||||
|
backgroundColor: context.colorScheme.surfaceContainer,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||||
|
),
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const Icon(Icons.close_rounded),
|
||||||
|
onPressed: () {
|
||||||
|
ref.read(multiSelectProvider.notifier).reset();
|
||||||
|
context.pop<Set<BaseAsset>>(null);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
centerTitle: true,
|
||||||
|
title: Text(
|
||||||
|
"Select {count}".t(
|
||||||
|
context: context,
|
||||||
|
args: {
|
||||||
|
'count': filteredAssets.length.toString(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => onDone(filteredAssets),
|
||||||
|
child: Text(
|
||||||
|
'done'.t(context: context),
|
||||||
|
style: context.textTheme.titleSmall?.copyWith(
|
||||||
|
color: context.colorScheme.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
194
mobile/lib/widgets/common/thumbhash.dart
Normal file
194
mobile/lib/widgets/common/thumbhash.dart
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:ui' as ui;
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:thumbhash/thumbhash.dart' as thumbhash;
|
||||||
|
|
||||||
|
class ThumbhashImage extends RenderBox {
|
||||||
|
Color _placeholderColor;
|
||||||
|
ui.Image? _image;
|
||||||
|
BoxFit _fit;
|
||||||
|
|
||||||
|
ThumbhashImage({
|
||||||
|
required ui.Image? image,
|
||||||
|
required BoxFit fit,
|
||||||
|
required Color placeholderColor,
|
||||||
|
}) : _image = image,
|
||||||
|
_fit = fit,
|
||||||
|
_placeholderColor = placeholderColor;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(PaintingContext context, Offset offset) {
|
||||||
|
final image = _image;
|
||||||
|
final rect = offset & size;
|
||||||
|
if (image == null) {
|
||||||
|
final paint = Paint();
|
||||||
|
paint.color = _placeholderColor;
|
||||||
|
context.canvas.drawRect(rect, paint);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
paintImage(
|
||||||
|
canvas: context.canvas,
|
||||||
|
rect: rect,
|
||||||
|
image: image,
|
||||||
|
fit: _fit,
|
||||||
|
filterQuality: FilterQuality.low,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void performLayout() {
|
||||||
|
size = constraints.biggest;
|
||||||
|
}
|
||||||
|
|
||||||
|
set image(ui.Image? value) {
|
||||||
|
if (_image != value) {
|
||||||
|
_image = value;
|
||||||
|
markNeedsPaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set fit(BoxFit value) {
|
||||||
|
if (_fit != value) {
|
||||||
|
_fit = value;
|
||||||
|
markNeedsPaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set placeholderColor(Color value) {
|
||||||
|
if (_placeholderColor != value) {
|
||||||
|
_placeholderColor = value;
|
||||||
|
markNeedsPaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThumbhashLeaf extends LeafRenderObjectWidget {
|
||||||
|
final ui.Image? image;
|
||||||
|
final BoxFit fit;
|
||||||
|
final Color placeholderColor;
|
||||||
|
|
||||||
|
const ThumbhashLeaf({
|
||||||
|
super.key,
|
||||||
|
required this.image,
|
||||||
|
required this.fit,
|
||||||
|
required this.placeholderColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
RenderObject createRenderObject(BuildContext context) {
|
||||||
|
return ThumbhashImage(
|
||||||
|
image: image,
|
||||||
|
fit: fit,
|
||||||
|
placeholderColor: placeholderColor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void updateRenderObject(BuildContext context, ThumbhashImage renderObject) {
|
||||||
|
renderObject.fit = fit;
|
||||||
|
renderObject.image = image;
|
||||||
|
renderObject.placeholderColor = placeholderColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Thumbhash extends StatefulWidget {
|
||||||
|
final String? blurhash;
|
||||||
|
final BoxFit fit;
|
||||||
|
final Color placeholderColor;
|
||||||
|
|
||||||
|
const Thumbhash({
|
||||||
|
required this.blurhash,
|
||||||
|
this.fit = BoxFit.cover,
|
||||||
|
this.placeholderColor = const Color.fromRGBO(0, 0, 0, 0.2),
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Thumbhash> createState() => _ThumbhashState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ThumbhashState extends State<Thumbhash> {
|
||||||
|
String? blurhash;
|
||||||
|
BoxFit? fit;
|
||||||
|
ui.Image? _image;
|
||||||
|
Color? placeholderColor;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
final blurhash_ = blurhash = widget.blurhash;
|
||||||
|
fit = widget.fit;
|
||||||
|
placeholderColor = widget.placeholderColor;
|
||||||
|
if (blurhash_ == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final image = thumbhash.thumbHashToRGBA(base64.decode(blurhash_));
|
||||||
|
_decode(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _decode(thumbhash.Image image) async {
|
||||||
|
if (!mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final buffer = await ImmutableBuffer.fromUint8List(image.rgba);
|
||||||
|
if (!mounted) {
|
||||||
|
buffer.dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final descriptor = ImageDescriptor.raw(
|
||||||
|
buffer,
|
||||||
|
width: image.width,
|
||||||
|
height: image.height,
|
||||||
|
pixelFormat: PixelFormat.rgba8888,
|
||||||
|
);
|
||||||
|
if (!mounted) {
|
||||||
|
buffer.dispose();
|
||||||
|
descriptor.dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final codec = await descriptor.instantiateCodec(
|
||||||
|
targetWidth: image.width,
|
||||||
|
targetHeight: image.height,
|
||||||
|
);
|
||||||
|
if (!mounted) {
|
||||||
|
buffer.dispose();
|
||||||
|
descriptor.dispose();
|
||||||
|
codec.dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final frame = (await codec.getNextFrame()).image;
|
||||||
|
buffer.dispose();
|
||||||
|
descriptor.dispose();
|
||||||
|
codec.dispose();
|
||||||
|
if (!mounted) {
|
||||||
|
frame.dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
_image = frame;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ThumbhashLeaf(
|
||||||
|
image: _image,
|
||||||
|
fit: fit!,
|
||||||
|
placeholderColor: placeholderColor!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_image?.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:immich_mobile/widgets/asset_grid/thumbnail_placeholder.dart';
|
import 'package:immich_mobile/widgets/common/thumbhash.dart';
|
||||||
import 'package:immich_mobile/widgets/common/fade_in_placeholder_image.dart';
|
|
||||||
import 'package:octo_image/octo_image.dart';
|
import 'package:octo_image/octo_image.dart';
|
||||||
|
|
||||||
/// Simple set to show [OctoPlaceholder.circularProgressIndicator] as
|
/// Simple set to show [OctoPlaceholder.circularProgressIndicator] as
|
||||||
/// placeholder and [OctoError.icon] as error.
|
/// placeholder and [OctoError.icon] as error.
|
||||||
OctoSet blurHashOrPlaceholder(
|
OctoSet blurHashOrPlaceholder(
|
||||||
Uint8List? blurhash, {
|
String? blurhash, {
|
||||||
BoxFit? fit,
|
BoxFit fit = BoxFit.cover,
|
||||||
Text? errorMessage,
|
Text? errorMessage,
|
||||||
}) {
|
}) {
|
||||||
return OctoSet(
|
return OctoSet(
|
||||||
@@ -19,21 +17,15 @@ OctoSet blurHashOrPlaceholder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
OctoPlaceholderBuilder blurHashPlaceholderBuilder(
|
OctoPlaceholderBuilder blurHashPlaceholderBuilder(
|
||||||
Uint8List? blurhash, {
|
String? blurhash, {
|
||||||
BoxFit? fit,
|
required BoxFit fit,
|
||||||
}) {
|
}) {
|
||||||
return (context) => blurhash == null
|
return (context) => Thumbhash(blurhash: blurhash, fit: fit);
|
||||||
? const ThumbnailPlaceholder()
|
|
||||||
: FadeInPlaceholderImage(
|
|
||||||
placeholder: const ThumbnailPlaceholder(),
|
|
||||||
image: MemoryImage(blurhash),
|
|
||||||
fit: fit ?? BoxFit.cover,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OctoErrorBuilder blurHashErrorBuilder(
|
OctoErrorBuilder blurHashErrorBuilder(
|
||||||
Uint8List? blurhash, {
|
String? blurhash, {
|
||||||
BoxFit? fit,
|
BoxFit fit = BoxFit.cover,
|
||||||
Text? message,
|
Text? message,
|
||||||
IconData? icon,
|
IconData? icon,
|
||||||
Color? iconColor,
|
Color? iconColor,
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/user_metadata.model.dart';
|
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
import 'package:immich_mobile/widgets/common/transparent_image.dart';
|
import 'package:immich_mobile/widgets/common/transparent_image.dart';
|
||||||
|
|
||||||
@@ -26,7 +24,7 @@ class UserCircleAvatar extends ConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
bool isDarkTheme = context.themeData.brightness == Brightness.dark;
|
final userAvatarColor = user.avatarColor.toColor();
|
||||||
final profileImageUrl =
|
final profileImageUrl =
|
||||||
'${Store.get(StoreKey.serverEndpoint)}/users/${user.id}/profile-image?d=${Random().nextInt(1024)}';
|
'${Store.get(StoreKey.serverEndpoint)}/users/${user.id}/profile-image?d=${Random().nextInt(1024)}';
|
||||||
|
|
||||||
@@ -34,14 +32,14 @@ class UserCircleAvatar extends ConsumerWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: isDarkTheme && user.avatarColor == AvatarColor.primary
|
color: userAvatarColor.computeLuminance() > 0.5
|
||||||
? Colors.black
|
? Colors.black
|
||||||
: Colors.white,
|
: Colors.white,
|
||||||
),
|
),
|
||||||
child: Text(user.name[0].toUpperCase()),
|
child: Text(user.name[0].toUpperCase()),
|
||||||
);
|
);
|
||||||
return CircleAvatar(
|
return CircleAvatar(
|
||||||
backgroundColor: user.avatarColor.toColor(),
|
backgroundColor: userAvatarColor,
|
||||||
radius: radius,
|
radius: radius,
|
||||||
child: user.profileImagePath == null
|
child: user.profileImagePath == null
|
||||||
? textIcon
|
? textIcon
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/pages/common/native_video_viewer.page.dart';
|
import 'package:immich_mobile/pages/common/native_video_viewer.page.dart';
|
||||||
import 'package:immich_mobile/utils/hooks/blurhash_hook.dart';
|
|
||||||
import 'package:immich_mobile/widgets/common/immich_image.dart';
|
import 'package:immich_mobile/widgets/common/immich_image.dart';
|
||||||
|
import 'package:immich_mobile/widgets/common/thumbhash.dart';
|
||||||
|
|
||||||
class MemoryCard extends StatelessWidget {
|
class MemoryCard extends StatelessWidget {
|
||||||
final Asset asset;
|
final Asset asset;
|
||||||
@@ -113,44 +113,35 @@ class _BlurredBackdrop extends HookWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final blurhash = useBlurHashRef(asset).value;
|
final blurhash = asset.thumbhash;
|
||||||
if (blurhash != null) {
|
if (blurhash != null) {
|
||||||
// Use a nice cheap blur hash image decoration
|
// Use a nice cheap blur hash image decoration
|
||||||
return Container(
|
return Stack(
|
||||||
|
children: [
|
||||||
|
const ColoredBox(color: Color.fromRGBO(0, 0, 0, 0.2)),
|
||||||
|
Thumbhash(blurhash: blurhash, fit: BoxFit.cover),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to using a more expensive image filtered
|
||||||
|
// Since the ImmichImage is already precached, we can
|
||||||
|
// safely use that as the image provider
|
||||||
|
return ImageFiltered(
|
||||||
|
imageFilter: ImageFilter.blur(sigmaX: 30, sigmaY: 30),
|
||||||
|
child: DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
image: MemoryImage(
|
image: ImmichImage.imageProvider(
|
||||||
blurhash,
|
asset: asset,
|
||||||
|
height: context.height,
|
||||||
|
width: context.width,
|
||||||
),
|
),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Container(
|
child: const ColoredBox(color: Color.fromRGBO(0, 0, 0, 0.2)),
|
||||||
color: Colors.black.withValues(alpha: 0.2),
|
),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Fall back to using a more expensive image filtered
|
|
||||||
// Since the ImmichImage is already precached, we can
|
|
||||||
// safely use that as the image provider
|
|
||||||
return ImageFiltered(
|
|
||||||
imageFilter: ImageFilter.blur(sigmaX: 30, sigmaY: 30),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
image: DecorationImage(
|
|
||||||
image: ImmichImage.imageProvider(
|
|
||||||
asset: asset,
|
|
||||||
height: context.height,
|
|
||||||
width: context.width,
|
|
||||||
),
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
color: Colors.black.withValues(alpha: 0.2),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class SystemConfigOAuthDto {
|
|||||||
required this.mobileOverrideEnabled,
|
required this.mobileOverrideEnabled,
|
||||||
required this.mobileRedirectUri,
|
required this.mobileRedirectUri,
|
||||||
required this.profileSigningAlgorithm,
|
required this.profileSigningAlgorithm,
|
||||||
|
required this.roleClaim,
|
||||||
required this.scope,
|
required this.scope,
|
||||||
required this.signingAlgorithm,
|
required this.signingAlgorithm,
|
||||||
required this.storageLabelClaim,
|
required this.storageLabelClaim,
|
||||||
@@ -55,6 +56,8 @@ class SystemConfigOAuthDto {
|
|||||||
|
|
||||||
String profileSigningAlgorithm;
|
String profileSigningAlgorithm;
|
||||||
|
|
||||||
|
String roleClaim;
|
||||||
|
|
||||||
String scope;
|
String scope;
|
||||||
|
|
||||||
String signingAlgorithm;
|
String signingAlgorithm;
|
||||||
@@ -81,6 +84,7 @@ class SystemConfigOAuthDto {
|
|||||||
other.mobileOverrideEnabled == mobileOverrideEnabled &&
|
other.mobileOverrideEnabled == mobileOverrideEnabled &&
|
||||||
other.mobileRedirectUri == mobileRedirectUri &&
|
other.mobileRedirectUri == mobileRedirectUri &&
|
||||||
other.profileSigningAlgorithm == profileSigningAlgorithm &&
|
other.profileSigningAlgorithm == profileSigningAlgorithm &&
|
||||||
|
other.roleClaim == roleClaim &&
|
||||||
other.scope == scope &&
|
other.scope == scope &&
|
||||||
other.signingAlgorithm == signingAlgorithm &&
|
other.signingAlgorithm == signingAlgorithm &&
|
||||||
other.storageLabelClaim == storageLabelClaim &&
|
other.storageLabelClaim == storageLabelClaim &&
|
||||||
@@ -102,6 +106,7 @@ class SystemConfigOAuthDto {
|
|||||||
(mobileOverrideEnabled.hashCode) +
|
(mobileOverrideEnabled.hashCode) +
|
||||||
(mobileRedirectUri.hashCode) +
|
(mobileRedirectUri.hashCode) +
|
||||||
(profileSigningAlgorithm.hashCode) +
|
(profileSigningAlgorithm.hashCode) +
|
||||||
|
(roleClaim.hashCode) +
|
||||||
(scope.hashCode) +
|
(scope.hashCode) +
|
||||||
(signingAlgorithm.hashCode) +
|
(signingAlgorithm.hashCode) +
|
||||||
(storageLabelClaim.hashCode) +
|
(storageLabelClaim.hashCode) +
|
||||||
@@ -110,7 +115,7 @@ class SystemConfigOAuthDto {
|
|||||||
(tokenEndpointAuthMethod.hashCode);
|
(tokenEndpointAuthMethod.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'SystemConfigOAuthDto[autoLaunch=$autoLaunch, autoRegister=$autoRegister, buttonText=$buttonText, clientId=$clientId, clientSecret=$clientSecret, defaultStorageQuota=$defaultStorageQuota, enabled=$enabled, issuerUrl=$issuerUrl, mobileOverrideEnabled=$mobileOverrideEnabled, mobileRedirectUri=$mobileRedirectUri, profileSigningAlgorithm=$profileSigningAlgorithm, scope=$scope, signingAlgorithm=$signingAlgorithm, storageLabelClaim=$storageLabelClaim, storageQuotaClaim=$storageQuotaClaim, timeout=$timeout, tokenEndpointAuthMethod=$tokenEndpointAuthMethod]';
|
String toString() => 'SystemConfigOAuthDto[autoLaunch=$autoLaunch, autoRegister=$autoRegister, buttonText=$buttonText, clientId=$clientId, clientSecret=$clientSecret, defaultStorageQuota=$defaultStorageQuota, enabled=$enabled, issuerUrl=$issuerUrl, mobileOverrideEnabled=$mobileOverrideEnabled, mobileRedirectUri=$mobileRedirectUri, profileSigningAlgorithm=$profileSigningAlgorithm, roleClaim=$roleClaim, scope=$scope, signingAlgorithm=$signingAlgorithm, storageLabelClaim=$storageLabelClaim, storageQuotaClaim=$storageQuotaClaim, timeout=$timeout, tokenEndpointAuthMethod=$tokenEndpointAuthMethod]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
@@ -129,6 +134,7 @@ class SystemConfigOAuthDto {
|
|||||||
json[r'mobileOverrideEnabled'] = this.mobileOverrideEnabled;
|
json[r'mobileOverrideEnabled'] = this.mobileOverrideEnabled;
|
||||||
json[r'mobileRedirectUri'] = this.mobileRedirectUri;
|
json[r'mobileRedirectUri'] = this.mobileRedirectUri;
|
||||||
json[r'profileSigningAlgorithm'] = this.profileSigningAlgorithm;
|
json[r'profileSigningAlgorithm'] = this.profileSigningAlgorithm;
|
||||||
|
json[r'roleClaim'] = this.roleClaim;
|
||||||
json[r'scope'] = this.scope;
|
json[r'scope'] = this.scope;
|
||||||
json[r'signingAlgorithm'] = this.signingAlgorithm;
|
json[r'signingAlgorithm'] = this.signingAlgorithm;
|
||||||
json[r'storageLabelClaim'] = this.storageLabelClaim;
|
json[r'storageLabelClaim'] = this.storageLabelClaim;
|
||||||
@@ -158,6 +164,7 @@ class SystemConfigOAuthDto {
|
|||||||
mobileOverrideEnabled: mapValueOfType<bool>(json, r'mobileOverrideEnabled')!,
|
mobileOverrideEnabled: mapValueOfType<bool>(json, r'mobileOverrideEnabled')!,
|
||||||
mobileRedirectUri: mapValueOfType<String>(json, r'mobileRedirectUri')!,
|
mobileRedirectUri: mapValueOfType<String>(json, r'mobileRedirectUri')!,
|
||||||
profileSigningAlgorithm: mapValueOfType<String>(json, r'profileSigningAlgorithm')!,
|
profileSigningAlgorithm: mapValueOfType<String>(json, r'profileSigningAlgorithm')!,
|
||||||
|
roleClaim: mapValueOfType<String>(json, r'roleClaim')!,
|
||||||
scope: mapValueOfType<String>(json, r'scope')!,
|
scope: mapValueOfType<String>(json, r'scope')!,
|
||||||
signingAlgorithm: mapValueOfType<String>(json, r'signingAlgorithm')!,
|
signingAlgorithm: mapValueOfType<String>(json, r'signingAlgorithm')!,
|
||||||
storageLabelClaim: mapValueOfType<String>(json, r'storageLabelClaim')!,
|
storageLabelClaim: mapValueOfType<String>(json, r'storageLabelClaim')!,
|
||||||
@@ -222,6 +229,7 @@ class SystemConfigOAuthDto {
|
|||||||
'mobileOverrideEnabled',
|
'mobileOverrideEnabled',
|
||||||
'mobileRedirectUri',
|
'mobileRedirectUri',
|
||||||
'profileSigningAlgorithm',
|
'profileSigningAlgorithm',
|
||||||
|
'roleClaim',
|
||||||
'scope',
|
'scope',
|
||||||
'signingAlgorithm',
|
'signingAlgorithm',
|
||||||
'storageLabelClaim',
|
'storageLabelClaim',
|
||||||
|
|||||||
@@ -89,6 +89,18 @@ void main() {
|
|||||||
.thenAnswer(successHandler);
|
.thenAnswer(successHandler);
|
||||||
when(() => mockSyncStreamRepo.deleteMemoryAssetsV1(any()))
|
when(() => mockSyncStreamRepo.deleteMemoryAssetsV1(any()))
|
||||||
.thenAnswer(successHandler);
|
.thenAnswer(successHandler);
|
||||||
|
when(
|
||||||
|
() => mockSyncStreamRepo.updateStacksV1(
|
||||||
|
any(),
|
||||||
|
debugLabel: any(named: 'debugLabel'),
|
||||||
|
),
|
||||||
|
).thenAnswer(successHandler);
|
||||||
|
when(
|
||||||
|
() => mockSyncStreamRepo.deleteStacksV1(
|
||||||
|
any(),
|
||||||
|
debugLabel: any(named: 'debugLabel'),
|
||||||
|
),
|
||||||
|
).thenAnswer(successHandler);
|
||||||
|
|
||||||
sut = SyncStreamService(
|
sut = SyncStreamService(
|
||||||
syncApiRepository: mockSyncApiRepo,
|
syncApiRepository: mockSyncApiRepo,
|
||||||
|
|||||||
@@ -14654,6 +14654,9 @@
|
|||||||
"profileSigningAlgorithm": {
|
"profileSigningAlgorithm": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"roleClaim": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"scope": {
|
"scope": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@@ -14690,6 +14693,7 @@
|
|||||||
"mobileOverrideEnabled",
|
"mobileOverrideEnabled",
|
||||||
"mobileRedirectUri",
|
"mobileRedirectUri",
|
||||||
"profileSigningAlgorithm",
|
"profileSigningAlgorithm",
|
||||||
|
"roleClaim",
|
||||||
"scope",
|
"scope",
|
||||||
"signingAlgorithm",
|
"signingAlgorithm",
|
||||||
"storageLabelClaim",
|
"storageLabelClaim",
|
||||||
|
|||||||
@@ -1398,6 +1398,7 @@ export type SystemConfigOAuthDto = {
|
|||||||
mobileOverrideEnabled: boolean;
|
mobileOverrideEnabled: boolean;
|
||||||
mobileRedirectUri: string;
|
mobileRedirectUri: string;
|
||||||
profileSigningAlgorithm: string;
|
profileSigningAlgorithm: string;
|
||||||
|
roleClaim: string;
|
||||||
scope: string;
|
scope: string;
|
||||||
signingAlgorithm: string;
|
signingAlgorithm: string;
|
||||||
storageLabelClaim: string;
|
storageLabelClaim: string;
|
||||||
|
|||||||
300
server/package-lock.json
generated
300
server/package-lock.json
generated
@@ -1134,9 +1134,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-array": {
|
"node_modules/@eslint/config-array": {
|
||||||
"version": "0.20.1",
|
"version": "0.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz",
|
||||||
"integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
|
"integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1149,9 +1149,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-helpers": {
|
"node_modules/@eslint/config-helpers": {
|
||||||
"version": "0.2.3",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz",
|
||||||
"integrity": "sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==",
|
"integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1209,9 +1209,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.29.0",
|
"version": "9.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.1.tgz",
|
||||||
"integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
|
"integrity": "sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -5472,9 +5472,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@swc/core": {
|
"node_modules/@swc/core": {
|
||||||
"version": "1.12.7",
|
"version": "1.12.9",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.12.9.tgz",
|
||||||
"integrity": "sha512-bcpllEihyUSnqp0UtXTvXc19CT4wp3tGWLENhWnjr4B5iEOkzqMu+xHGz1FI5IBatjfqOQb29tgIfv6IL05QaA==",
|
"integrity": "sha512-O+LfT2JlVMsIMWG9x+rdxg8GzpzeGtCZQfXV7cKc1PjIKUkLFf1QJ7okuseA4f/9vncu37dQ2ZcRrPKy0Ndd5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
@@ -5490,16 +5490,16 @@
|
|||||||
"url": "https://opencollective.com/swc"
|
"url": "https://opencollective.com/swc"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@swc/core-darwin-arm64": "1.12.7",
|
"@swc/core-darwin-arm64": "1.12.9",
|
||||||
"@swc/core-darwin-x64": "1.12.7",
|
"@swc/core-darwin-x64": "1.12.9",
|
||||||
"@swc/core-linux-arm-gnueabihf": "1.12.7",
|
"@swc/core-linux-arm-gnueabihf": "1.12.9",
|
||||||
"@swc/core-linux-arm64-gnu": "1.12.7",
|
"@swc/core-linux-arm64-gnu": "1.12.9",
|
||||||
"@swc/core-linux-arm64-musl": "1.12.7",
|
"@swc/core-linux-arm64-musl": "1.12.9",
|
||||||
"@swc/core-linux-x64-gnu": "1.12.7",
|
"@swc/core-linux-x64-gnu": "1.12.9",
|
||||||
"@swc/core-linux-x64-musl": "1.12.7",
|
"@swc/core-linux-x64-musl": "1.12.9",
|
||||||
"@swc/core-win32-arm64-msvc": "1.12.7",
|
"@swc/core-win32-arm64-msvc": "1.12.9",
|
||||||
"@swc/core-win32-ia32-msvc": "1.12.7",
|
"@swc/core-win32-ia32-msvc": "1.12.9",
|
||||||
"@swc/core-win32-x64-msvc": "1.12.7"
|
"@swc/core-win32-x64-msvc": "1.12.9"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@swc/helpers": ">=0.5.17"
|
"@swc/helpers": ">=0.5.17"
|
||||||
@@ -5511,9 +5511,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@swc/core-darwin-arm64": {
|
"node_modules/@swc/core-darwin-arm64": {
|
||||||
"version": "1.12.7",
|
"version": "1.12.9",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.12.9.tgz",
|
||||||
"integrity": "sha512-w6BBT0hBRS56yS+LbReVym0h+iB7/PpCddqrn1ha94ra4rZ4R/A91A/rkv+LnQlPqU/+fhqdlXtCJU9mrhCBtA==",
|
"integrity": "sha512-GACFEp4nD6V+TZNR2JwbMZRHB+Yyvp14FrcmB6UCUYmhuNWjkxi+CLnEvdbuiKyQYv0zA+TRpCHZ+whEs6gwfA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -5528,9 +5528,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@swc/core-darwin-x64": {
|
"node_modules/@swc/core-darwin-x64": {
|
||||||
"version": "1.12.7",
|
"version": "1.12.9",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.12.9.tgz",
|
||||||
"integrity": "sha512-jN6LhFfGOpm4DY2mXPgwH4aa9GLOwublwMVFFZ/bGnHYYCRitLZs9+JWBbyWs7MyGcA246Ew+EREx36KVEAxjA==",
|
"integrity": "sha512-hv2kls7Ilkm2EpeJz+I9MCil7pGS3z55ZAgZfxklEuYsxpICycxeH+RNRv4EraggN44ms+FWCjtZFu0LGg2V3g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -5545,9 +5545,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@swc/core-linux-arm-gnueabihf": {
|
"node_modules/@swc/core-linux-arm-gnueabihf": {
|
||||||
"version": "1.12.7",
|
"version": "1.12.9",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.12.9.tgz",
|
||||||
"integrity": "sha512-rHn8XXi7G2StEtZRAeJ6c7nhJPDnqsHXmeNrAaYwk8Tvpa6ZYG2nT9E1OQNXj1/dfbSFTjdiA8M8ZvGYBlpBoA==",
|
"integrity": "sha512-od9tDPiG+wMU9wKtd6y3nYJdNqgDOyLdgRRcrj1/hrbHoUPOM8wZQZdwQYGarw63iLXGgsw7t5HAF9Yc51ilFA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -5562,9 +5562,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@swc/core-linux-arm64-gnu": {
|
"node_modules/@swc/core-linux-arm64-gnu": {
|
||||||
"version": "1.12.7",
|
"version": "1.12.9",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.12.9.tgz",
|
||||||
"integrity": "sha512-N15hKizSSh+hkZ2x3TDVrxq0TDcbvDbkQJi2ZrLb9fK+NdFUV/x+XF16ZDPlbxtrGXl1CT7VD439SNaMN9F7qw==",
|
"integrity": "sha512-6qx1ka9LHcLzxIgn2Mros+CZLkHK2TawlXzi/h7DJeNnzi8F1Hw0Yzjp8WimxNCg6s2n+o3jnmin1oXB7gg8rw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -5579,9 +5579,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@swc/core-linux-arm64-musl": {
|
"node_modules/@swc/core-linux-arm64-musl": {
|
||||||
"version": "1.12.7",
|
"version": "1.12.9",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.12.9.tgz",
|
||||||
"integrity": "sha512-jxyINtBezpxd3eIUDiDXv7UQ87YWlPsM9KumOwJk09FkFSO4oYxV2RT+Wu+Nt5tVWue4N0MdXT/p7SQsDEk4YA==",
|
"integrity": "sha512-yghFZWKPVVGbUdqiD7ft23G0JX6YFGDJPz9YbLLAwGuKZ9th3/jlWoQDAw1Naci31LQhVC+oIji6ozihSuwB2A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -5596,9 +5596,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@swc/core-linux-x64-gnu": {
|
"node_modules/@swc/core-linux-x64-gnu": {
|
||||||
"version": "1.12.7",
|
"version": "1.12.9",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.12.9.tgz",
|
||||||
"integrity": "sha512-PR4tPVwU1BQBfFDk2XfzXxsEIjF3x/bOV1BzZpYvrlkU0TKUDbR4t2wzvsYwD/coW7/yoQmlL70/qnuPtTp1Zw==",
|
"integrity": "sha512-SFUxyhWLZRNL8QmgGNqdi2Q43PNyFVkRZ2zIif30SOGFSxnxcf2JNeSeBgKIGVgaLSuk6xFVVCtJ3KIeaStgRg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -5613,9 +5613,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@swc/core-linux-x64-musl": {
|
"node_modules/@swc/core-linux-x64-musl": {
|
||||||
"version": "1.12.7",
|
"version": "1.12.9",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.12.9.tgz",
|
||||||
"integrity": "sha512-zy7JWfQtQItgMfUjSbbcS3DZqQUn2d9VuV0LSGpJxtTXwgzhRpF1S2Sj7cU9hGpbM27Y8RJ4DeFb3qbAufjbrw==",
|
"integrity": "sha512-9FB0wM+6idCGTI20YsBNBg9xSWtkDBymnpaTCsZM3qDc0l4uOpJMqbfWhQvp17x7r/ulZfb2QY8RDvQmCL6AcQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -5630,9 +5630,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@swc/core-win32-arm64-msvc": {
|
"node_modules/@swc/core-win32-arm64-msvc": {
|
||||||
"version": "1.12.7",
|
"version": "1.12.9",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.12.9.tgz",
|
||||||
"integrity": "sha512-52PeF0tyX04ZFD8nibNhy/GjMFOZWTEWPmIB3wpD1vIJ1po+smtBnEdRRll5WIXITKoiND8AeHlBNBPqcsdcwA==",
|
"integrity": "sha512-zHOusMVbOH9ik5RtRrMiGzLpKwxrPXgXkBm3SbUCa65HAdjV33NZ0/R9Rv1uPESALtEl2tzMYLUxYA5ECFDFhA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -5647,9 +5647,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@swc/core-win32-ia32-msvc": {
|
"node_modules/@swc/core-win32-ia32-msvc": {
|
||||||
"version": "1.12.7",
|
"version": "1.12.9",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.12.9.tgz",
|
||||||
"integrity": "sha512-WzQwkNMuhB1qQShT9uUgz/mX2j7NIEPExEtzvGsBT7TlZ9j1kGZ8NJcZH/fwOFcSJL4W7DnkL7nAhx6DBlSPaA==",
|
"integrity": "sha512-aWZf0PqE0ot7tCuhAjRkDFf41AzzSQO0x2xRfTbnhpROp57BRJ/N5eee1VULO/UA2PIJRG7GKQky5bSGBYlFug==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -5664,9 +5664,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@swc/core-win32-x64-msvc": {
|
"node_modules/@swc/core-win32-x64-msvc": {
|
||||||
"version": "1.12.7",
|
"version": "1.12.9",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.12.9.tgz",
|
||||||
"integrity": "sha512-R52ivBi2lgjl+Bd3XCPum0YfgbZq/W1AUExITysddP9ErsNSwnreYyNB3exEijiazWGcqHEas2ChiuMOP7NYrA==",
|
"integrity": "sha512-C25fYftXOras3P3anSUeXXIpxmEkdAcsIL9yrr0j1xepTZ/yKwpnQ6g3coj8UXdeJy4GTVlR6+Ow/QiBgZQNOg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -6037,9 +6037,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/lodash": {
|
"node_modules/@types/lodash": {
|
||||||
"version": "4.17.19",
|
"version": "4.17.20",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.19.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz",
|
||||||
"integrity": "sha512-NYqRyg/hIQrYPT9lbOeYc3kIRabJDn/k4qQHIXUpx88CBDww2fD15Sg5kbXlW86zm2XEW4g0QxkTI3/Kfkc7xQ==",
|
"integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@@ -6344,17 +6344,17 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.1.tgz",
|
||||||
"integrity": "sha512-ijItUYaiWuce0N1SoSMrEd0b6b6lYkYt99pqCPfybd+HKVXtEvYhICfLdwp42MhiI5mp0oq7PKEL+g1cNiz/Eg==",
|
"integrity": "sha512-9XNTlo7P7RJxbVeICaIIIEipqxLKguyh+3UbXuT2XQuFp6d8VOeDEGuz5IiX0dgZo8CiI6aOFLg4e8cF71SFVg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "8.35.0",
|
"@typescript-eslint/scope-manager": "8.35.1",
|
||||||
"@typescript-eslint/type-utils": "8.35.0",
|
"@typescript-eslint/type-utils": "8.35.1",
|
||||||
"@typescript-eslint/utils": "8.35.0",
|
"@typescript-eslint/utils": "8.35.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.35.0",
|
"@typescript-eslint/visitor-keys": "8.35.1",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^7.0.0",
|
"ignore": "^7.0.0",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -6368,7 +6368,7 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@typescript-eslint/parser": "^8.35.0",
|
"@typescript-eslint/parser": "^8.35.1",
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0",
|
||||||
"typescript": ">=4.8.4 <5.9.0"
|
"typescript": ">=4.8.4 <5.9.0"
|
||||||
}
|
}
|
||||||
@@ -6384,16 +6384,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.35.1.tgz",
|
||||||
"integrity": "sha512-6sMvZePQrnZH2/cJkwRpkT7DxoAWh+g6+GFRK6bV3YQo7ogi3SX5rgF6099r5Q53Ma5qeT7LGmOmuIutF4t3lA==",
|
"integrity": "sha512-3MyiDfrfLeK06bi/g9DqJxP5pV74LNv4rFTyvGDmT3x2p1yp1lOd+qYZfiRPIOf/oON+WRZR5wxxuF85qOar+w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.35.0",
|
"@typescript-eslint/scope-manager": "8.35.1",
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.35.0",
|
"@typescript-eslint/typescript-estree": "8.35.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.35.0",
|
"@typescript-eslint/visitor-keys": "8.35.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -6409,14 +6409,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/project-service": {
|
"node_modules/@typescript-eslint/project-service": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.35.1.tgz",
|
||||||
"integrity": "sha512-41xatqRwWZuhUMF/aZm2fcUsOFKNcG28xqRSS6ZVr9BVJtGExosLAm5A1OxTjRMagx8nJqva+P5zNIGt8RIgbQ==",
|
"integrity": "sha512-VYxn/5LOpVxADAuP3NrnxxHYfzVtQzLKeldIhDhzC8UHaiQvYlXvKuVho1qLduFbJjjy5U5bkGwa3rUGUb1Q6Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.35.0",
|
"@typescript-eslint/tsconfig-utils": "^8.35.1",
|
||||||
"@typescript-eslint/types": "^8.35.0",
|
"@typescript-eslint/types": "^8.35.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -6431,14 +6431,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.35.1.tgz",
|
||||||
"integrity": "sha512-+AgL5+mcoLxl1vGjwNfiWq5fLDZM1TmTPYs2UkyHfFhgERxBbqHlNjRzhThJqz+ktBqTChRYY6zwbMwy0591AA==",
|
"integrity": "sha512-s/Bpd4i7ht2934nG+UoSPlYXd08KYz3bmjLEb7Ye1UVob0d1ENiT3lY8bsCmik4RqfSbPw9xJJHbugpPpP5JUg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.35.0"
|
"@typescript-eslint/visitor-keys": "8.35.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -6449,9 +6449,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.1.tgz",
|
||||||
"integrity": "sha512-04k/7247kZzFraweuEirmvUj+W3bJLI9fX6fbo1Qm2YykuBvEhRTPl8tcxlYO8kZZW+HIXfkZNoasVb8EV4jpA==",
|
"integrity": "sha512-K5/U9VmT9dTHoNowWZpz+/TObS3xqC5h0xAIjXPw+MNcKV9qg6eSatEnmeAwkjHijhACH0/N7bkhKvbt1+DXWQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -6466,14 +6466,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.35.1.tgz",
|
||||||
"integrity": "sha512-ceNNttjfmSEoM9PW87bWLDEIaLAyR+E6BoYJQ5PfaDau37UGca9Nyq3lBk8Bw2ad0AKvYabz6wxc7DMTO2jnNA==",
|
"integrity": "sha512-HOrUBlfVRz5W2LIKpXzZoy6VTZzMu2n8q9C2V/cFngIC5U1nStJgv0tMV4sZPzdf4wQm9/ToWUFPMN9Vq9VJQQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "8.35.0",
|
"@typescript-eslint/typescript-estree": "8.35.1",
|
||||||
"@typescript-eslint/utils": "8.35.0",
|
"@typescript-eslint/utils": "8.35.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^2.1.0"
|
"ts-api-utils": "^2.1.0"
|
||||||
},
|
},
|
||||||
@@ -6490,9 +6490,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.1.tgz",
|
||||||
"integrity": "sha512-0mYH3emanku0vHw2aRLNGqe7EXh9WHEhi7kZzscrMDf6IIRUQ5Jk4wp1QrledE/36KtdZrVfKnE32eZCf/vaVQ==",
|
"integrity": "sha512-q/O04vVnKHfrrhNAscndAn1tuQhIkwqnaW+eu5waD5IPts2eX1dgJxgqcPx5BX109/qAz7IG6VrEPTOYKCNfRQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -6504,16 +6504,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.35.1.tgz",
|
||||||
"integrity": "sha512-F+BhnaBemgu1Qf8oHrxyw14wq6vbL8xwWKKMwTMwYIRmFFY/1n/9T/jpbobZL8vp7QyEUcC6xGrnAO4ua8Kp7w==",
|
"integrity": "sha512-Vvpuvj4tBxIka7cPs6Y1uvM7gJgdF5Uu9F+mBJBPY4MhvjrjWGK4H0lVgLJd/8PWZ23FTqsaJaLEkBCFUk8Y9g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.35.0",
|
"@typescript-eslint/project-service": "8.35.1",
|
||||||
"@typescript-eslint/tsconfig-utils": "8.35.0",
|
"@typescript-eslint/tsconfig-utils": "8.35.1",
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.35.0",
|
"@typescript-eslint/visitor-keys": "8.35.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@@ -6559,16 +6559,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.1.tgz",
|
||||||
"integrity": "sha512-nqoMu7WWM7ki5tPgLVsmPM8CkqtoPUG6xXGeefM5t4x3XumOEKMoUZPdi+7F+/EotukN4R9OWdmDxN80fqoZeg==",
|
"integrity": "sha512-lhnwatFmOFcazAsUm3ZnZFpXSxiwoa1Lj50HphnDe1Et01NF4+hrdXONSUHIcbVu2eFb1bAf+5yjXkGVkXBKAQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.7.0",
|
"@eslint-community/eslint-utils": "^4.7.0",
|
||||||
"@typescript-eslint/scope-manager": "8.35.0",
|
"@typescript-eslint/scope-manager": "8.35.1",
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.35.0"
|
"@typescript-eslint/typescript-estree": "8.35.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -6583,13 +6583,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.35.1.tgz",
|
||||||
"integrity": "sha512-zTh2+1Y8ZpmeQaQVIc/ZZxsx8UzgKJyNg1PTvjzC7WMhPSVS8bfDX34k1SrwOf016qd5RU3az2UxUNue3IfQ5g==",
|
"integrity": "sha512-VRwixir4zBWCSTP/ljEo091lbpypz57PoeAQ9imjG+vbeof9LplljsL1mos4ccG6H9IjfrVGM359RozUnuFhpw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.35.0",
|
"@typescript-eslint/types": "8.35.1",
|
||||||
"eslint-visitor-keys": "^4.2.1"
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -9510,19 +9510,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.29.0",
|
"version": "9.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.1.tgz",
|
||||||
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
|
"integrity": "sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
"@eslint/config-array": "^0.20.1",
|
"@eslint/config-array": "^0.21.0",
|
||||||
"@eslint/config-helpers": "^0.2.1",
|
"@eslint/config-helpers": "^0.3.0",
|
||||||
"@eslint/core": "^0.14.0",
|
"@eslint/core": "^0.14.0",
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@eslint/js": "9.29.0",
|
"@eslint/js": "9.30.1",
|
||||||
"@eslint/plugin-kit": "^0.3.1",
|
"@eslint/plugin-kit": "^0.3.1",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
@@ -10724,9 +10724,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/globals": {
|
"node_modules/globals": {
|
||||||
"version": "16.2.0",
|
"version": "16.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz",
|
||||||
"integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==",
|
"integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -12944,9 +12944,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/nodemailer": {
|
"node_modules/nodemailer": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.4.tgz",
|
||||||
"integrity": "sha512-Ajq6Sz1x7cIK3pN6KesGTah+1gnwMnx5gKl3piQlQQE/PwyJ4Mbc8is2psWYxK3RJTVeqsDaCv8ZzXLCDHMTZw==",
|
"integrity": "sha512-9O00Vh89/Ld2EcVCqJ/etd7u20UhME0f/NToPfArwPEe1Don1zy4mAIz6ariRr7mJ2RDxtaDzN0WJVdVXPtZaw==",
|
||||||
"license": "MIT-0",
|
"license": "MIT-0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
@@ -13007,9 +13007,9 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/oauth4webapi": {
|
"node_modules/oauth4webapi": {
|
||||||
"version": "3.5.3",
|
"version": "3.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.5.5.tgz",
|
||||||
"integrity": "sha512-2bnHosmBLAQpXNBLOvaJMyMkr4Yya5ohE5Q9jqyxiN+aa7GFCzvDN1RRRMrp0NkfqRR2MTaQNkcSUCCjILD9oQ==",
|
"integrity": "sha512-1K88D2GiAydGblHo39NBro5TebGXa+7tYoyIbxvqv3+haDDry7CBE1eSYuNbOSsYCCU6y0gdynVZAkm4YPw4hg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/panva"
|
"url": "https://github.com/sponsors/panva"
|
||||||
@@ -13103,13 +13103,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/openid-client": {
|
"node_modules/openid-client": {
|
||||||
"version": "6.6.1",
|
"version": "6.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.6.2.tgz",
|
||||||
"integrity": "sha512-GmqoICGMI3IyFFjhvXxad8of4QWk2D0tm4vdJkldGm9nw7J3p1f7LPLWgGeFuKuw8HjDVe8Dd8QLGBe0NFvSSg==",
|
"integrity": "sha512-Xya5TNMnnZuTM6DbHdB4q0S3ig2NTAELnii/ASie1xDEr8iiB8zZbO871OWBdrw++sd3hW6bqWjgcmSy1RTWHA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jose": "^6.0.11",
|
"jose": "^6.0.11",
|
||||||
"oauth4webapi": "^3.5.3"
|
"oauth4webapi": "^3.5.4"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/panva"
|
"url": "https://github.com/sponsors/panva"
|
||||||
@@ -13453,14 +13453,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg": {
|
"node_modules/pg": {
|
||||||
"version": "8.16.2",
|
"version": "8.16.3",
|
||||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.2.tgz",
|
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
|
||||||
"integrity": "sha512-OtLWF0mKLmpxelOt9BqVq83QV6bTfsS0XLegIeAKqKjurRnRKie1Dc1iL89MugmSLhftxw6NNCyZhm1yQFLMEQ==",
|
"integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pg-connection-string": "^2.9.1",
|
"pg-connection-string": "^2.9.1",
|
||||||
"pg-pool": "^3.10.1",
|
"pg-pool": "^3.10.1",
|
||||||
"pg-protocol": "^1.10.2",
|
"pg-protocol": "^1.10.3",
|
||||||
"pg-types": "2.2.0",
|
"pg-types": "2.2.0",
|
||||||
"pgpass": "1.0.5"
|
"pgpass": "1.0.5"
|
||||||
},
|
},
|
||||||
@@ -13468,7 +13468,7 @@
|
|||||||
"node": ">= 16.0.0"
|
"node": ">= 16.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"pg-cloudflare": "^1.2.6"
|
"pg-cloudflare": "^1.2.7"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"pg-native": ">=3.0.1"
|
"pg-native": ">=3.0.1"
|
||||||
@@ -13480,9 +13480,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg-cloudflare": {
|
"node_modules/pg-cloudflare": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz",
|
||||||
"integrity": "sha512-uxmJAnmIgmYgnSFzgOf2cqGQBzwnRYcrEgXuFjJNEkpedEIPBSEzxY7ph4uA9k1mI+l/GR0HjPNS6FKNZe8SBQ==",
|
"integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
@@ -13520,9 +13520,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg-protocol": {
|
"node_modules/pg-protocol": {
|
||||||
"version": "1.10.2",
|
"version": "1.10.3",
|
||||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz",
|
||||||
"integrity": "sha512-Ci7jy8PbaWxfsck2dwZdERcDG2A0MG8JoQILs+uZNjABFuBuItAZCWUNz8sXRDMoui24rJw7WlXqgpMdBSN/vQ==",
|
"integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/pg-types": {
|
"node_modules/pg-types": {
|
||||||
@@ -13963,9 +13963,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
||||||
"integrity": "sha512-5xGWRa90Sp2+x1dQtNpIpeOQpTDBs9cZDmA/qs2vDNN2i18PdapqY7CmBeyLlMuGqXJRIOPaCaVZTLNQRWUH/A==",
|
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
@@ -15655,9 +15655,9 @@
|
|||||||
"license": "BSD-3-Clause"
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/sql-formatter": {
|
"node_modules/sql-formatter": {
|
||||||
"version": "15.6.5",
|
"version": "15.6.6",
|
||||||
"resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.6.5.tgz",
|
"resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.6.6.tgz",
|
||||||
"integrity": "sha512-fr4TyM1udCSrOHOmouotwUi8dxIDhSLpYNmPePGFVzxq8/i8jd828IapE49QXG7Gzkswxo5WwdAGnYX4YpKoTg==",
|
"integrity": "sha512-bZydXEXhaNDQBr8xYHC3a8thwcaMuTBp0CkKGjwGYDsIB26tnlWeWPwJtSQ0TEwiJcz9iJJON5mFPkx7XroHcg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -17363,15 +17363,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript-eslint": {
|
"node_modules/typescript-eslint": {
|
||||||
"version": "8.35.0",
|
"version": "8.35.1",
|
||||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.35.1.tgz",
|
||||||
"integrity": "sha512-uEnz70b7kBz6eg/j0Czy6K5NivaYopgxRjsnAJ2Fx5oTLo3wefTHIbL7AkQr1+7tJCRVpTs/wiM8JR/11Loq9A==",
|
"integrity": "sha512-xslJjFzhOmHYQzSB/QTeASAHbjmxOGEP6Coh93TXmUBFQoJ1VU35UHIDmG06Jd6taf3wqqC1ntBnCMeymy5Ovw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "8.35.0",
|
"@typescript-eslint/eslint-plugin": "8.35.1",
|
||||||
"@typescript-eslint/parser": "8.35.0",
|
"@typescript-eslint/parser": "8.35.1",
|
||||||
"@typescript-eslint/utils": "8.35.0"
|
"@typescript-eslint/utils": "8.35.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
|||||||
@@ -107,25 +107,21 @@ const compare = async () => {
|
|||||||
const { database } = configRepository.getEnv();
|
const { database } = configRepository.getEnv();
|
||||||
const db = postgres(asPostgresConnectionConfig(database.config));
|
const db = postgres(asPostgresConnectionConfig(database.config));
|
||||||
|
|
||||||
const source = schemaFromCode();
|
const source = schemaFromCode({ overrides: true });
|
||||||
const target = await schemaFromDatabase(db, {});
|
const target = await schemaFromDatabase(db, {});
|
||||||
|
|
||||||
const sourceParams = new Set(source.parameters.map(({ name }) => name));
|
|
||||||
target.parameters = target.parameters.filter(({ name }) => sourceParams.has(name));
|
|
||||||
|
|
||||||
const sourceTables = new Set(source.tables.map(({ name }) => name));
|
|
||||||
target.tables = target.tables.filter(({ name }) => sourceTables.has(name));
|
|
||||||
|
|
||||||
console.log(source.warnings.join('\n'));
|
console.log(source.warnings.join('\n'));
|
||||||
|
|
||||||
const up = schemaDiff(source, target, {
|
const up = schemaDiff(source, target, {
|
||||||
tables: { ignoreExtra: true },
|
tables: { ignoreExtra: true },
|
||||||
functions: { ignoreExtra: false },
|
functions: { ignoreExtra: false },
|
||||||
|
parameters: { ignoreExtra: true },
|
||||||
});
|
});
|
||||||
const down = schemaDiff(target, source, {
|
const down = schemaDiff(target, source, {
|
||||||
tables: { ignoreExtra: false },
|
tables: { ignoreExtra: false, ignoreMissing: true },
|
||||||
functions: { ignoreExtra: false },
|
functions: { ignoreExtra: false },
|
||||||
extension: { ignoreMissing: true },
|
extensions: { ignoreMissing: true },
|
||||||
|
parameters: { ignoreMissing: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
return { up, down };
|
return { up, down };
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ export interface SystemConfig {
|
|||||||
timeout: number;
|
timeout: number;
|
||||||
storageLabelClaim: string;
|
storageLabelClaim: string;
|
||||||
storageQuotaClaim: string;
|
storageQuotaClaim: string;
|
||||||
|
roleClaim: string;
|
||||||
};
|
};
|
||||||
passwordLogin: {
|
passwordLogin: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
@@ -263,6 +264,7 @@ export const defaults = Object.freeze<SystemConfig>({
|
|||||||
profileSigningAlgorithm: 'none',
|
profileSigningAlgorithm: 'none',
|
||||||
storageLabelClaim: 'preferred_username',
|
storageLabelClaim: 'preferred_username',
|
||||||
storageQuotaClaim: 'immich_quota',
|
storageQuotaClaim: 'immich_quota',
|
||||||
|
roleClaim: 'immich_role',
|
||||||
tokenEndpointAuthMethod: OAuthTokenEndpointAuthMethod.CLIENT_SECRET_POST,
|
tokenEndpointAuthMethod: OAuthTokenEndpointAuthMethod.CLIENT_SECRET_POST,
|
||||||
timeout: 30_000,
|
timeout: 30_000,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -395,6 +395,9 @@ class SystemConfigOAuthDto {
|
|||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
storageQuotaClaim!: string;
|
storageQuotaClaim!: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
roleClaim!: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class SystemConfigPasswordLoginDto {
|
class SystemConfigPasswordLoginDto {
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ export const immich_uuid_v7 = registerFunction({
|
|||||||
),
|
),
|
||||||
'hex')::uuid;
|
'hex')::uuid;
|
||||||
`,
|
`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const album_user_after_insert = registerFunction({
|
export const album_user_after_insert = registerFunction({
|
||||||
@@ -33,7 +32,6 @@ export const album_user_after_insert = registerFunction({
|
|||||||
WHERE "id" IN (SELECT DISTINCT "albumsId" FROM inserted_rows);
|
WHERE "id" IN (SELECT DISTINCT "albumsId" FROM inserted_rows);
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END`,
|
END`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const updated_at = registerFunction({
|
export const updated_at = registerFunction({
|
||||||
@@ -48,7 +46,6 @@ export const updated_at = registerFunction({
|
|||||||
new."updateId" = immich_uuid_v7(clock_timestamp);
|
new."updateId" = immich_uuid_v7(clock_timestamp);
|
||||||
return new;
|
return new;
|
||||||
END;`,
|
END;`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const f_concat_ws = registerFunction({
|
export const f_concat_ws = registerFunction({
|
||||||
@@ -59,7 +56,6 @@ export const f_concat_ws = registerFunction({
|
|||||||
parallel: 'safe',
|
parallel: 'safe',
|
||||||
behavior: 'immutable',
|
behavior: 'immutable',
|
||||||
body: `SELECT array_to_string($2, $1)`,
|
body: `SELECT array_to_string($2, $1)`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const f_unaccent = registerFunction({
|
export const f_unaccent = registerFunction({
|
||||||
@@ -71,7 +67,6 @@ export const f_unaccent = registerFunction({
|
|||||||
strict: true,
|
strict: true,
|
||||||
behavior: 'immutable',
|
behavior: 'immutable',
|
||||||
return: `unaccent('unaccent', $1)`,
|
return: `unaccent('unaccent', $1)`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ll_to_earth_public = registerFunction({
|
export const ll_to_earth_public = registerFunction({
|
||||||
@@ -83,7 +78,6 @@ export const ll_to_earth_public = registerFunction({
|
|||||||
strict: true,
|
strict: true,
|
||||||
behavior: 'immutable',
|
behavior: 'immutable',
|
||||||
body: `SELECT public.cube(public.cube(public.cube(public.earth()*cos(radians(latitude))*cos(radians(longitude))),public.earth()*cos(radians(latitude))*sin(radians(longitude))),public.earth()*sin(radians(latitude)))::public.earth`,
|
body: `SELECT public.cube(public.cube(public.cube(public.earth()*cos(radians(latitude))*cos(radians(longitude))),public.earth()*cos(radians(latitude))*sin(radians(longitude))),public.earth()*sin(radians(latitude)))::public.earth`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const users_delete_audit = registerFunction({
|
export const users_delete_audit = registerFunction({
|
||||||
@@ -97,7 +91,6 @@ export const users_delete_audit = registerFunction({
|
|||||||
FROM OLD;
|
FROM OLD;
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END`,
|
END`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const partners_delete_audit = registerFunction({
|
export const partners_delete_audit = registerFunction({
|
||||||
@@ -111,7 +104,6 @@ export const partners_delete_audit = registerFunction({
|
|||||||
FROM OLD;
|
FROM OLD;
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END`,
|
END`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const assets_delete_audit = registerFunction({
|
export const assets_delete_audit = registerFunction({
|
||||||
@@ -125,7 +117,6 @@ export const assets_delete_audit = registerFunction({
|
|||||||
FROM OLD;
|
FROM OLD;
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END`,
|
END`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const albums_delete_audit = registerFunction({
|
export const albums_delete_audit = registerFunction({
|
||||||
@@ -139,7 +130,6 @@ export const albums_delete_audit = registerFunction({
|
|||||||
FROM OLD;
|
FROM OLD;
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END`,
|
END`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const album_assets_delete_audit = registerFunction({
|
export const album_assets_delete_audit = registerFunction({
|
||||||
@@ -153,7 +143,6 @@ export const album_assets_delete_audit = registerFunction({
|
|||||||
WHERE "albumsId" IN (SELECT "id" FROM albums WHERE "id" IN (SELECT "albumsId" FROM OLD));
|
WHERE "albumsId" IN (SELECT "id" FROM albums WHERE "id" IN (SELECT "albumsId" FROM OLD));
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END`,
|
END`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const album_users_delete_audit = registerFunction({
|
export const album_users_delete_audit = registerFunction({
|
||||||
@@ -174,7 +163,6 @@ export const album_users_delete_audit = registerFunction({
|
|||||||
|
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END`,
|
END`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const memories_delete_audit = registerFunction({
|
export const memories_delete_audit = registerFunction({
|
||||||
@@ -188,7 +176,6 @@ export const memories_delete_audit = registerFunction({
|
|||||||
FROM OLD;
|
FROM OLD;
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END`,
|
END`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const memory_assets_delete_audit = registerFunction({
|
export const memory_assets_delete_audit = registerFunction({
|
||||||
@@ -202,7 +189,6 @@ export const memory_assets_delete_audit = registerFunction({
|
|||||||
WHERE "memoriesId" IN (SELECT "id" FROM memories WHERE "id" IN (SELECT "memoriesId" FROM OLD));
|
WHERE "memoriesId" IN (SELECT "id" FROM memories WHERE "id" IN (SELECT "memoriesId" FROM OLD));
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END`,
|
END`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const stacks_delete_audit = registerFunction({
|
export const stacks_delete_audit = registerFunction({
|
||||||
@@ -216,5 +202,4 @@ export const stacks_delete_audit = registerFunction({
|
|||||||
FROM OLD;
|
FROM OLD;
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END`,
|
END`,
|
||||||
synchronize: false,
|
|
||||||
});
|
});
|
||||||
|
|||||||
66
server/src/schema/migrations/1751924596408-AddOverrides.ts
Normal file
66
server/src/schema/migrations/1751924596408-AddOverrides.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { Kysely, sql } from 'kysely';
|
||||||
|
|
||||||
|
export async function up(db: Kysely<any>): Promise<void> {
|
||||||
|
await sql`CREATE TABLE "migration_overrides" ("name" character varying NOT NULL, "value" jsonb NOT NULL);`.execute(db);
|
||||||
|
await sql`ALTER TABLE "migration_overrides" ADD CONSTRAINT "migration_overrides_pkey" PRIMARY KEY ("name");`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_immich_uuid_v7', '{"type":"function","name":"immich_uuid_v7","sql":"CREATE OR REPLACE FUNCTION immich_uuid_v7(p_timestamp timestamp with time zone default clock_timestamp())\\n RETURNS uuid\\n VOLATILE LANGUAGE SQL\\n AS $$\\n SELECT encode(\\n set_bit(\\n set_bit(\\n overlay(uuid_send(gen_random_uuid())\\n placing substring(int8send(floor(extract(epoch from p_timestamp) * 1000)::bigint) from 3)\\n from 1 for 6\\n ),\\n 52, 1\\n ),\\n 53, 1\\n ),\\n ''hex'')::uuid;\\n $$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_album_user_after_insert', '{"type":"function","name":"album_user_after_insert","sql":"CREATE OR REPLACE FUNCTION album_user_after_insert()\\n RETURNS TRIGGER\\n LANGUAGE PLPGSQL\\n AS $$\\n BEGIN\\n UPDATE albums SET \\"updatedAt\\" = clock_timestamp(), \\"updateId\\" = immich_uuid_v7(clock_timestamp())\\n WHERE \\"id\\" IN (SELECT DISTINCT \\"albumsId\\" FROM inserted_rows);\\n RETURN NULL;\\n END\\n $$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_updated_at', '{"type":"function","name":"updated_at","sql":"CREATE OR REPLACE FUNCTION updated_at()\\n RETURNS TRIGGER\\n LANGUAGE PLPGSQL\\n AS $$\\n DECLARE\\n clock_timestamp TIMESTAMP := clock_timestamp();\\n BEGIN\\n new.\\"updatedAt\\" = clock_timestamp;\\n new.\\"updateId\\" = immich_uuid_v7(clock_timestamp);\\n return new;\\n END;\\n $$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_f_concat_ws', '{"type":"function","name":"f_concat_ws","sql":"CREATE OR REPLACE FUNCTION f_concat_ws(text, text[])\\n RETURNS text\\n PARALLEL SAFE IMMUTABLE LANGUAGE SQL\\n AS $$SELECT array_to_string($2, $1)$$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_f_unaccent', '{"type":"function","name":"f_unaccent","sql":"CREATE OR REPLACE FUNCTION f_unaccent(text)\\n RETURNS text\\n PARALLEL SAFE STRICT IMMUTABLE LANGUAGE SQL\\n RETURN unaccent(''unaccent'', $1)"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_ll_to_earth_public', '{"type":"function","name":"ll_to_earth_public","sql":"CREATE OR REPLACE FUNCTION ll_to_earth_public(latitude double precision, longitude double precision)\\n RETURNS public.earth\\n PARALLEL SAFE STRICT IMMUTABLE LANGUAGE SQL\\n AS $$SELECT public.cube(public.cube(public.cube(public.earth()*cos(radians(latitude))*cos(radians(longitude))),public.earth()*cos(radians(latitude))*sin(radians(longitude))),public.earth()*sin(radians(latitude)))::public.earth$$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_users_delete_audit', '{"type":"function","name":"users_delete_audit","sql":"CREATE OR REPLACE FUNCTION users_delete_audit()\\n RETURNS TRIGGER\\n LANGUAGE PLPGSQL\\n AS $$\\n BEGIN\\n INSERT INTO users_audit (\\"userId\\")\\n SELECT \\"id\\"\\n FROM OLD;\\n RETURN NULL;\\n END\\n $$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_partners_delete_audit', '{"type":"function","name":"partners_delete_audit","sql":"CREATE OR REPLACE FUNCTION partners_delete_audit()\\n RETURNS TRIGGER\\n LANGUAGE PLPGSQL\\n AS $$\\n BEGIN\\n INSERT INTO partners_audit (\\"sharedById\\", \\"sharedWithId\\")\\n SELECT \\"sharedById\\", \\"sharedWithId\\"\\n FROM OLD;\\n RETURN NULL;\\n END\\n $$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_assets_delete_audit', '{"type":"function","name":"assets_delete_audit","sql":"CREATE OR REPLACE FUNCTION assets_delete_audit()\\n RETURNS TRIGGER\\n LANGUAGE PLPGSQL\\n AS $$\\n BEGIN\\n INSERT INTO assets_audit (\\"assetId\\", \\"ownerId\\")\\n SELECT \\"id\\", \\"ownerId\\"\\n FROM OLD;\\n RETURN NULL;\\n END\\n $$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_albums_delete_audit', '{"type":"function","name":"albums_delete_audit","sql":"CREATE OR REPLACE FUNCTION albums_delete_audit()\\n RETURNS TRIGGER\\n LANGUAGE PLPGSQL\\n AS $$\\n BEGIN\\n INSERT INTO albums_audit (\\"albumId\\", \\"userId\\")\\n SELECT \\"id\\", \\"ownerId\\"\\n FROM OLD;\\n RETURN NULL;\\n END\\n $$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_album_assets_delete_audit', '{"type":"function","name":"album_assets_delete_audit","sql":"CREATE OR REPLACE FUNCTION album_assets_delete_audit()\\n RETURNS TRIGGER\\n LANGUAGE PLPGSQL\\n AS $$\\n BEGIN\\n INSERT INTO album_assets_audit (\\"albumId\\", \\"assetId\\")\\n SELECT \\"albumsId\\", \\"assetsId\\" FROM OLD\\n WHERE \\"albumsId\\" IN (SELECT \\"id\\" FROM albums WHERE \\"id\\" IN (SELECT \\"albumsId\\" FROM OLD));\\n RETURN NULL;\\n END\\n $$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_album_users_delete_audit', '{"type":"function","name":"album_users_delete_audit","sql":"CREATE OR REPLACE FUNCTION album_users_delete_audit()\\n RETURNS TRIGGER\\n LANGUAGE PLPGSQL\\n AS $$\\n BEGIN\\n INSERT INTO albums_audit (\\"albumId\\", \\"userId\\")\\n SELECT \\"albumsId\\", \\"usersId\\"\\n FROM OLD;\\n\\n IF pg_trigger_depth() = 1 THEN\\n INSERT INTO album_users_audit (\\"albumId\\", \\"userId\\")\\n SELECT \\"albumsId\\", \\"usersId\\"\\n FROM OLD;\\n END IF;\\n\\n RETURN NULL;\\n END\\n $$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_memories_delete_audit', '{"type":"function","name":"memories_delete_audit","sql":"CREATE OR REPLACE FUNCTION memories_delete_audit()\\n RETURNS TRIGGER\\n LANGUAGE PLPGSQL\\n AS $$\\n BEGIN\\n INSERT INTO memories_audit (\\"memoryId\\", \\"userId\\")\\n SELECT \\"id\\", \\"ownerId\\"\\n FROM OLD;\\n RETURN NULL;\\n END\\n $$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_memory_assets_delete_audit', '{"type":"function","name":"memory_assets_delete_audit","sql":"CREATE OR REPLACE FUNCTION memory_assets_delete_audit()\\n RETURNS TRIGGER\\n LANGUAGE PLPGSQL\\n AS $$\\n BEGIN\\n INSERT INTO memory_assets_audit (\\"memoryId\\", \\"assetId\\")\\n SELECT \\"memoriesId\\", \\"assetsId\\" FROM OLD\\n WHERE \\"memoriesId\\" IN (SELECT \\"id\\" FROM memories WHERE \\"id\\" IN (SELECT \\"memoriesId\\" FROM OLD));\\n RETURN NULL;\\n END\\n $$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('function_stacks_delete_audit', '{"type":"function","name":"stacks_delete_audit","sql":"CREATE OR REPLACE FUNCTION stacks_delete_audit()\\n RETURNS TRIGGER\\n LANGUAGE PLPGSQL\\n AS $$\\n BEGIN\\n INSERT INTO stacks_audit (\\"stackId\\", \\"userId\\")\\n SELECT \\"id\\", \\"ownerId\\"\\n FROM OLD;\\n RETURN NULL;\\n END\\n $$;"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_users_delete_audit', '{"type":"trigger","name":"users_delete_audit","sql":"CREATE OR REPLACE TRIGGER \\"users_delete_audit\\"\\n AFTER DELETE ON \\"users\\"\\n REFERENCING OLD TABLE AS \\"old\\"\\n FOR EACH STATEMENT\\n WHEN (pg_trigger_depth() = 0)\\n EXECUTE FUNCTION users_delete_audit();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_users_updated_at', '{"type":"trigger","name":"users_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"users_updated_at\\"\\n BEFORE UPDATE ON \\"users\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_libraries_updated_at', '{"type":"trigger","name":"libraries_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"libraries_updated_at\\"\\n BEFORE UPDATE ON \\"libraries\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_stacks_delete_audit', '{"type":"trigger","name":"stacks_delete_audit","sql":"CREATE OR REPLACE TRIGGER \\"stacks_delete_audit\\"\\n AFTER DELETE ON \\"asset_stack\\"\\n REFERENCING OLD TABLE AS \\"old\\"\\n FOR EACH STATEMENT\\n WHEN (pg_trigger_depth() = 0)\\n EXECUTE FUNCTION stacks_delete_audit();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_stacks_updated_at', '{"type":"trigger","name":"stacks_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"stacks_updated_at\\"\\n BEFORE UPDATE ON \\"asset_stack\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_assets_delete_audit', '{"type":"trigger","name":"assets_delete_audit","sql":"CREATE OR REPLACE TRIGGER \\"assets_delete_audit\\"\\n AFTER DELETE ON \\"assets\\"\\n REFERENCING OLD TABLE AS \\"old\\"\\n FOR EACH STATEMENT\\n WHEN (pg_trigger_depth() = 0)\\n EXECUTE FUNCTION assets_delete_audit();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_assets_updated_at', '{"type":"trigger","name":"assets_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"assets_updated_at\\"\\n BEFORE UPDATE ON \\"assets\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('index_idx_originalfilename_trigram', '{"type":"index","name":"idx_originalfilename_trigram","sql":"CREATE INDEX \\"idx_originalfilename_trigram\\" ON \\"assets\\" USING gin (f_unaccent(\\"originalFileName\\") gin_trgm_ops)"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('index_idx_local_date_time_month', '{"type":"index","name":"idx_local_date_time_month","sql":"CREATE INDEX \\"idx_local_date_time_month\\" ON \\"assets\\" ((date_trunc(''MONTH''::text, (\\"localDateTime\\" AT TIME ZONE ''UTC''::text)) AT TIME ZONE ''UTC''::text))"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('index_idx_local_date_time', '{"type":"index","name":"idx_local_date_time","sql":"CREATE INDEX \\"idx_local_date_time\\" ON \\"assets\\" (((\\"localDateTime\\" at time zone ''UTC'')::date))"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('index_UQ_assets_owner_library_checksum', '{"type":"index","name":"UQ_assets_owner_library_checksum","sql":"CREATE UNIQUE INDEX \\"UQ_assets_owner_library_checksum\\" ON \\"assets\\" (\\"ownerId\\", \\"libraryId\\", \\"checksum\\") WHERE (\\"libraryId\\" IS NOT NULL)"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('index_UQ_assets_owner_checksum', '{"type":"index","name":"UQ_assets_owner_checksum","sql":"CREATE UNIQUE INDEX \\"UQ_assets_owner_checksum\\" ON \\"assets\\" (\\"ownerId\\", \\"checksum\\") WHERE (\\"libraryId\\" IS NULL)"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_albums_delete_audit', '{"type":"trigger","name":"albums_delete_audit","sql":"CREATE OR REPLACE TRIGGER \\"albums_delete_audit\\"\\n AFTER DELETE ON \\"albums\\"\\n REFERENCING OLD TABLE AS \\"old\\"\\n FOR EACH STATEMENT\\n WHEN (pg_trigger_depth() = 0)\\n EXECUTE FUNCTION albums_delete_audit();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_albums_updated_at', '{"type":"trigger","name":"albums_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"albums_updated_at\\"\\n BEFORE UPDATE ON \\"albums\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_activity_updated_at', '{"type":"trigger","name":"activity_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"activity_updated_at\\"\\n BEFORE UPDATE ON \\"activity\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('index_IDX_activity_like', '{"type":"index","name":"IDX_activity_like","sql":"CREATE UNIQUE INDEX \\"IDX_activity_like\\" ON \\"activity\\" (\\"assetId\\", \\"userId\\", \\"albumId\\") WHERE (\\"isLiked\\" = true)"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_album_assets_delete_audit', '{"type":"trigger","name":"album_assets_delete_audit","sql":"CREATE OR REPLACE TRIGGER \\"album_assets_delete_audit\\"\\n AFTER DELETE ON \\"albums_assets_assets\\"\\n REFERENCING OLD TABLE AS \\"old\\"\\n FOR EACH STATEMENT\\n WHEN (pg_trigger_depth() <= 1)\\n EXECUTE FUNCTION album_assets_delete_audit();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_album_assets_updated_at', '{"type":"trigger","name":"album_assets_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"album_assets_updated_at\\"\\n BEFORE UPDATE ON \\"albums_assets_assets\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_album_users_delete_audit', '{"type":"trigger","name":"album_users_delete_audit","sql":"CREATE OR REPLACE TRIGGER \\"album_users_delete_audit\\"\\n AFTER DELETE ON \\"albums_shared_users_users\\"\\n REFERENCING OLD TABLE AS \\"old\\"\\n FOR EACH STATEMENT\\n WHEN (pg_trigger_depth() <= 1)\\n EXECUTE FUNCTION album_users_delete_audit();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_album_user_after_insert', '{"type":"trigger","name":"album_user_after_insert","sql":"CREATE OR REPLACE TRIGGER \\"album_user_after_insert\\"\\n AFTER INSERT ON \\"albums_shared_users_users\\"\\n REFERENCING NEW TABLE AS \\"inserted_rows\\"\\n FOR EACH STATEMENT\\n EXECUTE FUNCTION album_user_after_insert();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_album_users_updated_at', '{"type":"trigger","name":"album_users_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"album_users_updated_at\\"\\n BEFORE UPDATE ON \\"albums_shared_users_users\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_api_keys_updated_at', '{"type":"trigger","name":"api_keys_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"api_keys_updated_at\\"\\n BEFORE UPDATE ON \\"api_keys\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_person_updated_at', '{"type":"trigger","name":"person_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"person_updated_at\\"\\n BEFORE UPDATE ON \\"person\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_asset_files_updated_at', '{"type":"trigger","name":"asset_files_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"asset_files_updated_at\\"\\n BEFORE UPDATE ON \\"asset_files\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_asset_exif_updated_at', '{"type":"trigger","name":"asset_exif_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"asset_exif_updated_at\\"\\n BEFORE UPDATE ON \\"exif\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('index_face_index', '{"type":"index","name":"face_index","sql":"CREATE INDEX \\"face_index\\" ON \\"face_search\\" USING hnsw (embedding vector_cosine_ops) WITH (ef_construction = 300, m = 16)"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('index_IDX_geodata_gist_earthcoord', '{"type":"index","name":"IDX_geodata_gist_earthcoord","sql":"CREATE INDEX \\"IDX_geodata_gist_earthcoord\\" ON \\"geodata_places\\" (ll_to_earth_public(latitude, longitude))"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('index_idx_geodata_places_name', '{"type":"index","name":"idx_geodata_places_name","sql":"CREATE INDEX \\"idx_geodata_places_name\\" ON \\"geodata_places\\" USING gin (f_unaccent(\\"name\\") gin_trgm_ops)"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('index_idx_geodata_places_admin2_name', '{"type":"index","name":"idx_geodata_places_admin2_name","sql":"CREATE INDEX \\"idx_geodata_places_admin2_name\\" ON \\"geodata_places\\" USING gin (f_unaccent(\\"admin2Name\\") gin_trgm_ops)"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('index_idx_geodata_places_admin1_name', '{"type":"index","name":"idx_geodata_places_admin1_name","sql":"CREATE INDEX \\"idx_geodata_places_admin1_name\\" ON \\"geodata_places\\" USING gin (f_unaccent(\\"admin1Name\\") gin_trgm_ops)"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('index_idx_geodata_places_alternate_names', '{"type":"index","name":"idx_geodata_places_alternate_names","sql":"CREATE INDEX \\"idx_geodata_places_alternate_names\\" ON \\"geodata_places\\" USING gin (f_unaccent(\\"alternateNames\\") gin_trgm_ops)"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_memories_delete_audit', '{"type":"trigger","name":"memories_delete_audit","sql":"CREATE OR REPLACE TRIGGER \\"memories_delete_audit\\"\\n AFTER DELETE ON \\"memories\\"\\n REFERENCING OLD TABLE AS \\"old\\"\\n FOR EACH STATEMENT\\n WHEN (pg_trigger_depth() = 0)\\n EXECUTE FUNCTION memories_delete_audit();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_memories_updated_at', '{"type":"trigger","name":"memories_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"memories_updated_at\\"\\n BEFORE UPDATE ON \\"memories\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_memory_assets_delete_audit', '{"type":"trigger","name":"memory_assets_delete_audit","sql":"CREATE OR REPLACE TRIGGER \\"memory_assets_delete_audit\\"\\n AFTER DELETE ON \\"memories_assets_assets\\"\\n REFERENCING OLD TABLE AS \\"old\\"\\n FOR EACH STATEMENT\\n WHEN (pg_trigger_depth() <= 1)\\n EXECUTE FUNCTION memory_assets_delete_audit();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_memory_assets_updated_at', '{"type":"trigger","name":"memory_assets_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"memory_assets_updated_at\\"\\n BEFORE UPDATE ON \\"memories_assets_assets\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_notifications_updated_at', '{"type":"trigger","name":"notifications_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"notifications_updated_at\\"\\n BEFORE UPDATE ON \\"notifications\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_partners_delete_audit', '{"type":"trigger","name":"partners_delete_audit","sql":"CREATE OR REPLACE TRIGGER \\"partners_delete_audit\\"\\n AFTER DELETE ON \\"partners\\"\\n REFERENCING OLD TABLE AS \\"old\\"\\n FOR EACH STATEMENT\\n WHEN (pg_trigger_depth() = 0)\\n EXECUTE FUNCTION partners_delete_audit();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_partners_updated_at', '{"type":"trigger","name":"partners_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"partners_updated_at\\"\\n BEFORE UPDATE ON \\"partners\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_sessions_updated_at', '{"type":"trigger","name":"sessions_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"sessions_updated_at\\"\\n BEFORE UPDATE ON \\"sessions\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_session_sync_checkpoints_updated_at', '{"type":"trigger","name":"session_sync_checkpoints_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"session_sync_checkpoints_updated_at\\"\\n BEFORE UPDATE ON \\"session_sync_checkpoints\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
await sql`INSERT INTO "migration_overrides" ("name", "value") VALUES ('trigger_tags_updated_at', '{"type":"trigger","name":"tags_updated_at","sql":"CREATE OR REPLACE TRIGGER \\"tags_updated_at\\"\\n BEFORE UPDATE ON \\"tags\\"\\n FOR EACH ROW\\n EXECUTE FUNCTION updated_at();"}'::jsonb);`.execute(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(db: Kysely<any>): Promise<void> {
|
||||||
|
await sql`DROP TABLE "migration_overrides";`.execute(db);
|
||||||
|
}
|
||||||
@@ -44,7 +44,6 @@ import { ASSET_CHECKSUM_CONSTRAINT } from 'src/utils/database';
|
|||||||
@Index({
|
@Index({
|
||||||
name: 'idx_local_date_time',
|
name: 'idx_local_date_time',
|
||||||
expression: `(("localDateTime" at time zone 'UTC')::date)`,
|
expression: `(("localDateTime" at time zone 'UTC')::date)`,
|
||||||
synchronize: false,
|
|
||||||
})
|
})
|
||||||
@Index({
|
@Index({
|
||||||
name: 'idx_local_date_time_month',
|
name: 'idx_local_date_time_month',
|
||||||
@@ -56,7 +55,6 @@ import { ASSET_CHECKSUM_CONSTRAINT } from 'src/utils/database';
|
|||||||
name: 'idx_originalfilename_trigram',
|
name: 'idx_originalfilename_trigram',
|
||||||
using: 'gin',
|
using: 'gin',
|
||||||
expression: 'f_unaccent("originalFileName") gin_trgm_ops',
|
expression: 'f_unaccent("originalFileName") gin_trgm_ops',
|
||||||
synchronize: false,
|
|
||||||
})
|
})
|
||||||
// For all assets, each originalpath must be unique per user and library
|
// For all assets, each originalpath must be unique per user and library
|
||||||
export class AssetTable {
|
export class AssetTable {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { Column, ForeignKeyColumn, Index, Table } from 'src/sql-tools';
|
|||||||
using: 'hnsw',
|
using: 'hnsw',
|
||||||
expression: `embedding vector_cosine_ops`,
|
expression: `embedding vector_cosine_ops`,
|
||||||
with: 'ef_construction = 300, m = 16',
|
with: 'ef_construction = 300, m = 16',
|
||||||
synchronize: false,
|
|
||||||
})
|
})
|
||||||
export class FaceSearchTable {
|
export class FaceSearchTable {
|
||||||
@ForeignKeyColumn(() => AssetFaceTable, {
|
@ForeignKeyColumn(() => AssetFaceTable, {
|
||||||
|
|||||||
@@ -1,34 +1,29 @@
|
|||||||
import { Column, Index, PrimaryColumn, Table, Timestamp } from 'src/sql-tools';
|
import { Column, Index, PrimaryColumn, Table, Timestamp } from 'src/sql-tools';
|
||||||
|
|
||||||
@Table({ name: 'geodata_places', synchronize: false })
|
@Table({ name: 'geodata_places' })
|
||||||
@Index({
|
@Index({
|
||||||
name: 'idx_geodata_places_alternate_names',
|
name: 'idx_geodata_places_alternate_names',
|
||||||
using: 'gin',
|
using: 'gin',
|
||||||
expression: 'f_unaccent("alternateNames") gin_trgm_ops',
|
expression: 'f_unaccent("alternateNames") gin_trgm_ops',
|
||||||
synchronize: false,
|
|
||||||
})
|
})
|
||||||
@Index({
|
@Index({
|
||||||
name: 'idx_geodata_places_admin1_name',
|
name: 'idx_geodata_places_admin1_name',
|
||||||
using: 'gin',
|
using: 'gin',
|
||||||
expression: 'f_unaccent("admin1Name") gin_trgm_ops',
|
expression: 'f_unaccent("admin1Name") gin_trgm_ops',
|
||||||
synchronize: false,
|
|
||||||
})
|
})
|
||||||
@Index({
|
@Index({
|
||||||
name: 'idx_geodata_places_admin2_name',
|
name: 'idx_geodata_places_admin2_name',
|
||||||
using: 'gin',
|
using: 'gin',
|
||||||
expression: 'f_unaccent("admin2Name") gin_trgm_ops',
|
expression: 'f_unaccent("admin2Name") gin_trgm_ops',
|
||||||
synchronize: false,
|
|
||||||
})
|
})
|
||||||
@Index({
|
@Index({
|
||||||
name: 'idx_geodata_places_name',
|
name: 'idx_geodata_places_name',
|
||||||
using: 'gin',
|
using: 'gin',
|
||||||
expression: 'f_unaccent("name") gin_trgm_ops',
|
expression: 'f_unaccent("name") gin_trgm_ops',
|
||||||
synchronize: false,
|
|
||||||
})
|
})
|
||||||
@Index({
|
@Index({
|
||||||
name: 'IDX_geodata_gist_earthcoord',
|
name: 'IDX_geodata_gist_earthcoord',
|
||||||
expression: 'll_to_earth_public(latitude, longitude)',
|
expression: 'll_to_earth_public(latitude, longitude)',
|
||||||
synchronize: false,
|
|
||||||
})
|
})
|
||||||
export class GeodataPlacesTable {
|
export class GeodataPlacesTable {
|
||||||
@PrimaryColumn({ type: 'integer' })
|
@PrimaryColumn({ type: 'integer' })
|
||||||
|
|||||||
@@ -711,6 +711,7 @@ describe(AuthService.name, () => {
|
|||||||
|
|
||||||
expect(mocks.user.create).toHaveBeenCalledWith({
|
expect(mocks.user.create).toHaveBeenCalledWith({
|
||||||
email: user.email,
|
email: user.email,
|
||||||
|
isAdmin: false,
|
||||||
name: ' ',
|
name: ' ',
|
||||||
oauthId: user.oauthId,
|
oauthId: user.oauthId,
|
||||||
quotaSizeInBytes: 0,
|
quotaSizeInBytes: 0,
|
||||||
@@ -739,6 +740,7 @@ describe(AuthService.name, () => {
|
|||||||
|
|
||||||
expect(mocks.user.create).toHaveBeenCalledWith({
|
expect(mocks.user.create).toHaveBeenCalledWith({
|
||||||
email: user.email,
|
email: user.email,
|
||||||
|
isAdmin: false,
|
||||||
name: ' ',
|
name: ' ',
|
||||||
oauthId: user.oauthId,
|
oauthId: user.oauthId,
|
||||||
quotaSizeInBytes: 5_368_709_120,
|
quotaSizeInBytes: 5_368_709_120,
|
||||||
@@ -805,6 +807,93 @@ describe(AuthService.name, () => {
|
|||||||
expect(mocks.user.update).not.toHaveBeenCalled();
|
expect(mocks.user.update).not.toHaveBeenCalled();
|
||||||
expect(mocks.oauth.getProfilePicture).not.toHaveBeenCalled();
|
expect(mocks.oauth.getProfilePicture).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should only allow "admin" and "user" for the role claim', async () => {
|
||||||
|
const user = factory.userAdmin({ oauthId: 'oauth-id' });
|
||||||
|
|
||||||
|
mocks.systemMetadata.get.mockResolvedValue(systemConfigStub.oauthWithAutoRegister);
|
||||||
|
mocks.oauth.getProfile.mockResolvedValue({ sub: user.oauthId, email: user.email, immich_role: 'foo' });
|
||||||
|
mocks.user.getByEmail.mockResolvedValue(void 0);
|
||||||
|
mocks.user.getAdmin.mockResolvedValue(factory.userAdmin({ isAdmin: true }));
|
||||||
|
mocks.user.getByOAuthId.mockResolvedValue(void 0);
|
||||||
|
mocks.user.create.mockResolvedValue(user);
|
||||||
|
mocks.session.create.mockResolvedValue(factory.session());
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
sut.callback(
|
||||||
|
{ url: 'http://immich/auth/login?code=abc123', state: 'xyz789', codeVerifier: 'foo' },
|
||||||
|
{},
|
||||||
|
loginDetails,
|
||||||
|
),
|
||||||
|
).resolves.toEqual(oauthResponse(user));
|
||||||
|
|
||||||
|
expect(mocks.user.create).toHaveBeenCalledWith({
|
||||||
|
email: user.email,
|
||||||
|
name: ' ',
|
||||||
|
oauthId: user.oauthId,
|
||||||
|
quotaSizeInBytes: null,
|
||||||
|
storageLabel: null,
|
||||||
|
isAdmin: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create an admin user if the role claim is set to admin', async () => {
|
||||||
|
const user = factory.userAdmin({ oauthId: 'oauth-id' });
|
||||||
|
|
||||||
|
mocks.systemMetadata.get.mockResolvedValue(systemConfigStub.oauthWithAutoRegister);
|
||||||
|
mocks.oauth.getProfile.mockResolvedValue({ sub: user.oauthId, email: user.email, immich_role: 'admin' });
|
||||||
|
mocks.user.getByEmail.mockResolvedValue(void 0);
|
||||||
|
mocks.user.getByOAuthId.mockResolvedValue(void 0);
|
||||||
|
mocks.user.create.mockResolvedValue(user);
|
||||||
|
mocks.session.create.mockResolvedValue(factory.session());
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
sut.callback(
|
||||||
|
{ url: 'http://immich/auth/login?code=abc123', state: 'xyz789', codeVerifier: 'foo' },
|
||||||
|
{},
|
||||||
|
loginDetails,
|
||||||
|
),
|
||||||
|
).resolves.toEqual(oauthResponse(user));
|
||||||
|
|
||||||
|
expect(mocks.user.create).toHaveBeenCalledWith({
|
||||||
|
email: user.email,
|
||||||
|
name: ' ',
|
||||||
|
oauthId: user.oauthId,
|
||||||
|
quotaSizeInBytes: null,
|
||||||
|
storageLabel: null,
|
||||||
|
isAdmin: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should accept a custom role claim', async () => {
|
||||||
|
const user = factory.userAdmin({ oauthId: 'oauth-id' });
|
||||||
|
|
||||||
|
mocks.systemMetadata.get.mockResolvedValue({
|
||||||
|
oauth: { ...systemConfigStub.oauthWithAutoRegister, roleClaim: 'my_role' },
|
||||||
|
});
|
||||||
|
mocks.oauth.getProfile.mockResolvedValue({ sub: user.oauthId, email: user.email, my_role: 'admin' });
|
||||||
|
mocks.user.getByEmail.mockResolvedValue(void 0);
|
||||||
|
mocks.user.getByOAuthId.mockResolvedValue(void 0);
|
||||||
|
mocks.user.create.mockResolvedValue(user);
|
||||||
|
mocks.session.create.mockResolvedValue(factory.session());
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
sut.callback(
|
||||||
|
{ url: 'http://immich/auth/login?code=abc123', state: 'xyz789', codeVerifier: 'foo' },
|
||||||
|
{},
|
||||||
|
loginDetails,
|
||||||
|
),
|
||||||
|
).resolves.toEqual(oauthResponse(user));
|
||||||
|
|
||||||
|
expect(mocks.user.create).toHaveBeenCalledWith({
|
||||||
|
email: user.email,
|
||||||
|
name: ' ',
|
||||||
|
oauthId: user.oauthId,
|
||||||
|
quotaSizeInBytes: null,
|
||||||
|
storageLabel: null,
|
||||||
|
isAdmin: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('link', () => {
|
describe('link', () => {
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ export class AuthService extends BaseService {
|
|||||||
const { oauth } = await this.getConfig({ withCache: false });
|
const { oauth } = await this.getConfig({ withCache: false });
|
||||||
const url = this.resolveRedirectUri(oauth, dto.url);
|
const url = this.resolveRedirectUri(oauth, dto.url);
|
||||||
const profile = await this.oauthRepository.getProfile(oauth, url, expectedState, codeVerifier);
|
const profile = await this.oauthRepository.getProfile(oauth, url, expectedState, codeVerifier);
|
||||||
const { autoRegister, defaultStorageQuota, storageLabelClaim, storageQuotaClaim } = oauth;
|
const { autoRegister, defaultStorageQuota, storageLabelClaim, storageQuotaClaim, roleClaim } = oauth;
|
||||||
this.logger.debug(`Logging in with OAuth: ${JSON.stringify(profile)}`);
|
this.logger.debug(`Logging in with OAuth: ${JSON.stringify(profile)}`);
|
||||||
let user: UserAdmin | undefined = await this.userRepository.getByOAuthId(profile.sub);
|
let user: UserAdmin | undefined = await this.userRepository.getByOAuthId(profile.sub);
|
||||||
|
|
||||||
@@ -290,6 +290,11 @@ export class AuthService extends BaseService {
|
|||||||
default: defaultStorageQuota,
|
default: defaultStorageQuota,
|
||||||
isValid: (value: unknown) => Number(value) >= 0,
|
isValid: (value: unknown) => Number(value) >= 0,
|
||||||
});
|
});
|
||||||
|
const role = this.getClaim<'admin' | 'user'>(profile, {
|
||||||
|
key: roleClaim,
|
||||||
|
default: 'user',
|
||||||
|
isValid: (value: unknown) => isString(value) && ['admin', 'user'].includes(value),
|
||||||
|
});
|
||||||
|
|
||||||
const userName = profile.name ?? `${profile.given_name || ''} ${profile.family_name || ''}`;
|
const userName = profile.name ?? `${profile.given_name || ''} ${profile.family_name || ''}`;
|
||||||
user = await this.createUser({
|
user = await this.createUser({
|
||||||
@@ -298,6 +303,7 @@ export class AuthService extends BaseService {
|
|||||||
oauthId: profile.sub,
|
oauthId: profile.sub,
|
||||||
quotaSizeInBytes: storageQuota === null ? null : storageQuota * HumanReadableSize.GiB,
|
quotaSizeInBytes: storageQuota === null ? null : storageQuota * HumanReadableSize.GiB,
|
||||||
storageLabel: storageLabel || null,
|
storageLabel: storageLabel || null,
|
||||||
|
isAdmin: role === 'admin',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ const updatedConfig = Object.freeze<SystemConfig>({
|
|||||||
timeout: 30_000,
|
timeout: 30_000,
|
||||||
storageLabelClaim: 'preferred_username',
|
storageLabelClaim: 'preferred_username',
|
||||||
storageQuotaClaim: 'immich_quota',
|
storageQuotaClaim: 'immich_quota',
|
||||||
|
roleClaim: 'immich_role',
|
||||||
},
|
},
|
||||||
passwordLogin: {
|
passwordLogin: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|||||||
69
server/src/sql-tools/comparers/override.comparer.spec.ts
Normal file
69
server/src/sql-tools/comparers/override.comparer.spec.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import { compareOverrides } from 'src/sql-tools/comparers/override.comparer';
|
||||||
|
import { DatabaseOverride, Reason } from 'src/sql-tools/types';
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
const testOverride: DatabaseOverride = {
|
||||||
|
name: 'test',
|
||||||
|
value: { type: 'function', name: 'test_func', sql: 'func implementation' },
|
||||||
|
synchronize: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('compareOverrides', () => {
|
||||||
|
describe('onExtra', () => {
|
||||||
|
it('should work', () => {
|
||||||
|
expect(compareOverrides.onExtra(testOverride)).toEqual([
|
||||||
|
{
|
||||||
|
type: 'OverrideDrop',
|
||||||
|
overrideName: 'test',
|
||||||
|
reason: Reason.MissingInSource,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onMissing', () => {
|
||||||
|
it('should work', () => {
|
||||||
|
expect(compareOverrides.onMissing(testOverride)).toEqual([
|
||||||
|
{
|
||||||
|
type: 'OverrideCreate',
|
||||||
|
override: testOverride,
|
||||||
|
reason: Reason.MissingInTarget,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onCompare', () => {
|
||||||
|
it('should work', () => {
|
||||||
|
expect(compareOverrides.onCompare(testOverride, testOverride)).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should drop and recreate when the value changes', () => {
|
||||||
|
const source: DatabaseOverride = {
|
||||||
|
name: 'test',
|
||||||
|
value: {
|
||||||
|
type: 'function',
|
||||||
|
name: 'test_func',
|
||||||
|
sql: 'func implementation',
|
||||||
|
},
|
||||||
|
synchronize: true,
|
||||||
|
};
|
||||||
|
const target: DatabaseOverride = {
|
||||||
|
name: 'test',
|
||||||
|
value: {
|
||||||
|
type: 'function',
|
||||||
|
name: 'test_func',
|
||||||
|
sql: 'func implementation2',
|
||||||
|
},
|
||||||
|
synchronize: true,
|
||||||
|
};
|
||||||
|
expect(compareOverrides.onCompare(source, target)).toEqual([
|
||||||
|
{
|
||||||
|
override: source,
|
||||||
|
type: 'OverrideUpdate',
|
||||||
|
reason: expect.stringContaining('value is different'),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
29
server/src/sql-tools/comparers/override.comparer.ts
Normal file
29
server/src/sql-tools/comparers/override.comparer.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { Comparer, DatabaseOverride, Reason } from 'src/sql-tools/types';
|
||||||
|
|
||||||
|
export const compareOverrides: Comparer<DatabaseOverride> = {
|
||||||
|
onMissing: (source) => [
|
||||||
|
{
|
||||||
|
type: 'OverrideCreate',
|
||||||
|
override: source,
|
||||||
|
reason: Reason.MissingInTarget,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onExtra: (target) => [
|
||||||
|
{
|
||||||
|
type: 'OverrideDrop',
|
||||||
|
overrideName: target.name,
|
||||||
|
reason: Reason.MissingInSource,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onCompare: (source, target) => {
|
||||||
|
if (source.value.name !== target.value.name || source.value.sql !== target.value.sql) {
|
||||||
|
const sourceValue = JSON.stringify(source.value);
|
||||||
|
const targetValue = JSON.stringify(target.value);
|
||||||
|
return [
|
||||||
|
{ type: 'OverrideUpdate', override: source, reason: `value is different (${sourceValue} vs ${targetValue})` },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
};
|
||||||
74
server/src/sql-tools/contexts/base-context.ts
Normal file
74
server/src/sql-tools/contexts/base-context.ts
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import {
|
||||||
|
BaseContextOptions,
|
||||||
|
DatabaseEnum,
|
||||||
|
DatabaseExtension,
|
||||||
|
DatabaseFunction,
|
||||||
|
DatabaseOverride,
|
||||||
|
DatabaseParameter,
|
||||||
|
DatabaseSchema,
|
||||||
|
DatabaseTable,
|
||||||
|
} from 'src/sql-tools/types';
|
||||||
|
|
||||||
|
const asOverrideKey = (type: string, name: string) => `${type}:${name}`;
|
||||||
|
|
||||||
|
export class BaseContext {
|
||||||
|
databaseName: string;
|
||||||
|
schemaName: string;
|
||||||
|
overrideTableName: string;
|
||||||
|
|
||||||
|
tables: DatabaseTable[] = [];
|
||||||
|
functions: DatabaseFunction[] = [];
|
||||||
|
enums: DatabaseEnum[] = [];
|
||||||
|
extensions: DatabaseExtension[] = [];
|
||||||
|
parameters: DatabaseParameter[] = [];
|
||||||
|
overrides: DatabaseOverride[] = [];
|
||||||
|
warnings: string[] = [];
|
||||||
|
|
||||||
|
constructor(options: BaseContextOptions) {
|
||||||
|
this.databaseName = options.databaseName ?? 'postgres';
|
||||||
|
this.schemaName = options.schemaName ?? 'public';
|
||||||
|
this.overrideTableName = options.overrideTableName ?? 'migration_overrides';
|
||||||
|
}
|
||||||
|
|
||||||
|
getTableByName(name: string) {
|
||||||
|
return this.tables.find((table) => table.name === name);
|
||||||
|
}
|
||||||
|
|
||||||
|
warn(context: string, message: string) {
|
||||||
|
this.warnings.push(`[${context}] ${message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
build(): DatabaseSchema {
|
||||||
|
const overrideMap = new Map<string, DatabaseOverride>();
|
||||||
|
for (const override of this.overrides) {
|
||||||
|
const { type, name } = override.value;
|
||||||
|
overrideMap.set(asOverrideKey(type, name), override);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const func of this.functions) {
|
||||||
|
func.override = overrideMap.get(asOverrideKey('function', func.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const { indexes, triggers } of this.tables) {
|
||||||
|
for (const index of indexes) {
|
||||||
|
index.override = overrideMap.get(asOverrideKey('index', index.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const trigger of triggers) {
|
||||||
|
trigger.override = overrideMap.get(asOverrideKey('trigger', trigger.name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
databaseName: this.databaseName,
|
||||||
|
schemaName: this.schemaName,
|
||||||
|
tables: this.tables,
|
||||||
|
functions: this.functions,
|
||||||
|
enums: this.enums,
|
||||||
|
extensions: this.extensions,
|
||||||
|
parameters: this.parameters,
|
||||||
|
overrides: this.overrides,
|
||||||
|
warnings: this.warnings,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,45 +1,25 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
||||||
|
import { BaseContext } from 'src/sql-tools/contexts/base-context';
|
||||||
import { ColumnOptions, TableOptions } from 'src/sql-tools/decorators';
|
import { ColumnOptions, TableOptions } from 'src/sql-tools/decorators';
|
||||||
import { asKey } from 'src/sql-tools/helpers';
|
import { asKey } from 'src/sql-tools/helpers';
|
||||||
import {
|
import { DatabaseColumn, DatabaseTable, SchemaFromCodeOptions } from 'src/sql-tools/types';
|
||||||
DatabaseColumn,
|
|
||||||
DatabaseEnum,
|
|
||||||
DatabaseExtension,
|
|
||||||
DatabaseFunction,
|
|
||||||
DatabaseParameter,
|
|
||||||
DatabaseSchema,
|
|
||||||
DatabaseTable,
|
|
||||||
SchemaFromCodeOptions,
|
|
||||||
} from 'src/sql-tools/types';
|
|
||||||
|
|
||||||
type TableMetadata = { options: TableOptions; object: Function; methodToColumn: Map<string | symbol, DatabaseColumn> };
|
type TableMetadata = { options: TableOptions; object: Function; methodToColumn: Map<string | symbol, DatabaseColumn> };
|
||||||
|
|
||||||
export class SchemaBuilder {
|
export class ProcessorContext extends BaseContext {
|
||||||
databaseName: string;
|
constructor(public options: SchemaFromCodeOptions) {
|
||||||
schemaName: string;
|
options.createForeignKeyIndexes = options.createForeignKeyIndexes ?? true;
|
||||||
tables: DatabaseTable[] = [];
|
options.overrides = options.overrides ?? false;
|
||||||
functions: DatabaseFunction[] = [];
|
super(options);
|
||||||
enums: DatabaseEnum[] = [];
|
}
|
||||||
extensions: DatabaseExtension[] = [];
|
|
||||||
parameters: DatabaseParameter[] = [];
|
|
||||||
warnings: string[] = [];
|
|
||||||
|
|
||||||
classToTable: WeakMap<Function, DatabaseTable> = new WeakMap();
|
classToTable: WeakMap<Function, DatabaseTable> = new WeakMap();
|
||||||
tableToMetadata: WeakMap<DatabaseTable, TableMetadata> = new WeakMap();
|
tableToMetadata: WeakMap<DatabaseTable, TableMetadata> = new WeakMap();
|
||||||
|
|
||||||
constructor(options: SchemaFromCodeOptions) {
|
|
||||||
this.databaseName = options.databaseName ?? 'postgres';
|
|
||||||
this.schemaName = options.schemaName ?? 'public';
|
|
||||||
}
|
|
||||||
|
|
||||||
getTableByObject(object: Function) {
|
getTableByObject(object: Function) {
|
||||||
return this.classToTable.get(object);
|
return this.classToTable.get(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
getTableByName(name: string) {
|
|
||||||
return this.tables.find((table) => table.name === name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTableMetadata(table: DatabaseTable) {
|
getTableMetadata(table: DatabaseTable) {
|
||||||
const metadata = this.tableToMetadata.get(table);
|
const metadata = this.tableToMetadata.get(table);
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
@@ -92,10 +72,6 @@ export class SchemaBuilder {
|
|||||||
return asKey('IDX_', table, items);
|
return asKey('IDX_', table, items);
|
||||||
}
|
}
|
||||||
|
|
||||||
warn(context: string, message: string) {
|
|
||||||
this.warnings.push(`[${context}] ${message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
warnMissingTable(context: string, object: object, propertyName?: symbol | string) {
|
warnMissingTable(context: string, object: object, propertyName?: symbol | string) {
|
||||||
const label = object.constructor.name + (propertyName ? '.' + String(propertyName) : '');
|
const label = object.constructor.name + (propertyName ? '.' + String(propertyName) : '');
|
||||||
this.warn(context, `Unable to find table (${label})`);
|
this.warn(context, `Unable to find table (${label})`);
|
||||||
@@ -105,17 +81,4 @@ export class SchemaBuilder {
|
|||||||
const label = object.constructor.name + (propertyName ? '.' + String(propertyName) : '');
|
const label = object.constructor.name + (propertyName ? '.' + String(propertyName) : '');
|
||||||
this.warn(context, `Unable to find column (${label})`);
|
this.warn(context, `Unable to find column (${label})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
build(): DatabaseSchema {
|
|
||||||
return {
|
|
||||||
databaseName: this.databaseName,
|
|
||||||
schemaName: this.schemaName,
|
|
||||||
tables: this.tables,
|
|
||||||
functions: this.functions,
|
|
||||||
enums: this.enums,
|
|
||||||
extensions: this.extensions,
|
|
||||||
parameters: this.parameters,
|
|
||||||
warnings: this.warnings,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
8
server/src/sql-tools/contexts/reader-context.ts
Normal file
8
server/src/sql-tools/contexts/reader-context.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { BaseContext } from 'src/sql-tools/contexts/base-context';
|
||||||
|
import { SchemaFromDatabaseOptions } from 'src/sql-tools/types';
|
||||||
|
|
||||||
|
export class ReaderContext extends BaseContext {
|
||||||
|
constructor(public options: SchemaFromDatabaseOptions) {
|
||||||
|
super(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createHash } from 'node:crypto';
|
import { createHash } from 'node:crypto';
|
||||||
import { ColumnValue } from 'src/sql-tools/decorators/column.decorator';
|
import { ColumnValue } from 'src/sql-tools/decorators/column.decorator';
|
||||||
import { Comparer, DatabaseColumn, IgnoreOptions, SchemaDiff } from 'src/sql-tools/types';
|
import { Comparer, DatabaseColumn, DatabaseOverride, IgnoreOptions, SchemaDiff } from 'src/sql-tools/types';
|
||||||
|
|
||||||
export const asMetadataKey = (name: string) => `sql-tools:${name}`;
|
export const asMetadataKey = (name: string) => `sql-tools:${name}`;
|
||||||
|
|
||||||
@@ -56,6 +56,17 @@ export const haveEqualColumns = (sourceColumns?: string[], targetColumns?: strin
|
|||||||
return setIsEqual(new Set(sourceColumns ?? []), new Set(targetColumns ?? []));
|
return setIsEqual(new Set(sourceColumns ?? []), new Set(targetColumns ?? []));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const haveEqualOverrides = <T extends { override?: DatabaseOverride }>(source: T, target: T) => {
|
||||||
|
if (!source.override || !target.override) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sourceValue = source.override.value;
|
||||||
|
const targetValue = target.override.value;
|
||||||
|
|
||||||
|
return sourceValue.name === targetValue.name && sourceValue.sql === targetValue.sql;
|
||||||
|
};
|
||||||
|
|
||||||
export const compare = <T extends { name: string; synchronize: boolean }>(
|
export const compare = <T extends { name: string; synchronize: boolean }>(
|
||||||
sources: T[],
|
sources: T[],
|
||||||
targets: T[],
|
targets: T[],
|
||||||
@@ -72,7 +83,7 @@ export const compare = <T extends { name: string; synchronize: boolean }>(
|
|||||||
const source = sourceMap[key];
|
const source = sourceMap[key];
|
||||||
const target = targetMap[key];
|
const target = targetMap[key];
|
||||||
|
|
||||||
if (isIgnored(source, target, options)) {
|
if (isIgnored(source, target, options ?? true)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,6 +96,14 @@ export const compare = <T extends { name: string; synchronize: boolean }>(
|
|||||||
} else if (!source && target) {
|
} else if (!source && target) {
|
||||||
items.push(...comparer.onExtra(target));
|
items.push(...comparer.onExtra(target));
|
||||||
} else {
|
} else {
|
||||||
|
if (
|
||||||
|
haveEqualOverrides(
|
||||||
|
source as unknown as { override?: DatabaseOverride },
|
||||||
|
target as unknown as { override?: DatabaseOverride },
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
items.push(...comparer.onCompare(source, target));
|
items.push(...comparer.onCompare(source, target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,6 +116,9 @@ const isIgnored = (
|
|||||||
target: { synchronize?: boolean } | undefined,
|
target: { synchronize?: boolean } | undefined,
|
||||||
options: IgnoreOptions,
|
options: IgnoreOptions,
|
||||||
) => {
|
) => {
|
||||||
|
if (typeof options === 'boolean') {
|
||||||
|
return !options;
|
||||||
|
}
|
||||||
return (options.ignoreExtra && !source) || (options.ignoreMissing && !target);
|
return (options.ignoreExtra && !source) || (options.ignoreMissing && !target);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -165,3 +187,18 @@ export const asColumnComment = (tableName: string, columnName: string, comment:
|
|||||||
export const asColumnList = (columns: string[]) => columns.map((column) => `"${column}"`).join(', ');
|
export const asColumnList = (columns: string[]) => columns.map((column) => `"${column}"`).join(', ');
|
||||||
|
|
||||||
export const asForeignKeyConstraintName = (table: string, columns: string[]) => asKey('FK_', table, [...columns]);
|
export const asForeignKeyConstraintName = (table: string, columns: string[]) => asKey('FK_', table, [...columns]);
|
||||||
|
|
||||||
|
export const asJsonString = (value: unknown): string => {
|
||||||
|
return `'${escape(JSON.stringify(value))}'::jsonb`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const escape = (value: string) => {
|
||||||
|
return value
|
||||||
|
.replaceAll("'", "''")
|
||||||
|
.replaceAll(/[\\]/g, '\\\\')
|
||||||
|
.replaceAll(/[\b]/g, String.raw`\b`)
|
||||||
|
.replaceAll(/[\f]/g, String.raw`\f`)
|
||||||
|
.replaceAll(/[\n]/g, String.raw`\n`)
|
||||||
|
.replaceAll(/[\r]/g, String.raw`\r`)
|
||||||
|
.replaceAll(/[\t]/g, String.raw`\t`);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { asKey } from 'src/sql-tools/helpers';
|
import { asKey } from 'src/sql-tools/helpers';
|
||||||
import { ConstraintType, Processor } from 'src/sql-tools/types';
|
import { ConstraintType, Processor } from 'src/sql-tools/types';
|
||||||
|
|
||||||
export const processCheckConstraints: Processor = (builder, items) => {
|
export const processCheckConstraints: Processor = (ctx, items) => {
|
||||||
for (const {
|
for (const {
|
||||||
item: { object, options },
|
item: { object, options },
|
||||||
} of items.filter((item) => item.type === 'checkConstraint')) {
|
} of items.filter((item) => item.type === 'checkConstraint')) {
|
||||||
const table = builder.getTableByObject(object);
|
const table = ctx.getTableByObject(object);
|
||||||
if (!table) {
|
if (!table) {
|
||||||
builder.warnMissingTable('@Check', object);
|
ctx.warnMissingTable('@Check', object);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import { ColumnOptions } from 'src/sql-tools/decorators/column.decorator';
|
|||||||
import { fromColumnValue } from 'src/sql-tools/helpers';
|
import { fromColumnValue } from 'src/sql-tools/helpers';
|
||||||
import { Processor } from 'src/sql-tools/types';
|
import { Processor } from 'src/sql-tools/types';
|
||||||
|
|
||||||
export const processColumns: Processor = (builder, items) => {
|
export const processColumns: Processor = (ctx, items) => {
|
||||||
for (const {
|
for (const {
|
||||||
type,
|
type,
|
||||||
item: { object, propertyName, options },
|
item: { object, propertyName, options },
|
||||||
} of items.filter((item) => item.type === 'column' || item.type === 'foreignKeyColumn')) {
|
} of items.filter((item) => item.type === 'column' || item.type === 'foreignKeyColumn')) {
|
||||||
const table = builder.getTableByObject(object.constructor);
|
const table = ctx.getTableByObject(object.constructor);
|
||||||
if (!table) {
|
if (!table) {
|
||||||
builder.warnMissingTable(type === 'column' ? '@Column' : '@ForeignKeyColumn', object, propertyName);
|
ctx.warnMissingTable(type === 'column' ? '@Column' : '@ForeignKeyColumn', object, propertyName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ export const processColumns: Processor = (builder, items) => {
|
|||||||
|
|
||||||
const isEnum = !!(options as ColumnOptions).enum;
|
const isEnum = !!(options as ColumnOptions).enum;
|
||||||
|
|
||||||
builder.addColumn(
|
ctx.addColumn(
|
||||||
table,
|
table,
|
||||||
{
|
{
|
||||||
name: columnName,
|
name: columnName,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { fromColumnValue } from 'src/sql-tools/helpers';
|
import { fromColumnValue } from 'src/sql-tools/helpers';
|
||||||
import { Processor } from 'src/sql-tools/types';
|
import { Processor } from 'src/sql-tools/types';
|
||||||
|
|
||||||
export const processConfigurationParameters: Processor = (builder, items) => {
|
export const processConfigurationParameters: Processor = (ctx, items) => {
|
||||||
for (const {
|
for (const {
|
||||||
item: { options },
|
item: { options },
|
||||||
} of items.filter((item) => item.type === 'configurationParameter')) {
|
} of items.filter((item) => item.type === 'configurationParameter')) {
|
||||||
builder.parameters.push({
|
ctx.parameters.push({
|
||||||
databaseName: builder.databaseName,
|
databaseName: ctx.databaseName,
|
||||||
name: options.name,
|
name: options.name,
|
||||||
value: fromColumnValue(options.value),
|
value: fromColumnValue(options.value),
|
||||||
scope: options.scope,
|
scope: options.scope,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { asSnakeCase } from 'src/sql-tools/helpers';
|
import { asSnakeCase } from 'src/sql-tools/helpers';
|
||||||
import { Processor } from 'src/sql-tools/types';
|
import { Processor } from 'src/sql-tools/types';
|
||||||
|
|
||||||
export const processDatabases: Processor = (builder, items) => {
|
export const processDatabases: Processor = (ctx, items) => {
|
||||||
for (const {
|
for (const {
|
||||||
item: { object, options },
|
item: { object, options },
|
||||||
} of items.filter((item) => item.type === 'database')) {
|
} of items.filter((item) => item.type === 'database')) {
|
||||||
builder.databaseName = options.name || asSnakeCase(object.name);
|
ctx.databaseName = options.name || asSnakeCase(object.name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Processor } from 'src/sql-tools/types';
|
import { Processor } from 'src/sql-tools/types';
|
||||||
|
|
||||||
export const processEnums: Processor = (builder, items) => {
|
export const processEnums: Processor = (ctx, items) => {
|
||||||
for (const { item } of items.filter((item) => item.type === 'enum')) {
|
for (const { item } of items.filter((item) => item.type === 'enum')) {
|
||||||
// TODO log warnings if enum name is not unique
|
// TODO log warnings if enum name is not unique
|
||||||
builder.enums.push(item);
|
ctx.enums.push(item);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import { Processor } from 'src/sql-tools/types';
|
import { Processor } from 'src/sql-tools/types';
|
||||||
|
|
||||||
export const processExtensions: Processor = (builder, items) => {
|
export const processExtensions: Processor = (ctx, items) => {
|
||||||
|
if (ctx.options.extensions === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (const {
|
for (const {
|
||||||
item: { options },
|
item: { options },
|
||||||
} of items.filter((item) => item.type === 'extension')) {
|
} of items.filter((item) => item.type === 'extension')) {
|
||||||
builder.extensions.push({
|
ctx.extensions.push({
|
||||||
name: options.name,
|
name: options.name,
|
||||||
synchronize: options.synchronize ?? true,
|
synchronize: options.synchronize ?? true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
import { asForeignKeyConstraintName, asKey } from 'src/sql-tools/helpers';
|
import { asForeignKeyConstraintName, asKey } from 'src/sql-tools/helpers';
|
||||||
import { ActionType, ConstraintType, Processor } from 'src/sql-tools/types';
|
import { ActionType, ConstraintType, Processor } from 'src/sql-tools/types';
|
||||||
|
|
||||||
export const processForeignKeyColumns: Processor = (builder, items) => {
|
export const processForeignKeyColumns: Processor = (ctx, items) => {
|
||||||
for (const {
|
for (const {
|
||||||
item: { object, propertyName, options, target },
|
item: { object, propertyName, options, target },
|
||||||
} of items.filter((item) => item.type === 'foreignKeyColumn')) {
|
} of items.filter((item) => item.type === 'foreignKeyColumn')) {
|
||||||
const { table, column } = builder.getColumnByObjectAndPropertyName(object, propertyName);
|
const { table, column } = ctx.getColumnByObjectAndPropertyName(object, propertyName);
|
||||||
if (!table) {
|
if (!table) {
|
||||||
builder.warnMissingTable('@ForeignKeyColumn', object);
|
ctx.warnMissingTable('@ForeignKeyColumn', object);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!column) {
|
if (!column) {
|
||||||
// should be impossible since they are pre-created in `column.processor.ts`
|
// should be impossible since they are pre-created in `column.processor.ts`
|
||||||
builder.warnMissingColumn('@ForeignKeyColumn', object, propertyName);
|
ctx.warnMissingColumn('@ForeignKeyColumn', object, propertyName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const referenceTable = builder.getTableByObject(target());
|
const referenceTable = ctx.getTableByObject(target());
|
||||||
if (!referenceTable) {
|
if (!referenceTable) {
|
||||||
builder.warnMissingTable('@ForeignKeyColumn', object, propertyName);
|
ctx.warnMissingTable('@ForeignKeyColumn', object, propertyName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { asForeignKeyConstraintName } from 'src/sql-tools/helpers';
|
import { asForeignKeyConstraintName } from 'src/sql-tools/helpers';
|
||||||
import { ActionType, ConstraintType, Processor } from 'src/sql-tools/types';
|
import { ActionType, ConstraintType, Processor } from 'src/sql-tools/types';
|
||||||
|
|
||||||
export const processForeignKeyConstraints: Processor = (builder, items, config) => {
|
export const processForeignKeyConstraints: Processor = (ctx, items) => {
|
||||||
for (const {
|
for (const {
|
||||||
item: { object, options },
|
item: { object, options },
|
||||||
} of items.filter((item) => item.type === 'foreignKeyConstraint')) {
|
} of items.filter((item) => item.type === 'foreignKeyConstraint')) {
|
||||||
const table = builder.getTableByObject(object);
|
const table = ctx.getTableByObject(object);
|
||||||
if (!table) {
|
if (!table) {
|
||||||
builder.warnMissingTable('@ForeignKeyConstraint', { name: 'referenceTable' });
|
ctx.warnMissingTable('@ForeignKeyConstraint', { name: 'referenceTable' });
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const referenceTable = builder.getTableByObject(options.referenceTable());
|
const referenceTable = ctx.getTableByObject(options.referenceTable());
|
||||||
if (!referenceTable) {
|
if (!referenceTable) {
|
||||||
const referenceTableName = options.referenceTable()?.name;
|
const referenceTableName = options.referenceTable()?.name;
|
||||||
builder.warn(
|
ctx.warn(
|
||||||
'@ForeignKeyConstraint.referenceTable',
|
'@ForeignKeyConstraint.referenceTable',
|
||||||
`Unable to find table` + (referenceTableName ? ` (${referenceTableName})` : ''),
|
`Unable to find table` + (referenceTableName ? ` (${referenceTableName})` : ''),
|
||||||
);
|
);
|
||||||
@@ -25,16 +25,16 @@ export const processForeignKeyConstraints: Processor = (builder, items, config)
|
|||||||
|
|
||||||
for (const columnName of options.columns) {
|
for (const columnName of options.columns) {
|
||||||
if (!table.columns.some(({ name }) => name === columnName)) {
|
if (!table.columns.some(({ name }) => name === columnName)) {
|
||||||
const metadata = builder.getTableMetadata(table);
|
const metadata = ctx.getTableMetadata(table);
|
||||||
builder.warn('@ForeignKeyConstraint.columns', `Unable to find column (${metadata.object.name}.${columnName})`);
|
ctx.warn('@ForeignKeyConstraint.columns', `Unable to find column (${metadata.object.name}.${columnName})`);
|
||||||
missingColumn = true;
|
missingColumn = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const columnName of options.referenceColumns || []) {
|
for (const columnName of options.referenceColumns || []) {
|
||||||
if (!referenceTable.columns.some(({ name }) => name === columnName)) {
|
if (!referenceTable.columns.some(({ name }) => name === columnName)) {
|
||||||
const metadata = builder.getTableMetadata(referenceTable);
|
const metadata = ctx.getTableMetadata(referenceTable);
|
||||||
builder.warn(
|
ctx.warn(
|
||||||
'@ForeignKeyConstraint.referenceColumns',
|
'@ForeignKeyConstraint.referenceColumns',
|
||||||
`Unable to find column (${metadata.object.name}.${columnName})`,
|
`Unable to find column (${metadata.object.name}.${columnName})`,
|
||||||
);
|
);
|
||||||
@@ -67,9 +67,9 @@ export const processForeignKeyConstraints: Processor = (builder, items, config)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.index || options.indexName || config.createForeignKeyIndexes) {
|
if (options.index || options.indexName || ctx.options.createForeignKeyIndexes) {
|
||||||
table.indexes.push({
|
table.indexes.push({
|
||||||
name: options.indexName || builder.asIndexName(table.name, options.columns),
|
name: options.indexName || ctx.asIndexName(table.name, options.columns),
|
||||||
tableName: table.name,
|
tableName: table.name,
|
||||||
columnNames: options.columns,
|
columnNames: options.columns,
|
||||||
unique: false,
|
unique: false,
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import { Processor } from 'src/sql-tools/types';
|
import { Processor } from 'src/sql-tools/types';
|
||||||
|
|
||||||
export const processFunctions: Processor = (builder, items) => {
|
export const processFunctions: Processor = (ctx, items) => {
|
||||||
|
if (ctx.options.functions === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (const { item } of items.filter((item) => item.type === 'function')) {
|
for (const { item } of items.filter((item) => item.type === 'function')) {
|
||||||
// TODO log warnings if function name is not unique
|
// TODO log warnings if function name is not unique
|
||||||
builder.functions.push(item);
|
ctx.functions.push(item);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { Processor } from 'src/sql-tools/types';
|
import { Processor } from 'src/sql-tools/types';
|
||||||
|
|
||||||
export const processIndexes: Processor = (builder, items, config) => {
|
export const processIndexes: Processor = (ctx, items) => {
|
||||||
for (const {
|
for (const {
|
||||||
item: { object, options },
|
item: { object, options },
|
||||||
} of items.filter((item) => item.type === 'index')) {
|
} of items.filter((item) => item.type === 'index')) {
|
||||||
const table = builder.getTableByObject(object);
|
const table = ctx.getTableByObject(object);
|
||||||
if (!table) {
|
if (!table) {
|
||||||
builder.warnMissingTable('@Check', object);
|
ctx.warnMissingTable('@Check', object);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.indexes.push({
|
table.indexes.push({
|
||||||
name: options.name || builder.asIndexName(table.name, options.columns, options.where),
|
name: options.name || ctx.asIndexName(table.name, options.columns, options.where),
|
||||||
tableName: table.name,
|
tableName: table.name,
|
||||||
unique: options.unique ?? false,
|
unique: options.unique ?? false,
|
||||||
expression: options.expression,
|
expression: options.expression,
|
||||||
@@ -28,15 +28,15 @@ export const processIndexes: Processor = (builder, items, config) => {
|
|||||||
type,
|
type,
|
||||||
item: { object, propertyName, options },
|
item: { object, propertyName, options },
|
||||||
} of items.filter((item) => item.type === 'column' || item.type === 'foreignKeyColumn')) {
|
} of items.filter((item) => item.type === 'column' || item.type === 'foreignKeyColumn')) {
|
||||||
const { table, column } = builder.getColumnByObjectAndPropertyName(object, propertyName);
|
const { table, column } = ctx.getColumnByObjectAndPropertyName(object, propertyName);
|
||||||
if (!table) {
|
if (!table) {
|
||||||
builder.warnMissingTable('@Column', object);
|
ctx.warnMissingTable('@Column', object);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!column) {
|
if (!column) {
|
||||||
// should be impossible since they are created in `column.processor.ts`
|
// should be impossible since they are created in `column.processor.ts`
|
||||||
builder.warnMissingColumn('@Column', object, propertyName);
|
ctx.warnMissingColumn('@Column', object, propertyName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,12 +45,12 @@ export const processIndexes: Processor = (builder, items, config) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isIndexRequested =
|
const isIndexRequested =
|
||||||
options.indexName || options.index || (type === 'foreignKeyColumn' && config.createForeignKeyIndexes);
|
options.indexName || options.index || (type === 'foreignKeyColumn' && ctx.options.createForeignKeyIndexes);
|
||||||
if (!isIndexRequested) {
|
if (!isIndexRequested) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const indexName = options.indexName || builder.asIndexName(table.name, [column.name]);
|
const indexName = options.indexName || ctx.asIndexName(table.name, [column.name]);
|
||||||
|
|
||||||
const isIndexPresent = table.indexes.some((index) => index.name === indexName);
|
const isIndexPresent = table.indexes.some((index) => index.name === indexName);
|
||||||
if (isIndexPresent) {
|
if (isIndexPresent) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { processForeignKeyColumns } from 'src/sql-tools/processors/foreign-key-c
|
|||||||
import { processForeignKeyConstraints } from 'src/sql-tools/processors/foreign-key-constraint.processor';
|
import { processForeignKeyConstraints } from 'src/sql-tools/processors/foreign-key-constraint.processor';
|
||||||
import { processFunctions } from 'src/sql-tools/processors/function.processor';
|
import { processFunctions } from 'src/sql-tools/processors/function.processor';
|
||||||
import { processIndexes } from 'src/sql-tools/processors/index.processor';
|
import { processIndexes } from 'src/sql-tools/processors/index.processor';
|
||||||
|
import { processOverrides } from 'src/sql-tools/processors/override.processor';
|
||||||
import { processPrimaryKeyConstraints } from 'src/sql-tools/processors/primary-key-contraint.processor';
|
import { processPrimaryKeyConstraints } from 'src/sql-tools/processors/primary-key-contraint.processor';
|
||||||
import { processTables } from 'src/sql-tools/processors/table.processor';
|
import { processTables } from 'src/sql-tools/processors/table.processor';
|
||||||
import { processTriggers } from 'src/sql-tools/processors/trigger.processor';
|
import { processTriggers } from 'src/sql-tools/processors/trigger.processor';
|
||||||
@@ -29,4 +30,5 @@ export const processors: Processor[] = [
|
|||||||
processPrimaryKeyConstraints,
|
processPrimaryKeyConstraints,
|
||||||
processIndexes,
|
processIndexes,
|
||||||
processTriggers,
|
processTriggers,
|
||||||
|
processOverrides,
|
||||||
];
|
];
|
||||||
|
|||||||
50
server/src/sql-tools/processors/override.processor.ts
Normal file
50
server/src/sql-tools/processors/override.processor.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { asFunctionCreate } from 'src/sql-tools/transformers/function.transformer';
|
||||||
|
import { asIndexCreate } from 'src/sql-tools/transformers/index.transformer';
|
||||||
|
import { asTriggerCreate } from 'src/sql-tools/transformers/trigger.transformer';
|
||||||
|
import { Processor } from 'src/sql-tools/types';
|
||||||
|
|
||||||
|
export const processOverrides: Processor = (ctx) => {
|
||||||
|
if (ctx.options.overrides === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const func of ctx.functions) {
|
||||||
|
if (!func.synchronize) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.overrides.push({
|
||||||
|
name: `function_${func.name}`,
|
||||||
|
value: { type: 'function', name: func.name, sql: asFunctionCreate(func) },
|
||||||
|
synchronize: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const { triggers, indexes } of ctx.tables) {
|
||||||
|
for (const trigger of triggers) {
|
||||||
|
if (!trigger.synchronize) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.overrides.push({
|
||||||
|
name: `trigger_${trigger.name}`,
|
||||||
|
value: { type: 'trigger', name: trigger.name, sql: asTriggerCreate(trigger) },
|
||||||
|
synchronize: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const index of indexes) {
|
||||||
|
if (!index.synchronize) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index.expression || index.using || index.with || index.where) {
|
||||||
|
ctx.overrides.push({
|
||||||
|
name: `index_${index.name}`,
|
||||||
|
value: { type: 'index', name: index.name, sql: asIndexCreate(index) },
|
||||||
|
synchronize: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { asKey } from 'src/sql-tools/helpers';
|
import { asKey } from 'src/sql-tools/helpers';
|
||||||
import { ConstraintType, Processor } from 'src/sql-tools/types';
|
import { ConstraintType, Processor } from 'src/sql-tools/types';
|
||||||
|
|
||||||
export const processPrimaryKeyConstraints: Processor = (builder) => {
|
export const processPrimaryKeyConstraints: Processor = (ctx) => {
|
||||||
for (const table of builder.tables) {
|
for (const table of ctx.tables) {
|
||||||
const columnNames: string[] = [];
|
const columnNames: string[] = [];
|
||||||
|
|
||||||
for (const column of table.columns) {
|
for (const column of table.columns) {
|
||||||
@@ -12,7 +12,7 @@ export const processPrimaryKeyConstraints: Processor = (builder) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (columnNames.length > 0) {
|
if (columnNames.length > 0) {
|
||||||
const tableMetadata = builder.getTableMetadata(table);
|
const tableMetadata = ctx.getTableMetadata(table);
|
||||||
table.constraints.push({
|
table.constraints.push({
|
||||||
type: ConstraintType.PRIMARY_KEY,
|
type: ConstraintType.PRIMARY_KEY,
|
||||||
name: tableMetadata.options.primaryConstraintName || asPrimaryKeyConstraintName(table.name, columnNames),
|
name: tableMetadata.options.primaryConstraintName || asPrimaryKeyConstraintName(table.name, columnNames),
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user