feat: Add CalendarSelector component and install new dependencies.
This commit is contained in:
5
client/.dockerignore
Normal file
5
client/.dockerignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
.git
|
||||||
|
.env
|
||||||
|
dist
|
||||||
24
client/.gitignore
vendored
Normal file
24
client/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
13
client/Dockerfile
Normal file
13
client/Dockerfile
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json package-lock.json* ./
|
||||||
|
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 5173
|
||||||
|
|
||||||
|
CMD ["npm", "run", "dev", "--", "--host"]
|
||||||
16
client/README.md
Normal file
16
client/README.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# React + Vite
|
||||||
|
|
||||||
|
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||||
|
|
||||||
|
Currently, two official plugins are available:
|
||||||
|
|
||||||
|
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
|
||||||
|
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||||
|
|
||||||
|
## React Compiler
|
||||||
|
|
||||||
|
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
||||||
|
|
||||||
|
## Expanding the ESLint configuration
|
||||||
|
|
||||||
|
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
||||||
29
client/eslint.config.js
Normal file
29
client/eslint.config.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import js from '@eslint/js'
|
||||||
|
import globals from 'globals'
|
||||||
|
import reactHooks from 'eslint-plugin-react-hooks'
|
||||||
|
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||||
|
import { defineConfig, globalIgnores } from 'eslint/config'
|
||||||
|
|
||||||
|
export default defineConfig([
|
||||||
|
globalIgnores(['dist']),
|
||||||
|
{
|
||||||
|
files: ['**/*.{js,jsx}'],
|
||||||
|
extends: [
|
||||||
|
js.configs.recommended,
|
||||||
|
reactHooks.configs.flat.recommended,
|
||||||
|
reactRefresh.configs.vite,
|
||||||
|
],
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 2020,
|
||||||
|
globals: globals.browser,
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 'latest',
|
||||||
|
ecmaFeatures: { jsx: true },
|
||||||
|
sourceType: 'module',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
13
client/index.html
Normal file
13
client/index.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>client</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.jsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
3923
client/package-lock.json
generated
Normal file
3923
client/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
33
client/package.json
Normal file
33
client/package.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "client",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
|
"framer-motion": "^12.24.0",
|
||||||
|
"react": "^19.2.0",
|
||||||
|
"react-dom": "^19.2.0",
|
||||||
|
"react-router-dom": "^7.11.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.39.1",
|
||||||
|
"@types/react": "^19.2.5",
|
||||||
|
"@types/react-dom": "^19.2.3",
|
||||||
|
"@vitejs/plugin-react": "^5.1.1",
|
||||||
|
"autoprefixer": "^10.4.23",
|
||||||
|
"eslint": "^9.39.1",
|
||||||
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
|
"eslint-plugin-react-refresh": "^0.4.24",
|
||||||
|
"globals": "^16.5.0",
|
||||||
|
"postcss": "^8.5.6",
|
||||||
|
"tailwindcss": "^3.4.17",
|
||||||
|
"vite": "^7.2.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
client/postcss.config.js
Normal file
6
client/postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
1
client/public/vite.svg
Normal file
1
client/public/vite.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
42
client/src/App.css
Normal file
42
client/src/App.css
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#root {
|
||||||
|
max-width: 1280px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 6em;
|
||||||
|
padding: 1.5em;
|
||||||
|
will-change: filter;
|
||||||
|
transition: filter 300ms;
|
||||||
|
}
|
||||||
|
.logo:hover {
|
||||||
|
filter: drop-shadow(0 0 2em #646cffaa);
|
||||||
|
}
|
||||||
|
.logo.react:hover {
|
||||||
|
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes logo-spin {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
a:nth-of-type(2) .logo {
|
||||||
|
animation: logo-spin infinite 20s linear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.read-the-docs {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
36
client/src/App.jsx
Normal file
36
client/src/App.jsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { BrowserRouter, Routes, Route, Outlet } from 'react-router-dom';
|
||||||
|
import CreateEvent from './components/CreateEvent';
|
||||||
|
import EventPoll from './components/EventPoll';
|
||||||
|
import AnalyticsDashboard from './components/AnalyticsDashboard';
|
||||||
|
|
||||||
|
function Layout() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-slate-50 flex flex-col items-center p-4 sm:p-6 font-sans text-slate-900">
|
||||||
|
<header className="w-full max-w-2xl flex justify-between items-center py-6 mb-8">
|
||||||
|
<div className="text-xl font-bold tracking-tight text-slate-900 flex items-center gap-2">
|
||||||
|
<span className="w-8 h-8 rounded-lg bg-primary text-white flex items-center justify-center font-serif italic text-lg shadow-stripe">e</span>
|
||||||
|
eventy
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main className="w-full max-w-2xl relative z-10">
|
||||||
|
<Outlet />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<BrowserRouter>
|
||||||
|
<Routes>
|
||||||
|
<Route element={<Layout />}>
|
||||||
|
<Route path="/" element={<CreateEvent />} />
|
||||||
|
<Route path="/event/:id" element={<EventPoll />} />
|
||||||
|
<Route path="/event/:id/analytics" element={<AnalyticsDashboard />} />
|
||||||
|
</Route>
|
||||||
|
</Routes>
|
||||||
|
</BrowserRouter>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
1
client/src/assets/react.svg
Normal file
1
client/src/assets/react.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 4.0 KiB |
156
client/src/components/AnalyticsDashboard.jsx
Normal file
156
client/src/components/AnalyticsDashboard.jsx
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { format, parseISO, eachDayOfInterval } from 'date-fns';
|
||||||
|
|
||||||
|
export default function AnalyticsDashboard() {
|
||||||
|
const { id } = useParams();
|
||||||
|
const [data, setData] = useState(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch(`/api/events/${id}/analytics`)
|
||||||
|
.then(res => {
|
||||||
|
if (!res.ok) throw new Error('Failed to load analytics');
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.then(setData)
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
if (loading && !data) return <div className="text-slate-400 animate-pulse text-center mt-20 font-medium">Analysing responses...</div>;
|
||||||
|
if (!data) return <div className="text-rose-500 text-center mt-20">Failed to load analytics</div>;
|
||||||
|
|
||||||
|
const { event, participants, votes } = data;
|
||||||
|
|
||||||
|
const allDates = eachDayOfInterval({
|
||||||
|
start: parseISO(event.start_date),
|
||||||
|
end: parseISO(event.end_date)
|
||||||
|
}).map(d => format(d, 'yyyy-MM-dd'));
|
||||||
|
|
||||||
|
const scores = {};
|
||||||
|
allDates.forEach(date => scores[date] = 0);
|
||||||
|
|
||||||
|
votes.forEach(v => {
|
||||||
|
if (v.status === 'available') {
|
||||||
|
scores[v.date] = (scores[v.date] || 0) + 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const rankedDates = Object.entries(scores)
|
||||||
|
.sort(([, a], [, b]) => b - a)
|
||||||
|
.slice(0, 5);
|
||||||
|
|
||||||
|
const maxVotes = participants.length > 0 ? participants.length : 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full pb-32">
|
||||||
|
<div className="text-center mb-12">
|
||||||
|
<h2 className="text-xs uppercase tracking-widest text-slate-500 mb-2 font-bold">Results for</h2>
|
||||||
|
<h1 className="text-3xl md:text-5xl font-bold text-slate-900 capitalize leading-tight">{event.name}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid md:grid-cols-2 gap-8 max-w-5xl mx-auto">
|
||||||
|
{/* Best Dates Panel */}
|
||||||
|
<div className="bg-white p-6 rounded-xl shadow-stripe border border-slate-200">
|
||||||
|
<h2 className="text-lg font-bold mb-6 text-slate-800 flex items-center gap-2">
|
||||||
|
<span className="text-primary">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fillRule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clipRule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
Top Dates
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-6">
|
||||||
|
{rankedDates.map(([date, score], idx) => {
|
||||||
|
const percentage = Math.round((score / maxVotes) * 100);
|
||||||
|
return (
|
||||||
|
<div key={date} className="group">
|
||||||
|
<div className="flex justify-between items-end mb-2">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<span className={`font-semibold text-lg ${idx === 0 ? 'text-primary' : 'text-slate-700'}`}>
|
||||||
|
{format(parseISO(date), 'EEE, MMM do')}
|
||||||
|
</span>
|
||||||
|
{idx === 0 && <span className="text-[10px] uppercase font-bold tracking-wider bg-primary/10 text-primary px-2 py-0.5 rounded-full">Best</span>}
|
||||||
|
</div>
|
||||||
|
<span className="text-sm font-medium text-slate-500">{score} / {maxVotes}</span>
|
||||||
|
</div>
|
||||||
|
<div className="h-2.5 bg-slate-100 rounded-full overflow-hidden">
|
||||||
|
<div
|
||||||
|
className={`h-full rounded-full transition-all duration-1000 ease-out ${idx === 0 ? 'bg-primary' : 'bg-slate-300'}`}
|
||||||
|
style={{ width: `${percentage}%` }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Participants Panel */}
|
||||||
|
<div className="bg-white p-6 rounded-xl shadow-stripe border border-slate-200 overflow-hidden">
|
||||||
|
<div className="flex justify-between items-center mb-6">
|
||||||
|
<h2 className="text-lg font-bold text-slate-800 flex items-center gap-2">
|
||||||
|
<span className="text-slate-400">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path d="M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
Availability
|
||||||
|
</h2>
|
||||||
|
<span className="text-xs font-semibold text-slate-500 bg-slate-100 px-2.5 py-1 rounded-full">{participants.length}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="overflow-x-auto -mx-6 px-6 pb-2">
|
||||||
|
<table className="w-full text-left border-collapse min-w-[300px]">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th className="p-3 pl-0 text-xs font-bold text-slate-400 uppercase tracking-widest border-b border-slate-100 sticky left-0 bg-white z-10 w-32">Name</th>
|
||||||
|
{allDates.map(date => (
|
||||||
|
<th key={date} className="p-2 text-[10px] font-bold text-slate-400 border-b border-slate-100 text-center min-w-[40px]">
|
||||||
|
{format(parseISO(date), 'dd')}
|
||||||
|
</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{participants.map(p => (
|
||||||
|
<tr key={p.id} className="group hover:bg-slate-50 transition-colors">
|
||||||
|
<td className="p-3 pl-0 border-b border-slate-100 font-medium text-slate-700 sticky left-0 bg-white group-hover:bg-slate-50 transition-colors z-10 text-sm">{p.name}</td>
|
||||||
|
{allDates.map(date => {
|
||||||
|
const vote = votes.find(v => v.participant_id === p.id && v.date === date);
|
||||||
|
|
||||||
|
if (vote?.status === 'available') {
|
||||||
|
return (
|
||||||
|
<td key={date} className="p-2 border-b border-slate-100 text-center">
|
||||||
|
<div className="w-3 h-3 bg-primary rounded-full mx-auto"></div>
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
} else if (vote?.status === 'unavailable') {
|
||||||
|
return (
|
||||||
|
<td key={date} className="p-2 border-b border-slate-100 text-center">
|
||||||
|
<div className="w-1.5 h-1.5 bg-rose-200 rounded-full mx-auto"></div>
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<td key={date} className="p-2 border-b border-slate-100 text-center text-slate-200">·</td>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
{participants.length === 0 && (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={allDates.length + 1} className="p-8 text-center text-slate-400 text-sm italic">Waiting for responses...</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
102
client/src/components/CalendarSelector.jsx
Normal file
102
client/src/components/CalendarSelector.jsx
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { format, isWithinInterval, startOfMonth, endOfMonth, eachDayOfInterval, getDay, parseISO } from 'date-fns';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function CalendarSelector({ startDate, endDate, votes, onToggle, readOnly = false }) {
|
||||||
|
const start = parseISO(startDate);
|
||||||
|
const end = parseISO(endDate);
|
||||||
|
const months = eachDayOfInterval({ start: startOfMonth(start), end: endOfMonth(end) })
|
||||||
|
.filter(d => d.getDate() === 1);
|
||||||
|
|
||||||
|
const MonthView = ({ monthStart }) => {
|
||||||
|
const daysInMonth = eachDayOfInterval({
|
||||||
|
start: startOfMonth(monthStart),
|
||||||
|
end: endOfMonth(monthStart)
|
||||||
|
});
|
||||||
|
const startOffset = getDay(monthStart);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-8">
|
||||||
|
<h3 className="font-bold text-lg mb-4 text-slate-800 capitalize sticky top-0 bg-slate-50/95 backdrop-blur py-2 z-10 border-b border-slate-200/50">
|
||||||
|
{format(monthStart, 'MMMM yyyy')}
|
||||||
|
</h3>
|
||||||
|
<div className="grid grid-cols-7 gap-1 sm:gap-2">
|
||||||
|
{['S', 'M', 'T', 'W', 'T', 'F', 'S'].map(d => (
|
||||||
|
<div key={d} className="text-center text-xs text-slate-400 font-bold py-2">{d}</div>
|
||||||
|
))}
|
||||||
|
{Array(startOffset).fill(null).map((_, i) => <div key={`empty-${i}`} />)}
|
||||||
|
{daysInMonth.map(date => {
|
||||||
|
const inRange = isWithinInterval(date, { start, end });
|
||||||
|
const dateStr = format(date, 'yyyy-MM-dd');
|
||||||
|
const status = votes[dateStr];
|
||||||
|
|
||||||
|
if (!inRange) {
|
||||||
|
return (
|
||||||
|
<div key={dateStr} className="aspect-square flex items-center justify-center text-slate-300 text-sm">
|
||||||
|
{format(date, 'd')}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DateCell
|
||||||
|
key={dateStr}
|
||||||
|
date={date}
|
||||||
|
status={status}
|
||||||
|
onToggle={() => !readOnly && onToggle(dateStr)}
|
||||||
|
readOnly={readOnly}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full select-none">
|
||||||
|
{months.map(m => <MonthView key={m.toString()} monthStart={m} />)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DateCell({ date, status, onToggle, readOnly }) {
|
||||||
|
let bg = 'bg-white border border-slate-200';
|
||||||
|
let text = 'text-slate-600';
|
||||||
|
let scale = 1;
|
||||||
|
const isAvailable = status === 'available';
|
||||||
|
const isUnavailable = status === 'unavailable';
|
||||||
|
|
||||||
|
if (isAvailable) {
|
||||||
|
bg = 'bg-primary text-white border-primary shadow-md shadow-primary/30';
|
||||||
|
text = 'text-white';
|
||||||
|
scale = 1.05;
|
||||||
|
} else if (isUnavailable) {
|
||||||
|
bg = 'bg-rose-50 border-rose-200';
|
||||||
|
text = 'text-rose-400 line-through decoration-2';
|
||||||
|
scale = 0.95;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.button
|
||||||
|
whileTap={!readOnly ? { scale: 0.9 } : {}}
|
||||||
|
animate={{ scale }}
|
||||||
|
onClick={onToggle}
|
||||||
|
className={`
|
||||||
|
aspect-square rounded-lg flex items-center justify-center text-sm font-medium transition-all relative
|
||||||
|
${bg} ${text} ${readOnly ? 'cursor-default' : 'cursor-pointer hover:shadow-sm'}
|
||||||
|
${!status && !readOnly ? 'hover:border-primary/50' : ''}
|
||||||
|
`}
|
||||||
|
disabled={readOnly}
|
||||||
|
>
|
||||||
|
{format(date, 'd')}
|
||||||
|
{isAvailable && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ scale: 0 }}
|
||||||
|
animate={{ scale: 1 }}
|
||||||
|
className="absolute -top-1 -right-1 w-2.5 h-2.5 bg-white rounded-full border-2 border-primary"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</motion.button>
|
||||||
|
);
|
||||||
|
}
|
||||||
170
client/src/components/CreateEvent.jsx
Normal file
170
client/src/components/CreateEvent.jsx
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { format } from 'date-fns';
|
||||||
|
|
||||||
|
function CreateEvent() {
|
||||||
|
const [eventName, setEventName] = useState('');
|
||||||
|
const [description, setDescription] = useState('');
|
||||||
|
const [startDate, setStartDate] = useState(format(new Date(), 'yyyy-MM-dd'));
|
||||||
|
const [endDate, setEndDate] = useState(format(new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), 'yyyy-MM-dd'));
|
||||||
|
const [links, setLinks] = useState(null);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!eventName || !startDate || !endDate) return;
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/events', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: eventName,
|
||||||
|
description,
|
||||||
|
startDate,
|
||||||
|
endDate
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.id) {
|
||||||
|
const origin = window.location.origin;
|
||||||
|
setLinks({
|
||||||
|
invite: `${origin}/event/${data.id}`,
|
||||||
|
analytics: `${origin}/event/${data.id}/analytics`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating event:', error);
|
||||||
|
alert('Failed to create event');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (links) {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="bg-white shadow-stripe p-8 rounded-xl text-center max-w-lg mx-auto"
|
||||||
|
>
|
||||||
|
<div className="w-16 h-16 bg-emerald-50 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<svg className="w-8 h-8 text-emerald-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h1 className="text-2xl font-bold text-slate-800 mb-2">Event Created!</h1>
|
||||||
|
<p className="text-slate-500 mb-8">Share these links with your group.</p>
|
||||||
|
|
||||||
|
<div className="mb-6 text-left">
|
||||||
|
<label className="block text-slate-500 text-xs mb-2 uppercase tracking-wider font-bold">Invite Link</label>
|
||||||
|
<div
|
||||||
|
className="bg-slate-50 p-4 rounded-lg flex justify-between items-center group cursor-pointer border border-slate-200 hover:border-primary transition-colors"
|
||||||
|
onClick={() => navigator.clipboard.writeText(links.invite)}
|
||||||
|
>
|
||||||
|
<span className="truncate text-slate-700 text-sm font-mono">{links.invite}</span>
|
||||||
|
<span className="text-primary text-sm font-medium ml-2">Copy</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-8 text-left">
|
||||||
|
<label className="block text-slate-500 text-xs mb-2 uppercase tracking-wider font-bold">Analytics (Secret)</label>
|
||||||
|
<div
|
||||||
|
className="bg-slate-50 p-4 rounded-lg flex justify-between items-center group cursor-pointer border border-slate-200 hover:border-primary transition-colors"
|
||||||
|
onClick={() => navigator.clipboard.writeText(links.analytics)}
|
||||||
|
>
|
||||||
|
<span className="truncate text-slate-700 text-sm font-mono">{links.analytics}</span>
|
||||||
|
<span className="text-primary text-sm font-medium ml-2">Copy</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => setLinks(null)}
|
||||||
|
className="text-primary hover:text-primary-hover font-medium underline underline-offset-4 transition-colors"
|
||||||
|
>
|
||||||
|
Create Another Event
|
||||||
|
</button>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="w-full max-w-md mx-auto"
|
||||||
|
>
|
||||||
|
<div className="bg-white rounded-xl shadow-stripe p-6 sm:p-8">
|
||||||
|
<h1 className="text-2xl font-bold text-slate-800 mb-6">Create New Event</h1>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-6">
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-slate-700 mb-2">
|
||||||
|
Event Name
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={eventName}
|
||||||
|
onChange={(e) => setEventName(e.target.value)}
|
||||||
|
placeholder="e.g., Team Dinner, Project Kickoff"
|
||||||
|
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent outline-none transition-all placeholder:text-slate-400 text-slate-800"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-slate-700 mb-2">
|
||||||
|
Description (Optional)
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
value={description}
|
||||||
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
|
placeholder="Add some details about the event..."
|
||||||
|
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent outline-none transition-all placeholder:text-slate-400 text-slate-800 resize-none h-24"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-slate-700 mb-2">
|
||||||
|
Earliest Date
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
value={startDate}
|
||||||
|
onChange={(e) => setStartDate(e.target.value)}
|
||||||
|
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent outline-none transition-all text-slate-800"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-slate-700 mb-2">
|
||||||
|
Latest Date
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
value={endDate}
|
||||||
|
onChange={(e) => setEndDate(e.target.value)}
|
||||||
|
className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent outline-none transition-all text-slate-800"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={loading}
|
||||||
|
className="w-full bg-primary hover:bg-primary-hover text-white font-medium py-2.5 rounded-lg shadow-sm hover:shadow-md transition-all active:scale-[0.98] mt-8 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{loading ? 'Creating...' : 'Create Event'}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CreateEvent;
|
||||||
149
client/src/components/EventPoll.jsx
Normal file
149
client/src/components/EventPoll.jsx
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import CalendarSelector from './CalendarSelector';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
|
export default function EventPoll() {
|
||||||
|
const { id } = useParams();
|
||||||
|
const [event, setEvent] = useState(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [name, setName] = useState('');
|
||||||
|
const [votes, setVotes] = useState({});
|
||||||
|
const [submitting, setSubmitting] = useState(false);
|
||||||
|
const [submitted, setSubmitted] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch(`/api/events/${id}`)
|
||||||
|
.then(res => {
|
||||||
|
if (!res.ok) throw new Error('Event not found');
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
setEvent(data);
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
const toggleDate = (dateStr) => {
|
||||||
|
setVotes(prev => {
|
||||||
|
const current = prev[dateStr];
|
||||||
|
const next = !current ? 'available' : current === 'available' ? 'unavailable' : undefined;
|
||||||
|
const newVotes = { ...prev };
|
||||||
|
if (next) newVotes[dateStr] = next;
|
||||||
|
else delete newVotes[dateStr];
|
||||||
|
return newVotes;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!name.trim()) return alert('Please enter your name');
|
||||||
|
if (Object.keys(votes).length === 0) return alert('Please select at least one date preference');
|
||||||
|
setSubmitting(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const votesArray = Object.entries(votes).map(([date, status]) => ({ date, status }));
|
||||||
|
const res = await fetch(`/api/events/${id}/respond`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ name, votes: votesArray }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
setSubmitted(true);
|
||||||
|
} else {
|
||||||
|
alert('Failed to submit response');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
alert('Error submitting response');
|
||||||
|
} finally {
|
||||||
|
setSubmitting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) return <div className="text-slate-400 text-center mt-20 font-medium">Loading invitation...</div>;
|
||||||
|
if (!event) return <div className="text-rose-500 text-center mt-20">Event not found</div>;
|
||||||
|
|
||||||
|
if (submitted) {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="bg-white shadow-stripe p-10 rounded-xl text-center max-w-lg mx-auto mt-10"
|
||||||
|
>
|
||||||
|
<div className="w-16 h-16 bg-emerald-50 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
|
<svg className="w-8 h-8 text-emerald-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h1 className="text-2xl font-bold text-slate-800 mb-2">You're all set!</h1>
|
||||||
|
<p className="text-slate-500 mb-8">Thanks for helping pick a date.</p>
|
||||||
|
<button
|
||||||
|
onClick={() => window.location.reload()}
|
||||||
|
className="text-primary hover:text-primary-hover font-medium underline underline-offset-4 transition-colors"
|
||||||
|
>
|
||||||
|
Submit for someone else?
|
||||||
|
</button>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full pb-32 max-w-lg mx-auto">
|
||||||
|
<div className="text-center mb-10 px-4">
|
||||||
|
<h2 className="text-slate-500 font-medium text-sm uppercase tracking-wider mb-3">You're invited to</h2>
|
||||||
|
<h1 className="text-3xl md:text-4xl font-bold text-slate-900 mb-4 leading-tight">
|
||||||
|
{event.name}
|
||||||
|
</h1>
|
||||||
|
{event.description && (
|
||||||
|
<p className="text-slate-500 text-lg leading-relaxed">{event.description}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-10 px-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Enter your name..."
|
||||||
|
className="w-full bg-white border border-slate-200 shadow-sm rounded-lg px-4 py-3 text-lg text-center font-medium text-slate-900 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent transition-all"
|
||||||
|
value={name}
|
||||||
|
onChange={(e) => setName(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-white rounded-xl p-6 shadow-stripe border border-slate-100">
|
||||||
|
<div className="flex justify-between items-center mb-6 text-xs font-semibold text-slate-400 uppercase tracking-wider px-2">
|
||||||
|
<span>Select Dates</span>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<span className="flex items-center gap-1.5"><span className="w-2 h-2 rounded-full bg-primary"></span> Yes</span>
|
||||||
|
<span className="flex items-center gap-1.5"><span className="w-2 h-2 rounded-full bg-rose-400"></span> No</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CalendarSelector
|
||||||
|
startDate={event.start_date}
|
||||||
|
endDate={event.end_date}
|
||||||
|
votes={votes}
|
||||||
|
onToggle={toggleDate}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ y: 100 }}
|
||||||
|
animate={{ y: 0 }}
|
||||||
|
className="fixed bottom-0 left-0 w-full p-6 bg-white/80 backdrop-blur-lg border-t border-slate-200 flex justify-center z-50 transition-all"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
onClick={handleSubmit}
|
||||||
|
disabled={submitting}
|
||||||
|
className="bg-slate-900 text-white font-medium px-8 py-3 rounded-lg shadow-lg hover:shadow-xl hover:bg-slate-800 active:scale-[0.98] transition-all disabled:opacity-50 disabled:scale-100 w-full max-w-sm"
|
||||||
|
>
|
||||||
|
{submitting ? 'Sending...' : 'Confirm Availability'}
|
||||||
|
</button>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
26
client/src/index.css
Normal file
26
client/src/index.css
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
body {
|
||||||
|
@apply bg-slate-50 text-slate-900 antialiased;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom animations if needed outside of Tailwind config */
|
||||||
|
@keyframes fade-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in {
|
||||||
|
animation: fade-in 0.6s ease-out forwards;
|
||||||
|
}
|
||||||
10
client/src/main.jsx
Normal file
10
client/src/main.jsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { StrictMode } from 'react'
|
||||||
|
import { createRoot } from 'react-dom/client'
|
||||||
|
import './index.css'
|
||||||
|
import App from './App.jsx'
|
||||||
|
|
||||||
|
createRoot(document.getElementById('root')).render(
|
||||||
|
<StrictMode>
|
||||||
|
<App />
|
||||||
|
</StrictMode>,
|
||||||
|
)
|
||||||
41
client/tailwind.config.js
Normal file
41
client/tailwind.config.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export default {
|
||||||
|
content: [
|
||||||
|
"./index.html",
|
||||||
|
"./src/**/*.{js,ts,jsx,tsx}",
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['Inter', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'sans-serif'],
|
||||||
|
serif: ['"Editorial New"', 'Georgia', 'Cambria', 'Times New Roman', 'Times', 'serif'],
|
||||||
|
},
|
||||||
|
colors: {
|
||||||
|
slate: {
|
||||||
|
50: '#f8fafc',
|
||||||
|
100: '#f1f5f9',
|
||||||
|
200: '#e2e8f0',
|
||||||
|
300: '#cbd5e1',
|
||||||
|
400: '#94a3b8',
|
||||||
|
500: '#64748b',
|
||||||
|
600: '#475569',
|
||||||
|
700: '#334155',
|
||||||
|
800: '#1e293b',
|
||||||
|
900: '#0f172a',
|
||||||
|
},
|
||||||
|
primary: {
|
||||||
|
DEFAULT: '#635bff', // Stripe blurple
|
||||||
|
hover: '#0a2540',
|
||||||
|
},
|
||||||
|
accent: {
|
||||||
|
DEFAULT: '#e77d64', // Original accent preserved if needed
|
||||||
|
}
|
||||||
|
},
|
||||||
|
boxShadow: {
|
||||||
|
'stripe': '0 2px 5px -1px rgba(50, 50, 93, 0.25), 0 1px 3px -1px rgba(0, 0, 0, 0.3)',
|
||||||
|
'stripe-hover': '0 6px 12px -2px rgba(50, 50, 93, 0.25), 0 3px 7px -3px rgba(0, 0, 0, 0.3)',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
16
client/vite.config.js
Normal file
16
client/vite.config.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import react from '@vitejs/plugin-react'
|
||||||
|
|
||||||
|
// https://vite.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
// Use 'server' for Docker Compose networking, 'localhost' for local dev
|
||||||
|
target: process.env.VITE_API_URL || 'http://localhost:3000',
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
27
docker-compose.yml
Normal file
27
docker-compose.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
services:
|
||||||
|
server:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: server/Dockerfile
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
volumes:
|
||||||
|
- ./server:/app/server
|
||||||
|
- ./eventy.db:/app/eventy.db # Persist DB or mount existing one
|
||||||
|
environment:
|
||||||
|
- PORT=3000
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
client:
|
||||||
|
build:
|
||||||
|
context: ./client
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "5173:5173"
|
||||||
|
volumes:
|
||||||
|
- ./client:/app
|
||||||
|
depends_on:
|
||||||
|
- server
|
||||||
|
environment:
|
||||||
|
- VITE_API_URL=http://server:3000
|
||||||
|
restart: unless-stopped
|
||||||
1
node_modules/.bin/conc
generated
vendored
Symbolic link
1
node_modules/.bin/conc
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../concurrently/dist/bin/concurrently.js
|
||||||
1
node_modules/.bin/concurrently
generated
vendored
Symbolic link
1
node_modules/.bin/concurrently
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../concurrently/dist/bin/concurrently.js
|
||||||
1
node_modules/.bin/prebuild-install
generated
vendored
Symbolic link
1
node_modules/.bin/prebuild-install
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../prebuild-install/bin.js
|
||||||
1
node_modules/.bin/rc
generated
vendored
Symbolic link
1
node_modules/.bin/rc
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../rc/cli.js
|
||||||
1
node_modules/.bin/semver
generated
vendored
Symbolic link
1
node_modules/.bin/semver
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../semver/bin/semver.js
|
||||||
1
node_modules/.bin/tree-kill
generated
vendored
Symbolic link
1
node_modules/.bin/tree-kill
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../tree-kill/cli.js
|
||||||
1572
node_modules/.package-lock.json
generated
vendored
Normal file
1572
node_modules/.package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
250
node_modules/accepts/HISTORY.md
generated
vendored
Normal file
250
node_modules/accepts/HISTORY.md
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
2.0.0 / 2024-08-31
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Drop node <18 support
|
||||||
|
* deps: mime-types@^3.0.0
|
||||||
|
* deps: negotiator@^1.0.0
|
||||||
|
|
||||||
|
1.3.8 / 2022-02-02
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.34
|
||||||
|
- deps: mime-db@~1.51.0
|
||||||
|
* deps: negotiator@0.6.3
|
||||||
|
|
||||||
|
1.3.7 / 2019-04-29
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: negotiator@0.6.2
|
||||||
|
- Fix sorting charset, encoding, and language with extra parameters
|
||||||
|
|
||||||
|
1.3.6 / 2019-04-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.24
|
||||||
|
- deps: mime-db@~1.40.0
|
||||||
|
|
||||||
|
1.3.5 / 2018-02-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.18
|
||||||
|
- deps: mime-db@~1.33.0
|
||||||
|
|
||||||
|
1.3.4 / 2017-08-22
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.16
|
||||||
|
- deps: mime-db@~1.29.0
|
||||||
|
|
||||||
|
1.3.3 / 2016-05-02
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.11
|
||||||
|
- deps: mime-db@~1.23.0
|
||||||
|
* deps: negotiator@0.6.1
|
||||||
|
- perf: improve `Accept` parsing speed
|
||||||
|
- perf: improve `Accept-Charset` parsing speed
|
||||||
|
- perf: improve `Accept-Encoding` parsing speed
|
||||||
|
- perf: improve `Accept-Language` parsing speed
|
||||||
|
|
||||||
|
1.3.2 / 2016-03-08
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.10
|
||||||
|
- Fix extension of `application/dash+xml`
|
||||||
|
- Update primary extension for `audio/mp4`
|
||||||
|
- deps: mime-db@~1.22.0
|
||||||
|
|
||||||
|
1.3.1 / 2016-01-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.9
|
||||||
|
- deps: mime-db@~1.21.0
|
||||||
|
|
||||||
|
1.3.0 / 2015-09-29
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.7
|
||||||
|
- deps: mime-db@~1.19.0
|
||||||
|
* deps: negotiator@0.6.0
|
||||||
|
- Fix including type extensions in parameters in `Accept` parsing
|
||||||
|
- Fix parsing `Accept` parameters with quoted equals
|
||||||
|
- Fix parsing `Accept` parameters with quoted semicolons
|
||||||
|
- Lazy-load modules from main entry point
|
||||||
|
- perf: delay type concatenation until needed
|
||||||
|
- perf: enable strict mode
|
||||||
|
- perf: hoist regular expressions
|
||||||
|
- perf: remove closures getting spec properties
|
||||||
|
- perf: remove a closure from media type parsing
|
||||||
|
- perf: remove property delete from media type parsing
|
||||||
|
|
||||||
|
1.2.13 / 2015-09-06
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.6
|
||||||
|
- deps: mime-db@~1.18.0
|
||||||
|
|
||||||
|
1.2.12 / 2015-07-30
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.4
|
||||||
|
- deps: mime-db@~1.16.0
|
||||||
|
|
||||||
|
1.2.11 / 2015-07-16
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.3
|
||||||
|
- deps: mime-db@~1.15.0
|
||||||
|
|
||||||
|
1.2.10 / 2015-07-01
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.2
|
||||||
|
- deps: mime-db@~1.14.0
|
||||||
|
|
||||||
|
1.2.9 / 2015-06-08
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.1
|
||||||
|
- perf: fix deopt during mapping
|
||||||
|
|
||||||
|
1.2.8 / 2015-06-07
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.1.0
|
||||||
|
- deps: mime-db@~1.13.0
|
||||||
|
* perf: avoid argument reassignment & argument slice
|
||||||
|
* perf: avoid negotiator recursive construction
|
||||||
|
* perf: enable strict mode
|
||||||
|
* perf: remove unnecessary bitwise operator
|
||||||
|
|
||||||
|
1.2.7 / 2015-05-10
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: negotiator@0.5.3
|
||||||
|
- Fix media type parameter matching to be case-insensitive
|
||||||
|
|
||||||
|
1.2.6 / 2015-05-07
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.0.11
|
||||||
|
- deps: mime-db@~1.9.1
|
||||||
|
* deps: negotiator@0.5.2
|
||||||
|
- Fix comparing media types with quoted values
|
||||||
|
- Fix splitting media types with quoted commas
|
||||||
|
|
||||||
|
1.2.5 / 2015-03-13
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.0.10
|
||||||
|
- deps: mime-db@~1.8.0
|
||||||
|
|
||||||
|
1.2.4 / 2015-02-14
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Support Node.js 0.6
|
||||||
|
* deps: mime-types@~2.0.9
|
||||||
|
- deps: mime-db@~1.7.0
|
||||||
|
* deps: negotiator@0.5.1
|
||||||
|
- Fix preference sorting to be stable for long acceptable lists
|
||||||
|
|
||||||
|
1.2.3 / 2015-01-31
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.0.8
|
||||||
|
- deps: mime-db@~1.6.0
|
||||||
|
|
||||||
|
1.2.2 / 2014-12-30
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.0.7
|
||||||
|
- deps: mime-db@~1.5.0
|
||||||
|
|
||||||
|
1.2.1 / 2014-12-30
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.0.5
|
||||||
|
- deps: mime-db@~1.3.1
|
||||||
|
|
||||||
|
1.2.0 / 2014-12-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: negotiator@0.5.0
|
||||||
|
- Fix list return order when large accepted list
|
||||||
|
- Fix missing identity encoding when q=0 exists
|
||||||
|
- Remove dynamic building of Negotiator class
|
||||||
|
|
||||||
|
1.1.4 / 2014-12-10
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.0.4
|
||||||
|
- deps: mime-db@~1.3.0
|
||||||
|
|
||||||
|
1.1.3 / 2014-11-09
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.0.3
|
||||||
|
- deps: mime-db@~1.2.0
|
||||||
|
|
||||||
|
1.1.2 / 2014-10-14
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: negotiator@0.4.9
|
||||||
|
- Fix error when media type has invalid parameter
|
||||||
|
|
||||||
|
1.1.1 / 2014-09-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: mime-types@~2.0.2
|
||||||
|
- deps: mime-db@~1.1.0
|
||||||
|
* deps: negotiator@0.4.8
|
||||||
|
- Fix all negotiations to be case-insensitive
|
||||||
|
- Stable sort preferences of same quality according to client order
|
||||||
|
|
||||||
|
1.1.0 / 2014-09-02
|
||||||
|
==================
|
||||||
|
|
||||||
|
* update `mime-types`
|
||||||
|
|
||||||
|
1.0.7 / 2014-07-04
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix wrong type returned from `type` when match after unknown extension
|
||||||
|
|
||||||
|
1.0.6 / 2014-06-24
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: negotiator@0.4.7
|
||||||
|
|
||||||
|
1.0.5 / 2014-06-20
|
||||||
|
==================
|
||||||
|
|
||||||
|
* fix crash when unknown extension given
|
||||||
|
|
||||||
|
1.0.4 / 2014-06-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* use `mime-types`
|
||||||
|
|
||||||
|
1.0.3 / 2014-06-11
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: negotiator@0.4.6
|
||||||
|
- Order by specificity when quality is the same
|
||||||
|
|
||||||
|
1.0.2 / 2014-05-29
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix interpretation when header not in request
|
||||||
|
* deps: pin negotiator@0.4.5
|
||||||
|
|
||||||
|
1.0.1 / 2014-01-18
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Identity encoding isn't always acceptable
|
||||||
|
* deps: negotiator@~0.4.0
|
||||||
|
|
||||||
|
1.0.0 / 2013-12-27
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Genesis
|
||||||
23
node_modules/accepts/LICENSE
generated
vendored
Normal file
23
node_modules/accepts/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
|
||||||
|
Copyright (c) 2015 Douglas Christopher Wilson <doug@somethingdoug.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
'Software'), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
140
node_modules/accepts/README.md
generated
vendored
Normal file
140
node_modules/accepts/README.md
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
# accepts
|
||||||
|
|
||||||
|
[![NPM Version][npm-version-image]][npm-url]
|
||||||
|
[![NPM Downloads][npm-downloads-image]][npm-url]
|
||||||
|
[![Node.js Version][node-version-image]][node-version-url]
|
||||||
|
[![Build Status][github-actions-ci-image]][github-actions-ci-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
|
||||||
|
Higher level content negotiation based on [negotiator](https://www.npmjs.com/package/negotiator).
|
||||||
|
Extracted from [koa](https://www.npmjs.com/package/koa) for general use.
|
||||||
|
|
||||||
|
In addition to negotiator, it allows:
|
||||||
|
|
||||||
|
- Allows types as an array or arguments list, ie `(['text/html', 'application/json'])`
|
||||||
|
as well as `('text/html', 'application/json')`.
|
||||||
|
- Allows type shorthands such as `json`.
|
||||||
|
- Returns `false` when no types match
|
||||||
|
- Treats non-existent headers as `*`
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
This is a [Node.js](https://nodejs.org/en/) module available through the
|
||||||
|
[npm registry](https://www.npmjs.com/). Installation is done using the
|
||||||
|
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install accepts
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```js
|
||||||
|
var accepts = require('accepts')
|
||||||
|
```
|
||||||
|
|
||||||
|
### accepts(req)
|
||||||
|
|
||||||
|
Create a new `Accepts` object for the given `req`.
|
||||||
|
|
||||||
|
#### .charset(charsets)
|
||||||
|
|
||||||
|
Return the first accepted charset. If nothing in `charsets` is accepted,
|
||||||
|
then `false` is returned.
|
||||||
|
|
||||||
|
#### .charsets()
|
||||||
|
|
||||||
|
Return the charsets that the request accepts, in the order of the client's
|
||||||
|
preference (most preferred first).
|
||||||
|
|
||||||
|
#### .encoding(encodings)
|
||||||
|
|
||||||
|
Return the first accepted encoding. If nothing in `encodings` is accepted,
|
||||||
|
then `false` is returned.
|
||||||
|
|
||||||
|
#### .encodings()
|
||||||
|
|
||||||
|
Return the encodings that the request accepts, in the order of the client's
|
||||||
|
preference (most preferred first).
|
||||||
|
|
||||||
|
#### .language(languages)
|
||||||
|
|
||||||
|
Return the first accepted language. If nothing in `languages` is accepted,
|
||||||
|
then `false` is returned.
|
||||||
|
|
||||||
|
#### .languages()
|
||||||
|
|
||||||
|
Return the languages that the request accepts, in the order of the client's
|
||||||
|
preference (most preferred first).
|
||||||
|
|
||||||
|
#### .type(types)
|
||||||
|
|
||||||
|
Return the first accepted type (and it is returned as the same text as what
|
||||||
|
appears in the `types` array). If nothing in `types` is accepted, then `false`
|
||||||
|
is returned.
|
||||||
|
|
||||||
|
The `types` array can contain full MIME types or file extensions. Any value
|
||||||
|
that is not a full MIME type is passed to `require('mime-types').lookup`.
|
||||||
|
|
||||||
|
#### .types()
|
||||||
|
|
||||||
|
Return the types that the request accepts, in the order of the client's
|
||||||
|
preference (most preferred first).
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Simple type negotiation
|
||||||
|
|
||||||
|
This simple example shows how to use `accepts` to return a different typed
|
||||||
|
respond body based on what the client wants to accept. The server lists it's
|
||||||
|
preferences in order and will get back the best match between the client and
|
||||||
|
server.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var accepts = require('accepts')
|
||||||
|
var http = require('http')
|
||||||
|
|
||||||
|
function app (req, res) {
|
||||||
|
var accept = accepts(req)
|
||||||
|
|
||||||
|
// the order of this list is significant; should be server preferred order
|
||||||
|
switch (accept.type(['json', 'html'])) {
|
||||||
|
case 'json':
|
||||||
|
res.setHeader('Content-Type', 'application/json')
|
||||||
|
res.write('{"hello":"world!"}')
|
||||||
|
break
|
||||||
|
case 'html':
|
||||||
|
res.setHeader('Content-Type', 'text/html')
|
||||||
|
res.write('<b>hello, world!</b>')
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
// the fallback is text/plain, so no need to specify it above
|
||||||
|
res.setHeader('Content-Type', 'text/plain')
|
||||||
|
res.write('hello, world!')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
res.end()
|
||||||
|
}
|
||||||
|
|
||||||
|
http.createServer(app).listen(3000)
|
||||||
|
```
|
||||||
|
|
||||||
|
You can test this out with the cURL program:
|
||||||
|
```sh
|
||||||
|
curl -I -H'Accept: text/html' http://localhost:3000/
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/accepts/master
|
||||||
|
[coveralls-url]: https://coveralls.io/r/jshttp/accepts?branch=master
|
||||||
|
[github-actions-ci-image]: https://badgen.net/github/checks/jshttp/accepts/master?label=ci
|
||||||
|
[github-actions-ci-url]: https://github.com/jshttp/accepts/actions/workflows/ci.yml
|
||||||
|
[node-version-image]: https://badgen.net/npm/node/accepts
|
||||||
|
[node-version-url]: https://nodejs.org/en/download
|
||||||
|
[npm-downloads-image]: https://badgen.net/npm/dm/accepts
|
||||||
|
[npm-url]: https://npmjs.org/package/accepts
|
||||||
|
[npm-version-image]: https://badgen.net/npm/v/accepts
|
||||||
238
node_modules/accepts/index.js
generated
vendored
Normal file
238
node_modules/accepts/index.js
generated
vendored
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
/*!
|
||||||
|
* accepts
|
||||||
|
* Copyright(c) 2014 Jonathan Ong
|
||||||
|
* Copyright(c) 2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Negotiator = require('negotiator')
|
||||||
|
var mime = require('mime-types')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = Accepts
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Accepts object for the given req.
|
||||||
|
*
|
||||||
|
* @param {object} req
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Accepts (req) {
|
||||||
|
if (!(this instanceof Accepts)) {
|
||||||
|
return new Accepts(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.headers = req.headers
|
||||||
|
this.negotiator = new Negotiator(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given `type(s)` is acceptable, returning
|
||||||
|
* the best match when true, otherwise `undefined`, in which
|
||||||
|
* case you should respond with 406 "Not Acceptable".
|
||||||
|
*
|
||||||
|
* The `type` value may be a single mime type string
|
||||||
|
* such as "application/json", the extension name
|
||||||
|
* such as "json" or an array `["json", "html", "text/plain"]`. When a list
|
||||||
|
* or array is given the _best_ match, if any is returned.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* // Accept: text/html
|
||||||
|
* this.types('html');
|
||||||
|
* // => "html"
|
||||||
|
*
|
||||||
|
* // Accept: text/*, application/json
|
||||||
|
* this.types('html');
|
||||||
|
* // => "html"
|
||||||
|
* this.types('text/html');
|
||||||
|
* // => "text/html"
|
||||||
|
* this.types('json', 'text');
|
||||||
|
* // => "json"
|
||||||
|
* this.types('application/json');
|
||||||
|
* // => "application/json"
|
||||||
|
*
|
||||||
|
* // Accept: text/*, application/json
|
||||||
|
* this.types('image/png');
|
||||||
|
* this.types('png');
|
||||||
|
* // => undefined
|
||||||
|
*
|
||||||
|
* // Accept: text/*;q=.5, application/json
|
||||||
|
* this.types(['html', 'json']);
|
||||||
|
* this.types('html', 'json');
|
||||||
|
* // => "json"
|
||||||
|
*
|
||||||
|
* @param {String|Array} types...
|
||||||
|
* @return {String|Array|Boolean}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Accepts.prototype.type =
|
||||||
|
Accepts.prototype.types = function (types_) {
|
||||||
|
var types = types_
|
||||||
|
|
||||||
|
// support flattened arguments
|
||||||
|
if (types && !Array.isArray(types)) {
|
||||||
|
types = new Array(arguments.length)
|
||||||
|
for (var i = 0; i < types.length; i++) {
|
||||||
|
types[i] = arguments[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no types, return all requested types
|
||||||
|
if (!types || types.length === 0) {
|
||||||
|
return this.negotiator.mediaTypes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// no accept header, return first given type
|
||||||
|
if (!this.headers.accept) {
|
||||||
|
return types[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
var mimes = types.map(extToMime)
|
||||||
|
var accepts = this.negotiator.mediaTypes(mimes.filter(validMime))
|
||||||
|
var first = accepts[0]
|
||||||
|
|
||||||
|
return first
|
||||||
|
? types[mimes.indexOf(first)]
|
||||||
|
: false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return accepted encodings or best fit based on `encodings`.
|
||||||
|
*
|
||||||
|
* Given `Accept-Encoding: gzip, deflate`
|
||||||
|
* an array sorted by quality is returned:
|
||||||
|
*
|
||||||
|
* ['gzip', 'deflate']
|
||||||
|
*
|
||||||
|
* @param {String|Array} encodings...
|
||||||
|
* @return {String|Array}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Accepts.prototype.encoding =
|
||||||
|
Accepts.prototype.encodings = function (encodings_) {
|
||||||
|
var encodings = encodings_
|
||||||
|
|
||||||
|
// support flattened arguments
|
||||||
|
if (encodings && !Array.isArray(encodings)) {
|
||||||
|
encodings = new Array(arguments.length)
|
||||||
|
for (var i = 0; i < encodings.length; i++) {
|
||||||
|
encodings[i] = arguments[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no encodings, return all requested encodings
|
||||||
|
if (!encodings || encodings.length === 0) {
|
||||||
|
return this.negotiator.encodings()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.negotiator.encodings(encodings)[0] || false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return accepted charsets or best fit based on `charsets`.
|
||||||
|
*
|
||||||
|
* Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5`
|
||||||
|
* an array sorted by quality is returned:
|
||||||
|
*
|
||||||
|
* ['utf-8', 'utf-7', 'iso-8859-1']
|
||||||
|
*
|
||||||
|
* @param {String|Array} charsets...
|
||||||
|
* @return {String|Array}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Accepts.prototype.charset =
|
||||||
|
Accepts.prototype.charsets = function (charsets_) {
|
||||||
|
var charsets = charsets_
|
||||||
|
|
||||||
|
// support flattened arguments
|
||||||
|
if (charsets && !Array.isArray(charsets)) {
|
||||||
|
charsets = new Array(arguments.length)
|
||||||
|
for (var i = 0; i < charsets.length; i++) {
|
||||||
|
charsets[i] = arguments[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no charsets, return all requested charsets
|
||||||
|
if (!charsets || charsets.length === 0) {
|
||||||
|
return this.negotiator.charsets()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.negotiator.charsets(charsets)[0] || false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return accepted languages or best fit based on `langs`.
|
||||||
|
*
|
||||||
|
* Given `Accept-Language: en;q=0.8, es, pt`
|
||||||
|
* an array sorted by quality is returned:
|
||||||
|
*
|
||||||
|
* ['es', 'pt', 'en']
|
||||||
|
*
|
||||||
|
* @param {String|Array} langs...
|
||||||
|
* @return {Array|String}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Accepts.prototype.lang =
|
||||||
|
Accepts.prototype.langs =
|
||||||
|
Accepts.prototype.language =
|
||||||
|
Accepts.prototype.languages = function (languages_) {
|
||||||
|
var languages = languages_
|
||||||
|
|
||||||
|
// support flattened arguments
|
||||||
|
if (languages && !Array.isArray(languages)) {
|
||||||
|
languages = new Array(arguments.length)
|
||||||
|
for (var i = 0; i < languages.length; i++) {
|
||||||
|
languages[i] = arguments[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no languages, return all requested languages
|
||||||
|
if (!languages || languages.length === 0) {
|
||||||
|
return this.negotiator.languages()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.negotiator.languages(languages)[0] || false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert extnames to mime.
|
||||||
|
*
|
||||||
|
* @param {String} type
|
||||||
|
* @return {String}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function extToMime (type) {
|
||||||
|
return type.indexOf('/') === -1
|
||||||
|
? mime.lookup(type)
|
||||||
|
: type
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if mime is valid.
|
||||||
|
*
|
||||||
|
* @param {String} type
|
||||||
|
* @return {Boolean}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function validMime (type) {
|
||||||
|
return typeof type === 'string'
|
||||||
|
}
|
||||||
47
node_modules/accepts/package.json
generated
vendored
Normal file
47
node_modules/accepts/package.json
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"name": "accepts",
|
||||||
|
"description": "Higher-level content negotiation",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"contributors": [
|
||||||
|
"Douglas Christopher Wilson <doug@somethingdoug.com>",
|
||||||
|
"Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": "jshttp/accepts",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-types": "^3.0.0",
|
||||||
|
"negotiator": "^1.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"deep-equal": "1.0.1",
|
||||||
|
"eslint": "7.32.0",
|
||||||
|
"eslint-config-standard": "14.1.1",
|
||||||
|
"eslint-plugin-import": "2.25.4",
|
||||||
|
"eslint-plugin-markdown": "2.2.1",
|
||||||
|
"eslint-plugin-node": "11.1.0",
|
||||||
|
"eslint-plugin-promise": "4.3.1",
|
||||||
|
"eslint-plugin-standard": "4.1.0",
|
||||||
|
"mocha": "9.2.0",
|
||||||
|
"nyc": "15.1.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"LICENSE",
|
||||||
|
"HISTORY.md",
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"lint": "eslint .",
|
||||||
|
"test": "mocha --reporter spec --check-leaks --bail test/",
|
||||||
|
"test-ci": "nyc --reporter=lcov --reporter=text npm test",
|
||||||
|
"test-cov": "nyc --reporter=html --reporter=text npm test"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"content",
|
||||||
|
"negotiation",
|
||||||
|
"accept",
|
||||||
|
"accepts"
|
||||||
|
]
|
||||||
|
}
|
||||||
37
node_modules/ansi-regex/index.d.ts
generated
vendored
Normal file
37
node_modules/ansi-regex/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
declare namespace ansiRegex {
|
||||||
|
interface Options {
|
||||||
|
/**
|
||||||
|
Match only the first ANSI escape.
|
||||||
|
|
||||||
|
@default false
|
||||||
|
*/
|
||||||
|
onlyFirst: boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Regular expression for matching ANSI escape codes.
|
||||||
|
|
||||||
|
@example
|
||||||
|
```
|
||||||
|
import ansiRegex = require('ansi-regex');
|
||||||
|
|
||||||
|
ansiRegex().test('\u001B[4mcake\u001B[0m');
|
||||||
|
//=> true
|
||||||
|
|
||||||
|
ansiRegex().test('cake');
|
||||||
|
//=> false
|
||||||
|
|
||||||
|
'\u001B[4mcake\u001B[0m'.match(ansiRegex());
|
||||||
|
//=> ['\u001B[4m', '\u001B[0m']
|
||||||
|
|
||||||
|
'\u001B[4mcake\u001B[0m'.match(ansiRegex({onlyFirst: true}));
|
||||||
|
//=> ['\u001B[4m']
|
||||||
|
|
||||||
|
'\u001B]8;;https://github.com\u0007click\u001B]8;;\u0007'.match(ansiRegex());
|
||||||
|
//=> ['\u001B]8;;https://github.com\u0007', '\u001B]8;;\u0007']
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
declare function ansiRegex(options?: ansiRegex.Options): RegExp;
|
||||||
|
|
||||||
|
export = ansiRegex;
|
||||||
10
node_modules/ansi-regex/index.js
generated
vendored
Normal file
10
node_modules/ansi-regex/index.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = ({onlyFirst = false} = {}) => {
|
||||||
|
const pattern = [
|
||||||
|
'[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
|
||||||
|
'(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'
|
||||||
|
].join('|');
|
||||||
|
|
||||||
|
return new RegExp(pattern, onlyFirst ? undefined : 'g');
|
||||||
|
};
|
||||||
9
node_modules/ansi-regex/license
generated
vendored
Normal file
9
node_modules/ansi-regex/license
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
55
node_modules/ansi-regex/package.json
generated
vendored
Normal file
55
node_modules/ansi-regex/package.json
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"name": "ansi-regex",
|
||||||
|
"version": "5.0.1",
|
||||||
|
"description": "Regular expression for matching ANSI escape codes",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": "chalk/ansi-regex",
|
||||||
|
"author": {
|
||||||
|
"name": "Sindre Sorhus",
|
||||||
|
"email": "sindresorhus@gmail.com",
|
||||||
|
"url": "sindresorhus.com"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "xo && ava && tsd",
|
||||||
|
"view-supported": "node fixtures/view-codes.js"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"index.js",
|
||||||
|
"index.d.ts"
|
||||||
|
],
|
||||||
|
"keywords": [
|
||||||
|
"ansi",
|
||||||
|
"styles",
|
||||||
|
"color",
|
||||||
|
"colour",
|
||||||
|
"colors",
|
||||||
|
"terminal",
|
||||||
|
"console",
|
||||||
|
"cli",
|
||||||
|
"string",
|
||||||
|
"tty",
|
||||||
|
"escape",
|
||||||
|
"formatting",
|
||||||
|
"rgb",
|
||||||
|
"256",
|
||||||
|
"shell",
|
||||||
|
"xterm",
|
||||||
|
"command-line",
|
||||||
|
"text",
|
||||||
|
"regex",
|
||||||
|
"regexp",
|
||||||
|
"re",
|
||||||
|
"match",
|
||||||
|
"test",
|
||||||
|
"find",
|
||||||
|
"pattern"
|
||||||
|
],
|
||||||
|
"devDependencies": {
|
||||||
|
"ava": "^2.4.0",
|
||||||
|
"tsd": "^0.9.0",
|
||||||
|
"xo": "^0.25.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
78
node_modules/ansi-regex/readme.md
generated
vendored
Normal file
78
node_modules/ansi-regex/readme.md
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# ansi-regex
|
||||||
|
|
||||||
|
> Regular expression for matching [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code)
|
||||||
|
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm install ansi-regex
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
const ansiRegex = require('ansi-regex');
|
||||||
|
|
||||||
|
ansiRegex().test('\u001B[4mcake\u001B[0m');
|
||||||
|
//=> true
|
||||||
|
|
||||||
|
ansiRegex().test('cake');
|
||||||
|
//=> false
|
||||||
|
|
||||||
|
'\u001B[4mcake\u001B[0m'.match(ansiRegex());
|
||||||
|
//=> ['\u001B[4m', '\u001B[0m']
|
||||||
|
|
||||||
|
'\u001B[4mcake\u001B[0m'.match(ansiRegex({onlyFirst: true}));
|
||||||
|
//=> ['\u001B[4m']
|
||||||
|
|
||||||
|
'\u001B]8;;https://github.com\u0007click\u001B]8;;\u0007'.match(ansiRegex());
|
||||||
|
//=> ['\u001B]8;;https://github.com\u0007', '\u001B]8;;\u0007']
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### ansiRegex(options?)
|
||||||
|
|
||||||
|
Returns a regex for matching ANSI escape codes.
|
||||||
|
|
||||||
|
#### options
|
||||||
|
|
||||||
|
Type: `object`
|
||||||
|
|
||||||
|
##### onlyFirst
|
||||||
|
|
||||||
|
Type: `boolean`<br>
|
||||||
|
Default: `false` *(Matches any ANSI escape codes in a string)*
|
||||||
|
|
||||||
|
Match only the first ANSI escape.
|
||||||
|
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### Why do you test for codes not in the ECMA 48 standard?
|
||||||
|
|
||||||
|
Some of the codes we run as a test are codes that we acquired finding various lists of non-standard or manufacturer specific codes. We test for both standard and non-standard codes, as most of them follow the same or similar format and can be safely matched in strings without the risk of removing actual string content. There are a few non-standard control codes that do not follow the traditional format (i.e. they end in numbers) thus forcing us to exclude them from the test because we cannot reliably match them.
|
||||||
|
|
||||||
|
On the historical side, those ECMA standards were established in the early 90's whereas the VT100, for example, was designed in the mid/late 70's. At that point in time, control codes were still pretty ungoverned and engineers used them for a multitude of things, namely to activate hardware ports that may have been proprietary. Somewhere else you see a similar 'anarchy' of codes is in the x86 architecture for processors; there are a ton of "interrupts" that can mean different things on certain brands of processors, most of which have been phased out.
|
||||||
|
|
||||||
|
|
||||||
|
## Maintainers
|
||||||
|
|
||||||
|
- [Sindre Sorhus](https://github.com/sindresorhus)
|
||||||
|
- [Josh Junon](https://github.com/qix-)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<b>
|
||||||
|
<a href="https://tidelift.com/subscription/pkg/npm-ansi-regex?utm_source=npm-ansi-regex&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
|
||||||
|
</b>
|
||||||
|
<br>
|
||||||
|
<sub>
|
||||||
|
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
|
||||||
|
</sub>
|
||||||
|
</div>
|
||||||
345
node_modules/ansi-styles/index.d.ts
generated
vendored
Normal file
345
node_modules/ansi-styles/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
declare type CSSColor =
|
||||||
|
| 'aliceblue'
|
||||||
|
| 'antiquewhite'
|
||||||
|
| 'aqua'
|
||||||
|
| 'aquamarine'
|
||||||
|
| 'azure'
|
||||||
|
| 'beige'
|
||||||
|
| 'bisque'
|
||||||
|
| 'black'
|
||||||
|
| 'blanchedalmond'
|
||||||
|
| 'blue'
|
||||||
|
| 'blueviolet'
|
||||||
|
| 'brown'
|
||||||
|
| 'burlywood'
|
||||||
|
| 'cadetblue'
|
||||||
|
| 'chartreuse'
|
||||||
|
| 'chocolate'
|
||||||
|
| 'coral'
|
||||||
|
| 'cornflowerblue'
|
||||||
|
| 'cornsilk'
|
||||||
|
| 'crimson'
|
||||||
|
| 'cyan'
|
||||||
|
| 'darkblue'
|
||||||
|
| 'darkcyan'
|
||||||
|
| 'darkgoldenrod'
|
||||||
|
| 'darkgray'
|
||||||
|
| 'darkgreen'
|
||||||
|
| 'darkgrey'
|
||||||
|
| 'darkkhaki'
|
||||||
|
| 'darkmagenta'
|
||||||
|
| 'darkolivegreen'
|
||||||
|
| 'darkorange'
|
||||||
|
| 'darkorchid'
|
||||||
|
| 'darkred'
|
||||||
|
| 'darksalmon'
|
||||||
|
| 'darkseagreen'
|
||||||
|
| 'darkslateblue'
|
||||||
|
| 'darkslategray'
|
||||||
|
| 'darkslategrey'
|
||||||
|
| 'darkturquoise'
|
||||||
|
| 'darkviolet'
|
||||||
|
| 'deeppink'
|
||||||
|
| 'deepskyblue'
|
||||||
|
| 'dimgray'
|
||||||
|
| 'dimgrey'
|
||||||
|
| 'dodgerblue'
|
||||||
|
| 'firebrick'
|
||||||
|
| 'floralwhite'
|
||||||
|
| 'forestgreen'
|
||||||
|
| 'fuchsia'
|
||||||
|
| 'gainsboro'
|
||||||
|
| 'ghostwhite'
|
||||||
|
| 'gold'
|
||||||
|
| 'goldenrod'
|
||||||
|
| 'gray'
|
||||||
|
| 'green'
|
||||||
|
| 'greenyellow'
|
||||||
|
| 'grey'
|
||||||
|
| 'honeydew'
|
||||||
|
| 'hotpink'
|
||||||
|
| 'indianred'
|
||||||
|
| 'indigo'
|
||||||
|
| 'ivory'
|
||||||
|
| 'khaki'
|
||||||
|
| 'lavender'
|
||||||
|
| 'lavenderblush'
|
||||||
|
| 'lawngreen'
|
||||||
|
| 'lemonchiffon'
|
||||||
|
| 'lightblue'
|
||||||
|
| 'lightcoral'
|
||||||
|
| 'lightcyan'
|
||||||
|
| 'lightgoldenrodyellow'
|
||||||
|
| 'lightgray'
|
||||||
|
| 'lightgreen'
|
||||||
|
| 'lightgrey'
|
||||||
|
| 'lightpink'
|
||||||
|
| 'lightsalmon'
|
||||||
|
| 'lightseagreen'
|
||||||
|
| 'lightskyblue'
|
||||||
|
| 'lightslategray'
|
||||||
|
| 'lightslategrey'
|
||||||
|
| 'lightsteelblue'
|
||||||
|
| 'lightyellow'
|
||||||
|
| 'lime'
|
||||||
|
| 'limegreen'
|
||||||
|
| 'linen'
|
||||||
|
| 'magenta'
|
||||||
|
| 'maroon'
|
||||||
|
| 'mediumaquamarine'
|
||||||
|
| 'mediumblue'
|
||||||
|
| 'mediumorchid'
|
||||||
|
| 'mediumpurple'
|
||||||
|
| 'mediumseagreen'
|
||||||
|
| 'mediumslateblue'
|
||||||
|
| 'mediumspringgreen'
|
||||||
|
| 'mediumturquoise'
|
||||||
|
| 'mediumvioletred'
|
||||||
|
| 'midnightblue'
|
||||||
|
| 'mintcream'
|
||||||
|
| 'mistyrose'
|
||||||
|
| 'moccasin'
|
||||||
|
| 'navajowhite'
|
||||||
|
| 'navy'
|
||||||
|
| 'oldlace'
|
||||||
|
| 'olive'
|
||||||
|
| 'olivedrab'
|
||||||
|
| 'orange'
|
||||||
|
| 'orangered'
|
||||||
|
| 'orchid'
|
||||||
|
| 'palegoldenrod'
|
||||||
|
| 'palegreen'
|
||||||
|
| 'paleturquoise'
|
||||||
|
| 'palevioletred'
|
||||||
|
| 'papayawhip'
|
||||||
|
| 'peachpuff'
|
||||||
|
| 'peru'
|
||||||
|
| 'pink'
|
||||||
|
| 'plum'
|
||||||
|
| 'powderblue'
|
||||||
|
| 'purple'
|
||||||
|
| 'rebeccapurple'
|
||||||
|
| 'red'
|
||||||
|
| 'rosybrown'
|
||||||
|
| 'royalblue'
|
||||||
|
| 'saddlebrown'
|
||||||
|
| 'salmon'
|
||||||
|
| 'sandybrown'
|
||||||
|
| 'seagreen'
|
||||||
|
| 'seashell'
|
||||||
|
| 'sienna'
|
||||||
|
| 'silver'
|
||||||
|
| 'skyblue'
|
||||||
|
| 'slateblue'
|
||||||
|
| 'slategray'
|
||||||
|
| 'slategrey'
|
||||||
|
| 'snow'
|
||||||
|
| 'springgreen'
|
||||||
|
| 'steelblue'
|
||||||
|
| 'tan'
|
||||||
|
| 'teal'
|
||||||
|
| 'thistle'
|
||||||
|
| 'tomato'
|
||||||
|
| 'turquoise'
|
||||||
|
| 'violet'
|
||||||
|
| 'wheat'
|
||||||
|
| 'white'
|
||||||
|
| 'whitesmoke'
|
||||||
|
| 'yellow'
|
||||||
|
| 'yellowgreen';
|
||||||
|
|
||||||
|
declare namespace ansiStyles {
|
||||||
|
interface ColorConvert {
|
||||||
|
/**
|
||||||
|
The RGB color space.
|
||||||
|
|
||||||
|
@param red - (`0`-`255`)
|
||||||
|
@param green - (`0`-`255`)
|
||||||
|
@param blue - (`0`-`255`)
|
||||||
|
*/
|
||||||
|
rgb(red: number, green: number, blue: number): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The RGB HEX color space.
|
||||||
|
|
||||||
|
@param hex - A hexadecimal string containing RGB data.
|
||||||
|
*/
|
||||||
|
hex(hex: string): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
@param keyword - A CSS color name.
|
||||||
|
*/
|
||||||
|
keyword(keyword: CSSColor): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The HSL color space.
|
||||||
|
|
||||||
|
@param hue - (`0`-`360`)
|
||||||
|
@param saturation - (`0`-`100`)
|
||||||
|
@param lightness - (`0`-`100`)
|
||||||
|
*/
|
||||||
|
hsl(hue: number, saturation: number, lightness: number): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The HSV color space.
|
||||||
|
|
||||||
|
@param hue - (`0`-`360`)
|
||||||
|
@param saturation - (`0`-`100`)
|
||||||
|
@param value - (`0`-`100`)
|
||||||
|
*/
|
||||||
|
hsv(hue: number, saturation: number, value: number): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The HSV color space.
|
||||||
|
|
||||||
|
@param hue - (`0`-`360`)
|
||||||
|
@param whiteness - (`0`-`100`)
|
||||||
|
@param blackness - (`0`-`100`)
|
||||||
|
*/
|
||||||
|
hwb(hue: number, whiteness: number, blackness: number): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Use a [4-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4-bit) to set text color.
|
||||||
|
*/
|
||||||
|
ansi(ansi: number): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Use an [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set text color.
|
||||||
|
*/
|
||||||
|
ansi256(ansi: number): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CSPair {
|
||||||
|
/**
|
||||||
|
The ANSI terminal control sequence for starting this style.
|
||||||
|
*/
|
||||||
|
readonly open: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The ANSI terminal control sequence for ending this style.
|
||||||
|
*/
|
||||||
|
readonly close: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ColorBase {
|
||||||
|
readonly ansi: ColorConvert;
|
||||||
|
readonly ansi256: ColorConvert;
|
||||||
|
readonly ansi16m: ColorConvert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The ANSI terminal control sequence for ending this color.
|
||||||
|
*/
|
||||||
|
readonly close: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Modifier {
|
||||||
|
/**
|
||||||
|
Resets the current color chain.
|
||||||
|
*/
|
||||||
|
readonly reset: CSPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Make text bold.
|
||||||
|
*/
|
||||||
|
readonly bold: CSPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Emitting only a small amount of light.
|
||||||
|
*/
|
||||||
|
readonly dim: CSPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Make text italic. (Not widely supported)
|
||||||
|
*/
|
||||||
|
readonly italic: CSPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Make text underline. (Not widely supported)
|
||||||
|
*/
|
||||||
|
readonly underline: CSPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Inverse background and foreground colors.
|
||||||
|
*/
|
||||||
|
readonly inverse: CSPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Prints the text, but makes it invisible.
|
||||||
|
*/
|
||||||
|
readonly hidden: CSPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Puts a horizontal line through the center of the text. (Not widely supported)
|
||||||
|
*/
|
||||||
|
readonly strikethrough: CSPair;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ForegroundColor {
|
||||||
|
readonly black: CSPair;
|
||||||
|
readonly red: CSPair;
|
||||||
|
readonly green: CSPair;
|
||||||
|
readonly yellow: CSPair;
|
||||||
|
readonly blue: CSPair;
|
||||||
|
readonly cyan: CSPair;
|
||||||
|
readonly magenta: CSPair;
|
||||||
|
readonly white: CSPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Alias for `blackBright`.
|
||||||
|
*/
|
||||||
|
readonly gray: CSPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Alias for `blackBright`.
|
||||||
|
*/
|
||||||
|
readonly grey: CSPair;
|
||||||
|
|
||||||
|
readonly blackBright: CSPair;
|
||||||
|
readonly redBright: CSPair;
|
||||||
|
readonly greenBright: CSPair;
|
||||||
|
readonly yellowBright: CSPair;
|
||||||
|
readonly blueBright: CSPair;
|
||||||
|
readonly cyanBright: CSPair;
|
||||||
|
readonly magentaBright: CSPair;
|
||||||
|
readonly whiteBright: CSPair;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BackgroundColor {
|
||||||
|
readonly bgBlack: CSPair;
|
||||||
|
readonly bgRed: CSPair;
|
||||||
|
readonly bgGreen: CSPair;
|
||||||
|
readonly bgYellow: CSPair;
|
||||||
|
readonly bgBlue: CSPair;
|
||||||
|
readonly bgCyan: CSPair;
|
||||||
|
readonly bgMagenta: CSPair;
|
||||||
|
readonly bgWhite: CSPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Alias for `bgBlackBright`.
|
||||||
|
*/
|
||||||
|
readonly bgGray: CSPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Alias for `bgBlackBright`.
|
||||||
|
*/
|
||||||
|
readonly bgGrey: CSPair;
|
||||||
|
|
||||||
|
readonly bgBlackBright: CSPair;
|
||||||
|
readonly bgRedBright: CSPair;
|
||||||
|
readonly bgGreenBright: CSPair;
|
||||||
|
readonly bgYellowBright: CSPair;
|
||||||
|
readonly bgBlueBright: CSPair;
|
||||||
|
readonly bgCyanBright: CSPair;
|
||||||
|
readonly bgMagentaBright: CSPair;
|
||||||
|
readonly bgWhiteBright: CSPair;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const ansiStyles: {
|
||||||
|
readonly modifier: ansiStyles.Modifier;
|
||||||
|
readonly color: ansiStyles.ForegroundColor & ansiStyles.ColorBase;
|
||||||
|
readonly bgColor: ansiStyles.BackgroundColor & ansiStyles.ColorBase;
|
||||||
|
readonly codes: ReadonlyMap<number, number>;
|
||||||
|
} & ansiStyles.BackgroundColor & ansiStyles.ForegroundColor & ansiStyles.Modifier;
|
||||||
|
|
||||||
|
export = ansiStyles;
|
||||||
163
node_modules/ansi-styles/index.js
generated
vendored
Normal file
163
node_modules/ansi-styles/index.js
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const wrapAnsi16 = (fn, offset) => (...args) => {
|
||||||
|
const code = fn(...args);
|
||||||
|
return `\u001B[${code + offset}m`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapAnsi256 = (fn, offset) => (...args) => {
|
||||||
|
const code = fn(...args);
|
||||||
|
return `\u001B[${38 + offset};5;${code}m`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapAnsi16m = (fn, offset) => (...args) => {
|
||||||
|
const rgb = fn(...args);
|
||||||
|
return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ansi2ansi = n => n;
|
||||||
|
const rgb2rgb = (r, g, b) => [r, g, b];
|
||||||
|
|
||||||
|
const setLazyProperty = (object, property, get) => {
|
||||||
|
Object.defineProperty(object, property, {
|
||||||
|
get: () => {
|
||||||
|
const value = get();
|
||||||
|
|
||||||
|
Object.defineProperty(object, property, {
|
||||||
|
value,
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @type {typeof import('color-convert')} */
|
||||||
|
let colorConvert;
|
||||||
|
const makeDynamicStyles = (wrap, targetSpace, identity, isBackground) => {
|
||||||
|
if (colorConvert === undefined) {
|
||||||
|
colorConvert = require('color-convert');
|
||||||
|
}
|
||||||
|
|
||||||
|
const offset = isBackground ? 10 : 0;
|
||||||
|
const styles = {};
|
||||||
|
|
||||||
|
for (const [sourceSpace, suite] of Object.entries(colorConvert)) {
|
||||||
|
const name = sourceSpace === 'ansi16' ? 'ansi' : sourceSpace;
|
||||||
|
if (sourceSpace === targetSpace) {
|
||||||
|
styles[name] = wrap(identity, offset);
|
||||||
|
} else if (typeof suite === 'object') {
|
||||||
|
styles[name] = wrap(suite[targetSpace], offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return styles;
|
||||||
|
};
|
||||||
|
|
||||||
|
function assembleStyles() {
|
||||||
|
const codes = new Map();
|
||||||
|
const styles = {
|
||||||
|
modifier: {
|
||||||
|
reset: [0, 0],
|
||||||
|
// 21 isn't widely supported and 22 does the same thing
|
||||||
|
bold: [1, 22],
|
||||||
|
dim: [2, 22],
|
||||||
|
italic: [3, 23],
|
||||||
|
underline: [4, 24],
|
||||||
|
inverse: [7, 27],
|
||||||
|
hidden: [8, 28],
|
||||||
|
strikethrough: [9, 29]
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
black: [30, 39],
|
||||||
|
red: [31, 39],
|
||||||
|
green: [32, 39],
|
||||||
|
yellow: [33, 39],
|
||||||
|
blue: [34, 39],
|
||||||
|
magenta: [35, 39],
|
||||||
|
cyan: [36, 39],
|
||||||
|
white: [37, 39],
|
||||||
|
|
||||||
|
// Bright color
|
||||||
|
blackBright: [90, 39],
|
||||||
|
redBright: [91, 39],
|
||||||
|
greenBright: [92, 39],
|
||||||
|
yellowBright: [93, 39],
|
||||||
|
blueBright: [94, 39],
|
||||||
|
magentaBright: [95, 39],
|
||||||
|
cyanBright: [96, 39],
|
||||||
|
whiteBright: [97, 39]
|
||||||
|
},
|
||||||
|
bgColor: {
|
||||||
|
bgBlack: [40, 49],
|
||||||
|
bgRed: [41, 49],
|
||||||
|
bgGreen: [42, 49],
|
||||||
|
bgYellow: [43, 49],
|
||||||
|
bgBlue: [44, 49],
|
||||||
|
bgMagenta: [45, 49],
|
||||||
|
bgCyan: [46, 49],
|
||||||
|
bgWhite: [47, 49],
|
||||||
|
|
||||||
|
// Bright color
|
||||||
|
bgBlackBright: [100, 49],
|
||||||
|
bgRedBright: [101, 49],
|
||||||
|
bgGreenBright: [102, 49],
|
||||||
|
bgYellowBright: [103, 49],
|
||||||
|
bgBlueBright: [104, 49],
|
||||||
|
bgMagentaBright: [105, 49],
|
||||||
|
bgCyanBright: [106, 49],
|
||||||
|
bgWhiteBright: [107, 49]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Alias bright black as gray (and grey)
|
||||||
|
styles.color.gray = styles.color.blackBright;
|
||||||
|
styles.bgColor.bgGray = styles.bgColor.bgBlackBright;
|
||||||
|
styles.color.grey = styles.color.blackBright;
|
||||||
|
styles.bgColor.bgGrey = styles.bgColor.bgBlackBright;
|
||||||
|
|
||||||
|
for (const [groupName, group] of Object.entries(styles)) {
|
||||||
|
for (const [styleName, style] of Object.entries(group)) {
|
||||||
|
styles[styleName] = {
|
||||||
|
open: `\u001B[${style[0]}m`,
|
||||||
|
close: `\u001B[${style[1]}m`
|
||||||
|
};
|
||||||
|
|
||||||
|
group[styleName] = styles[styleName];
|
||||||
|
|
||||||
|
codes.set(style[0], style[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(styles, groupName, {
|
||||||
|
value: group,
|
||||||
|
enumerable: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(styles, 'codes', {
|
||||||
|
value: codes,
|
||||||
|
enumerable: false
|
||||||
|
});
|
||||||
|
|
||||||
|
styles.color.close = '\u001B[39m';
|
||||||
|
styles.bgColor.close = '\u001B[49m';
|
||||||
|
|
||||||
|
setLazyProperty(styles.color, 'ansi', () => makeDynamicStyles(wrapAnsi16, 'ansi16', ansi2ansi, false));
|
||||||
|
setLazyProperty(styles.color, 'ansi256', () => makeDynamicStyles(wrapAnsi256, 'ansi256', ansi2ansi, false));
|
||||||
|
setLazyProperty(styles.color, 'ansi16m', () => makeDynamicStyles(wrapAnsi16m, 'rgb', rgb2rgb, false));
|
||||||
|
setLazyProperty(styles.bgColor, 'ansi', () => makeDynamicStyles(wrapAnsi16, 'ansi16', ansi2ansi, true));
|
||||||
|
setLazyProperty(styles.bgColor, 'ansi256', () => makeDynamicStyles(wrapAnsi256, 'ansi256', ansi2ansi, true));
|
||||||
|
setLazyProperty(styles.bgColor, 'ansi16m', () => makeDynamicStyles(wrapAnsi16m, 'rgb', rgb2rgb, true));
|
||||||
|
|
||||||
|
return styles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the export immutable
|
||||||
|
Object.defineProperty(module, 'exports', {
|
||||||
|
enumerable: true,
|
||||||
|
get: assembleStyles
|
||||||
|
});
|
||||||
9
node_modules/ansi-styles/license
generated
vendored
Normal file
9
node_modules/ansi-styles/license
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
56
node_modules/ansi-styles/package.json
generated
vendored
Normal file
56
node_modules/ansi-styles/package.json
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"name": "ansi-styles",
|
||||||
|
"version": "4.3.0",
|
||||||
|
"description": "ANSI escape codes for styling strings in the terminal",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": "chalk/ansi-styles",
|
||||||
|
"funding": "https://github.com/chalk/ansi-styles?sponsor=1",
|
||||||
|
"author": {
|
||||||
|
"name": "Sindre Sorhus",
|
||||||
|
"email": "sindresorhus@gmail.com",
|
||||||
|
"url": "sindresorhus.com"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "xo && ava && tsd",
|
||||||
|
"screenshot": "svg-term --command='node screenshot' --out=screenshot.svg --padding=3 --width=55 --height=3 --at=1000 --no-cursor"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"index.js",
|
||||||
|
"index.d.ts"
|
||||||
|
],
|
||||||
|
"keywords": [
|
||||||
|
"ansi",
|
||||||
|
"styles",
|
||||||
|
"color",
|
||||||
|
"colour",
|
||||||
|
"colors",
|
||||||
|
"terminal",
|
||||||
|
"console",
|
||||||
|
"cli",
|
||||||
|
"string",
|
||||||
|
"tty",
|
||||||
|
"escape",
|
||||||
|
"formatting",
|
||||||
|
"rgb",
|
||||||
|
"256",
|
||||||
|
"shell",
|
||||||
|
"xterm",
|
||||||
|
"log",
|
||||||
|
"logging",
|
||||||
|
"command-line",
|
||||||
|
"text"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/color-convert": "^1.9.0",
|
||||||
|
"ava": "^2.3.0",
|
||||||
|
"svg-term-cli": "^2.1.1",
|
||||||
|
"tsd": "^0.11.0",
|
||||||
|
"xo": "^0.25.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
152
node_modules/ansi-styles/readme.md
generated
vendored
Normal file
152
node_modules/ansi-styles/readme.md
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
# ansi-styles [](https://travis-ci.org/chalk/ansi-styles)
|
||||||
|
|
||||||
|
> [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles) for styling strings in the terminal
|
||||||
|
|
||||||
|
You probably want the higher-level [chalk](https://github.com/chalk/chalk) module for styling your strings.
|
||||||
|
|
||||||
|
<img src="screenshot.svg" width="900">
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm install ansi-styles
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
const style = require('ansi-styles');
|
||||||
|
|
||||||
|
console.log(`${style.green.open}Hello world!${style.green.close}`);
|
||||||
|
|
||||||
|
|
||||||
|
// Color conversion between 16/256/truecolor
|
||||||
|
// NOTE: If conversion goes to 16 colors or 256 colors, the original color
|
||||||
|
// may be degraded to fit that color palette. This means terminals
|
||||||
|
// that do not support 16 million colors will best-match the
|
||||||
|
// original color.
|
||||||
|
console.log(style.bgColor.ansi.hsl(120, 80, 72) + 'Hello world!' + style.bgColor.close);
|
||||||
|
console.log(style.color.ansi256.rgb(199, 20, 250) + 'Hello world!' + style.color.close);
|
||||||
|
console.log(style.color.ansi16m.hex('#abcdef') + 'Hello world!' + style.color.close);
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
Each style has an `open` and `close` property.
|
||||||
|
|
||||||
|
## Styles
|
||||||
|
|
||||||
|
### Modifiers
|
||||||
|
|
||||||
|
- `reset`
|
||||||
|
- `bold`
|
||||||
|
- `dim`
|
||||||
|
- `italic` *(Not widely supported)*
|
||||||
|
- `underline`
|
||||||
|
- `inverse`
|
||||||
|
- `hidden`
|
||||||
|
- `strikethrough` *(Not widely supported)*
|
||||||
|
|
||||||
|
### Colors
|
||||||
|
|
||||||
|
- `black`
|
||||||
|
- `red`
|
||||||
|
- `green`
|
||||||
|
- `yellow`
|
||||||
|
- `blue`
|
||||||
|
- `magenta`
|
||||||
|
- `cyan`
|
||||||
|
- `white`
|
||||||
|
- `blackBright` (alias: `gray`, `grey`)
|
||||||
|
- `redBright`
|
||||||
|
- `greenBright`
|
||||||
|
- `yellowBright`
|
||||||
|
- `blueBright`
|
||||||
|
- `magentaBright`
|
||||||
|
- `cyanBright`
|
||||||
|
- `whiteBright`
|
||||||
|
|
||||||
|
### Background colors
|
||||||
|
|
||||||
|
- `bgBlack`
|
||||||
|
- `bgRed`
|
||||||
|
- `bgGreen`
|
||||||
|
- `bgYellow`
|
||||||
|
- `bgBlue`
|
||||||
|
- `bgMagenta`
|
||||||
|
- `bgCyan`
|
||||||
|
- `bgWhite`
|
||||||
|
- `bgBlackBright` (alias: `bgGray`, `bgGrey`)
|
||||||
|
- `bgRedBright`
|
||||||
|
- `bgGreenBright`
|
||||||
|
- `bgYellowBright`
|
||||||
|
- `bgBlueBright`
|
||||||
|
- `bgMagentaBright`
|
||||||
|
- `bgCyanBright`
|
||||||
|
- `bgWhiteBright`
|
||||||
|
|
||||||
|
## Advanced usage
|
||||||
|
|
||||||
|
By default, you get a map of styles, but the styles are also available as groups. They are non-enumerable so they don't show up unless you access them explicitly. This makes it easier to expose only a subset in a higher-level module.
|
||||||
|
|
||||||
|
- `style.modifier`
|
||||||
|
- `style.color`
|
||||||
|
- `style.bgColor`
|
||||||
|
|
||||||
|
###### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
console.log(style.color.green.open);
|
||||||
|
```
|
||||||
|
|
||||||
|
Raw escape codes (i.e. without the CSI escape prefix `\u001B[` and render mode postfix `m`) are available under `style.codes`, which returns a `Map` with the open codes as keys and close codes as values.
|
||||||
|
|
||||||
|
###### Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
console.log(style.codes.get(36));
|
||||||
|
//=> 39
|
||||||
|
```
|
||||||
|
|
||||||
|
## [256 / 16 million (TrueColor) support](https://gist.github.com/XVilka/8346728)
|
||||||
|
|
||||||
|
`ansi-styles` uses the [`color-convert`](https://github.com/Qix-/color-convert) package to allow for converting between various colors and ANSI escapes, with support for 256 and 16 million colors.
|
||||||
|
|
||||||
|
The following color spaces from `color-convert` are supported:
|
||||||
|
|
||||||
|
- `rgb`
|
||||||
|
- `hex`
|
||||||
|
- `keyword`
|
||||||
|
- `hsl`
|
||||||
|
- `hsv`
|
||||||
|
- `hwb`
|
||||||
|
- `ansi`
|
||||||
|
- `ansi256`
|
||||||
|
|
||||||
|
To use these, call the associated conversion function with the intended output, for example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
style.color.ansi.rgb(100, 200, 15); // RGB to 16 color ansi foreground code
|
||||||
|
style.bgColor.ansi.rgb(100, 200, 15); // RGB to 16 color ansi background code
|
||||||
|
|
||||||
|
style.color.ansi256.hsl(120, 100, 60); // HSL to 256 color ansi foreground code
|
||||||
|
style.bgColor.ansi256.hsl(120, 100, 60); // HSL to 256 color ansi foreground code
|
||||||
|
|
||||||
|
style.color.ansi16m.hex('#C0FFEE'); // Hex (RGB) to 16 million color foreground code
|
||||||
|
style.bgColor.ansi16m.hex('#C0FFEE'); // Hex (RGB) to 16 million color background code
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [ansi-escapes](https://github.com/sindresorhus/ansi-escapes) - ANSI escape codes for manipulating the terminal
|
||||||
|
|
||||||
|
## Maintainers
|
||||||
|
|
||||||
|
- [Sindre Sorhus](https://github.com/sindresorhus)
|
||||||
|
- [Josh Junon](https://github.com/qix-)
|
||||||
|
|
||||||
|
## For enterprise
|
||||||
|
|
||||||
|
Available as part of the Tidelift Subscription.
|
||||||
|
|
||||||
|
The maintainers of `ansi-styles` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-ansi-styles?utm_source=npm-ansi-styles&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
|
||||||
21
node_modules/base64-js/LICENSE
generated
vendored
Normal file
21
node_modules/base64-js/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Jameson Little
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
34
node_modules/base64-js/README.md
generated
vendored
Normal file
34
node_modules/base64-js/README.md
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
base64-js
|
||||||
|
=========
|
||||||
|
|
||||||
|
`base64-js` does basic base64 encoding/decoding in pure JS.
|
||||||
|
|
||||||
|
[](http://travis-ci.org/beatgammit/base64-js)
|
||||||
|
|
||||||
|
Many browsers already have base64 encoding/decoding functionality, but it is for text data, not all-purpose binary data.
|
||||||
|
|
||||||
|
Sometimes encoding/decoding binary data in the browser is useful, and that is what this module does.
|
||||||
|
|
||||||
|
## install
|
||||||
|
|
||||||
|
With [npm](https://npmjs.org) do:
|
||||||
|
|
||||||
|
`npm install base64-js` and `var base64js = require('base64-js')`
|
||||||
|
|
||||||
|
For use in web browsers do:
|
||||||
|
|
||||||
|
`<script src="base64js.min.js"></script>`
|
||||||
|
|
||||||
|
[Get supported base64-js with the Tidelift Subscription](https://tidelift.com/subscription/pkg/npm-base64-js?utm_source=npm-base64-js&utm_medium=referral&utm_campaign=readme)
|
||||||
|
|
||||||
|
## methods
|
||||||
|
|
||||||
|
`base64js` has three exposed functions, `byteLength`, `toByteArray` and `fromByteArray`, which both take a single argument.
|
||||||
|
|
||||||
|
* `byteLength` - Takes a base64 string and returns length of byte array
|
||||||
|
* `toByteArray` - Takes a base64 string and returns a byte array
|
||||||
|
* `fromByteArray` - Takes a byte array and returns a base64 string
|
||||||
|
|
||||||
|
## license
|
||||||
|
|
||||||
|
MIT
|
||||||
1
node_modules/base64-js/base64js.min.js
generated
vendored
Normal file
1
node_modules/base64-js/base64js.min.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
(function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"==typeof window?"undefined"==typeof global?"undefined"==typeof self?this:self:global:window,b.base64js=a()}})(function(){return function(){function b(d,e,g){function a(j,i){if(!e[j]){if(!d[j]){var f="function"==typeof require&&require;if(!i&&f)return f(j,!0);if(h)return h(j,!0);var c=new Error("Cannot find module '"+j+"'");throw c.code="MODULE_NOT_FOUND",c}var k=e[j]={exports:{}};d[j][0].call(k.exports,function(b){var c=d[j][1][b];return a(c||b)},k,k.exports,b,d,e,g)}return e[j].exports}for(var h="function"==typeof require&&require,c=0;c<g.length;c++)a(g[c]);return a}return b}()({"/":[function(a,b,c){'use strict';function d(a){var b=a.length;if(0<b%4)throw new Error("Invalid string. Length must be a multiple of 4");var c=a.indexOf("=");-1===c&&(c=b);var d=c===b?0:4-c%4;return[c,d]}function e(a,b,c){return 3*(b+c)/4-c}function f(a){var b,c,f=d(a),g=f[0],h=f[1],j=new m(e(a,g,h)),k=0,n=0<h?g-4:g;for(c=0;c<n;c+=4)b=l[a.charCodeAt(c)]<<18|l[a.charCodeAt(c+1)]<<12|l[a.charCodeAt(c+2)]<<6|l[a.charCodeAt(c+3)],j[k++]=255&b>>16,j[k++]=255&b>>8,j[k++]=255&b;return 2===h&&(b=l[a.charCodeAt(c)]<<2|l[a.charCodeAt(c+1)]>>4,j[k++]=255&b),1===h&&(b=l[a.charCodeAt(c)]<<10|l[a.charCodeAt(c+1)]<<4|l[a.charCodeAt(c+2)]>>2,j[k++]=255&b>>8,j[k++]=255&b),j}function g(a){return k[63&a>>18]+k[63&a>>12]+k[63&a>>6]+k[63&a]}function h(a,b,c){for(var d,e=[],f=b;f<c;f+=3)d=(16711680&a[f]<<16)+(65280&a[f+1]<<8)+(255&a[f+2]),e.push(g(d));return e.join("")}function j(a){for(var b,c=a.length,d=c%3,e=[],f=16383,g=0,j=c-d;g<j;g+=f)e.push(h(a,g,g+f>j?j:g+f));return 1===d?(b=a[c-1],e.push(k[b>>2]+k[63&b<<4]+"==")):2===d&&(b=(a[c-2]<<8)+a[c-1],e.push(k[b>>10]+k[63&b>>4]+k[63&b<<2]+"=")),e.join("")}c.byteLength=function(a){var b=d(a),c=b[0],e=b[1];return 3*(c+e)/4-e},c.toByteArray=f,c.fromByteArray=j;for(var k=[],l=[],m="undefined"==typeof Uint8Array?Array:Uint8Array,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o=0,p=n.length;o<p;++o)k[o]=n[o],l[n.charCodeAt(o)]=o;l[45]=62,l[95]=63},{}]},{},[])("/")});
|
||||||
3
node_modules/base64-js/index.d.ts
generated
vendored
Normal file
3
node_modules/base64-js/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export function byteLength(b64: string): number;
|
||||||
|
export function toByteArray(b64: string): Uint8Array;
|
||||||
|
export function fromByteArray(uint8: Uint8Array): string;
|
||||||
150
node_modules/base64-js/index.js
generated
vendored
Normal file
150
node_modules/base64-js/index.js
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
exports.byteLength = byteLength
|
||||||
|
exports.toByteArray = toByteArray
|
||||||
|
exports.fromByteArray = fromByteArray
|
||||||
|
|
||||||
|
var lookup = []
|
||||||
|
var revLookup = []
|
||||||
|
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
|
||||||
|
|
||||||
|
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||||
|
for (var i = 0, len = code.length; i < len; ++i) {
|
||||||
|
lookup[i] = code[i]
|
||||||
|
revLookup[code.charCodeAt(i)] = i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support decoding URL-safe base64 strings, as Node.js does.
|
||||||
|
// See: https://en.wikipedia.org/wiki/Base64#URL_applications
|
||||||
|
revLookup['-'.charCodeAt(0)] = 62
|
||||||
|
revLookup['_'.charCodeAt(0)] = 63
|
||||||
|
|
||||||
|
function getLens (b64) {
|
||||||
|
var len = b64.length
|
||||||
|
|
||||||
|
if (len % 4 > 0) {
|
||||||
|
throw new Error('Invalid string. Length must be a multiple of 4')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim off extra bytes after placeholder bytes are found
|
||||||
|
// See: https://github.com/beatgammit/base64-js/issues/42
|
||||||
|
var validLen = b64.indexOf('=')
|
||||||
|
if (validLen === -1) validLen = len
|
||||||
|
|
||||||
|
var placeHoldersLen = validLen === len
|
||||||
|
? 0
|
||||||
|
: 4 - (validLen % 4)
|
||||||
|
|
||||||
|
return [validLen, placeHoldersLen]
|
||||||
|
}
|
||||||
|
|
||||||
|
// base64 is 4/3 + up to two characters of the original data
|
||||||
|
function byteLength (b64) {
|
||||||
|
var lens = getLens(b64)
|
||||||
|
var validLen = lens[0]
|
||||||
|
var placeHoldersLen = lens[1]
|
||||||
|
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
|
||||||
|
}
|
||||||
|
|
||||||
|
function _byteLength (b64, validLen, placeHoldersLen) {
|
||||||
|
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
|
||||||
|
}
|
||||||
|
|
||||||
|
function toByteArray (b64) {
|
||||||
|
var tmp
|
||||||
|
var lens = getLens(b64)
|
||||||
|
var validLen = lens[0]
|
||||||
|
var placeHoldersLen = lens[1]
|
||||||
|
|
||||||
|
var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))
|
||||||
|
|
||||||
|
var curByte = 0
|
||||||
|
|
||||||
|
// if there are placeholders, only get up to the last complete 4 chars
|
||||||
|
var len = placeHoldersLen > 0
|
||||||
|
? validLen - 4
|
||||||
|
: validLen
|
||||||
|
|
||||||
|
var i
|
||||||
|
for (i = 0; i < len; i += 4) {
|
||||||
|
tmp =
|
||||||
|
(revLookup[b64.charCodeAt(i)] << 18) |
|
||||||
|
(revLookup[b64.charCodeAt(i + 1)] << 12) |
|
||||||
|
(revLookup[b64.charCodeAt(i + 2)] << 6) |
|
||||||
|
revLookup[b64.charCodeAt(i + 3)]
|
||||||
|
arr[curByte++] = (tmp >> 16) & 0xFF
|
||||||
|
arr[curByte++] = (tmp >> 8) & 0xFF
|
||||||
|
arr[curByte++] = tmp & 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
if (placeHoldersLen === 2) {
|
||||||
|
tmp =
|
||||||
|
(revLookup[b64.charCodeAt(i)] << 2) |
|
||||||
|
(revLookup[b64.charCodeAt(i + 1)] >> 4)
|
||||||
|
arr[curByte++] = tmp & 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
if (placeHoldersLen === 1) {
|
||||||
|
tmp =
|
||||||
|
(revLookup[b64.charCodeAt(i)] << 10) |
|
||||||
|
(revLookup[b64.charCodeAt(i + 1)] << 4) |
|
||||||
|
(revLookup[b64.charCodeAt(i + 2)] >> 2)
|
||||||
|
arr[curByte++] = (tmp >> 8) & 0xFF
|
||||||
|
arr[curByte++] = tmp & 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
function tripletToBase64 (num) {
|
||||||
|
return lookup[num >> 18 & 0x3F] +
|
||||||
|
lookup[num >> 12 & 0x3F] +
|
||||||
|
lookup[num >> 6 & 0x3F] +
|
||||||
|
lookup[num & 0x3F]
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeChunk (uint8, start, end) {
|
||||||
|
var tmp
|
||||||
|
var output = []
|
||||||
|
for (var i = start; i < end; i += 3) {
|
||||||
|
tmp =
|
||||||
|
((uint8[i] << 16) & 0xFF0000) +
|
||||||
|
((uint8[i + 1] << 8) & 0xFF00) +
|
||||||
|
(uint8[i + 2] & 0xFF)
|
||||||
|
output.push(tripletToBase64(tmp))
|
||||||
|
}
|
||||||
|
return output.join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromByteArray (uint8) {
|
||||||
|
var tmp
|
||||||
|
var len = uint8.length
|
||||||
|
var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
|
||||||
|
var parts = []
|
||||||
|
var maxChunkLength = 16383 // must be multiple of 3
|
||||||
|
|
||||||
|
// go through the array every three bytes, we'll deal with trailing stuff later
|
||||||
|
for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
|
||||||
|
parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// pad the end with zeros, but make sure to not forget the extra bytes
|
||||||
|
if (extraBytes === 1) {
|
||||||
|
tmp = uint8[len - 1]
|
||||||
|
parts.push(
|
||||||
|
lookup[tmp >> 2] +
|
||||||
|
lookup[(tmp << 4) & 0x3F] +
|
||||||
|
'=='
|
||||||
|
)
|
||||||
|
} else if (extraBytes === 2) {
|
||||||
|
tmp = (uint8[len - 2] << 8) + uint8[len - 1]
|
||||||
|
parts.push(
|
||||||
|
lookup[tmp >> 10] +
|
||||||
|
lookup[(tmp >> 4) & 0x3F] +
|
||||||
|
lookup[(tmp << 2) & 0x3F] +
|
||||||
|
'='
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.join('')
|
||||||
|
}
|
||||||
47
node_modules/base64-js/package.json
generated
vendored
Normal file
47
node_modules/base64-js/package.json
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"name": "base64-js",
|
||||||
|
"description": "Base64 encoding/decoding in pure JS",
|
||||||
|
"version": "1.5.1",
|
||||||
|
"author": "T. Jameson Little <t.jameson.little@gmail.com>",
|
||||||
|
"typings": "index.d.ts",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/beatgammit/base64-js/issues"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-minify": "^0.5.1",
|
||||||
|
"benchmark": "^2.1.4",
|
||||||
|
"browserify": "^16.3.0",
|
||||||
|
"standard": "*",
|
||||||
|
"tape": "4.x"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/beatgammit/base64-js",
|
||||||
|
"keywords": [
|
||||||
|
"base64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "index.js",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/beatgammit/base64-js.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "browserify -s base64js -r ./ | minify > base64js.min.js",
|
||||||
|
"lint": "standard",
|
||||||
|
"test": "npm run lint && npm run unit",
|
||||||
|
"unit": "tape test/*.js"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
21
node_modules/better-sqlite3/LICENSE
generated
vendored
Normal file
21
node_modules/better-sqlite3/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017 Joshua Wise
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
99
node_modules/better-sqlite3/README.md
generated
vendored
Normal file
99
node_modules/better-sqlite3/README.md
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# better-sqlite3 [](https://github.com/JoshuaWise/better-sqlite3/actions/workflows/build.yml?query=branch%3Amaster)
|
||||||
|
|
||||||
|
The fastest and simplest library for SQLite in Node.js.
|
||||||
|
|
||||||
|
- Full transaction support
|
||||||
|
- High performance, efficiency, and safety
|
||||||
|
- Easy-to-use synchronous API *(better concurrency than an asynchronous API... yes, you read that correctly)*
|
||||||
|
- Support for user-defined functions, aggregates, virtual tables, and extensions
|
||||||
|
- 64-bit integers *(invisible until you need them)*
|
||||||
|
- Worker thread support *(for large/slow queries)*
|
||||||
|
|
||||||
|
## Help this project stay strong! 💪
|
||||||
|
|
||||||
|
`better-sqlite3` is used by thousands of developers and engineers on a daily basis. Long nights and weekends were spent keeping this project strong and dependable, with no ask for compensation or funding, until now. If your company uses `better-sqlite3`, ask your manager to consider supporting the project:
|
||||||
|
|
||||||
|
- [Become a GitHub sponsor](https://github.com/sponsors/JoshuaWise)
|
||||||
|
- [Become a backer on Patreon](https://www.patreon.com/joshuawise)
|
||||||
|
- [Make a one-time donation on PayPal](https://www.paypal.me/joshuathomaswise)
|
||||||
|
|
||||||
|
## How other libraries compare
|
||||||
|
|
||||||
|
| |select 1 row `get()` |select 100 rows `all()` |select 100 rows `iterate()` 1-by-1|insert 1 row `run()`|insert 100 rows in a transaction|
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
|better-sqlite3|1x|1x|1x|1x|1x|
|
||||||
|
|[sqlite](https://www.npmjs.com/package/sqlite) and [sqlite3](https://www.npmjs.com/package/sqlite3)|11.7x slower|2.9x slower|24.4x slower|2.8x slower|15.6x slower|
|
||||||
|
|
||||||
|
> You can verify these results by [running the benchmark yourself](./docs/benchmark.md).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install better-sqlite3
|
||||||
|
```
|
||||||
|
|
||||||
|
> Requires Node.js v14.21.1 or later. Prebuilt binaries are available for [LTS versions](https://nodejs.org/en/about/releases/). If you have trouble installing, check the [troubleshooting guide](./docs/troubleshooting.md).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
const db = require('better-sqlite3')('foobar.db', options);
|
||||||
|
|
||||||
|
const row = db.prepare('SELECT * FROM users WHERE id = ?').get(userId);
|
||||||
|
console.log(row.firstName, row.lastName, row.email);
|
||||||
|
```
|
||||||
|
|
||||||
|
Though not required, [it is generally important to set the WAL pragma for performance reasons](https://github.com/WiseLibs/better-sqlite3/blob/master/docs/performance.md).
|
||||||
|
|
||||||
|
```js
|
||||||
|
db.pragma('journal_mode = WAL');
|
||||||
|
```
|
||||||
|
|
||||||
|
##### In ES6 module notation:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import Database from 'better-sqlite3';
|
||||||
|
const db = new Database('foobar.db', options);
|
||||||
|
db.pragma('journal_mode = WAL');
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why should I use this instead of [node-sqlite3](https://github.com/mapbox/node-sqlite3)?
|
||||||
|
|
||||||
|
- `node-sqlite3` uses asynchronous APIs for tasks that are either CPU-bound or serialized. That's not only bad design, but it wastes tons of resources. It also causes [mutex thrashing](https://en.wikipedia.org/wiki/Resource_contention) which has devastating effects on performance.
|
||||||
|
- `node-sqlite3` exposes low-level (C language) memory management functions. `better-sqlite3` does it the JavaScript way, allowing the garbage collector to worry about memory management.
|
||||||
|
- `better-sqlite3` is simpler to use, and it provides nice utilities for some operations that are very difficult or impossible in `node-sqlite3`.
|
||||||
|
- `better-sqlite3` is much faster than `node-sqlite3` in most cases, and just as fast in all other cases.
|
||||||
|
|
||||||
|
#### When is this library not appropriate?
|
||||||
|
|
||||||
|
In most cases, if you're attempting something that cannot be reasonably accomplished with `better-sqlite3`, it probably cannot be reasonably accomplished with SQLite in general. For example, if you're executing queries that take one second to complete, and you expect to have many concurrent users executing those queries, no amount of asynchronicity will save you from SQLite's serialized nature. Fortunately, SQLite is very *very* fast. With proper indexing, we've been able to achieve upward of 2000 queries per second with 5-way-joins in a 60 GB database, where each query was handling 5–50 kilobytes of real data.
|
||||||
|
|
||||||
|
If you have a performance problem, the most likely causes are inefficient queries, improper indexing, or a lack of [WAL mode](./docs/performance.md)—not `better-sqlite3` itself. However, there are some cases where `better-sqlite3` could be inappropriate:
|
||||||
|
|
||||||
|
- If you expect a high volume of concurrent reads each returning many megabytes of data (i.e., videos)
|
||||||
|
- If you expect a high volume of concurrent writes (i.e., a social media site)
|
||||||
|
- If your database's size is near the terabyte range
|
||||||
|
|
||||||
|
For these situations, you should probably use a full-fledged RDBMS such as [PostgreSQL](https://www.postgresql.org/).
|
||||||
|
|
||||||
|
## Upgrading
|
||||||
|
|
||||||
|
Upgrading your `better-sqlite3` dependency can potentially introduce breaking changes, either in the `better-sqlite3` API (if you upgrade to a new [major version](https://semver.org/)), or between your existing database(s) and the underlying version of SQLite. Before upgrading, review:
|
||||||
|
|
||||||
|
* [`better-sqlite3` release notes](https://github.com/WiseLibs/better-sqlite3/releases)
|
||||||
|
* [SQLite release history](https://www.sqlite.org/changes.html)
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
- [API documentation](./docs/api.md)
|
||||||
|
- [Performance](./docs/performance.md) (also see [benchmark results](./docs/benchmark.md))
|
||||||
|
- [64-bit integer support](./docs/integer.md)
|
||||||
|
- [Worker thread support](./docs/threads.md)
|
||||||
|
- [Unsafe mode (advanced)](./docs/unsafe.md)
|
||||||
|
- [SQLite compilation (advanced)](./docs/compilation.md)
|
||||||
|
- [Contribution rules](./docs/contribution.md)
|
||||||
|
- [Code of conduct](./docs/conduct.md)
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
[MIT](./LICENSE)
|
||||||
38
node_modules/better-sqlite3/binding.gyp
generated
vendored
Normal file
38
node_modules/better-sqlite3/binding.gyp
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# ===
|
||||||
|
# This is the main GYP file, which builds better-sqlite3 with SQLite itself.
|
||||||
|
# ===
|
||||||
|
|
||||||
|
{
|
||||||
|
'includes': ['deps/common.gypi'],
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'better_sqlite3',
|
||||||
|
'dependencies': ['deps/sqlite3.gyp:sqlite3'],
|
||||||
|
'sources': ['src/better_sqlite3.cpp'],
|
||||||
|
'cflags_cc': ['-std=c++20'],
|
||||||
|
'xcode_settings': {
|
||||||
|
'OTHER_CPLUSPLUSFLAGS': ['-std=c++20', '-stdlib=libc++'],
|
||||||
|
},
|
||||||
|
'msvs_settings': {
|
||||||
|
'VCCLCompilerTool': {
|
||||||
|
'AdditionalOptions': [
|
||||||
|
'/std:c++20',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'conditions': [
|
||||||
|
['OS=="linux"', {
|
||||||
|
'ldflags': [
|
||||||
|
'-Wl,-Bsymbolic',
|
||||||
|
'-Wl,--exclude-libs,ALL',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'target_name': 'test_extension',
|
||||||
|
'dependencies': ['deps/sqlite3.gyp:sqlite3'],
|
||||||
|
'conditions': [['sqlite3 == ""', { 'sources': ['deps/test_extension.c'] }]],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
BIN
node_modules/better-sqlite3/build/Release/better_sqlite3.node
generated
vendored
Executable file
BIN
node_modules/better-sqlite3/build/Release/better_sqlite3.node
generated
vendored
Executable file
Binary file not shown.
68
node_modules/better-sqlite3/deps/common.gypi
generated
vendored
Normal file
68
node_modules/better-sqlite3/deps/common.gypi
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# ===
|
||||||
|
# This configuration defines the differences between Release and Debug builds.
|
||||||
|
# Some miscellaneous Windows settings are also defined here.
|
||||||
|
# ===
|
||||||
|
|
||||||
|
{
|
||||||
|
'variables': { 'sqlite3%': '' },
|
||||||
|
'target_defaults': {
|
||||||
|
'default_configuration': 'Release',
|
||||||
|
'msvs_settings': {
|
||||||
|
'VCCLCompilerTool': {
|
||||||
|
'ExceptionHandling': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'conditions': [
|
||||||
|
['OS == "win"', {
|
||||||
|
'defines': ['WIN32'],
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
'configurations': {
|
||||||
|
'Debug': {
|
||||||
|
'defines!': [
|
||||||
|
'NDEBUG',
|
||||||
|
],
|
||||||
|
'defines': [
|
||||||
|
'DEBUG',
|
||||||
|
'_DEBUG',
|
||||||
|
'SQLITE_DEBUG',
|
||||||
|
'SQLITE_MEMDEBUG',
|
||||||
|
'SQLITE_ENABLE_API_ARMOR',
|
||||||
|
'SQLITE_WIN32_MALLOC_VALIDATE',
|
||||||
|
],
|
||||||
|
'cflags': [
|
||||||
|
'-O0',
|
||||||
|
],
|
||||||
|
'xcode_settings': {
|
||||||
|
'MACOSX_DEPLOYMENT_TARGET': '10.7',
|
||||||
|
'GCC_OPTIMIZATION_LEVEL': '0',
|
||||||
|
'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES',
|
||||||
|
},
|
||||||
|
'msvs_settings': {
|
||||||
|
'VCLinkerTool': {
|
||||||
|
'GenerateDebugInformation': 'true',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'Release': {
|
||||||
|
'defines!': [
|
||||||
|
'DEBUG',
|
||||||
|
'_DEBUG',
|
||||||
|
],
|
||||||
|
'defines': [
|
||||||
|
'NDEBUG',
|
||||||
|
],
|
||||||
|
'cflags': [
|
||||||
|
'-O3',
|
||||||
|
],
|
||||||
|
'xcode_settings': {
|
||||||
|
'MACOSX_DEPLOYMENT_TARGET': '10.7',
|
||||||
|
'GCC_OPTIMIZATION_LEVEL': '3',
|
||||||
|
'GCC_GENERATE_DEBUGGING_SYMBOLS': 'NO',
|
||||||
|
'DEAD_CODE_STRIPPING': 'YES',
|
||||||
|
'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
31
node_modules/better-sqlite3/deps/copy.js
generated
vendored
Normal file
31
node_modules/better-sqlite3/deps/copy.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
'use strict';
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const dest = process.argv[2];
|
||||||
|
const source = path.resolve(path.sep, process.argv[3] || path.join(__dirname, 'sqlite3'));
|
||||||
|
const files = [
|
||||||
|
{ filename: 'sqlite3.c', optional: false },
|
||||||
|
{ filename: 'sqlite3.h', optional: false },
|
||||||
|
];
|
||||||
|
|
||||||
|
if (process.argv[3]) {
|
||||||
|
// Support "_HAVE_SQLITE_CONFIG_H" in custom builds.
|
||||||
|
files.push({ filename: 'config.h', optional: true });
|
||||||
|
} else {
|
||||||
|
// Required for some tests.
|
||||||
|
files.push({ filename: 'sqlite3ext.h', optional: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const { filename, optional } of files) {
|
||||||
|
const sourceFilepath = path.join(source, filename);
|
||||||
|
const destFilepath = path.join(dest, filename);
|
||||||
|
|
||||||
|
if (optional && !fs.existsSync(sourceFilepath)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.accessSync(sourceFilepath);
|
||||||
|
fs.mkdirSync(path.dirname(destFilepath), { recursive: true });
|
||||||
|
fs.copyFileSync(sourceFilepath, destFilepath);
|
||||||
|
}
|
||||||
41
node_modules/better-sqlite3/deps/defines.gypi
generated
vendored
Normal file
41
node_modules/better-sqlite3/deps/defines.gypi
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# THIS FILE IS AUTOMATICALLY GENERATED BY deps/download.sh (DO NOT EDIT)
|
||||||
|
|
||||||
|
{
|
||||||
|
'defines': [
|
||||||
|
'HAVE_INT16_T=1',
|
||||||
|
'HAVE_INT32_T=1',
|
||||||
|
'HAVE_INT8_T=1',
|
||||||
|
'HAVE_STDINT_H=1',
|
||||||
|
'HAVE_UINT16_T=1',
|
||||||
|
'HAVE_UINT32_T=1',
|
||||||
|
'HAVE_UINT8_T=1',
|
||||||
|
'HAVE_USLEEP=1',
|
||||||
|
'SQLITE_DEFAULT_CACHE_SIZE=-16000',
|
||||||
|
'SQLITE_DEFAULT_FOREIGN_KEYS=1',
|
||||||
|
'SQLITE_DEFAULT_MEMSTATUS=0',
|
||||||
|
'SQLITE_DEFAULT_WAL_SYNCHRONOUS=1',
|
||||||
|
'SQLITE_DQS=0',
|
||||||
|
'SQLITE_ENABLE_COLUMN_METADATA',
|
||||||
|
'SQLITE_ENABLE_DBSTAT_VTAB',
|
||||||
|
'SQLITE_ENABLE_DESERIALIZE',
|
||||||
|
'SQLITE_ENABLE_FTS3',
|
||||||
|
'SQLITE_ENABLE_FTS3_PARENTHESIS',
|
||||||
|
'SQLITE_ENABLE_FTS4',
|
||||||
|
'SQLITE_ENABLE_FTS5',
|
||||||
|
'SQLITE_ENABLE_GEOPOLY',
|
||||||
|
'SQLITE_ENABLE_JSON1',
|
||||||
|
'SQLITE_ENABLE_MATH_FUNCTIONS',
|
||||||
|
'SQLITE_ENABLE_RTREE',
|
||||||
|
'SQLITE_ENABLE_STAT4',
|
||||||
|
'SQLITE_ENABLE_UPDATE_DELETE_LIMIT',
|
||||||
|
'SQLITE_LIKE_DOESNT_MATCH_BLOBS',
|
||||||
|
'SQLITE_OMIT_DEPRECATED',
|
||||||
|
'SQLITE_OMIT_PROGRESS_CALLBACK',
|
||||||
|
'SQLITE_OMIT_SHARED_CACHE',
|
||||||
|
'SQLITE_OMIT_TCL_VARIABLE',
|
||||||
|
'SQLITE_SOUNDEX',
|
||||||
|
'SQLITE_THREADSAFE=2',
|
||||||
|
'SQLITE_TRACE_SIZE_LIMIT=32',
|
||||||
|
'SQLITE_USE_URI=0',
|
||||||
|
],
|
||||||
|
}
|
||||||
122
node_modules/better-sqlite3/deps/download.sh
generated
vendored
Executable file
122
node_modules/better-sqlite3/deps/download.sh
generated
vendored
Executable file
@@ -0,0 +1,122 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# ===
|
||||||
|
# This script defines and generates the bundled SQLite unit (sqlite3.c).
|
||||||
|
#
|
||||||
|
# The following steps are taken:
|
||||||
|
# 1. populate the shell environment with the defined compile-time options.
|
||||||
|
# 2. download and extract the SQLite source code into a temporary directory.
|
||||||
|
# 3. run "sh configure" and "make sqlite3.c" within the source directory.
|
||||||
|
# 4. copy the generated amalgamation into the output directory (./sqlite3).
|
||||||
|
# 5. export the defined compile-time options to a gyp file (./defines.gypi).
|
||||||
|
# 6. update the docs (../docs/compilation.md) with details of this distribution.
|
||||||
|
#
|
||||||
|
# When a user builds better-sqlite3, the following steps are taken:
|
||||||
|
# 1. node-gyp loads the previously exported compile-time options (defines.gypi).
|
||||||
|
# 2. the copy.js script copies the bundled amalgamation into the build folder.
|
||||||
|
# 3. node-gyp compiles the copied sqlite3.c along with better_sqlite3.cpp.
|
||||||
|
# 4. node-gyp links the two resulting binaries to generate better_sqlite3.node.
|
||||||
|
# ===
|
||||||
|
|
||||||
|
YEAR="2025"
|
||||||
|
VERSION="3510100"
|
||||||
|
|
||||||
|
# Defines below are sorted alphabetically
|
||||||
|
DEFINES="
|
||||||
|
HAVE_INT16_T=1
|
||||||
|
HAVE_INT32_T=1
|
||||||
|
HAVE_INT8_T=1
|
||||||
|
HAVE_STDINT_H=1
|
||||||
|
HAVE_UINT16_T=1
|
||||||
|
HAVE_UINT32_T=1
|
||||||
|
HAVE_UINT8_T=1
|
||||||
|
HAVE_USLEEP=1
|
||||||
|
SQLITE_DEFAULT_CACHE_SIZE=-16000
|
||||||
|
SQLITE_DEFAULT_FOREIGN_KEYS=1
|
||||||
|
SQLITE_DEFAULT_MEMSTATUS=0
|
||||||
|
SQLITE_DEFAULT_WAL_SYNCHRONOUS=1
|
||||||
|
SQLITE_DQS=0
|
||||||
|
SQLITE_ENABLE_COLUMN_METADATA
|
||||||
|
SQLITE_ENABLE_DBSTAT_VTAB
|
||||||
|
SQLITE_ENABLE_DESERIALIZE
|
||||||
|
SQLITE_ENABLE_FTS3
|
||||||
|
SQLITE_ENABLE_FTS3_PARENTHESIS
|
||||||
|
SQLITE_ENABLE_FTS4
|
||||||
|
SQLITE_ENABLE_FTS5
|
||||||
|
SQLITE_ENABLE_GEOPOLY
|
||||||
|
SQLITE_ENABLE_JSON1
|
||||||
|
SQLITE_ENABLE_MATH_FUNCTIONS
|
||||||
|
SQLITE_ENABLE_RTREE
|
||||||
|
SQLITE_ENABLE_STAT4
|
||||||
|
SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||||
|
SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
||||||
|
SQLITE_OMIT_DEPRECATED
|
||||||
|
SQLITE_OMIT_PROGRESS_CALLBACK
|
||||||
|
SQLITE_OMIT_SHARED_CACHE
|
||||||
|
SQLITE_OMIT_TCL_VARIABLE
|
||||||
|
SQLITE_SOUNDEX
|
||||||
|
SQLITE_THREADSAFE=2
|
||||||
|
SQLITE_TRACE_SIZE_LIMIT=32
|
||||||
|
SQLITE_USE_URI=0
|
||||||
|
"
|
||||||
|
|
||||||
|
# ========== START SCRIPT ========== #
|
||||||
|
|
||||||
|
echo "setting up environment..."
|
||||||
|
DEPS="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
||||||
|
TEMP="$DEPS/temp"
|
||||||
|
OUTPUT="$DEPS/sqlite3"
|
||||||
|
rm -rf "$TEMP"
|
||||||
|
rm -rf "$OUTPUT"
|
||||||
|
mkdir -p "$TEMP"
|
||||||
|
mkdir -p "$OUTPUT"
|
||||||
|
export CFLAGS=`echo $(echo "$DEFINES" | sed -e "/^\s*$/d" -e "s/^/-D/")`
|
||||||
|
|
||||||
|
echo "downloading source..."
|
||||||
|
curl -#f "https://www.sqlite.org/$YEAR/sqlite-src-$VERSION.zip" > "$TEMP/source.zip" || exit 1
|
||||||
|
|
||||||
|
echo "extracting source..."
|
||||||
|
unzip "$TEMP/source.zip" -d "$TEMP" > /dev/null || exit 1
|
||||||
|
cd "$TEMP/sqlite-src-$VERSION" || exit 1
|
||||||
|
|
||||||
|
echo "configuring amalgamation..."
|
||||||
|
sh configure > /dev/null || exit 1
|
||||||
|
|
||||||
|
echo "building amalgamation..."
|
||||||
|
make OPTIONS="$CFLAGS" sqlite3.c > /dev/null || exit 1
|
||||||
|
|
||||||
|
echo "copying amalgamation..."
|
||||||
|
cp sqlite3.c sqlite3.h sqlite3ext.h "$OUTPUT/" || exit 1
|
||||||
|
|
||||||
|
echo "applying patches..."
|
||||||
|
cd "$DEPS" || exit 1
|
||||||
|
for patch in patches/*.patch; do
|
||||||
|
# If a patch fails, just skip it an move on.
|
||||||
|
# By default `patch` tries to be clever and reverse the patch, so we have to specify `--forward`.
|
||||||
|
# If the patch fails, we # don't write .orig and .rej files, so we have to specify `--no-backup-if-mismatch` and `--reject-file=-`.
|
||||||
|
patch --batch --forward --no-backup-if-mismatch --reject-file=- -p2 < "$patch"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "updating gyp configs..."
|
||||||
|
GYP="$DEPS/defines.gypi"
|
||||||
|
printf "# THIS FILE IS AUTOMATICALLY GENERATED BY deps/download.sh (DO NOT EDIT)\n\n{\n 'defines': [\n" > "$GYP"
|
||||||
|
printf "$DEFINES" | sed -e "/^\s*$/d" -e "s/\(.*\)/ '\1',/" >> "$GYP"
|
||||||
|
printf " ],\n}\n" >> "$GYP"
|
||||||
|
|
||||||
|
echo "updating docs..."
|
||||||
|
DOCS="$DEPS/../docs/compilation.md"
|
||||||
|
MAJOR=`expr "${VERSION:0:1}" + 0`
|
||||||
|
MINOR=`expr "${VERSION:1:2}" + 0`
|
||||||
|
PATCH=`expr "${VERSION:3:2}" + 0`
|
||||||
|
sed -Ei.bak -e "s/version [0-9]+\.[0-9]+\.[0-9]+/version $MAJOR.$MINOR.$PATCH/g" "$DOCS"
|
||||||
|
sed -i.bak -e "/^SQLITE_/,\$d" "$DOCS"
|
||||||
|
sed -i.bak -e "/^HAVE_/,\$d" "$DOCS"
|
||||||
|
rm "$DOCS".bak
|
||||||
|
printf "$DEFINES" | sed -e "/^\s*$/d" >> "$DOCS"
|
||||||
|
printf "\`\`\`\n" >> "$DOCS"
|
||||||
|
|
||||||
|
echo "cleaning up..."
|
||||||
|
cd - > /dev/null || exit 1
|
||||||
|
rm -rf "$TEMP"
|
||||||
|
|
||||||
|
echo "done!"
|
||||||
15
node_modules/better-sqlite3/deps/patches/1208.patch
generated
vendored
Normal file
15
node_modules/better-sqlite3/deps/patches/1208.patch
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
diff --git a/deps/sqlite3/sqlite3.c b/deps/sqlite3/sqlite3.c
|
||||||
|
index b1a807f..38bd1e6 100644
|
||||||
|
--- a/deps/sqlite3/sqlite3.c
|
||||||
|
+++ b/deps/sqlite3/sqlite3.c
|
||||||
|
@@ -24887,8 +24887,8 @@ static const struct {
|
||||||
|
/* 1 */ { 6, "minute", 7.7379e+12, 60.0 },
|
||||||
|
/* 2 */ { 4, "hour", 1.2897e+11, 3600.0 },
|
||||||
|
/* 3 */ { 3, "day", 5373485.0, 86400.0 },
|
||||||
|
- /* 4 */ { 5, "month", 176546.0, 30.0*86400.0 },
|
||||||
|
- /* 5 */ { 4, "year", 14713.0, 365.0*86400.0 },
|
||||||
|
+ /* 4 */ { 5, "month", 176546.0, 2592000.0 },
|
||||||
|
+ /* 5 */ { 4, "year", 14713.0, 31536000.0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
80
node_modules/better-sqlite3/deps/sqlite3.gyp
generated
vendored
Executable file
80
node_modules/better-sqlite3/deps/sqlite3.gyp
generated
vendored
Executable file
@@ -0,0 +1,80 @@
|
|||||||
|
# ===
|
||||||
|
# This configuration defines options specific to compiling SQLite itself.
|
||||||
|
# Compile-time options are loaded by the auto-generated file "defines.gypi".
|
||||||
|
# The --sqlite3 option can be provided to use a custom amalgamation instead.
|
||||||
|
# ===
|
||||||
|
|
||||||
|
{
|
||||||
|
'includes': ['common.gypi'],
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'locate_sqlite3',
|
||||||
|
'type': 'none',
|
||||||
|
'hard_dependency': 1,
|
||||||
|
'conditions': [
|
||||||
|
['sqlite3 == ""', {
|
||||||
|
'actions': [{
|
||||||
|
'action_name': 'copy_builtin_sqlite3',
|
||||||
|
'inputs': [
|
||||||
|
'sqlite3/sqlite3.c',
|
||||||
|
'sqlite3/sqlite3.h',
|
||||||
|
'sqlite3/sqlite3ext.h',
|
||||||
|
],
|
||||||
|
'outputs': [
|
||||||
|
'<(SHARED_INTERMEDIATE_DIR)/sqlite3/sqlite3.c',
|
||||||
|
'<(SHARED_INTERMEDIATE_DIR)/sqlite3/sqlite3.h',
|
||||||
|
'<(SHARED_INTERMEDIATE_DIR)/sqlite3/sqlite3ext.h',
|
||||||
|
],
|
||||||
|
'action': ['node', 'copy.js', '<(SHARED_INTERMEDIATE_DIR)/sqlite3', ''],
|
||||||
|
}],
|
||||||
|
}, {
|
||||||
|
'actions': [{
|
||||||
|
'action_name': 'copy_custom_sqlite3',
|
||||||
|
'inputs': [
|
||||||
|
'<(sqlite3)/sqlite3.c',
|
||||||
|
'<(sqlite3)/sqlite3.h',
|
||||||
|
],
|
||||||
|
'outputs': [
|
||||||
|
'<(SHARED_INTERMEDIATE_DIR)/sqlite3/sqlite3.c',
|
||||||
|
'<(SHARED_INTERMEDIATE_DIR)/sqlite3/sqlite3.h',
|
||||||
|
],
|
||||||
|
'action': ['node', 'copy.js', '<(SHARED_INTERMEDIATE_DIR)/sqlite3', '<(sqlite3)'],
|
||||||
|
}],
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'target_name': 'sqlite3',
|
||||||
|
'type': 'static_library',
|
||||||
|
'dependencies': ['locate_sqlite3'],
|
||||||
|
'sources': ['<(SHARED_INTERMEDIATE_DIR)/sqlite3/sqlite3.c'],
|
||||||
|
'include_dirs': ['<(SHARED_INTERMEDIATE_DIR)/sqlite3/'],
|
||||||
|
'direct_dependent_settings': {
|
||||||
|
'include_dirs': ['<(SHARED_INTERMEDIATE_DIR)/sqlite3/'],
|
||||||
|
},
|
||||||
|
'cflags': ['-std=c99', '-w'],
|
||||||
|
'xcode_settings': {
|
||||||
|
'OTHER_CFLAGS': ['-std=c99'],
|
||||||
|
'WARNING_CFLAGS': ['-w'],
|
||||||
|
},
|
||||||
|
'conditions': [
|
||||||
|
['sqlite3 == ""', {
|
||||||
|
'includes': ['defines.gypi'],
|
||||||
|
}, {
|
||||||
|
'defines': [
|
||||||
|
# This is currently required by better-sqlite3.
|
||||||
|
'SQLITE_ENABLE_COLUMN_METADATA',
|
||||||
|
],
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
'configurations': {
|
||||||
|
'Debug': {
|
||||||
|
'msvs_settings': { 'VCCLCompilerTool': { 'RuntimeLibrary': 1 } }, # static debug
|
||||||
|
},
|
||||||
|
'Release': {
|
||||||
|
'msvs_settings': { 'VCCLCompilerTool': { 'RuntimeLibrary': 0 } }, # static release
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
265925
node_modules/better-sqlite3/deps/sqlite3/sqlite3.c
generated
vendored
Normal file
265925
node_modules/better-sqlite3/deps/sqlite3/sqlite3.c
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
13968
node_modules/better-sqlite3/deps/sqlite3/sqlite3.h
generated
vendored
Normal file
13968
node_modules/better-sqlite3/deps/sqlite3/sqlite3.h
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
730
node_modules/better-sqlite3/deps/sqlite3/sqlite3ext.h
generated
vendored
Normal file
730
node_modules/better-sqlite3/deps/sqlite3/sqlite3ext.h
generated
vendored
Normal file
@@ -0,0 +1,730 @@
|
|||||||
|
/*
|
||||||
|
** 2006 June 7
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
** This header file defines the SQLite interface for use by
|
||||||
|
** shared libraries that want to be imported as extensions into
|
||||||
|
** an SQLite instance. Shared libraries that intend to be loaded
|
||||||
|
** as extensions by SQLite should #include this file instead of
|
||||||
|
** sqlite3.h.
|
||||||
|
*/
|
||||||
|
#ifndef SQLITE3EXT_H
|
||||||
|
#define SQLITE3EXT_H
|
||||||
|
#include "sqlite3.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following structure holds pointers to all of the SQLite API
|
||||||
|
** routines.
|
||||||
|
**
|
||||||
|
** WARNING: In order to maintain backwards compatibility, add new
|
||||||
|
** interfaces to the end of this structure only. If you insert new
|
||||||
|
** interfaces in the middle of this structure, then older different
|
||||||
|
** versions of SQLite will not be able to load each other's shared
|
||||||
|
** libraries!
|
||||||
|
*/
|
||||||
|
struct sqlite3_api_routines {
|
||||||
|
void * (*aggregate_context)(sqlite3_context*,int nBytes);
|
||||||
|
int (*aggregate_count)(sqlite3_context*);
|
||||||
|
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
|
||||||
|
int (*bind_double)(sqlite3_stmt*,int,double);
|
||||||
|
int (*bind_int)(sqlite3_stmt*,int,int);
|
||||||
|
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
|
||||||
|
int (*bind_null)(sqlite3_stmt*,int);
|
||||||
|
int (*bind_parameter_count)(sqlite3_stmt*);
|
||||||
|
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
|
||||||
|
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
|
||||||
|
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
|
||||||
|
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
|
||||||
|
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
|
||||||
|
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
|
||||||
|
int (*busy_timeout)(sqlite3*,int ms);
|
||||||
|
int (*changes)(sqlite3*);
|
||||||
|
int (*close)(sqlite3*);
|
||||||
|
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||||
|
int eTextRep,const char*));
|
||||||
|
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||||
|
int eTextRep,const void*));
|
||||||
|
const void * (*column_blob)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_bytes)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_bytes16)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_count)(sqlite3_stmt*pStmt);
|
||||||
|
const char * (*column_database_name)(sqlite3_stmt*,int);
|
||||||
|
const void * (*column_database_name16)(sqlite3_stmt*,int);
|
||||||
|
const char * (*column_decltype)(sqlite3_stmt*,int i);
|
||||||
|
const void * (*column_decltype16)(sqlite3_stmt*,int);
|
||||||
|
double (*column_double)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_int)(sqlite3_stmt*,int iCol);
|
||||||
|
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
|
||||||
|
const char * (*column_name)(sqlite3_stmt*,int);
|
||||||
|
const void * (*column_name16)(sqlite3_stmt*,int);
|
||||||
|
const char * (*column_origin_name)(sqlite3_stmt*,int);
|
||||||
|
const void * (*column_origin_name16)(sqlite3_stmt*,int);
|
||||||
|
const char * (*column_table_name)(sqlite3_stmt*,int);
|
||||||
|
const void * (*column_table_name16)(sqlite3_stmt*,int);
|
||||||
|
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
|
||||||
|
const void * (*column_text16)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_type)(sqlite3_stmt*,int iCol);
|
||||||
|
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
|
||||||
|
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
|
||||||
|
int (*complete)(const char*sql);
|
||||||
|
int (*complete16)(const void*sql);
|
||||||
|
int (*create_collation)(sqlite3*,const char*,int,void*,
|
||||||
|
int(*)(void*,int,const void*,int,const void*));
|
||||||
|
int (*create_collation16)(sqlite3*,const void*,int,void*,
|
||||||
|
int(*)(void*,int,const void*,int,const void*));
|
||||||
|
int (*create_function)(sqlite3*,const char*,int,int,void*,
|
||||||
|
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xFinal)(sqlite3_context*));
|
||||||
|
int (*create_function16)(sqlite3*,const void*,int,int,void*,
|
||||||
|
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xFinal)(sqlite3_context*));
|
||||||
|
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
||||||
|
int (*data_count)(sqlite3_stmt*pStmt);
|
||||||
|
sqlite3 * (*db_handle)(sqlite3_stmt*);
|
||||||
|
int (*declare_vtab)(sqlite3*,const char*);
|
||||||
|
int (*enable_shared_cache)(int);
|
||||||
|
int (*errcode)(sqlite3*db);
|
||||||
|
const char * (*errmsg)(sqlite3*);
|
||||||
|
const void * (*errmsg16)(sqlite3*);
|
||||||
|
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
|
||||||
|
int (*expired)(sqlite3_stmt*);
|
||||||
|
int (*finalize)(sqlite3_stmt*pStmt);
|
||||||
|
void (*free)(void*);
|
||||||
|
void (*free_table)(char**result);
|
||||||
|
int (*get_autocommit)(sqlite3*);
|
||||||
|
void * (*get_auxdata)(sqlite3_context*,int);
|
||||||
|
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
|
||||||
|
int (*global_recover)(void);
|
||||||
|
void (*interruptx)(sqlite3*);
|
||||||
|
sqlite_int64 (*last_insert_rowid)(sqlite3*);
|
||||||
|
const char * (*libversion)(void);
|
||||||
|
int (*libversion_number)(void);
|
||||||
|
void *(*malloc)(int);
|
||||||
|
char * (*mprintf)(const char*,...);
|
||||||
|
int (*open)(const char*,sqlite3**);
|
||||||
|
int (*open16)(const void*,sqlite3**);
|
||||||
|
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||||
|
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||||
|
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
|
||||||
|
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
|
||||||
|
void *(*realloc)(void*,int);
|
||||||
|
int (*reset)(sqlite3_stmt*pStmt);
|
||||||
|
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||||
|
void (*result_double)(sqlite3_context*,double);
|
||||||
|
void (*result_error)(sqlite3_context*,const char*,int);
|
||||||
|
void (*result_error16)(sqlite3_context*,const void*,int);
|
||||||
|
void (*result_int)(sqlite3_context*,int);
|
||||||
|
void (*result_int64)(sqlite3_context*,sqlite_int64);
|
||||||
|
void (*result_null)(sqlite3_context*);
|
||||||
|
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
|
||||||
|
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||||
|
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||||
|
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||||
|
void (*result_value)(sqlite3_context*,sqlite3_value*);
|
||||||
|
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
|
||||||
|
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
|
||||||
|
const char*,const char*),void*);
|
||||||
|
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
||||||
|
char * (*xsnprintf)(int,char*,const char*,...);
|
||||||
|
int (*step)(sqlite3_stmt*);
|
||||||
|
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
|
||||||
|
char const**,char const**,int*,int*,int*);
|
||||||
|
void (*thread_cleanup)(void);
|
||||||
|
int (*total_changes)(sqlite3*);
|
||||||
|
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
|
||||||
|
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
|
||||||
|
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
|
||||||
|
sqlite_int64),void*);
|
||||||
|
void * (*user_data)(sqlite3_context*);
|
||||||
|
const void * (*value_blob)(sqlite3_value*);
|
||||||
|
int (*value_bytes)(sqlite3_value*);
|
||||||
|
int (*value_bytes16)(sqlite3_value*);
|
||||||
|
double (*value_double)(sqlite3_value*);
|
||||||
|
int (*value_int)(sqlite3_value*);
|
||||||
|
sqlite_int64 (*value_int64)(sqlite3_value*);
|
||||||
|
int (*value_numeric_type)(sqlite3_value*);
|
||||||
|
const unsigned char * (*value_text)(sqlite3_value*);
|
||||||
|
const void * (*value_text16)(sqlite3_value*);
|
||||||
|
const void * (*value_text16be)(sqlite3_value*);
|
||||||
|
const void * (*value_text16le)(sqlite3_value*);
|
||||||
|
int (*value_type)(sqlite3_value*);
|
||||||
|
char *(*vmprintf)(const char*,va_list);
|
||||||
|
/* Added ??? */
|
||||||
|
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
|
||||||
|
/* Added by 3.3.13 */
|
||||||
|
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||||
|
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||||
|
int (*clear_bindings)(sqlite3_stmt*);
|
||||||
|
/* Added by 3.4.1 */
|
||||||
|
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
|
||||||
|
void (*xDestroy)(void *));
|
||||||
|
/* Added by 3.5.0 */
|
||||||
|
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
|
||||||
|
int (*blob_bytes)(sqlite3_blob*);
|
||||||
|
int (*blob_close)(sqlite3_blob*);
|
||||||
|
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
|
||||||
|
int,sqlite3_blob**);
|
||||||
|
int (*blob_read)(sqlite3_blob*,void*,int,int);
|
||||||
|
int (*blob_write)(sqlite3_blob*,const void*,int,int);
|
||||||
|
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
|
||||||
|
int(*)(void*,int,const void*,int,const void*),
|
||||||
|
void(*)(void*));
|
||||||
|
int (*file_control)(sqlite3*,const char*,int,void*);
|
||||||
|
sqlite3_int64 (*memory_highwater)(int);
|
||||||
|
sqlite3_int64 (*memory_used)(void);
|
||||||
|
sqlite3_mutex *(*mutex_alloc)(int);
|
||||||
|
void (*mutex_enter)(sqlite3_mutex*);
|
||||||
|
void (*mutex_free)(sqlite3_mutex*);
|
||||||
|
void (*mutex_leave)(sqlite3_mutex*);
|
||||||
|
int (*mutex_try)(sqlite3_mutex*);
|
||||||
|
int (*open_v2)(const char*,sqlite3**,int,const char*);
|
||||||
|
int (*release_memory)(int);
|
||||||
|
void (*result_error_nomem)(sqlite3_context*);
|
||||||
|
void (*result_error_toobig)(sqlite3_context*);
|
||||||
|
int (*sleep)(int);
|
||||||
|
void (*soft_heap_limit)(int);
|
||||||
|
sqlite3_vfs *(*vfs_find)(const char*);
|
||||||
|
int (*vfs_register)(sqlite3_vfs*,int);
|
||||||
|
int (*vfs_unregister)(sqlite3_vfs*);
|
||||||
|
int (*xthreadsafe)(void);
|
||||||
|
void (*result_zeroblob)(sqlite3_context*,int);
|
||||||
|
void (*result_error_code)(sqlite3_context*,int);
|
||||||
|
int (*test_control)(int, ...);
|
||||||
|
void (*randomness)(int,void*);
|
||||||
|
sqlite3 *(*context_db_handle)(sqlite3_context*);
|
||||||
|
int (*extended_result_codes)(sqlite3*,int);
|
||||||
|
int (*limit)(sqlite3*,int,int);
|
||||||
|
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
|
||||||
|
const char *(*sql)(sqlite3_stmt*);
|
||||||
|
int (*status)(int,int*,int*,int);
|
||||||
|
int (*backup_finish)(sqlite3_backup*);
|
||||||
|
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
|
||||||
|
int (*backup_pagecount)(sqlite3_backup*);
|
||||||
|
int (*backup_remaining)(sqlite3_backup*);
|
||||||
|
int (*backup_step)(sqlite3_backup*,int);
|
||||||
|
const char *(*compileoption_get)(int);
|
||||||
|
int (*compileoption_used)(const char*);
|
||||||
|
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
|
||||||
|
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xFinal)(sqlite3_context*),
|
||||||
|
void(*xDestroy)(void*));
|
||||||
|
int (*db_config)(sqlite3*,int,...);
|
||||||
|
sqlite3_mutex *(*db_mutex)(sqlite3*);
|
||||||
|
int (*db_status)(sqlite3*,int,int*,int*,int);
|
||||||
|
int (*extended_errcode)(sqlite3*);
|
||||||
|
void (*log)(int,const char*,...);
|
||||||
|
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
|
||||||
|
const char *(*sourceid)(void);
|
||||||
|
int (*stmt_status)(sqlite3_stmt*,int,int);
|
||||||
|
int (*strnicmp)(const char*,const char*,int);
|
||||||
|
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
|
||||||
|
int (*wal_autocheckpoint)(sqlite3*,int);
|
||||||
|
int (*wal_checkpoint)(sqlite3*,const char*);
|
||||||
|
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
|
||||||
|
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
|
||||||
|
int (*vtab_config)(sqlite3*,int op,...);
|
||||||
|
int (*vtab_on_conflict)(sqlite3*);
|
||||||
|
/* Version 3.7.16 and later */
|
||||||
|
int (*close_v2)(sqlite3*);
|
||||||
|
const char *(*db_filename)(sqlite3*,const char*);
|
||||||
|
int (*db_readonly)(sqlite3*,const char*);
|
||||||
|
int (*db_release_memory)(sqlite3*);
|
||||||
|
const char *(*errstr)(int);
|
||||||
|
int (*stmt_busy)(sqlite3_stmt*);
|
||||||
|
int (*stmt_readonly)(sqlite3_stmt*);
|
||||||
|
int (*stricmp)(const char*,const char*);
|
||||||
|
int (*uri_boolean)(const char*,const char*,int);
|
||||||
|
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
|
||||||
|
const char *(*uri_parameter)(const char*,const char*);
|
||||||
|
char *(*xvsnprintf)(int,char*,const char*,va_list);
|
||||||
|
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
|
||||||
|
/* Version 3.8.7 and later */
|
||||||
|
int (*auto_extension)(void(*)(void));
|
||||||
|
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
|
||||||
|
void(*)(void*));
|
||||||
|
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
|
||||||
|
void(*)(void*),unsigned char);
|
||||||
|
int (*cancel_auto_extension)(void(*)(void));
|
||||||
|
int (*load_extension)(sqlite3*,const char*,const char*,char**);
|
||||||
|
void *(*malloc64)(sqlite3_uint64);
|
||||||
|
sqlite3_uint64 (*msize)(void*);
|
||||||
|
void *(*realloc64)(void*,sqlite3_uint64);
|
||||||
|
void (*reset_auto_extension)(void);
|
||||||
|
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
|
||||||
|
void(*)(void*));
|
||||||
|
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
|
||||||
|
void(*)(void*), unsigned char);
|
||||||
|
int (*strglob)(const char*,const char*);
|
||||||
|
/* Version 3.8.11 and later */
|
||||||
|
sqlite3_value *(*value_dup)(const sqlite3_value*);
|
||||||
|
void (*value_free)(sqlite3_value*);
|
||||||
|
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
|
||||||
|
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
|
||||||
|
/* Version 3.9.0 and later */
|
||||||
|
unsigned int (*value_subtype)(sqlite3_value*);
|
||||||
|
void (*result_subtype)(sqlite3_context*,unsigned int);
|
||||||
|
/* Version 3.10.0 and later */
|
||||||
|
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
|
||||||
|
int (*strlike)(const char*,const char*,unsigned int);
|
||||||
|
int (*db_cacheflush)(sqlite3*);
|
||||||
|
/* Version 3.12.0 and later */
|
||||||
|
int (*system_errno)(sqlite3*);
|
||||||
|
/* Version 3.14.0 and later */
|
||||||
|
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
|
||||||
|
char *(*expanded_sql)(sqlite3_stmt*);
|
||||||
|
/* Version 3.18.0 and later */
|
||||||
|
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
|
||||||
|
/* Version 3.20.0 and later */
|
||||||
|
int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
|
||||||
|
sqlite3_stmt**,const char**);
|
||||||
|
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
|
||||||
|
sqlite3_stmt**,const void**);
|
||||||
|
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
|
||||||
|
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
|
||||||
|
void *(*value_pointer)(sqlite3_value*,const char*);
|
||||||
|
int (*vtab_nochange)(sqlite3_context*);
|
||||||
|
int (*value_nochange)(sqlite3_value*);
|
||||||
|
const char *(*vtab_collation)(sqlite3_index_info*,int);
|
||||||
|
/* Version 3.24.0 and later */
|
||||||
|
int (*keyword_count)(void);
|
||||||
|
int (*keyword_name)(int,const char**,int*);
|
||||||
|
int (*keyword_check)(const char*,int);
|
||||||
|
sqlite3_str *(*str_new)(sqlite3*);
|
||||||
|
char *(*str_finish)(sqlite3_str*);
|
||||||
|
void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
|
||||||
|
void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
|
||||||
|
void (*str_append)(sqlite3_str*, const char *zIn, int N);
|
||||||
|
void (*str_appendall)(sqlite3_str*, const char *zIn);
|
||||||
|
void (*str_appendchar)(sqlite3_str*, int N, char C);
|
||||||
|
void (*str_reset)(sqlite3_str*);
|
||||||
|
int (*str_errcode)(sqlite3_str*);
|
||||||
|
int (*str_length)(sqlite3_str*);
|
||||||
|
char *(*str_value)(sqlite3_str*);
|
||||||
|
/* Version 3.25.0 and later */
|
||||||
|
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
|
||||||
|
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void (*xFinal)(sqlite3_context*),
|
||||||
|
void (*xValue)(sqlite3_context*),
|
||||||
|
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
|
||||||
|
void(*xDestroy)(void*));
|
||||||
|
/* Version 3.26.0 and later */
|
||||||
|
const char *(*normalized_sql)(sqlite3_stmt*);
|
||||||
|
/* Version 3.28.0 and later */
|
||||||
|
int (*stmt_isexplain)(sqlite3_stmt*);
|
||||||
|
int (*value_frombind)(sqlite3_value*);
|
||||||
|
/* Version 3.30.0 and later */
|
||||||
|
int (*drop_modules)(sqlite3*,const char**);
|
||||||
|
/* Version 3.31.0 and later */
|
||||||
|
sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
|
||||||
|
const char *(*uri_key)(const char*,int);
|
||||||
|
const char *(*filename_database)(const char*);
|
||||||
|
const char *(*filename_journal)(const char*);
|
||||||
|
const char *(*filename_wal)(const char*);
|
||||||
|
/* Version 3.32.0 and later */
|
||||||
|
const char *(*create_filename)(const char*,const char*,const char*,
|
||||||
|
int,const char**);
|
||||||
|
void (*free_filename)(const char*);
|
||||||
|
sqlite3_file *(*database_file_object)(const char*);
|
||||||
|
/* Version 3.34.0 and later */
|
||||||
|
int (*txn_state)(sqlite3*,const char*);
|
||||||
|
/* Version 3.36.1 and later */
|
||||||
|
sqlite3_int64 (*changes64)(sqlite3*);
|
||||||
|
sqlite3_int64 (*total_changes64)(sqlite3*);
|
||||||
|
/* Version 3.37.0 and later */
|
||||||
|
int (*autovacuum_pages)(sqlite3*,
|
||||||
|
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
|
||||||
|
void*, void(*)(void*));
|
||||||
|
/* Version 3.38.0 and later */
|
||||||
|
int (*error_offset)(sqlite3*);
|
||||||
|
int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
|
||||||
|
int (*vtab_distinct)(sqlite3_index_info*);
|
||||||
|
int (*vtab_in)(sqlite3_index_info*,int,int);
|
||||||
|
int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
|
||||||
|
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
|
||||||
|
/* Version 3.39.0 and later */
|
||||||
|
int (*deserialize)(sqlite3*,const char*,unsigned char*,
|
||||||
|
sqlite3_int64,sqlite3_int64,unsigned);
|
||||||
|
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
|
||||||
|
unsigned int);
|
||||||
|
const char *(*db_name)(sqlite3*,int);
|
||||||
|
/* Version 3.40.0 and later */
|
||||||
|
int (*value_encoding)(sqlite3_value*);
|
||||||
|
/* Version 3.41.0 and later */
|
||||||
|
int (*is_interrupted)(sqlite3*);
|
||||||
|
/* Version 3.43.0 and later */
|
||||||
|
int (*stmt_explain)(sqlite3_stmt*,int);
|
||||||
|
/* Version 3.44.0 and later */
|
||||||
|
void *(*get_clientdata)(sqlite3*,const char*);
|
||||||
|
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
|
||||||
|
/* Version 3.50.0 and later */
|
||||||
|
int (*setlk_timeout)(sqlite3*,int,int);
|
||||||
|
/* Version 3.51.0 and later */
|
||||||
|
int (*set_errmsg)(sqlite3*,int,const char*);
|
||||||
|
int (*db_status64)(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This is the function signature used for all extension entry points. It
|
||||||
|
** is also defined in the file "loadext.c".
|
||||||
|
*/
|
||||||
|
typedef int (*sqlite3_loadext_entry)(
|
||||||
|
sqlite3 *db, /* Handle to the database. */
|
||||||
|
char **pzErrMsg, /* Used to set error string on failure. */
|
||||||
|
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following macros redefine the API routines so that they are
|
||||||
|
** redirected through the global sqlite3_api structure.
|
||||||
|
**
|
||||||
|
** This header file is also used by the loadext.c source file
|
||||||
|
** (part of the main SQLite library - not an extension) so that
|
||||||
|
** it can get access to the sqlite3_api_routines structure
|
||||||
|
** definition. But the main library does not want to redefine
|
||||||
|
** the API. So the redefinition macros are only valid if the
|
||||||
|
** SQLITE_CORE macros is undefined.
|
||||||
|
*/
|
||||||
|
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||||
|
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
||||||
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
|
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
||||||
|
#endif
|
||||||
|
#define sqlite3_bind_blob sqlite3_api->bind_blob
|
||||||
|
#define sqlite3_bind_double sqlite3_api->bind_double
|
||||||
|
#define sqlite3_bind_int sqlite3_api->bind_int
|
||||||
|
#define sqlite3_bind_int64 sqlite3_api->bind_int64
|
||||||
|
#define sqlite3_bind_null sqlite3_api->bind_null
|
||||||
|
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
|
||||||
|
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
|
||||||
|
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
|
||||||
|
#define sqlite3_bind_text sqlite3_api->bind_text
|
||||||
|
#define sqlite3_bind_text16 sqlite3_api->bind_text16
|
||||||
|
#define sqlite3_bind_value sqlite3_api->bind_value
|
||||||
|
#define sqlite3_busy_handler sqlite3_api->busy_handler
|
||||||
|
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
|
||||||
|
#define sqlite3_changes sqlite3_api->changes
|
||||||
|
#define sqlite3_close sqlite3_api->close
|
||||||
|
#define sqlite3_collation_needed sqlite3_api->collation_needed
|
||||||
|
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
|
||||||
|
#define sqlite3_column_blob sqlite3_api->column_blob
|
||||||
|
#define sqlite3_column_bytes sqlite3_api->column_bytes
|
||||||
|
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
|
||||||
|
#define sqlite3_column_count sqlite3_api->column_count
|
||||||
|
#define sqlite3_column_database_name sqlite3_api->column_database_name
|
||||||
|
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
|
||||||
|
#define sqlite3_column_decltype sqlite3_api->column_decltype
|
||||||
|
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
|
||||||
|
#define sqlite3_column_double sqlite3_api->column_double
|
||||||
|
#define sqlite3_column_int sqlite3_api->column_int
|
||||||
|
#define sqlite3_column_int64 sqlite3_api->column_int64
|
||||||
|
#define sqlite3_column_name sqlite3_api->column_name
|
||||||
|
#define sqlite3_column_name16 sqlite3_api->column_name16
|
||||||
|
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
|
||||||
|
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
|
||||||
|
#define sqlite3_column_table_name sqlite3_api->column_table_name
|
||||||
|
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
|
||||||
|
#define sqlite3_column_text sqlite3_api->column_text
|
||||||
|
#define sqlite3_column_text16 sqlite3_api->column_text16
|
||||||
|
#define sqlite3_column_type sqlite3_api->column_type
|
||||||
|
#define sqlite3_column_value sqlite3_api->column_value
|
||||||
|
#define sqlite3_commit_hook sqlite3_api->commit_hook
|
||||||
|
#define sqlite3_complete sqlite3_api->complete
|
||||||
|
#define sqlite3_complete16 sqlite3_api->complete16
|
||||||
|
#define sqlite3_create_collation sqlite3_api->create_collation
|
||||||
|
#define sqlite3_create_collation16 sqlite3_api->create_collation16
|
||||||
|
#define sqlite3_create_function sqlite3_api->create_function
|
||||||
|
#define sqlite3_create_function16 sqlite3_api->create_function16
|
||||||
|
#define sqlite3_create_module sqlite3_api->create_module
|
||||||
|
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
|
||||||
|
#define sqlite3_data_count sqlite3_api->data_count
|
||||||
|
#define sqlite3_db_handle sqlite3_api->db_handle
|
||||||
|
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
|
||||||
|
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
|
||||||
|
#define sqlite3_errcode sqlite3_api->errcode
|
||||||
|
#define sqlite3_errmsg sqlite3_api->errmsg
|
||||||
|
#define sqlite3_errmsg16 sqlite3_api->errmsg16
|
||||||
|
#define sqlite3_exec sqlite3_api->exec
|
||||||
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
|
#define sqlite3_expired sqlite3_api->expired
|
||||||
|
#endif
|
||||||
|
#define sqlite3_finalize sqlite3_api->finalize
|
||||||
|
#define sqlite3_free sqlite3_api->free
|
||||||
|
#define sqlite3_free_table sqlite3_api->free_table
|
||||||
|
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
|
||||||
|
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
|
||||||
|
#define sqlite3_get_table sqlite3_api->get_table
|
||||||
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
|
#define sqlite3_global_recover sqlite3_api->global_recover
|
||||||
|
#endif
|
||||||
|
#define sqlite3_interrupt sqlite3_api->interruptx
|
||||||
|
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
|
||||||
|
#define sqlite3_libversion sqlite3_api->libversion
|
||||||
|
#define sqlite3_libversion_number sqlite3_api->libversion_number
|
||||||
|
#define sqlite3_malloc sqlite3_api->malloc
|
||||||
|
#define sqlite3_mprintf sqlite3_api->mprintf
|
||||||
|
#define sqlite3_open sqlite3_api->open
|
||||||
|
#define sqlite3_open16 sqlite3_api->open16
|
||||||
|
#define sqlite3_prepare sqlite3_api->prepare
|
||||||
|
#define sqlite3_prepare16 sqlite3_api->prepare16
|
||||||
|
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||||
|
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||||
|
#define sqlite3_profile sqlite3_api->profile
|
||||||
|
#define sqlite3_progress_handler sqlite3_api->progress_handler
|
||||||
|
#define sqlite3_realloc sqlite3_api->realloc
|
||||||
|
#define sqlite3_reset sqlite3_api->reset
|
||||||
|
#define sqlite3_result_blob sqlite3_api->result_blob
|
||||||
|
#define sqlite3_result_double sqlite3_api->result_double
|
||||||
|
#define sqlite3_result_error sqlite3_api->result_error
|
||||||
|
#define sqlite3_result_error16 sqlite3_api->result_error16
|
||||||
|
#define sqlite3_result_int sqlite3_api->result_int
|
||||||
|
#define sqlite3_result_int64 sqlite3_api->result_int64
|
||||||
|
#define sqlite3_result_null sqlite3_api->result_null
|
||||||
|
#define sqlite3_result_text sqlite3_api->result_text
|
||||||
|
#define sqlite3_result_text16 sqlite3_api->result_text16
|
||||||
|
#define sqlite3_result_text16be sqlite3_api->result_text16be
|
||||||
|
#define sqlite3_result_text16le sqlite3_api->result_text16le
|
||||||
|
#define sqlite3_result_value sqlite3_api->result_value
|
||||||
|
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
|
||||||
|
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
|
||||||
|
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
|
||||||
|
#define sqlite3_snprintf sqlite3_api->xsnprintf
|
||||||
|
#define sqlite3_step sqlite3_api->step
|
||||||
|
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
|
||||||
|
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
|
||||||
|
#define sqlite3_total_changes sqlite3_api->total_changes
|
||||||
|
#define sqlite3_trace sqlite3_api->trace
|
||||||
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
|
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
|
||||||
|
#endif
|
||||||
|
#define sqlite3_update_hook sqlite3_api->update_hook
|
||||||
|
#define sqlite3_user_data sqlite3_api->user_data
|
||||||
|
#define sqlite3_value_blob sqlite3_api->value_blob
|
||||||
|
#define sqlite3_value_bytes sqlite3_api->value_bytes
|
||||||
|
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
|
||||||
|
#define sqlite3_value_double sqlite3_api->value_double
|
||||||
|
#define sqlite3_value_int sqlite3_api->value_int
|
||||||
|
#define sqlite3_value_int64 sqlite3_api->value_int64
|
||||||
|
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
|
||||||
|
#define sqlite3_value_text sqlite3_api->value_text
|
||||||
|
#define sqlite3_value_text16 sqlite3_api->value_text16
|
||||||
|
#define sqlite3_value_text16be sqlite3_api->value_text16be
|
||||||
|
#define sqlite3_value_text16le sqlite3_api->value_text16le
|
||||||
|
#define sqlite3_value_type sqlite3_api->value_type
|
||||||
|
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||||
|
#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
|
||||||
|
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||||
|
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||||
|
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||||
|
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
|
||||||
|
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
|
||||||
|
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
|
||||||
|
#define sqlite3_blob_close sqlite3_api->blob_close
|
||||||
|
#define sqlite3_blob_open sqlite3_api->blob_open
|
||||||
|
#define sqlite3_blob_read sqlite3_api->blob_read
|
||||||
|
#define sqlite3_blob_write sqlite3_api->blob_write
|
||||||
|
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
|
||||||
|
#define sqlite3_file_control sqlite3_api->file_control
|
||||||
|
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
|
||||||
|
#define sqlite3_memory_used sqlite3_api->memory_used
|
||||||
|
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
|
||||||
|
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
|
||||||
|
#define sqlite3_mutex_free sqlite3_api->mutex_free
|
||||||
|
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
|
||||||
|
#define sqlite3_mutex_try sqlite3_api->mutex_try
|
||||||
|
#define sqlite3_open_v2 sqlite3_api->open_v2
|
||||||
|
#define sqlite3_release_memory sqlite3_api->release_memory
|
||||||
|
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
|
||||||
|
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
|
||||||
|
#define sqlite3_sleep sqlite3_api->sleep
|
||||||
|
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
|
||||||
|
#define sqlite3_vfs_find sqlite3_api->vfs_find
|
||||||
|
#define sqlite3_vfs_register sqlite3_api->vfs_register
|
||||||
|
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
|
||||||
|
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
|
||||||
|
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
|
||||||
|
#define sqlite3_result_error_code sqlite3_api->result_error_code
|
||||||
|
#define sqlite3_test_control sqlite3_api->test_control
|
||||||
|
#define sqlite3_randomness sqlite3_api->randomness
|
||||||
|
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
|
||||||
|
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
|
||||||
|
#define sqlite3_limit sqlite3_api->limit
|
||||||
|
#define sqlite3_next_stmt sqlite3_api->next_stmt
|
||||||
|
#define sqlite3_sql sqlite3_api->sql
|
||||||
|
#define sqlite3_status sqlite3_api->status
|
||||||
|
#define sqlite3_backup_finish sqlite3_api->backup_finish
|
||||||
|
#define sqlite3_backup_init sqlite3_api->backup_init
|
||||||
|
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
|
||||||
|
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
|
||||||
|
#define sqlite3_backup_step sqlite3_api->backup_step
|
||||||
|
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
|
||||||
|
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
|
||||||
|
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
|
||||||
|
#define sqlite3_db_config sqlite3_api->db_config
|
||||||
|
#define sqlite3_db_mutex sqlite3_api->db_mutex
|
||||||
|
#define sqlite3_db_status sqlite3_api->db_status
|
||||||
|
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
|
||||||
|
#define sqlite3_log sqlite3_api->log
|
||||||
|
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
|
||||||
|
#define sqlite3_sourceid sqlite3_api->sourceid
|
||||||
|
#define sqlite3_stmt_status sqlite3_api->stmt_status
|
||||||
|
#define sqlite3_strnicmp sqlite3_api->strnicmp
|
||||||
|
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
|
||||||
|
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
|
||||||
|
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
|
||||||
|
#define sqlite3_wal_hook sqlite3_api->wal_hook
|
||||||
|
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
|
||||||
|
#define sqlite3_vtab_config sqlite3_api->vtab_config
|
||||||
|
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
|
||||||
|
/* Version 3.7.16 and later */
|
||||||
|
#define sqlite3_close_v2 sqlite3_api->close_v2
|
||||||
|
#define sqlite3_db_filename sqlite3_api->db_filename
|
||||||
|
#define sqlite3_db_readonly sqlite3_api->db_readonly
|
||||||
|
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
|
||||||
|
#define sqlite3_errstr sqlite3_api->errstr
|
||||||
|
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
|
||||||
|
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
|
||||||
|
#define sqlite3_stricmp sqlite3_api->stricmp
|
||||||
|
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
|
||||||
|
#define sqlite3_uri_int64 sqlite3_api->uri_int64
|
||||||
|
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
|
||||||
|
#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
|
||||||
|
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
|
||||||
|
/* Version 3.8.7 and later */
|
||||||
|
#define sqlite3_auto_extension sqlite3_api->auto_extension
|
||||||
|
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
|
||||||
|
#define sqlite3_bind_text64 sqlite3_api->bind_text64
|
||||||
|
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
|
||||||
|
#define sqlite3_load_extension sqlite3_api->load_extension
|
||||||
|
#define sqlite3_malloc64 sqlite3_api->malloc64
|
||||||
|
#define sqlite3_msize sqlite3_api->msize
|
||||||
|
#define sqlite3_realloc64 sqlite3_api->realloc64
|
||||||
|
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
|
||||||
|
#define sqlite3_result_blob64 sqlite3_api->result_blob64
|
||||||
|
#define sqlite3_result_text64 sqlite3_api->result_text64
|
||||||
|
#define sqlite3_strglob sqlite3_api->strglob
|
||||||
|
/* Version 3.8.11 and later */
|
||||||
|
#define sqlite3_value_dup sqlite3_api->value_dup
|
||||||
|
#define sqlite3_value_free sqlite3_api->value_free
|
||||||
|
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
|
||||||
|
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
|
||||||
|
/* Version 3.9.0 and later */
|
||||||
|
#define sqlite3_value_subtype sqlite3_api->value_subtype
|
||||||
|
#define sqlite3_result_subtype sqlite3_api->result_subtype
|
||||||
|
/* Version 3.10.0 and later */
|
||||||
|
#define sqlite3_status64 sqlite3_api->status64
|
||||||
|
#define sqlite3_strlike sqlite3_api->strlike
|
||||||
|
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
|
||||||
|
/* Version 3.12.0 and later */
|
||||||
|
#define sqlite3_system_errno sqlite3_api->system_errno
|
||||||
|
/* Version 3.14.0 and later */
|
||||||
|
#define sqlite3_trace_v2 sqlite3_api->trace_v2
|
||||||
|
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
|
||||||
|
/* Version 3.18.0 and later */
|
||||||
|
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
|
||||||
|
/* Version 3.20.0 and later */
|
||||||
|
#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
|
||||||
|
#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
|
||||||
|
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
|
||||||
|
#define sqlite3_result_pointer sqlite3_api->result_pointer
|
||||||
|
#define sqlite3_value_pointer sqlite3_api->value_pointer
|
||||||
|
/* Version 3.22.0 and later */
|
||||||
|
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
|
||||||
|
#define sqlite3_value_nochange sqlite3_api->value_nochange
|
||||||
|
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
|
||||||
|
/* Version 3.24.0 and later */
|
||||||
|
#define sqlite3_keyword_count sqlite3_api->keyword_count
|
||||||
|
#define sqlite3_keyword_name sqlite3_api->keyword_name
|
||||||
|
#define sqlite3_keyword_check sqlite3_api->keyword_check
|
||||||
|
#define sqlite3_str_new sqlite3_api->str_new
|
||||||
|
#define sqlite3_str_finish sqlite3_api->str_finish
|
||||||
|
#define sqlite3_str_appendf sqlite3_api->str_appendf
|
||||||
|
#define sqlite3_str_vappendf sqlite3_api->str_vappendf
|
||||||
|
#define sqlite3_str_append sqlite3_api->str_append
|
||||||
|
#define sqlite3_str_appendall sqlite3_api->str_appendall
|
||||||
|
#define sqlite3_str_appendchar sqlite3_api->str_appendchar
|
||||||
|
#define sqlite3_str_reset sqlite3_api->str_reset
|
||||||
|
#define sqlite3_str_errcode sqlite3_api->str_errcode
|
||||||
|
#define sqlite3_str_length sqlite3_api->str_length
|
||||||
|
#define sqlite3_str_value sqlite3_api->str_value
|
||||||
|
/* Version 3.25.0 and later */
|
||||||
|
#define sqlite3_create_window_function sqlite3_api->create_window_function
|
||||||
|
/* Version 3.26.0 and later */
|
||||||
|
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
|
||||||
|
/* Version 3.28.0 and later */
|
||||||
|
#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
|
||||||
|
#define sqlite3_value_frombind sqlite3_api->value_frombind
|
||||||
|
/* Version 3.30.0 and later */
|
||||||
|
#define sqlite3_drop_modules sqlite3_api->drop_modules
|
||||||
|
/* Version 3.31.0 and later */
|
||||||
|
#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
|
||||||
|
#define sqlite3_uri_key sqlite3_api->uri_key
|
||||||
|
#define sqlite3_filename_database sqlite3_api->filename_database
|
||||||
|
#define sqlite3_filename_journal sqlite3_api->filename_journal
|
||||||
|
#define sqlite3_filename_wal sqlite3_api->filename_wal
|
||||||
|
/* Version 3.32.0 and later */
|
||||||
|
#define sqlite3_create_filename sqlite3_api->create_filename
|
||||||
|
#define sqlite3_free_filename sqlite3_api->free_filename
|
||||||
|
#define sqlite3_database_file_object sqlite3_api->database_file_object
|
||||||
|
/* Version 3.34.0 and later */
|
||||||
|
#define sqlite3_txn_state sqlite3_api->txn_state
|
||||||
|
/* Version 3.36.1 and later */
|
||||||
|
#define sqlite3_changes64 sqlite3_api->changes64
|
||||||
|
#define sqlite3_total_changes64 sqlite3_api->total_changes64
|
||||||
|
/* Version 3.37.0 and later */
|
||||||
|
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
|
||||||
|
/* Version 3.38.0 and later */
|
||||||
|
#define sqlite3_error_offset sqlite3_api->error_offset
|
||||||
|
#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
|
||||||
|
#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
|
||||||
|
#define sqlite3_vtab_in sqlite3_api->vtab_in
|
||||||
|
#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
|
||||||
|
#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
|
||||||
|
/* Version 3.39.0 and later */
|
||||||
|
#ifndef SQLITE_OMIT_DESERIALIZE
|
||||||
|
#define sqlite3_deserialize sqlite3_api->deserialize
|
||||||
|
#define sqlite3_serialize sqlite3_api->serialize
|
||||||
|
#endif
|
||||||
|
#define sqlite3_db_name sqlite3_api->db_name
|
||||||
|
/* Version 3.40.0 and later */
|
||||||
|
#define sqlite3_value_encoding sqlite3_api->value_encoding
|
||||||
|
/* Version 3.41.0 and later */
|
||||||
|
#define sqlite3_is_interrupted sqlite3_api->is_interrupted
|
||||||
|
/* Version 3.43.0 and later */
|
||||||
|
#define sqlite3_stmt_explain sqlite3_api->stmt_explain
|
||||||
|
/* Version 3.44.0 and later */
|
||||||
|
#define sqlite3_get_clientdata sqlite3_api->get_clientdata
|
||||||
|
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
|
||||||
|
/* Version 3.50.0 and later */
|
||||||
|
#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout
|
||||||
|
/* Version 3.51.0 and later */
|
||||||
|
#define sqlite3_set_errmsg sqlite3_api->set_errmsg
|
||||||
|
#define sqlite3_db_status64 sqlite3_api->db_status64
|
||||||
|
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||||
|
|
||||||
|
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||||
|
/* This case when the file really is being compiled as a loadable
|
||||||
|
** extension */
|
||||||
|
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
|
||||||
|
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
|
||||||
|
# define SQLITE_EXTENSION_INIT3 \
|
||||||
|
extern const sqlite3_api_routines *sqlite3_api;
|
||||||
|
#else
|
||||||
|
/* This case when the file is being statically linked into the
|
||||||
|
** application */
|
||||||
|
# define SQLITE_EXTENSION_INIT1 /*no-op*/
|
||||||
|
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
|
||||||
|
# define SQLITE_EXTENSION_INIT3 /*no-op*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SQLITE3EXT_H */
|
||||||
21
node_modules/better-sqlite3/deps/test_extension.c
generated
vendored
Normal file
21
node_modules/better-sqlite3/deps/test_extension.c
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#include <sqlite3ext.h>
|
||||||
|
SQLITE_EXTENSION_INIT1
|
||||||
|
|
||||||
|
/*
|
||||||
|
This SQLite extension is used only for testing purposes (npm test).
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void TestExtensionFunction(sqlite3_context* pCtx, int nVal, sqlite3_value** _) {
|
||||||
|
sqlite3_result_double(pCtx, (double)nVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
__declspec(dllexport)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int sqlite3_extension_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* pApi) {
|
||||||
|
SQLITE_EXTENSION_INIT2(pApi)
|
||||||
|
if (pzErrMsg != 0) *pzErrMsg = 0;
|
||||||
|
sqlite3_create_function(db, "testExtensionFunction", -1, SQLITE_UTF8, 0, TestExtensionFunction, 0, 0);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
90
node_modules/better-sqlite3/lib/database.js
generated
vendored
Normal file
90
node_modules/better-sqlite3/lib/database.js
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
'use strict';
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const util = require('./util');
|
||||||
|
const SqliteError = require('./sqlite-error');
|
||||||
|
|
||||||
|
let DEFAULT_ADDON;
|
||||||
|
|
||||||
|
function Database(filenameGiven, options) {
|
||||||
|
if (new.target == null) {
|
||||||
|
return new Database(filenameGiven, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply defaults
|
||||||
|
let buffer;
|
||||||
|
if (Buffer.isBuffer(filenameGiven)) {
|
||||||
|
buffer = filenameGiven;
|
||||||
|
filenameGiven = ':memory:';
|
||||||
|
}
|
||||||
|
if (filenameGiven == null) filenameGiven = '';
|
||||||
|
if (options == null) options = {};
|
||||||
|
|
||||||
|
// Validate arguments
|
||||||
|
if (typeof filenameGiven !== 'string') throw new TypeError('Expected first argument to be a string');
|
||||||
|
if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
|
||||||
|
if ('readOnly' in options) throw new TypeError('Misspelled option "readOnly" should be "readonly"');
|
||||||
|
if ('memory' in options) throw new TypeError('Option "memory" was removed in v7.0.0 (use ":memory:" filename instead)');
|
||||||
|
|
||||||
|
// Interpret options
|
||||||
|
const filename = filenameGiven.trim();
|
||||||
|
const anonymous = filename === '' || filename === ':memory:';
|
||||||
|
const readonly = util.getBooleanOption(options, 'readonly');
|
||||||
|
const fileMustExist = util.getBooleanOption(options, 'fileMustExist');
|
||||||
|
const timeout = 'timeout' in options ? options.timeout : 5000;
|
||||||
|
const verbose = 'verbose' in options ? options.verbose : null;
|
||||||
|
const nativeBinding = 'nativeBinding' in options ? options.nativeBinding : null;
|
||||||
|
|
||||||
|
// Validate interpreted options
|
||||||
|
if (readonly && anonymous && !buffer) throw new TypeError('In-memory/temporary databases cannot be readonly');
|
||||||
|
if (!Number.isInteger(timeout) || timeout < 0) throw new TypeError('Expected the "timeout" option to be a positive integer');
|
||||||
|
if (timeout > 0x7fffffff) throw new RangeError('Option "timeout" cannot be greater than 2147483647');
|
||||||
|
if (verbose != null && typeof verbose !== 'function') throw new TypeError('Expected the "verbose" option to be a function');
|
||||||
|
if (nativeBinding != null && typeof nativeBinding !== 'string' && typeof nativeBinding !== 'object') throw new TypeError('Expected the "nativeBinding" option to be a string or addon object');
|
||||||
|
|
||||||
|
// Load the native addon
|
||||||
|
let addon;
|
||||||
|
if (nativeBinding == null) {
|
||||||
|
addon = DEFAULT_ADDON || (DEFAULT_ADDON = require('bindings')('better_sqlite3.node'));
|
||||||
|
} else if (typeof nativeBinding === 'string') {
|
||||||
|
// See <https://webpack.js.org/api/module-variables/#__non_webpack_require__-webpack-specific>
|
||||||
|
const requireFunc = typeof __non_webpack_require__ === 'function' ? __non_webpack_require__ : require;
|
||||||
|
addon = requireFunc(path.resolve(nativeBinding).replace(/(\.node)?$/, '.node'));
|
||||||
|
} else {
|
||||||
|
// See <https://github.com/WiseLibs/better-sqlite3/issues/972>
|
||||||
|
addon = nativeBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!addon.isInitialized) {
|
||||||
|
addon.setErrorConstructor(SqliteError);
|
||||||
|
addon.isInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the specified directory exists
|
||||||
|
if (!anonymous && !filename.startsWith('file:') && !fs.existsSync(path.dirname(filename))) {
|
||||||
|
throw new TypeError('Cannot open database because the directory does not exist');
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperties(this, {
|
||||||
|
[util.cppdb]: { value: new addon.Database(filename, filenameGiven, anonymous, readonly, fileMustExist, timeout, verbose || null, buffer || null) },
|
||||||
|
...wrappers.getters,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrappers = require('./methods/wrappers');
|
||||||
|
Database.prototype.prepare = wrappers.prepare;
|
||||||
|
Database.prototype.transaction = require('./methods/transaction');
|
||||||
|
Database.prototype.pragma = require('./methods/pragma');
|
||||||
|
Database.prototype.backup = require('./methods/backup');
|
||||||
|
Database.prototype.serialize = require('./methods/serialize');
|
||||||
|
Database.prototype.function = require('./methods/function');
|
||||||
|
Database.prototype.aggregate = require('./methods/aggregate');
|
||||||
|
Database.prototype.table = require('./methods/table');
|
||||||
|
Database.prototype.loadExtension = wrappers.loadExtension;
|
||||||
|
Database.prototype.exec = wrappers.exec;
|
||||||
|
Database.prototype.close = wrappers.close;
|
||||||
|
Database.prototype.defaultSafeIntegers = wrappers.defaultSafeIntegers;
|
||||||
|
Database.prototype.unsafeMode = wrappers.unsafeMode;
|
||||||
|
Database.prototype[util.inspect] = require('./methods/inspect');
|
||||||
|
|
||||||
|
module.exports = Database;
|
||||||
3
node_modules/better-sqlite3/lib/index.js
generated
vendored
Normal file
3
node_modules/better-sqlite3/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
'use strict';
|
||||||
|
module.exports = require('./database');
|
||||||
|
module.exports.SqliteError = require('./sqlite-error');
|
||||||
43
node_modules/better-sqlite3/lib/methods/aggregate.js
generated
vendored
Normal file
43
node_modules/better-sqlite3/lib/methods/aggregate.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
'use strict';
|
||||||
|
const { getBooleanOption, cppdb } = require('../util');
|
||||||
|
|
||||||
|
module.exports = function defineAggregate(name, options) {
|
||||||
|
// Validate arguments
|
||||||
|
if (typeof name !== 'string') throw new TypeError('Expected first argument to be a string');
|
||||||
|
if (typeof options !== 'object' || options === null) throw new TypeError('Expected second argument to be an options object');
|
||||||
|
if (!name) throw new TypeError('User-defined function name cannot be an empty string');
|
||||||
|
|
||||||
|
// Interpret options
|
||||||
|
const start = 'start' in options ? options.start : null;
|
||||||
|
const step = getFunctionOption(options, 'step', true);
|
||||||
|
const inverse = getFunctionOption(options, 'inverse', false);
|
||||||
|
const result = getFunctionOption(options, 'result', false);
|
||||||
|
const safeIntegers = 'safeIntegers' in options ? +getBooleanOption(options, 'safeIntegers') : 2;
|
||||||
|
const deterministic = getBooleanOption(options, 'deterministic');
|
||||||
|
const directOnly = getBooleanOption(options, 'directOnly');
|
||||||
|
const varargs = getBooleanOption(options, 'varargs');
|
||||||
|
let argCount = -1;
|
||||||
|
|
||||||
|
// Determine argument count
|
||||||
|
if (!varargs) {
|
||||||
|
argCount = Math.max(getLength(step), inverse ? getLength(inverse) : 0);
|
||||||
|
if (argCount > 0) argCount -= 1;
|
||||||
|
if (argCount > 100) throw new RangeError('User-defined functions cannot have more than 100 arguments');
|
||||||
|
}
|
||||||
|
|
||||||
|
this[cppdb].aggregate(start, step, inverse, result, name, argCount, safeIntegers, deterministic, directOnly);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFunctionOption = (options, key, required) => {
|
||||||
|
const value = key in options ? options[key] : null;
|
||||||
|
if (typeof value === 'function') return value;
|
||||||
|
if (value != null) throw new TypeError(`Expected the "${key}" option to be a function`);
|
||||||
|
if (required) throw new TypeError(`Missing required option "${key}"`);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getLength = ({ length }) => {
|
||||||
|
if (Number.isInteger(length) && length >= 0) return length;
|
||||||
|
throw new TypeError('Expected function.length to be a positive integer');
|
||||||
|
};
|
||||||
67
node_modules/better-sqlite3/lib/methods/backup.js
generated
vendored
Normal file
67
node_modules/better-sqlite3/lib/methods/backup.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
'use strict';
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { promisify } = require('util');
|
||||||
|
const { cppdb } = require('../util');
|
||||||
|
const fsAccess = promisify(fs.access);
|
||||||
|
|
||||||
|
module.exports = async function backup(filename, options) {
|
||||||
|
if (options == null) options = {};
|
||||||
|
|
||||||
|
// Validate arguments
|
||||||
|
if (typeof filename !== 'string') throw new TypeError('Expected first argument to be a string');
|
||||||
|
if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
|
||||||
|
|
||||||
|
// Interpret options
|
||||||
|
filename = filename.trim();
|
||||||
|
const attachedName = 'attached' in options ? options.attached : 'main';
|
||||||
|
const handler = 'progress' in options ? options.progress : null;
|
||||||
|
|
||||||
|
// Validate interpreted options
|
||||||
|
if (!filename) throw new TypeError('Backup filename cannot be an empty string');
|
||||||
|
if (filename === ':memory:') throw new TypeError('Invalid backup filename ":memory:"');
|
||||||
|
if (typeof attachedName !== 'string') throw new TypeError('Expected the "attached" option to be a string');
|
||||||
|
if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
|
||||||
|
if (handler != null && typeof handler !== 'function') throw new TypeError('Expected the "progress" option to be a function');
|
||||||
|
|
||||||
|
// Make sure the specified directory exists
|
||||||
|
await fsAccess(path.dirname(filename)).catch(() => {
|
||||||
|
throw new TypeError('Cannot save backup because the directory does not exist');
|
||||||
|
});
|
||||||
|
|
||||||
|
const isNewFile = await fsAccess(filename).then(() => false, () => true);
|
||||||
|
return runBackup(this[cppdb].backup(this, attachedName, filename, isNewFile), handler || null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const runBackup = (backup, handler) => {
|
||||||
|
let rate = 0;
|
||||||
|
let useDefault = true;
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
setImmediate(function step() {
|
||||||
|
try {
|
||||||
|
const progress = backup.transfer(rate);
|
||||||
|
if (!progress.remainingPages) {
|
||||||
|
backup.close();
|
||||||
|
resolve(progress);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (useDefault) {
|
||||||
|
useDefault = false;
|
||||||
|
rate = 100;
|
||||||
|
}
|
||||||
|
if (handler) {
|
||||||
|
const ret = handler(progress);
|
||||||
|
if (ret !== undefined) {
|
||||||
|
if (typeof ret === 'number' && ret === ret) rate = Math.max(0, Math.min(0x7fffffff, Math.round(ret)));
|
||||||
|
else throw new TypeError('Expected progress callback to return a number or undefined');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setImmediate(step);
|
||||||
|
} catch (err) {
|
||||||
|
backup.close();
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
31
node_modules/better-sqlite3/lib/methods/function.js
generated
vendored
Normal file
31
node_modules/better-sqlite3/lib/methods/function.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
'use strict';
|
||||||
|
const { getBooleanOption, cppdb } = require('../util');
|
||||||
|
|
||||||
|
module.exports = function defineFunction(name, options, fn) {
|
||||||
|
// Apply defaults
|
||||||
|
if (options == null) options = {};
|
||||||
|
if (typeof options === 'function') { fn = options; options = {}; }
|
||||||
|
|
||||||
|
// Validate arguments
|
||||||
|
if (typeof name !== 'string') throw new TypeError('Expected first argument to be a string');
|
||||||
|
if (typeof fn !== 'function') throw new TypeError('Expected last argument to be a function');
|
||||||
|
if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
|
||||||
|
if (!name) throw new TypeError('User-defined function name cannot be an empty string');
|
||||||
|
|
||||||
|
// Interpret options
|
||||||
|
const safeIntegers = 'safeIntegers' in options ? +getBooleanOption(options, 'safeIntegers') : 2;
|
||||||
|
const deterministic = getBooleanOption(options, 'deterministic');
|
||||||
|
const directOnly = getBooleanOption(options, 'directOnly');
|
||||||
|
const varargs = getBooleanOption(options, 'varargs');
|
||||||
|
let argCount = -1;
|
||||||
|
|
||||||
|
// Determine argument count
|
||||||
|
if (!varargs) {
|
||||||
|
argCount = fn.length;
|
||||||
|
if (!Number.isInteger(argCount) || argCount < 0) throw new TypeError('Expected function.length to be a positive integer');
|
||||||
|
if (argCount > 100) throw new RangeError('User-defined functions cannot have more than 100 arguments');
|
||||||
|
}
|
||||||
|
|
||||||
|
this[cppdb].function(fn, name, argCount, safeIntegers, deterministic, directOnly);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
7
node_modules/better-sqlite3/lib/methods/inspect.js
generated
vendored
Normal file
7
node_modules/better-sqlite3/lib/methods/inspect.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
'use strict';
|
||||||
|
const DatabaseInspection = function Database() {};
|
||||||
|
|
||||||
|
module.exports = function inspect(depth, opts) {
|
||||||
|
return Object.assign(new DatabaseInspection(), this);
|
||||||
|
};
|
||||||
|
|
||||||
12
node_modules/better-sqlite3/lib/methods/pragma.js
generated
vendored
Normal file
12
node_modules/better-sqlite3/lib/methods/pragma.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
'use strict';
|
||||||
|
const { getBooleanOption, cppdb } = require('../util');
|
||||||
|
|
||||||
|
module.exports = function pragma(source, options) {
|
||||||
|
if (options == null) options = {};
|
||||||
|
if (typeof source !== 'string') throw new TypeError('Expected first argument to be a string');
|
||||||
|
if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object');
|
||||||
|
const simple = getBooleanOption(options, 'simple');
|
||||||
|
|
||||||
|
const stmt = this[cppdb].prepare(`PRAGMA ${source}`, this, true);
|
||||||
|
return simple ? stmt.pluck().get() : stmt.all();
|
||||||
|
};
|
||||||
16
node_modules/better-sqlite3/lib/methods/serialize.js
generated
vendored
Normal file
16
node_modules/better-sqlite3/lib/methods/serialize.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
'use strict';
|
||||||
|
const { cppdb } = require('../util');
|
||||||
|
|
||||||
|
module.exports = function serialize(options) {
|
||||||
|
if (options == null) options = {};
|
||||||
|
|
||||||
|
// Validate arguments
|
||||||
|
if (typeof options !== 'object') throw new TypeError('Expected first argument to be an options object');
|
||||||
|
|
||||||
|
// Interpret and validate options
|
||||||
|
const attachedName = 'attached' in options ? options.attached : 'main';
|
||||||
|
if (typeof attachedName !== 'string') throw new TypeError('Expected the "attached" option to be a string');
|
||||||
|
if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
|
||||||
|
|
||||||
|
return this[cppdb].serialize(attachedName);
|
||||||
|
};
|
||||||
189
node_modules/better-sqlite3/lib/methods/table.js
generated
vendored
Normal file
189
node_modules/better-sqlite3/lib/methods/table.js
generated
vendored
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
'use strict';
|
||||||
|
const { cppdb } = require('../util');
|
||||||
|
|
||||||
|
module.exports = function defineTable(name, factory) {
|
||||||
|
// Validate arguments
|
||||||
|
if (typeof name !== 'string') throw new TypeError('Expected first argument to be a string');
|
||||||
|
if (!name) throw new TypeError('Virtual table module name cannot be an empty string');
|
||||||
|
|
||||||
|
// Determine whether the module is eponymous-only or not
|
||||||
|
let eponymous = false;
|
||||||
|
if (typeof factory === 'object' && factory !== null) {
|
||||||
|
eponymous = true;
|
||||||
|
factory = defer(parseTableDefinition(factory, 'used', name));
|
||||||
|
} else {
|
||||||
|
if (typeof factory !== 'function') throw new TypeError('Expected second argument to be a function or a table definition object');
|
||||||
|
factory = wrapFactory(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
this[cppdb].table(factory, name, eponymous);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
function wrapFactory(factory) {
|
||||||
|
return function virtualTableFactory(moduleName, databaseName, tableName, ...args) {
|
||||||
|
const thisObject = {
|
||||||
|
module: moduleName,
|
||||||
|
database: databaseName,
|
||||||
|
table: tableName,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate a new table definition by invoking the factory
|
||||||
|
const def = apply.call(factory, thisObject, args);
|
||||||
|
if (typeof def !== 'object' || def === null) {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" did not return a table definition object`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseTableDefinition(def, 'returned', moduleName);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseTableDefinition(def, verb, moduleName) {
|
||||||
|
// Validate required properties
|
||||||
|
if (!hasOwnProperty.call(def, 'rows')) {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition without a "rows" property`);
|
||||||
|
}
|
||||||
|
if (!hasOwnProperty.call(def, 'columns')) {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition without a "columns" property`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate "rows" property
|
||||||
|
const rows = def.rows;
|
||||||
|
if (typeof rows !== 'function' || Object.getPrototypeOf(rows) !== GeneratorFunctionPrototype) {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "rows" property (should be a generator function)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate "columns" property
|
||||||
|
let columns = def.columns;
|
||||||
|
if (!Array.isArray(columns) || !(columns = [...columns]).every(x => typeof x === 'string')) {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "columns" property (should be an array of strings)`);
|
||||||
|
}
|
||||||
|
if (columns.length !== new Set(columns).size) {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with duplicate column names`);
|
||||||
|
}
|
||||||
|
if (!columns.length) {
|
||||||
|
throw new RangeError(`Virtual table module "${moduleName}" ${verb} a table definition with zero columns`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate "parameters" property
|
||||||
|
let parameters;
|
||||||
|
if (hasOwnProperty.call(def, 'parameters')) {
|
||||||
|
parameters = def.parameters;
|
||||||
|
if (!Array.isArray(parameters) || !(parameters = [...parameters]).every(x => typeof x === 'string')) {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "parameters" property (should be an array of strings)`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parameters = inferParameters(rows);
|
||||||
|
}
|
||||||
|
if (parameters.length !== new Set(parameters).size) {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with duplicate parameter names`);
|
||||||
|
}
|
||||||
|
if (parameters.length > 32) {
|
||||||
|
throw new RangeError(`Virtual table module "${moduleName}" ${verb} a table definition with more than the maximum number of 32 parameters`);
|
||||||
|
}
|
||||||
|
for (const parameter of parameters) {
|
||||||
|
if (columns.includes(parameter)) {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with column "${parameter}" which was ambiguously defined as both a column and parameter`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate "safeIntegers" option
|
||||||
|
let safeIntegers = 2;
|
||||||
|
if (hasOwnProperty.call(def, 'safeIntegers')) {
|
||||||
|
const bool = def.safeIntegers;
|
||||||
|
if (typeof bool !== 'boolean') {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "safeIntegers" property (should be a boolean)`);
|
||||||
|
}
|
||||||
|
safeIntegers = +bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate "directOnly" option
|
||||||
|
let directOnly = false;
|
||||||
|
if (hasOwnProperty.call(def, 'directOnly')) {
|
||||||
|
directOnly = def.directOnly;
|
||||||
|
if (typeof directOnly !== 'boolean') {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "directOnly" property (should be a boolean)`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate SQL for the virtual table definition
|
||||||
|
const columnDefinitions = [
|
||||||
|
...parameters.map(identifier).map(str => `${str} HIDDEN`),
|
||||||
|
...columns.map(identifier),
|
||||||
|
];
|
||||||
|
return [
|
||||||
|
`CREATE TABLE x(${columnDefinitions.join(', ')});`,
|
||||||
|
wrapGenerator(rows, new Map(columns.map((x, i) => [x, parameters.length + i])), moduleName),
|
||||||
|
parameters,
|
||||||
|
safeIntegers,
|
||||||
|
directOnly,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrapGenerator(generator, columnMap, moduleName) {
|
||||||
|
return function* virtualTable(...args) {
|
||||||
|
/*
|
||||||
|
We must defensively clone any buffers in the arguments, because
|
||||||
|
otherwise the generator could mutate one of them, which would cause
|
||||||
|
us to return incorrect values for hidden columns, potentially
|
||||||
|
corrupting the database.
|
||||||
|
*/
|
||||||
|
const output = args.map(x => Buffer.isBuffer(x) ? Buffer.from(x) : x);
|
||||||
|
for (let i = 0; i < columnMap.size; ++i) {
|
||||||
|
output.push(null); // Fill with nulls to prevent gaps in array (v8 optimization)
|
||||||
|
}
|
||||||
|
for (const row of generator(...args)) {
|
||||||
|
if (Array.isArray(row)) {
|
||||||
|
extractRowArray(row, output, columnMap.size, moduleName);
|
||||||
|
yield output;
|
||||||
|
} else if (typeof row === 'object' && row !== null) {
|
||||||
|
extractRowObject(row, output, columnMap, moduleName);
|
||||||
|
yield output;
|
||||||
|
} else {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" yielded something that isn't a valid row object`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractRowArray(row, output, columnCount, moduleName) {
|
||||||
|
if (row.length !== columnCount) {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" yielded a row with an incorrect number of columns`);
|
||||||
|
}
|
||||||
|
const offset = output.length - columnCount;
|
||||||
|
for (let i = 0; i < columnCount; ++i) {
|
||||||
|
output[i + offset] = row[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractRowObject(row, output, columnMap, moduleName) {
|
||||||
|
let count = 0;
|
||||||
|
for (const key of Object.keys(row)) {
|
||||||
|
const index = columnMap.get(key);
|
||||||
|
if (index === undefined) {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" yielded a row with an undeclared column "${key}"`);
|
||||||
|
}
|
||||||
|
output[index] = row[key];
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
if (count !== columnMap.size) {
|
||||||
|
throw new TypeError(`Virtual table module "${moduleName}" yielded a row with missing columns`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function inferParameters({ length }) {
|
||||||
|
if (!Number.isInteger(length) || length < 0) {
|
||||||
|
throw new TypeError('Expected function.length to be a positive integer');
|
||||||
|
}
|
||||||
|
const params = [];
|
||||||
|
for (let i = 0; i < length; ++i) {
|
||||||
|
params.push(`$${i + 1}`);
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { hasOwnProperty } = Object.prototype;
|
||||||
|
const { apply } = Function.prototype;
|
||||||
|
const GeneratorFunctionPrototype = Object.getPrototypeOf(function*(){});
|
||||||
|
const identifier = str => `"${str.replace(/"/g, '""')}"`;
|
||||||
|
const defer = x => () => x;
|
||||||
78
node_modules/better-sqlite3/lib/methods/transaction.js
generated
vendored
Normal file
78
node_modules/better-sqlite3/lib/methods/transaction.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
'use strict';
|
||||||
|
const { cppdb } = require('../util');
|
||||||
|
const controllers = new WeakMap();
|
||||||
|
|
||||||
|
module.exports = function transaction(fn) {
|
||||||
|
if (typeof fn !== 'function') throw new TypeError('Expected first argument to be a function');
|
||||||
|
|
||||||
|
const db = this[cppdb];
|
||||||
|
const controller = getController(db, this);
|
||||||
|
const { apply } = Function.prototype;
|
||||||
|
|
||||||
|
// Each version of the transaction function has these same properties
|
||||||
|
const properties = {
|
||||||
|
default: { value: wrapTransaction(apply, fn, db, controller.default) },
|
||||||
|
deferred: { value: wrapTransaction(apply, fn, db, controller.deferred) },
|
||||||
|
immediate: { value: wrapTransaction(apply, fn, db, controller.immediate) },
|
||||||
|
exclusive: { value: wrapTransaction(apply, fn, db, controller.exclusive) },
|
||||||
|
database: { value: this, enumerable: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.defineProperties(properties.default.value, properties);
|
||||||
|
Object.defineProperties(properties.deferred.value, properties);
|
||||||
|
Object.defineProperties(properties.immediate.value, properties);
|
||||||
|
Object.defineProperties(properties.exclusive.value, properties);
|
||||||
|
|
||||||
|
// Return the default version of the transaction function
|
||||||
|
return properties.default.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return the database's cached transaction controller, or create a new one
|
||||||
|
const getController = (db, self) => {
|
||||||
|
let controller = controllers.get(db);
|
||||||
|
if (!controller) {
|
||||||
|
const shared = {
|
||||||
|
commit: db.prepare('COMMIT', self, false),
|
||||||
|
rollback: db.prepare('ROLLBACK', self, false),
|
||||||
|
savepoint: db.prepare('SAVEPOINT `\t_bs3.\t`', self, false),
|
||||||
|
release: db.prepare('RELEASE `\t_bs3.\t`', self, false),
|
||||||
|
rollbackTo: db.prepare('ROLLBACK TO `\t_bs3.\t`', self, false),
|
||||||
|
};
|
||||||
|
controllers.set(db, controller = {
|
||||||
|
default: Object.assign({ begin: db.prepare('BEGIN', self, false) }, shared),
|
||||||
|
deferred: Object.assign({ begin: db.prepare('BEGIN DEFERRED', self, false) }, shared),
|
||||||
|
immediate: Object.assign({ begin: db.prepare('BEGIN IMMEDIATE', self, false) }, shared),
|
||||||
|
exclusive: Object.assign({ begin: db.prepare('BEGIN EXCLUSIVE', self, false) }, shared),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return controller;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return a new transaction function by wrapping the given function
|
||||||
|
const wrapTransaction = (apply, fn, db, { begin, commit, rollback, savepoint, release, rollbackTo }) => function sqliteTransaction() {
|
||||||
|
let before, after, undo;
|
||||||
|
if (db.inTransaction) {
|
||||||
|
before = savepoint;
|
||||||
|
after = release;
|
||||||
|
undo = rollbackTo;
|
||||||
|
} else {
|
||||||
|
before = begin;
|
||||||
|
after = commit;
|
||||||
|
undo = rollback;
|
||||||
|
}
|
||||||
|
before.run();
|
||||||
|
try {
|
||||||
|
const result = apply.call(fn, this, arguments);
|
||||||
|
if (result && typeof result.then === 'function') {
|
||||||
|
throw new TypeError('Transaction function cannot return a promise');
|
||||||
|
}
|
||||||
|
after.run();
|
||||||
|
return result;
|
||||||
|
} catch (ex) {
|
||||||
|
if (db.inTransaction) {
|
||||||
|
undo.run();
|
||||||
|
if (undo !== rollback) after.run();
|
||||||
|
}
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
};
|
||||||
54
node_modules/better-sqlite3/lib/methods/wrappers.js
generated
vendored
Normal file
54
node_modules/better-sqlite3/lib/methods/wrappers.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
'use strict';
|
||||||
|
const { cppdb } = require('../util');
|
||||||
|
|
||||||
|
exports.prepare = function prepare(sql) {
|
||||||
|
return this[cppdb].prepare(sql, this, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.exec = function exec(sql) {
|
||||||
|
this[cppdb].exec(sql);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.close = function close() {
|
||||||
|
this[cppdb].close();
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.loadExtension = function loadExtension(...args) {
|
||||||
|
this[cppdb].loadExtension(...args);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.defaultSafeIntegers = function defaultSafeIntegers(...args) {
|
||||||
|
this[cppdb].defaultSafeIntegers(...args);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.unsafeMode = function unsafeMode(...args) {
|
||||||
|
this[cppdb].unsafeMode(...args);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getters = {
|
||||||
|
name: {
|
||||||
|
get: function name() { return this[cppdb].name; },
|
||||||
|
enumerable: true,
|
||||||
|
},
|
||||||
|
open: {
|
||||||
|
get: function open() { return this[cppdb].open; },
|
||||||
|
enumerable: true,
|
||||||
|
},
|
||||||
|
inTransaction: {
|
||||||
|
get: function inTransaction() { return this[cppdb].inTransaction; },
|
||||||
|
enumerable: true,
|
||||||
|
},
|
||||||
|
readonly: {
|
||||||
|
get: function readonly() { return this[cppdb].readonly; },
|
||||||
|
enumerable: true,
|
||||||
|
},
|
||||||
|
memory: {
|
||||||
|
get: function memory() { return this[cppdb].memory; },
|
||||||
|
enumerable: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
20
node_modules/better-sqlite3/lib/sqlite-error.js
generated
vendored
Normal file
20
node_modules/better-sqlite3/lib/sqlite-error.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
'use strict';
|
||||||
|
const descriptor = { value: 'SqliteError', writable: true, enumerable: false, configurable: true };
|
||||||
|
|
||||||
|
function SqliteError(message, code) {
|
||||||
|
if (new.target !== SqliteError) {
|
||||||
|
return new SqliteError(message, code);
|
||||||
|
}
|
||||||
|
if (typeof code !== 'string') {
|
||||||
|
throw new TypeError('Expected second argument to be a string');
|
||||||
|
}
|
||||||
|
Error.call(this, message);
|
||||||
|
descriptor.value = '' + message;
|
||||||
|
Object.defineProperty(this, 'message', descriptor);
|
||||||
|
Error.captureStackTrace(this, SqliteError);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
Object.setPrototypeOf(SqliteError, Error);
|
||||||
|
Object.setPrototypeOf(SqliteError.prototype, Error.prototype);
|
||||||
|
Object.defineProperty(SqliteError.prototype, 'name', descriptor);
|
||||||
|
module.exports = SqliteError;
|
||||||
12
node_modules/better-sqlite3/lib/util.js
generated
vendored
Normal file
12
node_modules/better-sqlite3/lib/util.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
exports.getBooleanOption = (options, key) => {
|
||||||
|
let value = false;
|
||||||
|
if (key in options && typeof (value = options[key]) !== 'boolean') {
|
||||||
|
throw new TypeError(`Expected the "${key}" option to be a boolean`);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.cppdb = Symbol();
|
||||||
|
exports.inspect = Symbol.for('nodejs.util.inspect.custom');
|
||||||
59
node_modules/better-sqlite3/package.json
generated
vendored
Normal file
59
node_modules/better-sqlite3/package.json
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"name": "better-sqlite3",
|
||||||
|
"version": "12.5.0",
|
||||||
|
"description": "The fastest and simplest library for SQLite in Node.js.",
|
||||||
|
"homepage": "http://github.com/WiseLibs/better-sqlite3",
|
||||||
|
"author": "Joshua Wise <joshuathomaswise@gmail.com>",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/WiseLibs/better-sqlite3.git"
|
||||||
|
},
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"files": [
|
||||||
|
"binding.gyp",
|
||||||
|
"src/**/*.[ch]pp",
|
||||||
|
"lib/**",
|
||||||
|
"deps/**"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "20.x || 22.x || 23.x || 24.x || 25.x"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bindings": "^1.5.0",
|
||||||
|
"prebuild-install": "^7.1.1"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"prebuild": {
|
||||||
|
"node-abi": "4.15.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"chai": "^4.3.8",
|
||||||
|
"cli-color": "^2.0.3",
|
||||||
|
"fs-extra": "^11.1.1",
|
||||||
|
"mocha": "^10.2.0",
|
||||||
|
"nodemark": "^0.3.0",
|
||||||
|
"prebuild": "^13.0.1",
|
||||||
|
"sqlite": "^5.0.1",
|
||||||
|
"sqlite3": "^5.1.6"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"install": "prebuild-install || node-gyp rebuild --release",
|
||||||
|
"build-release": "node-gyp rebuild --release",
|
||||||
|
"build-debug": "node-gyp rebuild --debug",
|
||||||
|
"test": "mocha --exit --slow=75 --timeout=5000",
|
||||||
|
"benchmark": "node benchmark",
|
||||||
|
"download": "bash ./deps/download.sh"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"sql",
|
||||||
|
"sqlite",
|
||||||
|
"sqlite3",
|
||||||
|
"transactions",
|
||||||
|
"user-defined functions",
|
||||||
|
"aggregate functions",
|
||||||
|
"window functions",
|
||||||
|
"database"
|
||||||
|
]
|
||||||
|
}
|
||||||
47
node_modules/better-sqlite3/src/addon.cpp
generated
vendored
Normal file
47
node_modules/better-sqlite3/src/addon.cpp
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
struct Addon {
|
||||||
|
explicit Addon(v8::Isolate* isolate) :
|
||||||
|
privileged_info(NULL),
|
||||||
|
next_id(0),
|
||||||
|
cs(isolate) {}
|
||||||
|
|
||||||
|
static void Cleanup(void* ptr) {
|
||||||
|
Addon* addon = static_cast<Addon*>(ptr);
|
||||||
|
for (Database* db : addon->dbs) db->CloseHandles();
|
||||||
|
addon->dbs.clear();
|
||||||
|
delete addon;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline sqlite3_uint64 NextId() {
|
||||||
|
return next_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ConfigureURI() {
|
||||||
|
static std::once_flag init_flag;
|
||||||
|
std::call_once(init_flag, [](){
|
||||||
|
const char* env = getenv("SQLITE_USE_URI");
|
||||||
|
if (env != NULL) {
|
||||||
|
if (strcmp(env, "1") == 0) {
|
||||||
|
int status = sqlite3_config(SQLITE_CONFIG_URI, 1);
|
||||||
|
assert(status == SQLITE_OK); ((void)status);
|
||||||
|
} else if (strcmp(env, "0") == 0) {
|
||||||
|
int status = sqlite3_config(SQLITE_CONFIG_URI, 0);
|
||||||
|
assert(status == SQLITE_OK); ((void)status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static NODE_METHOD(JS_setErrorConstructor) {
|
||||||
|
REQUIRE_ARGUMENT_FUNCTION(first, v8::Local<v8::Function> SqliteError);
|
||||||
|
OnlyAddon->SqliteError.Reset(OnlyIsolate, SqliteError);
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Global<v8::Function> Statement;
|
||||||
|
v8::Global<v8::Function> StatementIterator;
|
||||||
|
v8::Global<v8::Function> Backup;
|
||||||
|
v8::Global<v8::Function> SqliteError;
|
||||||
|
NODE_ARGUMENTS_POINTER privileged_info;
|
||||||
|
sqlite3_uint64 next_id;
|
||||||
|
CS cs;
|
||||||
|
std::set<Database*, Database::CompareDatabase> dbs;
|
||||||
|
};
|
||||||
74
node_modules/better-sqlite3/src/better_sqlite3.cpp
generated
vendored
Normal file
74
node_modules/better-sqlite3/src/better_sqlite3.cpp
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include <climits>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <mutex>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include <node.h>
|
||||||
|
#include <node_object_wrap.h>
|
||||||
|
#include <node_buffer.h>
|
||||||
|
|
||||||
|
struct Addon;
|
||||||
|
class Database;
|
||||||
|
class Statement;
|
||||||
|
class StatementIterator;
|
||||||
|
class Backup;
|
||||||
|
|
||||||
|
#include "util/macros.cpp"
|
||||||
|
#include "util/helpers.cpp"
|
||||||
|
#include "util/constants.cpp"
|
||||||
|
#include "util/bind-map.cpp"
|
||||||
|
#include "util/data-converter.cpp"
|
||||||
|
#include "util/data.cpp"
|
||||||
|
#if defined(NODE_MODULE_VERSION) && NODE_MODULE_VERSION >= 127
|
||||||
|
#include "util/row-builder.cpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "objects/backup.hpp"
|
||||||
|
#include "objects/statement.hpp"
|
||||||
|
#include "objects/database.hpp"
|
||||||
|
#include "addon.cpp"
|
||||||
|
#include "objects/statement-iterator.hpp"
|
||||||
|
|
||||||
|
#include "util/query-macros.cpp"
|
||||||
|
#include "util/custom-function.cpp"
|
||||||
|
#include "util/custom-aggregate.cpp"
|
||||||
|
#include "util/custom-table.cpp"
|
||||||
|
#include "util/binder.cpp"
|
||||||
|
|
||||||
|
#include "objects/backup.cpp"
|
||||||
|
#include "objects/statement.cpp"
|
||||||
|
#include "objects/database.cpp"
|
||||||
|
#include "objects/statement-iterator.cpp"
|
||||||
|
|
||||||
|
NODE_MODULE_INIT(/* exports, context */) {
|
||||||
|
#if defined(NODE_MODULE_VERSION) && NODE_MODULE_VERSION >= 140
|
||||||
|
// Use Isolate::GetCurrent as stated in deprecation message within v8_context.h 13.9.72320122
|
||||||
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||||
|
#else
|
||||||
|
v8::Isolate* isolate = context->GetIsolate();
|
||||||
|
#endif
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
|
Addon::ConfigureURI();
|
||||||
|
|
||||||
|
// Initialize addon instance.
|
||||||
|
Addon* addon = new Addon(isolate);
|
||||||
|
v8::Local<v8::External> data = v8::External::New(isolate, addon);
|
||||||
|
node::AddEnvironmentCleanupHook(isolate, Addon::Cleanup, addon);
|
||||||
|
|
||||||
|
// Create and export native-backed classes and functions.
|
||||||
|
exports->Set(context, InternalizedFromLatin1(isolate, "Database"), Database::Init(isolate, data)).FromJust();
|
||||||
|
exports->Set(context, InternalizedFromLatin1(isolate, "Statement"), Statement::Init(isolate, data)).FromJust();
|
||||||
|
exports->Set(context, InternalizedFromLatin1(isolate, "StatementIterator"), StatementIterator::Init(isolate, data)).FromJust();
|
||||||
|
exports->Set(context, InternalizedFromLatin1(isolate, "Backup"), Backup::Init(isolate, data)).FromJust();
|
||||||
|
exports->Set(context, InternalizedFromLatin1(isolate, "setErrorConstructor"), v8::FunctionTemplate::New(isolate, Addon::JS_setErrorConstructor, data)->GetFunction(context).ToLocalChecked()).FromJust();
|
||||||
|
|
||||||
|
// Store addon instance data.
|
||||||
|
addon->Statement.Reset(isolate, exports->Get(context, InternalizedFromLatin1(isolate, "Statement")).ToLocalChecked().As<v8::Function>());
|
||||||
|
addon->StatementIterator.Reset(isolate, exports->Get(context, InternalizedFromLatin1(isolate, "StatementIterator")).ToLocalChecked().As<v8::Function>());
|
||||||
|
addon->Backup.Reset(isolate, exports->Get(context, InternalizedFromLatin1(isolate, "Backup")).ToLocalChecked().As<v8::Function>());
|
||||||
|
}
|
||||||
120
node_modules/better-sqlite3/src/objects/backup.cpp
generated
vendored
Normal file
120
node_modules/better-sqlite3/src/objects/backup.cpp
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
Backup::Backup(
|
||||||
|
Database* db,
|
||||||
|
sqlite3* dest_handle,
|
||||||
|
sqlite3_backup* backup_handle,
|
||||||
|
sqlite3_uint64 id,
|
||||||
|
bool unlink
|
||||||
|
) :
|
||||||
|
node::ObjectWrap(),
|
||||||
|
db(db),
|
||||||
|
dest_handle(dest_handle),
|
||||||
|
backup_handle(backup_handle),
|
||||||
|
id(id),
|
||||||
|
alive(true),
|
||||||
|
unlink(unlink) {
|
||||||
|
assert(db != NULL);
|
||||||
|
assert(dest_handle != NULL);
|
||||||
|
assert(backup_handle != NULL);
|
||||||
|
db->AddBackup(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Backup::~Backup() {
|
||||||
|
if (alive) db->RemoveBackup(this);
|
||||||
|
CloseHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whenever this is used, db->RemoveBackup must be invoked beforehand.
|
||||||
|
void Backup::CloseHandles() {
|
||||||
|
if (alive) {
|
||||||
|
alive = false;
|
||||||
|
std::string filename(sqlite3_db_filename(dest_handle, "main"));
|
||||||
|
sqlite3_backup_finish(backup_handle);
|
||||||
|
int status = sqlite3_close(dest_handle);
|
||||||
|
assert(status == SQLITE_OK); ((void)status);
|
||||||
|
if (unlink) remove(filename.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT(Backup::Init) {
|
||||||
|
v8::Local<v8::FunctionTemplate> t = NewConstructorTemplate(isolate, data, JS_new, "Backup");
|
||||||
|
SetPrototypeMethod(isolate, data, t, "transfer", JS_transfer);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "close", JS_close);
|
||||||
|
return t->GetFunction(OnlyContext).ToLocalChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Backup::JS_new) {
|
||||||
|
UseAddon;
|
||||||
|
if (!addon->privileged_info) return ThrowTypeError("Disabled constructor");
|
||||||
|
assert(info.IsConstructCall());
|
||||||
|
Database* db = Unwrap<Database>(addon->privileged_info->This());
|
||||||
|
REQUIRE_DATABASE_OPEN(db->GetState());
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(db->GetState());
|
||||||
|
|
||||||
|
v8::Local<v8::Object> database = (*addon->privileged_info)[0].As<v8::Object>();
|
||||||
|
v8::Local<v8::String> attachedName = (*addon->privileged_info)[1].As<v8::String>();
|
||||||
|
v8::Local<v8::String> destFile = (*addon->privileged_info)[2].As<v8::String>();
|
||||||
|
bool unlink = (*addon->privileged_info)[3].As<v8::Boolean>()->Value();
|
||||||
|
|
||||||
|
UseIsolate;
|
||||||
|
sqlite3* dest_handle;
|
||||||
|
v8::String::Utf8Value dest_file(isolate, destFile);
|
||||||
|
v8::String::Utf8Value attached_name(isolate, attachedName);
|
||||||
|
int mask = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
|
||||||
|
|
||||||
|
if (sqlite3_open_v2(*dest_file, &dest_handle, mask, NULL) != SQLITE_OK) {
|
||||||
|
Database::ThrowSqliteError(addon, dest_handle);
|
||||||
|
int status = sqlite3_close(dest_handle);
|
||||||
|
assert(status == SQLITE_OK); ((void)status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_extended_result_codes(dest_handle, 1);
|
||||||
|
sqlite3_limit(dest_handle, SQLITE_LIMIT_LENGTH, INT_MAX);
|
||||||
|
sqlite3_backup* backup_handle = sqlite3_backup_init(dest_handle, "main", db->GetHandle(), *attached_name);
|
||||||
|
if (backup_handle == NULL) {
|
||||||
|
Database::ThrowSqliteError(addon, dest_handle);
|
||||||
|
int status = sqlite3_close(dest_handle);
|
||||||
|
assert(status == SQLITE_OK); ((void)status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Backup* backup = new Backup(db, dest_handle, backup_handle, addon->NextId(), unlink);
|
||||||
|
backup->Wrap(info.This());
|
||||||
|
SetFrozen(isolate, OnlyContext, info.This(), addon->cs.database, database);
|
||||||
|
|
||||||
|
info.GetReturnValue().Set(info.This());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Backup::JS_transfer) {
|
||||||
|
Backup* backup = Unwrap<Backup>(info.This());
|
||||||
|
REQUIRE_ARGUMENT_INT32(first, int pages);
|
||||||
|
REQUIRE_DATABASE_OPEN(backup->db->GetState());
|
||||||
|
assert(backup->db->GetState()->busy == false);
|
||||||
|
assert(backup->alive == true);
|
||||||
|
|
||||||
|
sqlite3_backup* backup_handle = backup->backup_handle;
|
||||||
|
int status = sqlite3_backup_step(backup_handle, pages) & 0xff;
|
||||||
|
|
||||||
|
Addon* addon = backup->db->GetAddon();
|
||||||
|
if (status == SQLITE_OK || status == SQLITE_DONE || status == SQLITE_BUSY) {
|
||||||
|
int total_pages = sqlite3_backup_pagecount(backup_handle);
|
||||||
|
int remaining_pages = sqlite3_backup_remaining(backup_handle);
|
||||||
|
UseIsolate;
|
||||||
|
UseContext;
|
||||||
|
v8::Local<v8::Object> result = v8::Object::New(isolate);
|
||||||
|
result->Set(ctx, addon->cs.totalPages.Get(isolate), v8::Int32::New(isolate, total_pages)).FromJust();
|
||||||
|
result->Set(ctx, addon->cs.remainingPages.Get(isolate), v8::Int32::New(isolate, remaining_pages)).FromJust();
|
||||||
|
info.GetReturnValue().Set(result);
|
||||||
|
if (status == SQLITE_DONE) backup->unlink = false;
|
||||||
|
} else {
|
||||||
|
Database::ThrowSqliteError(addon, sqlite3_errstr(status), status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Backup::JS_close) {
|
||||||
|
Backup* backup = Unwrap<Backup>(info.This());
|
||||||
|
assert(backup->db->GetState()->busy == false);
|
||||||
|
if (backup->alive) backup->db->RemoveBackup(backup);
|
||||||
|
backup->CloseHandles();
|
||||||
|
info.GetReturnValue().Set(info.This());
|
||||||
|
}
|
||||||
36
node_modules/better-sqlite3/src/objects/backup.hpp
generated
vendored
Normal file
36
node_modules/better-sqlite3/src/objects/backup.hpp
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
class Backup : public node::ObjectWrap {
|
||||||
|
public:
|
||||||
|
|
||||||
|
~Backup();
|
||||||
|
|
||||||
|
// Whenever this is used, db->RemoveBackup must be invoked beforehand.
|
||||||
|
void CloseHandles();
|
||||||
|
|
||||||
|
// Used to support ordered containers.
|
||||||
|
static inline bool Compare(Backup const * const a, Backup const * const b) {
|
||||||
|
return a->id < b->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INIT(Init);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
explicit Backup(
|
||||||
|
Database* db,
|
||||||
|
sqlite3* dest_handle,
|
||||||
|
sqlite3_backup* backup_handle,
|
||||||
|
sqlite3_uint64 id,
|
||||||
|
bool unlink
|
||||||
|
);
|
||||||
|
|
||||||
|
static NODE_METHOD(JS_new);
|
||||||
|
static NODE_METHOD(JS_transfer);
|
||||||
|
static NODE_METHOD(JS_close);
|
||||||
|
|
||||||
|
Database* const db;
|
||||||
|
sqlite3* const dest_handle;
|
||||||
|
sqlite3_backup* const backup_handle;
|
||||||
|
const sqlite3_uint64 id;
|
||||||
|
bool alive;
|
||||||
|
bool unlink;
|
||||||
|
};
|
||||||
417
node_modules/better-sqlite3/src/objects/database.cpp
generated
vendored
Normal file
417
node_modules/better-sqlite3/src/objects/database.cpp
generated
vendored
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
const int Database::MAX_BUFFER_SIZE = (
|
||||||
|
node::Buffer::kMaxLength > INT_MAX
|
||||||
|
? INT_MAX
|
||||||
|
: static_cast<int>(node::Buffer::kMaxLength)
|
||||||
|
);
|
||||||
|
|
||||||
|
const int Database::MAX_STRING_SIZE = (
|
||||||
|
v8::String::kMaxLength > INT_MAX
|
||||||
|
? INT_MAX
|
||||||
|
: static_cast<int>(v8::String::kMaxLength)
|
||||||
|
);
|
||||||
|
|
||||||
|
Database::Database(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
Addon* addon,
|
||||||
|
sqlite3* db_handle,
|
||||||
|
v8::Local<v8::Value> logger
|
||||||
|
) :
|
||||||
|
node::ObjectWrap(),
|
||||||
|
db_handle(db_handle),
|
||||||
|
open(true),
|
||||||
|
busy(false),
|
||||||
|
safe_ints(false),
|
||||||
|
unsafe_mode(false),
|
||||||
|
was_js_error(false),
|
||||||
|
has_logger(logger->IsFunction()),
|
||||||
|
iterators(0),
|
||||||
|
addon(addon),
|
||||||
|
logger(isolate, logger),
|
||||||
|
stmts(),
|
||||||
|
backups() {
|
||||||
|
assert(db_handle != NULL);
|
||||||
|
addon->dbs.insert(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Database::~Database() {
|
||||||
|
if (open) addon->dbs.erase(this);
|
||||||
|
CloseHandles();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whenever this is used, addon->dbs.erase() must be invoked beforehand.
|
||||||
|
void Database::CloseHandles() {
|
||||||
|
if (open) {
|
||||||
|
open = false;
|
||||||
|
for (Statement* stmt : stmts) stmt->CloseHandles();
|
||||||
|
for (Backup* backup : backups) backup->CloseHandles();
|
||||||
|
stmts.clear();
|
||||||
|
backups.clear();
|
||||||
|
int status = sqlite3_close(db_handle);
|
||||||
|
assert(status == SQLITE_OK); ((void)status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Database::ThrowDatabaseError() {
|
||||||
|
if (was_js_error) was_js_error = false;
|
||||||
|
else ThrowSqliteError(addon, db_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Database::ThrowSqliteError(Addon* addon, sqlite3* db_handle) {
|
||||||
|
assert(db_handle != NULL);
|
||||||
|
ThrowSqliteError(addon, sqlite3_errmsg(db_handle), sqlite3_extended_errcode(db_handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Database::ThrowSqliteError(Addon* addon, const char* message, int code) {
|
||||||
|
assert(message != NULL);
|
||||||
|
assert((code & 0xff) != SQLITE_OK);
|
||||||
|
assert((code & 0xff) != SQLITE_ROW);
|
||||||
|
assert((code & 0xff) != SQLITE_DONE);
|
||||||
|
EasyIsolate;
|
||||||
|
v8::Local<v8::Value> args[2] = {
|
||||||
|
StringFromUtf8(isolate, message, -1),
|
||||||
|
addon->cs.Code(isolate, code)
|
||||||
|
};
|
||||||
|
isolate->ThrowException(addon->SqliteError.Get(isolate)
|
||||||
|
->NewInstance(OnlyContext, 2, args)
|
||||||
|
.ToLocalChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allows Statements to log their executed SQL.
|
||||||
|
bool Database::Log(v8::Isolate* isolate, sqlite3_stmt* handle) {
|
||||||
|
assert(was_js_error == false);
|
||||||
|
if (!has_logger) return false;
|
||||||
|
char* expanded = sqlite3_expanded_sql(handle);
|
||||||
|
v8::Local<v8::Value> arg = StringFromUtf8(isolate, expanded ? expanded : sqlite3_sql(handle), -1);
|
||||||
|
was_js_error = logger.Get(isolate).As<v8::Function>()
|
||||||
|
->Call(OnlyContext, v8::Undefined(isolate), 1, &arg)
|
||||||
|
.IsEmpty();
|
||||||
|
if (expanded) sqlite3_free(expanded);
|
||||||
|
return was_js_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Database::Deserialize(
|
||||||
|
v8::Local<v8::Object> buffer,
|
||||||
|
Addon* addon,
|
||||||
|
sqlite3* db_handle,
|
||||||
|
bool readonly
|
||||||
|
) {
|
||||||
|
size_t length = node::Buffer::Length(buffer);
|
||||||
|
unsigned char* data = (unsigned char*)sqlite3_malloc64(length);
|
||||||
|
unsigned int flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE;
|
||||||
|
|
||||||
|
if (readonly) {
|
||||||
|
flags |= SQLITE_DESERIALIZE_READONLY;
|
||||||
|
}
|
||||||
|
if (length) {
|
||||||
|
if (!data) {
|
||||||
|
ThrowError("Out of memory");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(data, node::Buffer::Data(buffer), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = sqlite3_deserialize(db_handle, "main", data, length, length, flags);
|
||||||
|
if (status != SQLITE_OK) {
|
||||||
|
ThrowSqliteError(addon, status == SQLITE_ERROR ? "unable to deserialize database" : sqlite3_errstr(status), status);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Database::FreeSerialization(char* data, void* _) {
|
||||||
|
sqlite3_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT(Database::Init) {
|
||||||
|
v8::Local<v8::FunctionTemplate> t = NewConstructorTemplate(isolate, data, JS_new, "Database");
|
||||||
|
SetPrototypeMethod(isolate, data, t, "prepare", JS_prepare);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "exec", JS_exec);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "backup", JS_backup);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "serialize", JS_serialize);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "function", JS_function);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "aggregate", JS_aggregate);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "table", JS_table);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "loadExtension", JS_loadExtension);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "close", JS_close);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "defaultSafeIntegers", JS_defaultSafeIntegers);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "unsafeMode", JS_unsafeMode);
|
||||||
|
SetPrototypeGetter(isolate, data, t, "open", JS_open);
|
||||||
|
SetPrototypeGetter(isolate, data, t, "inTransaction", JS_inTransaction);
|
||||||
|
return t->GetFunction(OnlyContext).ToLocalChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Database::JS_new) {
|
||||||
|
assert(info.IsConstructCall());
|
||||||
|
REQUIRE_ARGUMENT_STRING(first, v8::Local<v8::String> filename);
|
||||||
|
REQUIRE_ARGUMENT_STRING(second, v8::Local<v8::String> filenameGiven);
|
||||||
|
REQUIRE_ARGUMENT_BOOLEAN(third, bool in_memory);
|
||||||
|
REQUIRE_ARGUMENT_BOOLEAN(fourth, bool readonly);
|
||||||
|
REQUIRE_ARGUMENT_BOOLEAN(fifth, bool must_exist);
|
||||||
|
REQUIRE_ARGUMENT_INT32(sixth, int timeout);
|
||||||
|
REQUIRE_ARGUMENT_ANY(seventh, v8::Local<v8::Value> logger);
|
||||||
|
REQUIRE_ARGUMENT_ANY(eighth, v8::Local<v8::Value> buffer);
|
||||||
|
|
||||||
|
UseAddon;
|
||||||
|
UseIsolate;
|
||||||
|
sqlite3* db_handle;
|
||||||
|
v8::String::Utf8Value utf8(isolate, filename);
|
||||||
|
int mask = readonly ? SQLITE_OPEN_READONLY
|
||||||
|
: must_exist ? SQLITE_OPEN_READWRITE
|
||||||
|
: (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
|
||||||
|
|
||||||
|
if (sqlite3_open_v2(*utf8, &db_handle, mask, NULL) != SQLITE_OK) {
|
||||||
|
ThrowSqliteError(addon, db_handle);
|
||||||
|
int status = sqlite3_close(db_handle);
|
||||||
|
assert(status == SQLITE_OK); ((void)status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(sqlite3_db_mutex(db_handle) == NULL);
|
||||||
|
sqlite3_extended_result_codes(db_handle, 1);
|
||||||
|
sqlite3_busy_timeout(db_handle, timeout);
|
||||||
|
sqlite3_limit(db_handle, SQLITE_LIMIT_LENGTH, MAX_BUFFER_SIZE < MAX_STRING_SIZE ? MAX_BUFFER_SIZE : MAX_STRING_SIZE);
|
||||||
|
sqlite3_limit(db_handle, SQLITE_LIMIT_SQL_LENGTH, MAX_STRING_SIZE);
|
||||||
|
int status = sqlite3_db_config(db_handle, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL);
|
||||||
|
assert(status == SQLITE_OK); ((void)status);
|
||||||
|
status = sqlite3_db_config(db_handle, SQLITE_DBCONFIG_DEFENSIVE, 1, NULL);
|
||||||
|
assert(status == SQLITE_OK); ((void)status);
|
||||||
|
|
||||||
|
if (node::Buffer::HasInstance(buffer) && !Deserialize(buffer.As<v8::Object>(), addon, db_handle, readonly)) {
|
||||||
|
int status = sqlite3_close(db_handle);
|
||||||
|
assert(status == SQLITE_OK); ((void)status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UseContext;
|
||||||
|
Database* db = new Database(isolate, addon, db_handle, logger);
|
||||||
|
db->Wrap(info.This());
|
||||||
|
SetFrozen(isolate, ctx, info.This(), addon->cs.memory, v8::Boolean::New(isolate, in_memory));
|
||||||
|
SetFrozen(isolate, ctx, info.This(), addon->cs.readonly, v8::Boolean::New(isolate, readonly));
|
||||||
|
SetFrozen(isolate, ctx, info.This(), addon->cs.name, filenameGiven);
|
||||||
|
|
||||||
|
info.GetReturnValue().Set(info.This());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Database::JS_prepare) {
|
||||||
|
REQUIRE_ARGUMENT_STRING(first, v8::Local<v8::String> source);
|
||||||
|
REQUIRE_ARGUMENT_OBJECT(second, v8::Local<v8::Object> database);
|
||||||
|
REQUIRE_ARGUMENT_BOOLEAN(third, bool pragmaMode);
|
||||||
|
(void)source;
|
||||||
|
(void)database;
|
||||||
|
(void)pragmaMode;
|
||||||
|
UseAddon;
|
||||||
|
UseIsolate;
|
||||||
|
v8::Local<v8::Function> c = addon->Statement.Get(isolate);
|
||||||
|
addon->privileged_info = &info;
|
||||||
|
v8::MaybeLocal<v8::Object> maybeStatement = c->NewInstance(OnlyContext, 0, NULL);
|
||||||
|
addon->privileged_info = NULL;
|
||||||
|
if (!maybeStatement.IsEmpty()) info.GetReturnValue().Set(maybeStatement.ToLocalChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Database::JS_exec) {
|
||||||
|
Database* db = Unwrap<Database>(info.This());
|
||||||
|
REQUIRE_ARGUMENT_STRING(first, v8::Local<v8::String> source);
|
||||||
|
REQUIRE_DATABASE_OPEN(db);
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(db);
|
||||||
|
REQUIRE_DATABASE_NO_ITERATORS_UNLESS_UNSAFE(db);
|
||||||
|
db->busy = true;
|
||||||
|
|
||||||
|
UseIsolate;
|
||||||
|
v8::String::Utf8Value utf8(isolate, source);
|
||||||
|
const char* sql = *utf8;
|
||||||
|
const char* tail;
|
||||||
|
|
||||||
|
int status;
|
||||||
|
const bool has_logger = db->has_logger;
|
||||||
|
sqlite3* const db_handle = db->db_handle;
|
||||||
|
sqlite3_stmt* handle;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
while (IS_SKIPPED(*sql)) ++sql;
|
||||||
|
status = sqlite3_prepare_v2(db_handle, sql, -1, &handle, &tail);
|
||||||
|
sql = tail;
|
||||||
|
if (!handle) break;
|
||||||
|
if (has_logger && db->Log(isolate, handle)) {
|
||||||
|
sqlite3_finalize(handle);
|
||||||
|
status = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
do status = sqlite3_step(handle);
|
||||||
|
while (status == SQLITE_ROW);
|
||||||
|
status = sqlite3_finalize(handle);
|
||||||
|
if (status != SQLITE_OK) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
db->busy = false;
|
||||||
|
if (status != SQLITE_OK) {
|
||||||
|
db->ThrowDatabaseError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Database::JS_backup) {
|
||||||
|
REQUIRE_ARGUMENT_OBJECT(first, v8::Local<v8::Object> database);
|
||||||
|
REQUIRE_ARGUMENT_STRING(second, v8::Local<v8::String> attachedName);
|
||||||
|
REQUIRE_ARGUMENT_STRING(third, v8::Local<v8::String> destFile);
|
||||||
|
REQUIRE_ARGUMENT_BOOLEAN(fourth, bool unlink);
|
||||||
|
(void)database;
|
||||||
|
(void)attachedName;
|
||||||
|
(void)destFile;
|
||||||
|
(void)unlink;
|
||||||
|
UseAddon;
|
||||||
|
UseIsolate;
|
||||||
|
v8::Local<v8::Function> c = addon->Backup.Get(isolate);
|
||||||
|
addon->privileged_info = &info;
|
||||||
|
v8::MaybeLocal<v8::Object> maybeBackup = c->NewInstance(OnlyContext, 0, NULL);
|
||||||
|
addon->privileged_info = NULL;
|
||||||
|
if (!maybeBackup.IsEmpty()) info.GetReturnValue().Set(maybeBackup.ToLocalChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Database::JS_serialize) {
|
||||||
|
Database* db = Unwrap<Database>(info.This());
|
||||||
|
REQUIRE_ARGUMENT_STRING(first, v8::Local<v8::String> attachedName);
|
||||||
|
REQUIRE_DATABASE_OPEN(db);
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(db);
|
||||||
|
REQUIRE_DATABASE_NO_ITERATORS(db);
|
||||||
|
|
||||||
|
UseIsolate;
|
||||||
|
v8::String::Utf8Value attached_name(isolate, attachedName);
|
||||||
|
sqlite3_int64 length = -1;
|
||||||
|
unsigned char* data = sqlite3_serialize(db->db_handle, *attached_name, &length, 0);
|
||||||
|
|
||||||
|
if (!data && length) {
|
||||||
|
ThrowError("Out of memory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.GetReturnValue().Set(
|
||||||
|
SAFE_NEW_BUFFER(isolate, reinterpret_cast<char*>(data), length, FreeSerialization, NULL).ToLocalChecked()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Database::JS_function) {
|
||||||
|
Database* db = Unwrap<Database>(info.This());
|
||||||
|
REQUIRE_ARGUMENT_FUNCTION(first, v8::Local<v8::Function> fn);
|
||||||
|
REQUIRE_ARGUMENT_STRING(second, v8::Local<v8::String> nameString);
|
||||||
|
REQUIRE_ARGUMENT_INT32(third, int argc);
|
||||||
|
REQUIRE_ARGUMENT_INT32(fourth, int safe_ints);
|
||||||
|
REQUIRE_ARGUMENT_BOOLEAN(fifth, bool deterministic);
|
||||||
|
REQUIRE_ARGUMENT_BOOLEAN(sixth, bool direct_only);
|
||||||
|
REQUIRE_DATABASE_OPEN(db);
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(db);
|
||||||
|
REQUIRE_DATABASE_NO_ITERATORS(db);
|
||||||
|
|
||||||
|
UseIsolate;
|
||||||
|
v8::String::Utf8Value name(isolate, nameString);
|
||||||
|
int mask = SQLITE_UTF8;
|
||||||
|
if (deterministic) mask |= SQLITE_DETERMINISTIC;
|
||||||
|
if (direct_only) mask |= SQLITE_DIRECTONLY;
|
||||||
|
safe_ints = safe_ints < 2 ? safe_ints : static_cast<int>(db->safe_ints);
|
||||||
|
|
||||||
|
if (sqlite3_create_function_v2(db->db_handle, *name, argc, mask, new CustomFunction(isolate, db, *name, fn, safe_ints), CustomFunction::xFunc, NULL, NULL, CustomFunction::xDestroy) != SQLITE_OK) {
|
||||||
|
db->ThrowDatabaseError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Database::JS_aggregate) {
|
||||||
|
Database* db = Unwrap<Database>(info.This());
|
||||||
|
REQUIRE_ARGUMENT_ANY(first, v8::Local<v8::Value> start);
|
||||||
|
REQUIRE_ARGUMENT_FUNCTION(second, v8::Local<v8::Function> step);
|
||||||
|
REQUIRE_ARGUMENT_ANY(third, v8::Local<v8::Value> inverse);
|
||||||
|
REQUIRE_ARGUMENT_ANY(fourth, v8::Local<v8::Value> result);
|
||||||
|
REQUIRE_ARGUMENT_STRING(fifth, v8::Local<v8::String> nameString);
|
||||||
|
REQUIRE_ARGUMENT_INT32(sixth, int argc);
|
||||||
|
REQUIRE_ARGUMENT_INT32(seventh, int safe_ints);
|
||||||
|
REQUIRE_ARGUMENT_BOOLEAN(eighth, bool deterministic);
|
||||||
|
REQUIRE_ARGUMENT_BOOLEAN(ninth, bool direct_only);
|
||||||
|
REQUIRE_DATABASE_OPEN(db);
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(db);
|
||||||
|
REQUIRE_DATABASE_NO_ITERATORS(db);
|
||||||
|
|
||||||
|
UseIsolate;
|
||||||
|
v8::String::Utf8Value name(isolate, nameString);
|
||||||
|
auto xInverse = inverse->IsFunction() ? CustomAggregate::xInverse : NULL;
|
||||||
|
auto xValue = xInverse ? CustomAggregate::xValue : NULL;
|
||||||
|
int mask = SQLITE_UTF8;
|
||||||
|
if (deterministic) mask |= SQLITE_DETERMINISTIC;
|
||||||
|
if (direct_only) mask |= SQLITE_DIRECTONLY;
|
||||||
|
safe_ints = safe_ints < 2 ? safe_ints : static_cast<int>(db->safe_ints);
|
||||||
|
|
||||||
|
if (sqlite3_create_window_function(db->db_handle, *name, argc, mask, new CustomAggregate(isolate, db, *name, start, step, inverse, result, safe_ints), CustomAggregate::xStep, CustomAggregate::xFinal, xValue, xInverse, CustomAggregate::xDestroy) != SQLITE_OK) {
|
||||||
|
db->ThrowDatabaseError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Database::JS_table) {
|
||||||
|
Database* db = Unwrap<Database>(info.This());
|
||||||
|
REQUIRE_ARGUMENT_FUNCTION(first, v8::Local<v8::Function> factory);
|
||||||
|
REQUIRE_ARGUMENT_STRING(second, v8::Local<v8::String> nameString);
|
||||||
|
REQUIRE_ARGUMENT_BOOLEAN(third, bool eponymous);
|
||||||
|
REQUIRE_DATABASE_OPEN(db);
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(db);
|
||||||
|
REQUIRE_DATABASE_NO_ITERATORS(db);
|
||||||
|
|
||||||
|
UseIsolate;
|
||||||
|
v8::String::Utf8Value name(isolate, nameString);
|
||||||
|
sqlite3_module* module = eponymous ? &CustomTable::EPONYMOUS_MODULE : &CustomTable::MODULE;
|
||||||
|
|
||||||
|
db->busy = true;
|
||||||
|
if (sqlite3_create_module_v2(db->db_handle, *name, module, new CustomTable(isolate, db, *name, factory), CustomTable::Destructor) != SQLITE_OK) {
|
||||||
|
db->ThrowDatabaseError();
|
||||||
|
}
|
||||||
|
db->busy = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Database::JS_loadExtension) {
|
||||||
|
Database* db = Unwrap<Database>(info.This());
|
||||||
|
v8::Local<v8::String> entryPoint;
|
||||||
|
REQUIRE_ARGUMENT_STRING(first, v8::Local<v8::String> filename);
|
||||||
|
if (info.Length() > 1) { REQUIRE_ARGUMENT_STRING(second, entryPoint); }
|
||||||
|
REQUIRE_DATABASE_OPEN(db);
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(db);
|
||||||
|
REQUIRE_DATABASE_NO_ITERATORS(db);
|
||||||
|
UseIsolate;
|
||||||
|
char* error;
|
||||||
|
int status = sqlite3_load_extension(
|
||||||
|
db->db_handle,
|
||||||
|
*v8::String::Utf8Value(isolate, filename),
|
||||||
|
entryPoint.IsEmpty() ? NULL : *v8::String::Utf8Value(isolate, entryPoint),
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
if (status != SQLITE_OK) {
|
||||||
|
ThrowSqliteError(db->addon, error, status);
|
||||||
|
}
|
||||||
|
sqlite3_free(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Database::JS_close) {
|
||||||
|
Database* db = Unwrap<Database>(info.This());
|
||||||
|
if (db->open) {
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(db);
|
||||||
|
REQUIRE_DATABASE_NO_ITERATORS(db);
|
||||||
|
db->addon->dbs.erase(db);
|
||||||
|
db->CloseHandles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Database::JS_defaultSafeIntegers) {
|
||||||
|
Database* db = Unwrap<Database>(info.This());
|
||||||
|
if (info.Length() == 0) db->safe_ints = true;
|
||||||
|
else { REQUIRE_ARGUMENT_BOOLEAN(first, db->safe_ints); }
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Database::JS_unsafeMode) {
|
||||||
|
Database* db = Unwrap<Database>(info.This());
|
||||||
|
if (info.Length() == 0) db->unsafe_mode = true;
|
||||||
|
else { REQUIRE_ARGUMENT_BOOLEAN(first, db->unsafe_mode); }
|
||||||
|
sqlite3_db_config(db->db_handle, SQLITE_DBCONFIG_DEFENSIVE, static_cast<int>(!db->unsafe_mode), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_GETTER(Database::JS_open) {
|
||||||
|
info.GetReturnValue().Set(Unwrap<Database>(info.This())->open);
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_GETTER(Database::JS_inTransaction) {
|
||||||
|
Database* db = Unwrap<Database>(info.This());
|
||||||
|
info.GetReturnValue().Set(db->open && !static_cast<bool>(sqlite3_get_autocommit(db->db_handle)));
|
||||||
|
}
|
||||||
103
node_modules/better-sqlite3/src/objects/database.hpp
generated
vendored
Normal file
103
node_modules/better-sqlite3/src/objects/database.hpp
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
class Database : public node::ObjectWrap {
|
||||||
|
public:
|
||||||
|
|
||||||
|
~Database();
|
||||||
|
|
||||||
|
// Whenever this is used, addon->dbs.erase() must be invoked beforehand.
|
||||||
|
void CloseHandles();
|
||||||
|
|
||||||
|
// Used to support ordered containers.
|
||||||
|
class CompareDatabase { public:
|
||||||
|
inline bool operator() (Database const * const a, Database const * const b) const {
|
||||||
|
return a < b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class CompareStatement { public:
|
||||||
|
inline bool operator() (Statement const * const a, Statement const * const b) const {
|
||||||
|
return Statement::Compare(a, b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class CompareBackup { public:
|
||||||
|
inline bool operator() (Backup const * const a, Backup const * const b) const {
|
||||||
|
return Backup::Compare(a, b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Proper error handling logic for when an sqlite3 operation fails.
|
||||||
|
void ThrowDatabaseError();
|
||||||
|
static void ThrowSqliteError(Addon* addon, sqlite3* db_handle);
|
||||||
|
static void ThrowSqliteError(Addon* addon, const char* message, int code);
|
||||||
|
|
||||||
|
// Allows Statements to log their executed SQL.
|
||||||
|
bool Log(v8::Isolate* isolate, sqlite3_stmt* handle);
|
||||||
|
|
||||||
|
// Allow Statements to manage themselves when created and garbage collected.
|
||||||
|
inline void AddStatement(Statement* stmt) { stmts.insert(stmts.end(), stmt); }
|
||||||
|
inline void RemoveStatement(Statement* stmt) { stmts.erase(stmt); }
|
||||||
|
|
||||||
|
// Allow Backups to manage themselves when created and garbage collected.
|
||||||
|
inline void AddBackup(Backup* backup) { backups.insert(backups.end(), backup); }
|
||||||
|
inline void RemoveBackup(Backup* backup) { backups.erase(backup); }
|
||||||
|
|
||||||
|
// A view for Statements to see and modify Database state.
|
||||||
|
// The order of these fields must exactly match their actual order.
|
||||||
|
struct State {
|
||||||
|
const bool open;
|
||||||
|
bool busy;
|
||||||
|
const bool safe_ints;
|
||||||
|
const bool unsafe_mode;
|
||||||
|
bool was_js_error;
|
||||||
|
const bool has_logger;
|
||||||
|
unsigned short iterators;
|
||||||
|
Addon* const addon;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline State* GetState() { return reinterpret_cast<State*>(&open); }
|
||||||
|
inline sqlite3* GetHandle() { return db_handle; }
|
||||||
|
inline Addon* GetAddon() { return addon; }
|
||||||
|
|
||||||
|
static INIT(Init);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
explicit Database(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
Addon* addon,
|
||||||
|
sqlite3* db_handle,
|
||||||
|
v8::Local<v8::Value> logger
|
||||||
|
);
|
||||||
|
|
||||||
|
static NODE_METHOD(JS_new);
|
||||||
|
static NODE_METHOD(JS_prepare);
|
||||||
|
static NODE_METHOD(JS_exec);
|
||||||
|
static NODE_METHOD(JS_backup);
|
||||||
|
static NODE_METHOD(JS_serialize);
|
||||||
|
static NODE_METHOD(JS_function);
|
||||||
|
static NODE_METHOD(JS_aggregate);
|
||||||
|
static NODE_METHOD(JS_table);
|
||||||
|
static NODE_METHOD(JS_loadExtension);
|
||||||
|
static NODE_METHOD(JS_close);
|
||||||
|
static NODE_METHOD(JS_defaultSafeIntegers);
|
||||||
|
static NODE_METHOD(JS_unsafeMode);
|
||||||
|
static NODE_GETTER(JS_open);
|
||||||
|
static NODE_GETTER(JS_inTransaction);
|
||||||
|
|
||||||
|
static bool Deserialize(v8::Local<v8::Object> buffer, Addon* addon, sqlite3* db_handle, bool readonly);
|
||||||
|
static void FreeSerialization(char* data, void* _);
|
||||||
|
|
||||||
|
static const int MAX_BUFFER_SIZE;
|
||||||
|
static const int MAX_STRING_SIZE;
|
||||||
|
|
||||||
|
sqlite3* const db_handle;
|
||||||
|
bool open;
|
||||||
|
bool busy;
|
||||||
|
bool safe_ints;
|
||||||
|
bool unsafe_mode;
|
||||||
|
bool was_js_error;
|
||||||
|
const bool has_logger;
|
||||||
|
unsigned short iterators;
|
||||||
|
Addon* const addon;
|
||||||
|
const v8::Global<v8::Value> logger;
|
||||||
|
std::set<Statement*, CompareStatement> stmts;
|
||||||
|
std::set<Backup*, CompareBackup> backups;
|
||||||
|
};
|
||||||
113
node_modules/better-sqlite3/src/objects/statement-iterator.cpp
generated
vendored
Normal file
113
node_modules/better-sqlite3/src/objects/statement-iterator.cpp
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
StatementIterator::StatementIterator(Statement* stmt, bool bound) :
|
||||||
|
node::ObjectWrap(),
|
||||||
|
stmt(stmt),
|
||||||
|
handle(stmt->handle),
|
||||||
|
db_state(stmt->db->GetState()),
|
||||||
|
bound(bound),
|
||||||
|
safe_ints(stmt->safe_ints),
|
||||||
|
mode(stmt->mode),
|
||||||
|
alive(true),
|
||||||
|
logged(!db_state->has_logger) {
|
||||||
|
assert(stmt != NULL);
|
||||||
|
assert(handle != NULL);
|
||||||
|
assert(stmt->bound == bound);
|
||||||
|
assert(stmt->alive == true);
|
||||||
|
assert(stmt->locked == false);
|
||||||
|
assert(db_state->iterators < USHRT_MAX);
|
||||||
|
stmt->locked = true;
|
||||||
|
db_state->iterators += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ~Statement destructor currently covers any state this object creates.
|
||||||
|
// Additionally, we actually DON'T want to revert stmt->locked or db_state
|
||||||
|
// ->iterators in this destructor, to ensure deterministic database access.
|
||||||
|
StatementIterator::~StatementIterator() {}
|
||||||
|
|
||||||
|
void StatementIterator::Next(NODE_ARGUMENTS info) {
|
||||||
|
assert(alive == true);
|
||||||
|
db_state->busy = true;
|
||||||
|
if (!logged) {
|
||||||
|
logged = true;
|
||||||
|
if (stmt->db->Log(OnlyIsolate, handle)) {
|
||||||
|
db_state->busy = false;
|
||||||
|
Throw();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int status = sqlite3_step(handle);
|
||||||
|
db_state->busy = false;
|
||||||
|
if (status == SQLITE_ROW) {
|
||||||
|
UseIsolate;
|
||||||
|
UseContext;
|
||||||
|
info.GetReturnValue().Set(
|
||||||
|
NewRecord(isolate, ctx, Data::GetRowJS(isolate, ctx, handle, safe_ints, mode), db_state->addon, false)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (status == SQLITE_DONE) Return(info);
|
||||||
|
else Throw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatementIterator::Return(NODE_ARGUMENTS info) {
|
||||||
|
Cleanup();
|
||||||
|
STATEMENT_RETURN_LOGIC(DoneRecord(OnlyIsolate, db_state->addon));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatementIterator::Throw() {
|
||||||
|
Cleanup();
|
||||||
|
Database* db = stmt->db;
|
||||||
|
STATEMENT_THROW_LOGIC();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatementIterator::Cleanup() {
|
||||||
|
assert(alive == true);
|
||||||
|
alive = false;
|
||||||
|
stmt->locked = false;
|
||||||
|
db_state->iterators -= 1;
|
||||||
|
sqlite3_reset(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT(StatementIterator::Init) {
|
||||||
|
v8::Local<v8::FunctionTemplate> t = NewConstructorTemplate(isolate, data, JS_new, "StatementIterator");
|
||||||
|
SetPrototypeMethod(isolate, data, t, "next", JS_next);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "return", JS_return);
|
||||||
|
SetPrototypeSymbolMethod(isolate, data, t, v8::Symbol::GetIterator(isolate), JS_symbolIterator);
|
||||||
|
return t->GetFunction(OnlyContext).ToLocalChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(StatementIterator::JS_new) {
|
||||||
|
UseAddon;
|
||||||
|
if (!addon->privileged_info) return ThrowTypeError("Disabled constructor");
|
||||||
|
assert(info.IsConstructCall());
|
||||||
|
|
||||||
|
StatementIterator* iter;
|
||||||
|
{
|
||||||
|
NODE_ARGUMENTS info = *addon->privileged_info;
|
||||||
|
STATEMENT_START_LOGIC(REQUIRE_STATEMENT_RETURNS_DATA, DOES_ADD_ITERATOR);
|
||||||
|
iter = new StatementIterator(stmt, bound);
|
||||||
|
}
|
||||||
|
UseIsolate;
|
||||||
|
UseContext;
|
||||||
|
iter->Wrap(info.This());
|
||||||
|
SetFrozen(isolate, ctx, info.This(), addon->cs.statement, addon->privileged_info->This());
|
||||||
|
|
||||||
|
info.GetReturnValue().Set(info.This());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(StatementIterator::JS_next) {
|
||||||
|
StatementIterator* iter = Unwrap<StatementIterator>(info.This());
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(iter->db_state);
|
||||||
|
if (iter->alive) iter->Next(info);
|
||||||
|
else info.GetReturnValue().Set(DoneRecord(OnlyIsolate, iter->db_state->addon));
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(StatementIterator::JS_return) {
|
||||||
|
StatementIterator* iter = Unwrap<StatementIterator>(info.This());
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(iter->db_state);
|
||||||
|
if (iter->alive) iter->Return(info);
|
||||||
|
else info.GetReturnValue().Set(DoneRecord(OnlyIsolate, iter->db_state->addon));
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(StatementIterator::JS_symbolIterator) {
|
||||||
|
info.GetReturnValue().Set(info.This());
|
||||||
|
}
|
||||||
50
node_modules/better-sqlite3/src/objects/statement-iterator.hpp
generated
vendored
Normal file
50
node_modules/better-sqlite3/src/objects/statement-iterator.hpp
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
class StatementIterator : public node::ObjectWrap {
|
||||||
|
public:
|
||||||
|
|
||||||
|
// The ~Statement destructor currently covers any state this object creates.
|
||||||
|
// Additionally, we actually DON'T want to revert stmt->locked or db_state
|
||||||
|
// ->iterators in this destructor, to ensure deterministic database access.
|
||||||
|
~StatementIterator();
|
||||||
|
|
||||||
|
static INIT(Init);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
explicit StatementIterator(Statement* stmt, bool bound);
|
||||||
|
|
||||||
|
void Next(NODE_ARGUMENTS info);
|
||||||
|
void Return(NODE_ARGUMENTS info);
|
||||||
|
void Throw();
|
||||||
|
void Cleanup();
|
||||||
|
|
||||||
|
static inline v8::Local<v8::Object> NewRecord(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::Context> ctx,
|
||||||
|
v8::Local<v8::Value> value,
|
||||||
|
Addon* addon,
|
||||||
|
bool done
|
||||||
|
) {
|
||||||
|
v8::Local<v8::Object> record = v8::Object::New(isolate);
|
||||||
|
record->Set(ctx, addon->cs.value.Get(isolate), value).FromJust();
|
||||||
|
record->Set(ctx, addon->cs.done.Get(isolate), v8::Boolean::New(isolate, done)).FromJust();
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline v8::Local<v8::Object> DoneRecord(v8::Isolate* isolate, Addon* addon) {
|
||||||
|
return NewRecord(isolate, OnlyContext, v8::Undefined(isolate), addon, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NODE_METHOD(JS_new);
|
||||||
|
static NODE_METHOD(JS_next);
|
||||||
|
static NODE_METHOD(JS_return);
|
||||||
|
static NODE_METHOD(JS_symbolIterator);
|
||||||
|
|
||||||
|
Statement* const stmt;
|
||||||
|
sqlite3_stmt* const handle;
|
||||||
|
Database::State* const db_state;
|
||||||
|
const bool bound;
|
||||||
|
const bool safe_ints;
|
||||||
|
const char mode;
|
||||||
|
bool alive;
|
||||||
|
bool logged;
|
||||||
|
};
|
||||||
383
node_modules/better-sqlite3/src/objects/statement.cpp
generated
vendored
Normal file
383
node_modules/better-sqlite3/src/objects/statement.cpp
generated
vendored
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
Statement::Statement(
|
||||||
|
Database* db,
|
||||||
|
sqlite3_stmt* handle,
|
||||||
|
sqlite3_uint64 id,
|
||||||
|
bool returns_data
|
||||||
|
) :
|
||||||
|
node::ObjectWrap(),
|
||||||
|
db(db),
|
||||||
|
handle(handle),
|
||||||
|
extras(new Extras(id)),
|
||||||
|
alive(true),
|
||||||
|
locked(false),
|
||||||
|
bound(false),
|
||||||
|
has_bind_map(false),
|
||||||
|
safe_ints(db->GetState()->safe_ints),
|
||||||
|
mode(Data::FLAT),
|
||||||
|
returns_data(returns_data) {
|
||||||
|
assert(db != NULL);
|
||||||
|
assert(handle != NULL);
|
||||||
|
assert(db->GetState()->open);
|
||||||
|
assert(!db->GetState()->busy);
|
||||||
|
db->AddStatement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement::~Statement() {
|
||||||
|
if (alive) db->RemoveStatement(this);
|
||||||
|
CloseHandles();
|
||||||
|
delete extras;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whenever this is used, db->RemoveStatement must be invoked beforehand.
|
||||||
|
void Statement::CloseHandles() {
|
||||||
|
if (alive) {
|
||||||
|
alive = false;
|
||||||
|
sqlite3_finalize(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the Statement's bind map (creates it upon first execution).
|
||||||
|
BindMap* Statement::GetBindMap(v8::Isolate* isolate) {
|
||||||
|
if (has_bind_map) return &extras->bind_map;
|
||||||
|
BindMap* bind_map = &extras->bind_map;
|
||||||
|
int param_count = sqlite3_bind_parameter_count(handle);
|
||||||
|
for (int i = 1; i <= param_count; ++i) {
|
||||||
|
const char* name = sqlite3_bind_parameter_name(handle, i);
|
||||||
|
if (name != NULL) bind_map->Add(isolate, name + 1, i);
|
||||||
|
}
|
||||||
|
has_bind_map = true;
|
||||||
|
return bind_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement::Extras::Extras(sqlite3_uint64 id)
|
||||||
|
: bind_map(0), id(id) {}
|
||||||
|
|
||||||
|
INIT(Statement::Init) {
|
||||||
|
v8::Local<v8::FunctionTemplate> t = NewConstructorTemplate(isolate, data, JS_new, "Statement");
|
||||||
|
SetPrototypeMethod(isolate, data, t, "run", JS_run);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "get", JS_get);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "all", JS_all);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "iterate", JS_iterate);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "bind", JS_bind);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "pluck", JS_pluck);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "expand", JS_expand);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "raw", JS_raw);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "safeIntegers", JS_safeIntegers);
|
||||||
|
SetPrototypeMethod(isolate, data, t, "columns", JS_columns);
|
||||||
|
SetPrototypeGetter(isolate, data, t, "busy", JS_busy);
|
||||||
|
return t->GetFunction(OnlyContext).ToLocalChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Statement::JS_new) {
|
||||||
|
UseAddon;
|
||||||
|
if (!addon->privileged_info) {
|
||||||
|
return ThrowTypeError("Statements can only be constructed by the db.prepare() method");
|
||||||
|
}
|
||||||
|
assert(info.IsConstructCall());
|
||||||
|
Database* db = Unwrap<Database>(addon->privileged_info->This());
|
||||||
|
REQUIRE_DATABASE_OPEN(db->GetState());
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(db->GetState());
|
||||||
|
|
||||||
|
v8::Local<v8::String> source = (*addon->privileged_info)[0].As<v8::String>();
|
||||||
|
v8::Local<v8::Object> database = (*addon->privileged_info)[1].As<v8::Object>();
|
||||||
|
bool pragmaMode = (*addon->privileged_info)[2].As<v8::Boolean>()->Value();
|
||||||
|
int flags = SQLITE_PREPARE_PERSISTENT;
|
||||||
|
|
||||||
|
if (pragmaMode) {
|
||||||
|
REQUIRE_DATABASE_NO_ITERATORS_UNLESS_UNSAFE(db->GetState());
|
||||||
|
flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UseIsolate;
|
||||||
|
v8::String::Utf8Value utf8(isolate, source);
|
||||||
|
sqlite3_stmt* handle;
|
||||||
|
const char* tail;
|
||||||
|
|
||||||
|
if (sqlite3_prepare_v3(db->GetHandle(), *utf8, utf8.length() + 1, flags, &handle, &tail) != SQLITE_OK) {
|
||||||
|
return db->ThrowDatabaseError();
|
||||||
|
}
|
||||||
|
if (handle == NULL) {
|
||||||
|
return ThrowRangeError("The supplied SQL string contains no statements");
|
||||||
|
}
|
||||||
|
// https://github.com/WiseLibs/better-sqlite3/issues/975#issuecomment-1520934678
|
||||||
|
for (char c; (c = *tail); ) {
|
||||||
|
if (IS_SKIPPED(c)) {
|
||||||
|
++tail;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '/' && tail[1] == '*') {
|
||||||
|
tail += 2;
|
||||||
|
for (char c; (c = *tail); ++tail) {
|
||||||
|
if (c == '*' && tail[1] == '/') {
|
||||||
|
tail += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (c == '-' && tail[1] == '-') {
|
||||||
|
tail += 2;
|
||||||
|
for (char c; (c = *tail); ++tail) {
|
||||||
|
if (c == '\n') {
|
||||||
|
++tail;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sqlite3_finalize(handle);
|
||||||
|
return ThrowRangeError("The supplied SQL string contains more than one statement");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UseContext;
|
||||||
|
bool returns_data = sqlite3_column_count(handle) >= 1 || pragmaMode;
|
||||||
|
Statement* stmt = new Statement(db, handle, addon->NextId(), returns_data);
|
||||||
|
stmt->Wrap(info.This());
|
||||||
|
SetFrozen(isolate, ctx, info.This(), addon->cs.reader, v8::Boolean::New(isolate, returns_data));
|
||||||
|
SetFrozen(isolate, ctx, info.This(), addon->cs.readonly, v8::Boolean::New(isolate, sqlite3_stmt_readonly(handle) != 0));
|
||||||
|
SetFrozen(isolate, ctx, info.This(), addon->cs.source, source);
|
||||||
|
SetFrozen(isolate, ctx, info.This(), addon->cs.database, database);
|
||||||
|
|
||||||
|
info.GetReturnValue().Set(info.This());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Statement::JS_run) {
|
||||||
|
STATEMENT_START(ALLOW_ANY_STATEMENT, DOES_MUTATE);
|
||||||
|
sqlite3* db_handle = db->GetHandle();
|
||||||
|
int total_changes_before = sqlite3_total_changes(db_handle);
|
||||||
|
|
||||||
|
sqlite3_step(handle);
|
||||||
|
if (sqlite3_reset(handle) == SQLITE_OK) {
|
||||||
|
int changes = sqlite3_total_changes(db_handle) == total_changes_before ? 0 : sqlite3_changes(db_handle);
|
||||||
|
sqlite3_int64 id = sqlite3_last_insert_rowid(db_handle);
|
||||||
|
Addon* addon = db->GetAddon();
|
||||||
|
UseContext;
|
||||||
|
v8::Local<v8::Object> result = v8::Object::New(isolate);
|
||||||
|
result->Set(ctx, addon->cs.changes.Get(isolate), v8::Int32::New(isolate, changes)).FromJust();
|
||||||
|
result->Set(ctx, addon->cs.lastInsertRowid.Get(isolate),
|
||||||
|
stmt->safe_ints
|
||||||
|
? v8::BigInt::New(isolate, id).As<v8::Value>()
|
||||||
|
: v8::Number::New(isolate, (double)id).As<v8::Value>()
|
||||||
|
).FromJust();
|
||||||
|
STATEMENT_RETURN(result);
|
||||||
|
}
|
||||||
|
STATEMENT_THROW();
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Statement::JS_get) {
|
||||||
|
STATEMENT_START(REQUIRE_STATEMENT_RETURNS_DATA, DOES_NOT_MUTATE);
|
||||||
|
int status = sqlite3_step(handle);
|
||||||
|
if (status == SQLITE_ROW) {
|
||||||
|
v8::Local<v8::Value> result = Data::GetRowJS(isolate, OnlyContext, handle, stmt->safe_ints, stmt->mode);
|
||||||
|
sqlite3_reset(handle);
|
||||||
|
STATEMENT_RETURN(result);
|
||||||
|
} else if (status == SQLITE_DONE) {
|
||||||
|
sqlite3_reset(handle);
|
||||||
|
STATEMENT_RETURN(v8::Undefined(isolate));
|
||||||
|
}
|
||||||
|
sqlite3_reset(handle);
|
||||||
|
STATEMENT_THROW();
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Statement::JS_all) {
|
||||||
|
STATEMENT_START(REQUIRE_STATEMENT_RETURNS_DATA, DOES_NOT_MUTATE);
|
||||||
|
UseContext;
|
||||||
|
const bool safe_ints = stmt->safe_ints;
|
||||||
|
const char mode = stmt->mode;
|
||||||
|
|
||||||
|
#if !defined(NODE_MODULE_VERSION) || NODE_MODULE_VERSION < 127
|
||||||
|
bool js_error = false;
|
||||||
|
uint32_t row_count = 0;
|
||||||
|
v8::Local<v8::Array> result = v8::Array::New(isolate, 0);
|
||||||
|
|
||||||
|
while (sqlite3_step(handle) == SQLITE_ROW) {
|
||||||
|
if (row_count == 0xffffffff) { ThrowRangeError("Array overflow (too many rows returned)"); js_error = true; break; }
|
||||||
|
result->Set(ctx, row_count++, Data::GetRowJS(isolate, ctx, handle, safe_ints, mode)).FromJust();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sqlite3_reset(handle) == SQLITE_OK && !js_error) {
|
||||||
|
STATEMENT_RETURN(result);
|
||||||
|
}
|
||||||
|
if (js_error) db->GetState()->was_js_error = true;
|
||||||
|
STATEMENT_THROW();
|
||||||
|
#else
|
||||||
|
v8::LocalVector<v8::Value> rows(isolate);
|
||||||
|
rows.reserve(8);
|
||||||
|
|
||||||
|
if (mode == Data::FLAT) {
|
||||||
|
RowBuilder rowBuilder(isolate, handle, safe_ints);
|
||||||
|
while (sqlite3_step(handle) == SQLITE_ROW) {
|
||||||
|
rows.emplace_back(rowBuilder.GetRowJS());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (sqlite3_step(handle) == SQLITE_ROW) {
|
||||||
|
rows.emplace_back(Data::GetRowJS(isolate, ctx, handle, safe_ints, mode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sqlite3_reset(handle) == SQLITE_OK) {
|
||||||
|
if (rows.size() > 0xffffffff) {
|
||||||
|
ThrowRangeError("Array overflow (too many rows returned)");
|
||||||
|
db->GetState()->was_js_error = true;
|
||||||
|
} else {
|
||||||
|
STATEMENT_RETURN(v8::Array::New(isolate, rows.data(), rows.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
STATEMENT_THROW();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Statement::JS_iterate) {
|
||||||
|
UseAddon;
|
||||||
|
UseIsolate;
|
||||||
|
v8::Local<v8::Function> c = addon->StatementIterator.Get(isolate);
|
||||||
|
addon->privileged_info = &info;
|
||||||
|
v8::MaybeLocal<v8::Object> maybeIterator = c->NewInstance(OnlyContext, 0, NULL);
|
||||||
|
addon->privileged_info = NULL;
|
||||||
|
if (!maybeIterator.IsEmpty()) info.GetReturnValue().Set(maybeIterator.ToLocalChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Statement::JS_bind) {
|
||||||
|
Statement* stmt = Unwrap<Statement>(info.This());
|
||||||
|
if (stmt->bound) return ThrowTypeError("The bind() method can only be invoked once per statement object");
|
||||||
|
REQUIRE_DATABASE_OPEN(stmt->db->GetState());
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
|
||||||
|
REQUIRE_STATEMENT_NOT_LOCKED(stmt);
|
||||||
|
STATEMENT_BIND(stmt->handle);
|
||||||
|
stmt->bound = true;
|
||||||
|
info.GetReturnValue().Set(info.This());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Statement::JS_pluck) {
|
||||||
|
Statement* stmt = Unwrap<Statement>(info.This());
|
||||||
|
if (!stmt->returns_data) return ThrowTypeError("The pluck() method is only for statements that return data");
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
|
||||||
|
REQUIRE_STATEMENT_NOT_LOCKED(stmt);
|
||||||
|
bool use = true;
|
||||||
|
if (info.Length() != 0) { REQUIRE_ARGUMENT_BOOLEAN(first, use); }
|
||||||
|
stmt->mode = use ? Data::PLUCK : stmt->mode == Data::PLUCK ? Data::FLAT : stmt->mode;
|
||||||
|
info.GetReturnValue().Set(info.This());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Statement::JS_expand) {
|
||||||
|
Statement* stmt = Unwrap<Statement>(info.This());
|
||||||
|
if (!stmt->returns_data) return ThrowTypeError("The expand() method is only for statements that return data");
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
|
||||||
|
REQUIRE_STATEMENT_NOT_LOCKED(stmt);
|
||||||
|
bool use = true;
|
||||||
|
if (info.Length() != 0) { REQUIRE_ARGUMENT_BOOLEAN(first, use); }
|
||||||
|
stmt->mode = use ? Data::EXPAND : stmt->mode == Data::EXPAND ? Data::FLAT : stmt->mode;
|
||||||
|
info.GetReturnValue().Set(info.This());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Statement::JS_raw) {
|
||||||
|
Statement* stmt = Unwrap<Statement>(info.This());
|
||||||
|
if (!stmt->returns_data) return ThrowTypeError("The raw() method is only for statements that return data");
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
|
||||||
|
REQUIRE_STATEMENT_NOT_LOCKED(stmt);
|
||||||
|
bool use = true;
|
||||||
|
if (info.Length() != 0) { REQUIRE_ARGUMENT_BOOLEAN(first, use); }
|
||||||
|
stmt->mode = use ? Data::RAW : stmt->mode == Data::RAW ? Data::FLAT : stmt->mode;
|
||||||
|
info.GetReturnValue().Set(info.This());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Statement::JS_safeIntegers) {
|
||||||
|
Statement* stmt = Unwrap<Statement>(info.This());
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
|
||||||
|
REQUIRE_STATEMENT_NOT_LOCKED(stmt);
|
||||||
|
if (info.Length() == 0) stmt->safe_ints = true;
|
||||||
|
else { REQUIRE_ARGUMENT_BOOLEAN(first, stmt->safe_ints); }
|
||||||
|
info.GetReturnValue().Set(info.This());
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_METHOD(Statement::JS_columns) {
|
||||||
|
Statement* stmt = Unwrap<Statement>(info.This());
|
||||||
|
if (!stmt->returns_data) return ThrowTypeError("The columns() method is only for statements that return data");
|
||||||
|
REQUIRE_DATABASE_OPEN(stmt->db->GetState());
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(stmt->db->GetState());
|
||||||
|
Addon* addon = stmt->db->GetAddon();
|
||||||
|
UseIsolate;
|
||||||
|
|
||||||
|
#if !defined(NODE_MODULE_VERSION) || NODE_MODULE_VERSION < 127
|
||||||
|
UseContext;
|
||||||
|
int column_count = sqlite3_column_count(stmt->handle);
|
||||||
|
v8::Local<v8::Array> columns = v8::Array::New(isolate);
|
||||||
|
|
||||||
|
v8::Local<v8::String> name = addon->cs.name.Get(isolate);
|
||||||
|
v8::Local<v8::String> columnName = addon->cs.column.Get(isolate);
|
||||||
|
v8::Local<v8::String> tableName = addon->cs.table.Get(isolate);
|
||||||
|
v8::Local<v8::String> databaseName = addon->cs.database.Get(isolate);
|
||||||
|
v8::Local<v8::String> typeName = addon->cs.type.Get(isolate);
|
||||||
|
|
||||||
|
for (int i = 0; i < column_count; ++i) {
|
||||||
|
v8::Local<v8::Object> column = v8::Object::New(isolate);
|
||||||
|
|
||||||
|
column->Set(ctx, name,
|
||||||
|
InternalizedFromUtf8OrNull(isolate, sqlite3_column_name(stmt->handle, i), -1)
|
||||||
|
).FromJust();
|
||||||
|
column->Set(ctx, columnName,
|
||||||
|
InternalizedFromUtf8OrNull(isolate, sqlite3_column_origin_name(stmt->handle, i), -1)
|
||||||
|
).FromJust();
|
||||||
|
column->Set(ctx, tableName,
|
||||||
|
InternalizedFromUtf8OrNull(isolate, sqlite3_column_table_name(stmt->handle, i), -1)
|
||||||
|
).FromJust();
|
||||||
|
column->Set(ctx, databaseName,
|
||||||
|
InternalizedFromUtf8OrNull(isolate, sqlite3_column_database_name(stmt->handle, i), -1)
|
||||||
|
).FromJust();
|
||||||
|
column->Set(ctx, typeName,
|
||||||
|
InternalizedFromUtf8OrNull(isolate, sqlite3_column_decltype(stmt->handle, i), -1)
|
||||||
|
).FromJust();
|
||||||
|
|
||||||
|
columns->Set(ctx, i, column).FromJust();
|
||||||
|
}
|
||||||
|
|
||||||
|
info.GetReturnValue().Set(columns);
|
||||||
|
#else
|
||||||
|
v8::LocalVector<v8::Name> keys(isolate);
|
||||||
|
keys.reserve(5);
|
||||||
|
keys.emplace_back(addon->cs.name.Get(isolate).As<v8::Name>());
|
||||||
|
keys.emplace_back(addon->cs.column.Get(isolate).As<v8::Name>());
|
||||||
|
keys.emplace_back(addon->cs.table.Get(isolate).As<v8::Name>());
|
||||||
|
keys.emplace_back(addon->cs.database.Get(isolate).As<v8::Name>());
|
||||||
|
keys.emplace_back(addon->cs.type.Get(isolate).As<v8::Name>());
|
||||||
|
|
||||||
|
int column_count = sqlite3_column_count(stmt->handle);
|
||||||
|
v8::LocalVector<v8::Value> columns(isolate);
|
||||||
|
columns.reserve(column_count);
|
||||||
|
|
||||||
|
for (int i = 0; i < column_count; ++i) {
|
||||||
|
v8::LocalVector<v8::Value> values(isolate);
|
||||||
|
keys.reserve(5);
|
||||||
|
values.emplace_back(
|
||||||
|
InternalizedFromUtf8OrNull(isolate, sqlite3_column_name(stmt->handle, i), -1)
|
||||||
|
);
|
||||||
|
values.emplace_back(
|
||||||
|
InternalizedFromUtf8OrNull(isolate, sqlite3_column_origin_name(stmt->handle, i), -1)
|
||||||
|
);
|
||||||
|
values.emplace_back(
|
||||||
|
InternalizedFromUtf8OrNull(isolate, sqlite3_column_table_name(stmt->handle, i), -1)
|
||||||
|
);
|
||||||
|
values.emplace_back(
|
||||||
|
InternalizedFromUtf8OrNull(isolate, sqlite3_column_database_name(stmt->handle, i), -1)
|
||||||
|
);
|
||||||
|
values.emplace_back(
|
||||||
|
InternalizedFromUtf8OrNull(isolate, sqlite3_column_decltype(stmt->handle, i), -1)
|
||||||
|
);
|
||||||
|
columns.emplace_back(
|
||||||
|
v8::Object::New(isolate,
|
||||||
|
GET_PROTOTYPE(v8::Object::New(isolate)),
|
||||||
|
keys.data(),
|
||||||
|
values.data(),
|
||||||
|
keys.size()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
info.GetReturnValue().Set(
|
||||||
|
v8::Array::New(isolate, columns.data(), columns.size())
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_GETTER(Statement::JS_busy) {
|
||||||
|
Statement* stmt = Unwrap<Statement>(info.This());
|
||||||
|
info.GetReturnValue().Set(stmt->alive && stmt->locked);
|
||||||
|
}
|
||||||
58
node_modules/better-sqlite3/src/objects/statement.hpp
generated
vendored
Normal file
58
node_modules/better-sqlite3/src/objects/statement.hpp
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
class Statement : public node::ObjectWrap { friend class StatementIterator;
|
||||||
|
public:
|
||||||
|
|
||||||
|
~Statement();
|
||||||
|
|
||||||
|
// Whenever this is used, db->RemoveStatement must be invoked beforehand.
|
||||||
|
void CloseHandles();
|
||||||
|
|
||||||
|
// Used to support ordered containers.
|
||||||
|
static inline bool Compare(Statement const * const a, Statement const * const b) {
|
||||||
|
return a->extras->id < b->extras->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the Statement's bind map (creates it upon first execution).
|
||||||
|
BindMap* GetBindMap(v8::Isolate* isolate);
|
||||||
|
|
||||||
|
static INIT(Init);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// A class for holding values that are less often used.
|
||||||
|
class Extras { friend class Statement;
|
||||||
|
explicit Extras(sqlite3_uint64 id);
|
||||||
|
BindMap bind_map;
|
||||||
|
const sqlite3_uint64 id;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit Statement(
|
||||||
|
Database* db,
|
||||||
|
sqlite3_stmt* handle,
|
||||||
|
sqlite3_uint64 id,
|
||||||
|
bool returns_data
|
||||||
|
);
|
||||||
|
|
||||||
|
static NODE_METHOD(JS_new);
|
||||||
|
static NODE_METHOD(JS_run);
|
||||||
|
static NODE_METHOD(JS_get);
|
||||||
|
static NODE_METHOD(JS_all);
|
||||||
|
static NODE_METHOD(JS_iterate);
|
||||||
|
static NODE_METHOD(JS_bind);
|
||||||
|
static NODE_METHOD(JS_pluck);
|
||||||
|
static NODE_METHOD(JS_expand);
|
||||||
|
static NODE_METHOD(JS_raw);
|
||||||
|
static NODE_METHOD(JS_safeIntegers);
|
||||||
|
static NODE_METHOD(JS_columns);
|
||||||
|
static NODE_GETTER(JS_busy);
|
||||||
|
|
||||||
|
Database* const db;
|
||||||
|
sqlite3_stmt* const handle;
|
||||||
|
Extras* const extras;
|
||||||
|
bool alive;
|
||||||
|
bool locked;
|
||||||
|
bool bound;
|
||||||
|
bool has_bind_map;
|
||||||
|
bool safe_ints;
|
||||||
|
char mode;
|
||||||
|
const bool returns_data;
|
||||||
|
};
|
||||||
73
node_modules/better-sqlite3/src/util/bind-map.cpp
generated
vendored
Normal file
73
node_modules/better-sqlite3/src/util/bind-map.cpp
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
class BindMap {
|
||||||
|
public:
|
||||||
|
|
||||||
|
// This nested class represents a single mapping between a parameter name
|
||||||
|
// and its associated parameter index in a prepared statement.
|
||||||
|
class Pair { friend class BindMap;
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline int GetIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline v8::Local<v8::String> GetName(v8::Isolate* isolate) {
|
||||||
|
return name.Get(isolate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
explicit Pair(v8::Isolate* isolate, const char* name, int index)
|
||||||
|
: name(isolate, InternalizedFromUtf8(isolate, name, -1)), index(index) {}
|
||||||
|
|
||||||
|
explicit Pair(v8::Isolate* isolate, Pair* pair)
|
||||||
|
: name(isolate, pair->name), index(pair->index) {}
|
||||||
|
|
||||||
|
const v8::Global<v8::String> name;
|
||||||
|
const int index;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit BindMap(char _) {
|
||||||
|
assert(_ == 0);
|
||||||
|
pairs = NULL;
|
||||||
|
capacity = 0;
|
||||||
|
length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~BindMap() {
|
||||||
|
while (length) pairs[--length].~Pair();
|
||||||
|
FREE_ARRAY<Pair>(pairs);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Pair* GetPairs() {
|
||||||
|
return pairs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int GetSize() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a pair to the bind map, expanding the capacity if necessary.
|
||||||
|
void Add(v8::Isolate* isolate, const char* name, int index) {
|
||||||
|
assert(name != NULL);
|
||||||
|
if (capacity == length) Grow(isolate);
|
||||||
|
new (pairs + length++) Pair(isolate, name, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void Grow(v8::Isolate* isolate) {
|
||||||
|
assert(capacity == length);
|
||||||
|
capacity = (capacity << 1) | 2;
|
||||||
|
Pair* new_pairs = ALLOC_ARRAY<Pair>(capacity);
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
new (new_pairs + i) Pair(isolate, pairs + i);
|
||||||
|
pairs[i].~Pair();
|
||||||
|
}
|
||||||
|
FREE_ARRAY<Pair>(pairs);
|
||||||
|
pairs = new_pairs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pair* pairs;
|
||||||
|
int capacity;
|
||||||
|
int length;
|
||||||
|
};
|
||||||
193
node_modules/better-sqlite3/src/util/binder.cpp
generated
vendored
Normal file
193
node_modules/better-sqlite3/src/util/binder.cpp
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
class Binder {
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit Binder(sqlite3_stmt* _handle) {
|
||||||
|
handle = _handle;
|
||||||
|
param_count = sqlite3_bind_parameter_count(_handle);
|
||||||
|
anon_index = 0;
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bind(NODE_ARGUMENTS info, int argc, Statement* stmt) {
|
||||||
|
assert(anon_index == 0);
|
||||||
|
Result result = BindArgs(info, argc, stmt);
|
||||||
|
if (success && result.count != param_count) {
|
||||||
|
if (result.count < param_count) {
|
||||||
|
if (!result.bound_object && stmt->GetBindMap(OnlyIsolate)->GetSize()) {
|
||||||
|
Fail(ThrowTypeError, "Missing named parameters");
|
||||||
|
} else {
|
||||||
|
Fail(ThrowRangeError, "Too few parameter values were provided");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Fail(ThrowRangeError, "Too many parameter values were provided");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct Result {
|
||||||
|
int count;
|
||||||
|
bool bound_object;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool IsPlainObject(v8::Isolate* isolate, v8::Local<v8::Object> obj) {
|
||||||
|
v8::Local<v8::Value> proto = GET_PROTOTYPE(obj);
|
||||||
|
v8::Local<v8::Context> ctx = obj->GetCreationContext().ToLocalChecked();
|
||||||
|
ctx->Enter();
|
||||||
|
v8::Local<v8::Value> baseProto = GET_PROTOTYPE(v8::Object::New(isolate));
|
||||||
|
ctx->Exit();
|
||||||
|
return proto->StrictEquals(baseProto) || proto->StrictEquals(v8::Null(isolate));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fail(void (*Throw)(const char* _), const char* message) {
|
||||||
|
assert(success == true);
|
||||||
|
assert((Throw == NULL) == (message == NULL));
|
||||||
|
assert(Throw == ThrowError || Throw == ThrowTypeError || Throw == ThrowRangeError || Throw == NULL);
|
||||||
|
if (Throw) Throw(message);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NextAnonIndex() {
|
||||||
|
while (sqlite3_bind_parameter_name(handle, ++anon_index) != NULL) {}
|
||||||
|
return anon_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binds the value at the given index or throws an appropriate error.
|
||||||
|
void BindValue(v8::Isolate* isolate, v8::Local<v8::Value> value, int index) {
|
||||||
|
int status = Data::BindValueFromJS(isolate, handle, index, value);
|
||||||
|
if (status != SQLITE_OK) {
|
||||||
|
switch (status) {
|
||||||
|
case -1:
|
||||||
|
return Fail(ThrowTypeError, "SQLite3 can only bind numbers, strings, bigints, buffers, and null");
|
||||||
|
case SQLITE_TOOBIG:
|
||||||
|
return Fail(ThrowRangeError, "The bound string, buffer, or bigint is too big");
|
||||||
|
case SQLITE_RANGE:
|
||||||
|
return Fail(ThrowRangeError, "Too many parameter values were provided");
|
||||||
|
case SQLITE_NOMEM:
|
||||||
|
return Fail(ThrowError, "Out of memory");
|
||||||
|
default:
|
||||||
|
return Fail(ThrowError, "An unexpected error occured while trying to bind parameters");
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binds each value in the array or throws an appropriate error.
|
||||||
|
// The number of successfully bound parameters is returned.
|
||||||
|
int BindArray(v8::Isolate* isolate, v8::Local<v8::Array> arr) {
|
||||||
|
UseContext;
|
||||||
|
uint32_t length = arr->Length();
|
||||||
|
if (length > INT_MAX) {
|
||||||
|
Fail(ThrowRangeError, "Too many parameter values were provided");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int len = static_cast<int>(length);
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
v8::MaybeLocal<v8::Value> maybeValue = arr->Get(ctx, i);
|
||||||
|
if (maybeValue.IsEmpty()) {
|
||||||
|
Fail(NULL, NULL);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
BindValue(isolate, maybeValue.ToLocalChecked(), NextAnonIndex());
|
||||||
|
if (!success) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binds all named parameters using the values found in the given object.
|
||||||
|
// The number of successfully bound parameters is returned.
|
||||||
|
// If a named parameter is missing from the object, an error is thrown.
|
||||||
|
// This should only be invoked once per instance.
|
||||||
|
int BindObject(v8::Isolate* isolate, v8::Local<v8::Object> obj, Statement* stmt) {
|
||||||
|
UseContext;
|
||||||
|
BindMap* bind_map = stmt->GetBindMap(isolate);
|
||||||
|
BindMap::Pair* pairs = bind_map->GetPairs();
|
||||||
|
int len = bind_map->GetSize();
|
||||||
|
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
v8::Local<v8::String> key = pairs[i].GetName(isolate);
|
||||||
|
|
||||||
|
// Check if the named parameter was provided.
|
||||||
|
v8::Maybe<bool> has_property = obj->HasOwnProperty(ctx, key);
|
||||||
|
if (has_property.IsNothing()) {
|
||||||
|
Fail(NULL, NULL);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
if (!has_property.FromJust()) {
|
||||||
|
v8::String::Utf8Value param_name(isolate, key);
|
||||||
|
Fail(ThrowRangeError, (std::string("Missing named parameter \"") + *param_name + "\"").c_str());
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current property value.
|
||||||
|
v8::MaybeLocal<v8::Value> maybeValue = obj->Get(ctx, key);
|
||||||
|
if (maybeValue.IsEmpty()) {
|
||||||
|
Fail(NULL, NULL);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
BindValue(isolate, maybeValue.ToLocalChecked(), pairs[i].GetIndex());
|
||||||
|
if (!success) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binds all parameters using the values found in the arguments object.
|
||||||
|
// Anonymous parameter values can be directly in the arguments object or in an Array.
|
||||||
|
// Named parameter values can be provided in a plain Object argument.
|
||||||
|
// Only one plain Object argument may be provided.
|
||||||
|
// If an error occurs, an appropriate error is thrown.
|
||||||
|
// The return value is a struct indicating how many parameters were successfully bound
|
||||||
|
// and whether or not it tried to bind an object.
|
||||||
|
Result BindArgs(NODE_ARGUMENTS info, int argc, Statement* stmt) {
|
||||||
|
UseIsolate;
|
||||||
|
int count = 0;
|
||||||
|
bool bound_object = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < argc; ++i) {
|
||||||
|
v8::Local<v8::Value> arg = info[i];
|
||||||
|
|
||||||
|
if (arg->IsArray()) {
|
||||||
|
count += BindArray(isolate, arg.As<v8::Array>());
|
||||||
|
if (!success) break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg->IsObject() && !node::Buffer::HasInstance(arg)) {
|
||||||
|
v8::Local<v8::Object> obj = arg.As<v8::Object>();
|
||||||
|
if (IsPlainObject(isolate, obj)) {
|
||||||
|
if (bound_object) {
|
||||||
|
Fail(ThrowTypeError, "You cannot specify named parameters in two different objects");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bound_object = true;
|
||||||
|
|
||||||
|
count += BindObject(isolate, obj, stmt);
|
||||||
|
if (!success) break;
|
||||||
|
continue;
|
||||||
|
} else if (stmt->GetBindMap(isolate)->GetSize()) {
|
||||||
|
Fail(ThrowTypeError, "Named parameters can only be passed within plain objects");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BindValue(isolate, arg, NextAnonIndex());
|
||||||
|
if (!success) break;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { count, bound_object };
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_stmt* handle;
|
||||||
|
int param_count;
|
||||||
|
int anon_index; // This value should only be used by NextAnonIndex()
|
||||||
|
bool success; // This value should only be set by Fail()
|
||||||
|
};
|
||||||
172
node_modules/better-sqlite3/src/util/constants.cpp
generated
vendored
Normal file
172
node_modules/better-sqlite3/src/util/constants.cpp
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
class CS {
|
||||||
|
public:
|
||||||
|
|
||||||
|
v8::Local<v8::String> Code(v8::Isolate* isolate, int code) {
|
||||||
|
auto element = codes.find(code);
|
||||||
|
if (element != codes.end()) return element->second.Get(isolate);
|
||||||
|
return StringFromUtf8(isolate, (std::string("UNKNOWN_SQLITE_ERROR_") + std::to_string(code)).c_str(), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit CS(v8::Isolate* isolate) {
|
||||||
|
SetString(isolate, database, "database");
|
||||||
|
SetString(isolate, reader, "reader");
|
||||||
|
SetString(isolate, source, "source");
|
||||||
|
SetString(isolate, memory, "memory");
|
||||||
|
SetString(isolate, readonly, "readonly");
|
||||||
|
SetString(isolate, name, "name");
|
||||||
|
SetString(isolate, next, "next");
|
||||||
|
SetString(isolate, length, "length");
|
||||||
|
SetString(isolate, done, "done");
|
||||||
|
SetString(isolate, value, "value");
|
||||||
|
SetString(isolate, changes, "changes");
|
||||||
|
SetString(isolate, lastInsertRowid, "lastInsertRowid");
|
||||||
|
SetString(isolate, statement, "statement");
|
||||||
|
SetString(isolate, column, "column");
|
||||||
|
SetString(isolate, table, "table");
|
||||||
|
SetString(isolate, type, "type");
|
||||||
|
SetString(isolate, totalPages, "totalPages");
|
||||||
|
SetString(isolate, remainingPages, "remainingPages");
|
||||||
|
|
||||||
|
SetCode(isolate, SQLITE_OK, "SQLITE_OK");
|
||||||
|
SetCode(isolate, SQLITE_ERROR, "SQLITE_ERROR");
|
||||||
|
SetCode(isolate, SQLITE_INTERNAL, "SQLITE_INTERNAL");
|
||||||
|
SetCode(isolate, SQLITE_PERM, "SQLITE_PERM");
|
||||||
|
SetCode(isolate, SQLITE_ABORT, "SQLITE_ABORT");
|
||||||
|
SetCode(isolate, SQLITE_BUSY, "SQLITE_BUSY");
|
||||||
|
SetCode(isolate, SQLITE_LOCKED, "SQLITE_LOCKED");
|
||||||
|
SetCode(isolate, SQLITE_NOMEM, "SQLITE_NOMEM");
|
||||||
|
SetCode(isolate, SQLITE_READONLY, "SQLITE_READONLY");
|
||||||
|
SetCode(isolate, SQLITE_INTERRUPT, "SQLITE_INTERRUPT");
|
||||||
|
SetCode(isolate, SQLITE_IOERR, "SQLITE_IOERR");
|
||||||
|
SetCode(isolate, SQLITE_CORRUPT, "SQLITE_CORRUPT");
|
||||||
|
SetCode(isolate, SQLITE_NOTFOUND, "SQLITE_NOTFOUND");
|
||||||
|
SetCode(isolate, SQLITE_FULL, "SQLITE_FULL");
|
||||||
|
SetCode(isolate, SQLITE_CANTOPEN, "SQLITE_CANTOPEN");
|
||||||
|
SetCode(isolate, SQLITE_PROTOCOL, "SQLITE_PROTOCOL");
|
||||||
|
SetCode(isolate, SQLITE_EMPTY, "SQLITE_EMPTY");
|
||||||
|
SetCode(isolate, SQLITE_SCHEMA, "SQLITE_SCHEMA");
|
||||||
|
SetCode(isolate, SQLITE_TOOBIG, "SQLITE_TOOBIG");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT, "SQLITE_CONSTRAINT");
|
||||||
|
SetCode(isolate, SQLITE_MISMATCH, "SQLITE_MISMATCH");
|
||||||
|
SetCode(isolate, SQLITE_MISUSE, "SQLITE_MISUSE");
|
||||||
|
SetCode(isolate, SQLITE_NOLFS, "SQLITE_NOLFS");
|
||||||
|
SetCode(isolate, SQLITE_AUTH, "SQLITE_AUTH");
|
||||||
|
SetCode(isolate, SQLITE_FORMAT, "SQLITE_FORMAT");
|
||||||
|
SetCode(isolate, SQLITE_RANGE, "SQLITE_RANGE");
|
||||||
|
SetCode(isolate, SQLITE_NOTADB, "SQLITE_NOTADB");
|
||||||
|
SetCode(isolate, SQLITE_NOTICE, "SQLITE_NOTICE");
|
||||||
|
SetCode(isolate, SQLITE_WARNING, "SQLITE_WARNING");
|
||||||
|
SetCode(isolate, SQLITE_ROW, "SQLITE_ROW");
|
||||||
|
SetCode(isolate, SQLITE_DONE, "SQLITE_DONE");
|
||||||
|
|
||||||
|
SetCode(isolate, SQLITE_ERROR_MISSING_COLLSEQ, "SQLITE_ERROR_MISSING_COLLSEQ");
|
||||||
|
SetCode(isolate, SQLITE_ERROR_RETRY, "SQLITE_ERROR_RETRY");
|
||||||
|
SetCode(isolate, SQLITE_ERROR_SNAPSHOT, "SQLITE_ERROR_SNAPSHOT");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_READ, "SQLITE_IOERR_READ");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_SHORT_READ, "SQLITE_IOERR_SHORT_READ");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_WRITE, "SQLITE_IOERR_WRITE");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_FSYNC, "SQLITE_IOERR_FSYNC");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_DIR_FSYNC, "SQLITE_IOERR_DIR_FSYNC");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_TRUNCATE, "SQLITE_IOERR_TRUNCATE");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_FSTAT, "SQLITE_IOERR_FSTAT");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_UNLOCK, "SQLITE_IOERR_UNLOCK");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_RDLOCK, "SQLITE_IOERR_RDLOCK");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_DELETE, "SQLITE_IOERR_DELETE");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_BLOCKED, "SQLITE_IOERR_BLOCKED");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_NOMEM, "SQLITE_IOERR_NOMEM");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_ACCESS, "SQLITE_IOERR_ACCESS");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_CHECKRESERVEDLOCK, "SQLITE_IOERR_CHECKRESERVEDLOCK");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_LOCK, "SQLITE_IOERR_LOCK");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_CLOSE, "SQLITE_IOERR_CLOSE");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_DIR_CLOSE, "SQLITE_IOERR_DIR_CLOSE");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_SHMOPEN, "SQLITE_IOERR_SHMOPEN");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_SHMSIZE, "SQLITE_IOERR_SHMSIZE");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_SHMLOCK, "SQLITE_IOERR_SHMLOCK");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_SHMMAP, "SQLITE_IOERR_SHMMAP");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_SEEK, "SQLITE_IOERR_SEEK");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_DELETE_NOENT, "SQLITE_IOERR_DELETE_NOENT");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_MMAP, "SQLITE_IOERR_MMAP");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_GETTEMPPATH, "SQLITE_IOERR_GETTEMPPATH");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_CONVPATH, "SQLITE_IOERR_CONVPATH");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_VNODE, "SQLITE_IOERR_VNODE");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_AUTH, "SQLITE_IOERR_AUTH");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_BEGIN_ATOMIC, "SQLITE_IOERR_BEGIN_ATOMIC");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_COMMIT_ATOMIC, "SQLITE_IOERR_COMMIT_ATOMIC");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_ROLLBACK_ATOMIC, "SQLITE_IOERR_ROLLBACK_ATOMIC");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_DATA, "SQLITE_IOERR_DATA");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_CORRUPTFS, "SQLITE_IOERR_CORRUPTFS");
|
||||||
|
SetCode(isolate, SQLITE_IOERR_IN_PAGE, "SQLITE_IOERR_IN_PAGE");
|
||||||
|
SetCode(isolate, SQLITE_LOCKED_SHAREDCACHE, "SQLITE_LOCKED_SHAREDCACHE");
|
||||||
|
SetCode(isolate, SQLITE_LOCKED_VTAB, "SQLITE_LOCKED_VTAB");
|
||||||
|
SetCode(isolate, SQLITE_BUSY_RECOVERY, "SQLITE_BUSY_RECOVERY");
|
||||||
|
SetCode(isolate, SQLITE_BUSY_SNAPSHOT, "SQLITE_BUSY_SNAPSHOT");
|
||||||
|
SetCode(isolate, SQLITE_CANTOPEN_NOTEMPDIR, "SQLITE_CANTOPEN_NOTEMPDIR");
|
||||||
|
SetCode(isolate, SQLITE_CANTOPEN_ISDIR, "SQLITE_CANTOPEN_ISDIR");
|
||||||
|
SetCode(isolate, SQLITE_CANTOPEN_FULLPATH, "SQLITE_CANTOPEN_FULLPATH");
|
||||||
|
SetCode(isolate, SQLITE_CANTOPEN_CONVPATH, "SQLITE_CANTOPEN_CONVPATH");
|
||||||
|
SetCode(isolate, SQLITE_CANTOPEN_DIRTYWAL, "SQLITE_CANTOPEN_DIRTYWAL");
|
||||||
|
SetCode(isolate, SQLITE_CANTOPEN_SYMLINK, "SQLITE_CANTOPEN_SYMLINK");
|
||||||
|
SetCode(isolate, SQLITE_CORRUPT_VTAB, "SQLITE_CORRUPT_VTAB");
|
||||||
|
SetCode(isolate, SQLITE_CORRUPT_SEQUENCE, "SQLITE_CORRUPT_SEQUENCE");
|
||||||
|
SetCode(isolate, SQLITE_CORRUPT_INDEX, "SQLITE_CORRUPT_INDEX");
|
||||||
|
SetCode(isolate, SQLITE_READONLY_RECOVERY, "SQLITE_READONLY_RECOVERY");
|
||||||
|
SetCode(isolate, SQLITE_READONLY_CANTLOCK, "SQLITE_READONLY_CANTLOCK");
|
||||||
|
SetCode(isolate, SQLITE_READONLY_ROLLBACK, "SQLITE_READONLY_ROLLBACK");
|
||||||
|
SetCode(isolate, SQLITE_READONLY_DBMOVED, "SQLITE_READONLY_DBMOVED");
|
||||||
|
SetCode(isolate, SQLITE_READONLY_CANTINIT, "SQLITE_READONLY_CANTINIT");
|
||||||
|
SetCode(isolate, SQLITE_READONLY_DIRECTORY, "SQLITE_READONLY_DIRECTORY");
|
||||||
|
SetCode(isolate, SQLITE_ABORT_ROLLBACK, "SQLITE_ABORT_ROLLBACK");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT_CHECK, "SQLITE_CONSTRAINT_CHECK");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT_COMMITHOOK, "SQLITE_CONSTRAINT_COMMITHOOK");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT_FOREIGNKEY, "SQLITE_CONSTRAINT_FOREIGNKEY");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT_FUNCTION, "SQLITE_CONSTRAINT_FUNCTION");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT_NOTNULL, "SQLITE_CONSTRAINT_NOTNULL");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT_PRIMARYKEY, "SQLITE_CONSTRAINT_PRIMARYKEY");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT_TRIGGER, "SQLITE_CONSTRAINT_TRIGGER");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT_UNIQUE, "SQLITE_CONSTRAINT_UNIQUE");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT_VTAB, "SQLITE_CONSTRAINT_VTAB");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT_ROWID, "SQLITE_CONSTRAINT_ROWID");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT_PINNED, "SQLITE_CONSTRAINT_PINNED");
|
||||||
|
SetCode(isolate, SQLITE_CONSTRAINT_DATATYPE, "SQLITE_CONSTRAINT_DATATYPE");
|
||||||
|
SetCode(isolate, SQLITE_NOTICE_RECOVER_WAL, "SQLITE_NOTICE_RECOVER_WAL");
|
||||||
|
SetCode(isolate, SQLITE_NOTICE_RECOVER_ROLLBACK, "SQLITE_NOTICE_RECOVER_ROLLBACK");
|
||||||
|
SetCode(isolate, SQLITE_NOTICE_RBU, "SQLITE_NOTICE_RBU");
|
||||||
|
SetCode(isolate, SQLITE_WARNING_AUTOINDEX, "SQLITE_WARNING_AUTOINDEX");
|
||||||
|
SetCode(isolate, SQLITE_AUTH_USER, "SQLITE_AUTH_USER");
|
||||||
|
SetCode(isolate, SQLITE_OK_LOAD_PERMANENTLY, "SQLITE_OK_LOAD_PERMANENTLY");
|
||||||
|
SetCode(isolate, SQLITE_OK_SYMLINK, "SQLITE_OK_SYMLINK");
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Global<v8::String> database;
|
||||||
|
v8::Global<v8::String> reader;
|
||||||
|
v8::Global<v8::String> source;
|
||||||
|
v8::Global<v8::String> memory;
|
||||||
|
v8::Global<v8::String> readonly;
|
||||||
|
v8::Global<v8::String> name;
|
||||||
|
v8::Global<v8::String> next;
|
||||||
|
v8::Global<v8::String> length;
|
||||||
|
v8::Global<v8::String> done;
|
||||||
|
v8::Global<v8::String> value;
|
||||||
|
v8::Global<v8::String> changes;
|
||||||
|
v8::Global<v8::String> lastInsertRowid;
|
||||||
|
v8::Global<v8::String> statement;
|
||||||
|
v8::Global<v8::String> column;
|
||||||
|
v8::Global<v8::String> table;
|
||||||
|
v8::Global<v8::String> type;
|
||||||
|
v8::Global<v8::String> totalPages;
|
||||||
|
v8::Global<v8::String> remainingPages;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static void SetString(v8::Isolate* isolate, v8::Global<v8::String>& constant, const char* str) {
|
||||||
|
constant.Reset(isolate, InternalizedFromLatin1(isolate, str));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCode(v8::Isolate* isolate, int code, const char* str) {
|
||||||
|
codes.emplace(std::piecewise_construct,
|
||||||
|
std::forward_as_tuple(code),
|
||||||
|
std::forward_as_tuple(isolate, InternalizedFromLatin1(isolate, str)));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<int, v8::Global<v8::String> > codes;
|
||||||
|
};
|
||||||
121
node_modules/better-sqlite3/src/util/custom-aggregate.cpp
generated
vendored
Normal file
121
node_modules/better-sqlite3/src/util/custom-aggregate.cpp
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
class CustomAggregate : public CustomFunction {
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit CustomAggregate(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
Database* db,
|
||||||
|
const char* name,
|
||||||
|
v8::Local<v8::Value> start,
|
||||||
|
v8::Local<v8::Function> step,
|
||||||
|
v8::Local<v8::Value> inverse,
|
||||||
|
v8::Local<v8::Value> result,
|
||||||
|
bool safe_ints
|
||||||
|
) :
|
||||||
|
CustomFunction(isolate, db, name, step, safe_ints),
|
||||||
|
invoke_result(result->IsFunction()),
|
||||||
|
invoke_start(start->IsFunction()),
|
||||||
|
inverse(isolate, inverse->IsFunction() ? inverse.As<v8::Function>() : v8::Local<v8::Function>()),
|
||||||
|
result(isolate, result->IsFunction() ? result.As<v8::Function>() : v8::Local<v8::Function>()),
|
||||||
|
start(isolate, start) {}
|
||||||
|
|
||||||
|
static void xStep(sqlite3_context* invocation, int argc, sqlite3_value** argv) {
|
||||||
|
xStepBase(invocation, argc, argv, &CustomAggregate::fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xInverse(sqlite3_context* invocation, int argc, sqlite3_value** argv) {
|
||||||
|
xStepBase(invocation, argc, argv, &CustomAggregate::inverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xValue(sqlite3_context* invocation) {
|
||||||
|
xValueBase(invocation, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xFinal(sqlite3_context* invocation) {
|
||||||
|
xValueBase(invocation, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static inline void xStepBase(sqlite3_context* invocation, int argc, sqlite3_value** argv, const v8::Global<v8::Function> CustomAggregate::*ptrtm) {
|
||||||
|
AGGREGATE_START();
|
||||||
|
|
||||||
|
v8::Local<v8::Value> args_fast[5];
|
||||||
|
v8::Local<v8::Value>* args = argc <= 4 ? args_fast : ALLOC_ARRAY<v8::Local<v8::Value>>(argc + 1);
|
||||||
|
args[0] = acc->value.Get(isolate);
|
||||||
|
if (argc != 0) Data::GetArgumentsJS(isolate, args + 1, argv, argc, self->safe_ints);
|
||||||
|
|
||||||
|
v8::MaybeLocal<v8::Value> maybeReturnValue = (self->*ptrtm).Get(isolate)->Call(OnlyContext, v8::Undefined(isolate), argc + 1, args);
|
||||||
|
if (args != args_fast) delete[] args;
|
||||||
|
|
||||||
|
if (maybeReturnValue.IsEmpty()) {
|
||||||
|
self->PropagateJSError(invocation);
|
||||||
|
} else {
|
||||||
|
v8::Local<v8::Value> returnValue = maybeReturnValue.ToLocalChecked();
|
||||||
|
if (!returnValue->IsUndefined()) acc->value.Reset(isolate, returnValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void xValueBase(sqlite3_context* invocation, bool is_final) {
|
||||||
|
AGGREGATE_START();
|
||||||
|
|
||||||
|
if (!is_final) {
|
||||||
|
acc->is_window = true;
|
||||||
|
} else if (acc->is_window) {
|
||||||
|
DestroyAccumulator(invocation);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> result = acc->value.Get(isolate);
|
||||||
|
if (self->invoke_result) {
|
||||||
|
v8::MaybeLocal<v8::Value> maybeResult = self->result.Get(isolate)->Call(OnlyContext, v8::Undefined(isolate), 1, &result);
|
||||||
|
if (maybeResult.IsEmpty()) {
|
||||||
|
self->PropagateJSError(invocation);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = maybeResult.ToLocalChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
Data::ResultValueFromJS(isolate, invocation, result, self);
|
||||||
|
if (is_final) DestroyAccumulator(invocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Accumulator { public:
|
||||||
|
v8::Global<v8::Value> value;
|
||||||
|
bool initialized;
|
||||||
|
bool is_window;
|
||||||
|
};
|
||||||
|
|
||||||
|
Accumulator* GetAccumulator(sqlite3_context* invocation) {
|
||||||
|
Accumulator* acc = static_cast<Accumulator*>(sqlite3_aggregate_context(invocation, sizeof(Accumulator)));
|
||||||
|
if (!acc->initialized) {
|
||||||
|
assert(acc->value.IsEmpty());
|
||||||
|
acc->initialized = true;
|
||||||
|
if (invoke_start) {
|
||||||
|
v8::MaybeLocal<v8::Value> maybeSeed = start.Get(isolate).As<v8::Function>()->Call(OnlyContext, v8::Undefined(isolate), 0, NULL);
|
||||||
|
if (maybeSeed.IsEmpty()) PropagateJSError(invocation);
|
||||||
|
else acc->value.Reset(isolate, maybeSeed.ToLocalChecked());
|
||||||
|
} else {
|
||||||
|
assert(!start.IsEmpty());
|
||||||
|
acc->value.Reset(isolate, start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DestroyAccumulator(sqlite3_context* invocation) {
|
||||||
|
Accumulator* acc = static_cast<Accumulator*>(sqlite3_aggregate_context(invocation, sizeof(Accumulator)));
|
||||||
|
assert(acc->initialized);
|
||||||
|
acc->value.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropagateJSError(sqlite3_context* invocation) {
|
||||||
|
DestroyAccumulator(invocation);
|
||||||
|
CustomFunction::PropagateJSError(invocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool invoke_result;
|
||||||
|
const bool invoke_start;
|
||||||
|
const v8::Global<v8::Function> inverse;
|
||||||
|
const v8::Global<v8::Function> result;
|
||||||
|
const v8::Global<v8::Value> start;
|
||||||
|
};
|
||||||
59
node_modules/better-sqlite3/src/util/custom-function.cpp
generated
vendored
Normal file
59
node_modules/better-sqlite3/src/util/custom-function.cpp
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
class CustomFunction : protected DataConverter {
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit CustomFunction(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
Database* db,
|
||||||
|
const char* name,
|
||||||
|
v8::Local<v8::Function> fn,
|
||||||
|
bool safe_ints
|
||||||
|
) :
|
||||||
|
name(name),
|
||||||
|
db(db),
|
||||||
|
isolate(isolate),
|
||||||
|
fn(isolate, fn),
|
||||||
|
safe_ints(safe_ints) {}
|
||||||
|
|
||||||
|
virtual ~CustomFunction() {}
|
||||||
|
|
||||||
|
static void xDestroy(void* self) {
|
||||||
|
delete static_cast<CustomFunction*>(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xFunc(sqlite3_context* invocation, int argc, sqlite3_value** argv) {
|
||||||
|
FUNCTION_START();
|
||||||
|
|
||||||
|
v8::Local<v8::Value> args_fast[4];
|
||||||
|
v8::Local<v8::Value>* args = NULL;
|
||||||
|
if (argc != 0) {
|
||||||
|
args = argc <= 4 ? args_fast : ALLOC_ARRAY<v8::Local<v8::Value>>(argc);
|
||||||
|
Data::GetArgumentsJS(isolate, args, argv, argc, self->safe_ints);
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::MaybeLocal<v8::Value> maybeReturnValue = self->fn.Get(isolate)->Call(OnlyContext, v8::Undefined(isolate), argc, args);
|
||||||
|
if (args != args_fast) delete[] args;
|
||||||
|
|
||||||
|
if (maybeReturnValue.IsEmpty()) self->PropagateJSError(invocation);
|
||||||
|
else Data::ResultValueFromJS(isolate, invocation, maybeReturnValue.ToLocalChecked(), self);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void PropagateJSError(sqlite3_context* invocation) {
|
||||||
|
assert(db->GetState()->was_js_error == false);
|
||||||
|
db->GetState()->was_js_error = true;
|
||||||
|
sqlite3_result_error(invocation, "", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetDataErrorPrefix() {
|
||||||
|
return std::string("User-defined function ") + name + "() returned";
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string name;
|
||||||
|
Database* const db;
|
||||||
|
protected:
|
||||||
|
v8::Isolate* const isolate;
|
||||||
|
const v8::Global<v8::Function> fn;
|
||||||
|
const bool safe_ints;
|
||||||
|
};
|
||||||
409
node_modules/better-sqlite3/src/util/custom-table.cpp
generated
vendored
Normal file
409
node_modules/better-sqlite3/src/util/custom-table.cpp
generated
vendored
Normal file
@@ -0,0 +1,409 @@
|
|||||||
|
class CustomTable {
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit CustomTable(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
Database* db,
|
||||||
|
const char* name,
|
||||||
|
v8::Local<v8::Function> factory
|
||||||
|
) :
|
||||||
|
addon(db->GetAddon()),
|
||||||
|
isolate(isolate),
|
||||||
|
db(db),
|
||||||
|
name(name),
|
||||||
|
factory(isolate, factory) {}
|
||||||
|
|
||||||
|
static void Destructor(void* self) {
|
||||||
|
delete static_cast<CustomTable*>(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static sqlite3_module MODULE;
|
||||||
|
static sqlite3_module EPONYMOUS_MODULE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// This nested class is instantiated on each CREATE VIRTUAL TABLE statement.
|
||||||
|
class VTab { friend class CustomTable;
|
||||||
|
explicit VTab(
|
||||||
|
CustomTable* parent,
|
||||||
|
v8::Local<v8::Function> generator,
|
||||||
|
std::vector<std::string> parameter_names,
|
||||||
|
bool safe_ints
|
||||||
|
) :
|
||||||
|
parent(parent),
|
||||||
|
parameter_count(parameter_names.size()),
|
||||||
|
safe_ints(safe_ints),
|
||||||
|
generator(parent->isolate, generator),
|
||||||
|
parameter_names(parameter_names) {
|
||||||
|
((void)base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline CustomTable::VTab* Upcast(sqlite3_vtab* vtab) {
|
||||||
|
return reinterpret_cast<VTab*>(vtab);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline sqlite3_vtab* Downcast() {
|
||||||
|
return reinterpret_cast<sqlite3_vtab*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_vtab base;
|
||||||
|
CustomTable * const parent;
|
||||||
|
const int parameter_count;
|
||||||
|
const bool safe_ints;
|
||||||
|
const v8::Global<v8::Function> generator;
|
||||||
|
const std::vector<std::string> parameter_names;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This nested class is instantiated each time a virtual table is scanned.
|
||||||
|
class Cursor { friend class CustomTable;
|
||||||
|
static inline CustomTable::Cursor* Upcast(sqlite3_vtab_cursor* cursor) {
|
||||||
|
return reinterpret_cast<Cursor*>(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline sqlite3_vtab_cursor* Downcast() {
|
||||||
|
return reinterpret_cast<sqlite3_vtab_cursor*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CustomTable::VTab* GetVTab() {
|
||||||
|
return VTab::Upcast(base.pVtab);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_vtab_cursor base;
|
||||||
|
v8::Global<v8::Object> iterator;
|
||||||
|
v8::Global<v8::Function> next;
|
||||||
|
v8::Global<v8::Array> row;
|
||||||
|
bool done;
|
||||||
|
sqlite_int64 rowid;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This nested class is used by Data::ResultValueFromJS to report errors.
|
||||||
|
class TempDataConverter : DataConverter { friend class CustomTable;
|
||||||
|
explicit TempDataConverter(CustomTable* parent) :
|
||||||
|
parent(parent),
|
||||||
|
status(SQLITE_OK) {}
|
||||||
|
|
||||||
|
void PropagateJSError(sqlite3_context* invocation) {
|
||||||
|
status = SQLITE_ERROR;
|
||||||
|
parent->PropagateJSError();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetDataErrorPrefix() {
|
||||||
|
return std::string("Virtual table module \"") + parent->name + "\" yielded";
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTable * const parent;
|
||||||
|
int status;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Although this function does nothing, we cannot use xConnect directly,
|
||||||
|
// because that would cause SQLite to register an eponymous virtual table.
|
||||||
|
static int xCreate(sqlite3* db_handle, void* _self, int argc, const char* const * argv, sqlite3_vtab** output, char** errOutput) {
|
||||||
|
return xConnect(db_handle, _self, argc, argv, output, errOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method uses the factory function to instantiate a new virtual table.
|
||||||
|
static int xConnect(sqlite3* db_handle, void* _self, int argc, const char* const * argv, sqlite3_vtab** output, char** errOutput) {
|
||||||
|
CustomTable* self = static_cast<CustomTable*>(_self);
|
||||||
|
v8::Isolate* isolate = self->isolate;
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
|
UseContext;
|
||||||
|
|
||||||
|
v8::Local<v8::Value>* args = ALLOC_ARRAY<v8::Local<v8::Value>>(argc);
|
||||||
|
for (int i = 0; i < argc; ++i) {
|
||||||
|
args[i] = StringFromUtf8(isolate, argv[i], -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the factory function to receive a new virtual table definition.
|
||||||
|
v8::MaybeLocal<v8::Value> maybeReturnValue = self->factory.Get(isolate)->Call(ctx, v8::Undefined(isolate), argc, args);
|
||||||
|
delete[] args;
|
||||||
|
|
||||||
|
if (maybeReturnValue.IsEmpty()) {
|
||||||
|
self->PropagateJSError();
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract each part of the virtual table definition.
|
||||||
|
v8::Local<v8::Array> returnValue = maybeReturnValue.ToLocalChecked().As<v8::Array>();
|
||||||
|
v8::Local<v8::String> sqlString = returnValue->Get(ctx, 0).ToLocalChecked().As<v8::String>();
|
||||||
|
v8::Local<v8::Function> generator = returnValue->Get(ctx, 1).ToLocalChecked().As<v8::Function>();
|
||||||
|
v8::Local<v8::Array> parameterNames = returnValue->Get(ctx, 2).ToLocalChecked().As<v8::Array>();
|
||||||
|
int safe_ints = returnValue->Get(ctx, 3).ToLocalChecked().As<v8::Int32>()->Value();
|
||||||
|
bool direct_only = returnValue->Get(ctx, 4).ToLocalChecked().As<v8::Boolean>()->Value();
|
||||||
|
|
||||||
|
v8::String::Utf8Value sql(isolate, sqlString);
|
||||||
|
safe_ints = safe_ints < 2 ? safe_ints : static_cast<int>(self->db->GetState()->safe_ints);
|
||||||
|
|
||||||
|
// Copy the parameter names into a std::vector.
|
||||||
|
std::vector<std::string> parameter_names;
|
||||||
|
for (int i = 0, len = parameterNames->Length(); i < len; ++i) {
|
||||||
|
v8::Local<v8::String> parameterName = parameterNames->Get(ctx, i).ToLocalChecked().As<v8::String>();
|
||||||
|
v8::String::Utf8Value parameter_name(isolate, parameterName);
|
||||||
|
parameter_names.emplace_back(*parameter_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass our SQL table definition to SQLite (this should never fail).
|
||||||
|
if (sqlite3_declare_vtab(db_handle, *sql) != SQLITE_OK) {
|
||||||
|
*errOutput = sqlite3_mprintf("failed to declare virtual table \"%s\"", argv[2]);
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
if (direct_only && sqlite3_vtab_config(db_handle, SQLITE_VTAB_DIRECTONLY) != SQLITE_OK) {
|
||||||
|
*errOutput = sqlite3_mprintf("failed to configure virtual table \"%s\"", argv[2]);
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the successfully created virtual table.
|
||||||
|
*output = (new VTab(self, generator, parameter_names, safe_ints))->Downcast();
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xDisconnect(sqlite3_vtab* vtab) {
|
||||||
|
delete VTab::Upcast(vtab);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xOpen(sqlite3_vtab* vtab, sqlite3_vtab_cursor** output) {
|
||||||
|
*output = (new Cursor())->Downcast();
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xClose(sqlite3_vtab_cursor* cursor) {
|
||||||
|
delete Cursor::Upcast(cursor);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method uses a fresh cursor to start a new scan of a virtual table.
|
||||||
|
// The args and idxNum are provided by xBestIndex (idxStr is unused).
|
||||||
|
// idxNum is a bitmap that provides the proper indices of the received args.
|
||||||
|
static int xFilter(sqlite3_vtab_cursor* _cursor, int idxNum, const char* idxStr, int argc, sqlite3_value** argv) {
|
||||||
|
Cursor* cursor = Cursor::Upcast(_cursor);
|
||||||
|
VTab* vtab = cursor->GetVTab();
|
||||||
|
CustomTable* self = vtab->parent;
|
||||||
|
Addon* addon = self->addon;
|
||||||
|
v8::Isolate* isolate = self->isolate;
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
|
UseContext;
|
||||||
|
|
||||||
|
// Convert the SQLite arguments into JavaScript arguments. Note that
|
||||||
|
// the values in argv may be in the wrong order, so we fix that here.
|
||||||
|
v8::Local<v8::Value> args_fast[4];
|
||||||
|
v8::Local<v8::Value>* args = NULL;
|
||||||
|
int parameter_count = vtab->parameter_count;
|
||||||
|
if (parameter_count != 0) {
|
||||||
|
args = parameter_count <= 4 ? args_fast : ALLOC_ARRAY<v8::Local<v8::Value>>(parameter_count);
|
||||||
|
int argn = 0;
|
||||||
|
bool safe_ints = vtab->safe_ints;
|
||||||
|
for (int i = 0; i < parameter_count; ++i) {
|
||||||
|
if (idxNum & 1 << i) {
|
||||||
|
args[i] = Data::GetValueJS(isolate, argv[argn++], safe_ints);
|
||||||
|
// If any arguments are NULL, the result set is necessarily
|
||||||
|
// empty, so don't bother to run the generator function.
|
||||||
|
if (args[i]->IsNull()) {
|
||||||
|
if (args != args_fast) delete[] args;
|
||||||
|
cursor->done = true;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args[i] = v8::Undefined(isolate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke the generator function to create a new iterator.
|
||||||
|
v8::MaybeLocal<v8::Value> maybeIterator = vtab->generator.Get(isolate)->Call(ctx, v8::Undefined(isolate), parameter_count, args);
|
||||||
|
if (args != args_fast) delete[] args;
|
||||||
|
|
||||||
|
if (maybeIterator.IsEmpty()) {
|
||||||
|
self->PropagateJSError();
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the iterator and its next() method; we'll be using it a lot.
|
||||||
|
v8::Local<v8::Object> iterator = maybeIterator.ToLocalChecked().As<v8::Object>();
|
||||||
|
v8::Local<v8::Function> next = iterator->Get(ctx, addon->cs.next.Get(isolate)).ToLocalChecked().As<v8::Function>();
|
||||||
|
cursor->iterator.Reset(isolate, iterator);
|
||||||
|
cursor->next.Reset(isolate, next);
|
||||||
|
cursor->rowid = 0;
|
||||||
|
|
||||||
|
// Advance the iterator/cursor to the first row.
|
||||||
|
return xNext(cursor->Downcast());
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method advances a virtual table's cursor to the next row.
|
||||||
|
// SQLite will call this method repeatedly, driving the generator function.
|
||||||
|
static int xNext(sqlite3_vtab_cursor* _cursor) {
|
||||||
|
Cursor* cursor = Cursor::Upcast(_cursor);
|
||||||
|
CustomTable* self = cursor->GetVTab()->parent;
|
||||||
|
Addon* addon = self->addon;
|
||||||
|
v8::Isolate* isolate = self->isolate;
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
|
UseContext;
|
||||||
|
|
||||||
|
v8::Local<v8::Object> iterator = cursor->iterator.Get(isolate);
|
||||||
|
v8::Local<v8::Function> next = cursor->next.Get(isolate);
|
||||||
|
|
||||||
|
v8::MaybeLocal<v8::Value> maybeRecord = next->Call(ctx, iterator, 0, NULL);
|
||||||
|
if (maybeRecord.IsEmpty()) {
|
||||||
|
self->PropagateJSError();
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Object> record = maybeRecord.ToLocalChecked().As<v8::Object>();
|
||||||
|
bool done = record->Get(ctx, addon->cs.done.Get(isolate)).ToLocalChecked().As<v8::Boolean>()->Value();
|
||||||
|
if (!done) {
|
||||||
|
cursor->row.Reset(isolate, record->Get(ctx, addon->cs.value.Get(isolate)).ToLocalChecked().As<v8::Array>());
|
||||||
|
}
|
||||||
|
cursor->done = done;
|
||||||
|
cursor->rowid += 1;
|
||||||
|
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this method returns 1, SQLite will stop scanning the virtual table.
|
||||||
|
static int xEof(sqlite3_vtab_cursor* cursor) {
|
||||||
|
return Cursor::Upcast(cursor)->done;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method extracts some column from the cursor's current row.
|
||||||
|
static int xColumn(sqlite3_vtab_cursor* _cursor, sqlite3_context* invocation, int column) {
|
||||||
|
Cursor* cursor = Cursor::Upcast(_cursor);
|
||||||
|
CustomTable* self = cursor->GetVTab()->parent;
|
||||||
|
TempDataConverter temp_data_converter(self);
|
||||||
|
v8::Isolate* isolate = self->isolate;
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
|
|
||||||
|
v8::Local<v8::Array> row = cursor->row.Get(isolate);
|
||||||
|
v8::MaybeLocal<v8::Value> maybeColumnValue = row->Get(OnlyContext, column);
|
||||||
|
if (maybeColumnValue.IsEmpty()) {
|
||||||
|
temp_data_converter.PropagateJSError(NULL);
|
||||||
|
} else {
|
||||||
|
Data::ResultValueFromJS(isolate, invocation, maybeColumnValue.ToLocalChecked(), &temp_data_converter);
|
||||||
|
}
|
||||||
|
return temp_data_converter.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method outputs the rowid of the cursor's current row.
|
||||||
|
static int xRowid(sqlite3_vtab_cursor* cursor, sqlite_int64* output) {
|
||||||
|
*output = Cursor::Upcast(cursor)->rowid;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method tells SQLite how to *plan* queries on our virtual table.
|
||||||
|
// It gets invoked (typically multiple times) during db.prepare().
|
||||||
|
static int xBestIndex(sqlite3_vtab* vtab, sqlite3_index_info* output) {
|
||||||
|
int parameter_count = VTab::Upcast(vtab)->parameter_count;
|
||||||
|
int argument_count = 0;
|
||||||
|
std::vector<std::pair<int, int>> forwarded;
|
||||||
|
|
||||||
|
for (int i = 0, len = output->nConstraint; i < len; ++i) {
|
||||||
|
auto item = output->aConstraint[i];
|
||||||
|
|
||||||
|
// The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET
|
||||||
|
// operators have no left-hand operand, and so for those operators the
|
||||||
|
// corresponding item.iColumn is meaningless.
|
||||||
|
// We don't care those constraints.
|
||||||
|
if (item.op == SQLITE_INDEX_CONSTRAINT_LIMIT || item.op == SQLITE_INDEX_CONSTRAINT_OFFSET) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// We only care about constraints on parameters, not regular columns.
|
||||||
|
if (item.iColumn >= 0 && item.iColumn < parameter_count) {
|
||||||
|
if (item.op != SQLITE_INDEX_CONSTRAINT_EQ) {
|
||||||
|
sqlite3_free(vtab->zErrMsg);
|
||||||
|
vtab->zErrMsg = sqlite3_mprintf(
|
||||||
|
"virtual table parameter \"%s\" can only be constrained by the '=' operator",
|
||||||
|
VTab::Upcast(vtab)->parameter_names.at(item.iColumn).c_str());
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
if (!item.usable) {
|
||||||
|
// Don't allow SQLite to make plans that ignore arguments.
|
||||||
|
// Otherwise, a user could pass arguments, but then they
|
||||||
|
// could appear undefined in the generator function.
|
||||||
|
return SQLITE_CONSTRAINT;
|
||||||
|
}
|
||||||
|
forwarded.emplace_back(item.iColumn, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell SQLite to forward arguments to xFilter.
|
||||||
|
std::sort(forwarded.begin(), forwarded.end());
|
||||||
|
for (std::pair<int, int> pair : forwarded) {
|
||||||
|
int bit = 1 << pair.first;
|
||||||
|
if (!(output->idxNum & bit)) {
|
||||||
|
output->idxNum |= bit;
|
||||||
|
output->aConstraintUsage[pair.second].argvIndex = ++argument_count;
|
||||||
|
output->aConstraintUsage[pair.second].omit = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use a very high estimated cost so SQLite is not tempted to invoke the
|
||||||
|
// generator function within a loop, if it can be avoided.
|
||||||
|
output->estimatedCost = output->estimatedRows = 1000000000 / (argument_count + 1);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropagateJSError() {
|
||||||
|
assert(db->GetState()->was_js_error == false);
|
||||||
|
db->GetState()->was_js_error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addon* const addon;
|
||||||
|
v8::Isolate* const isolate;
|
||||||
|
Database* const db;
|
||||||
|
const std::string name;
|
||||||
|
const v8::Global<v8::Function> factory;
|
||||||
|
};
|
||||||
|
|
||||||
|
sqlite3_module CustomTable::MODULE = {
|
||||||
|
0, /* iVersion */
|
||||||
|
xCreate, /* xCreate */
|
||||||
|
xConnect, /* xConnect */
|
||||||
|
xBestIndex, /* xBestIndex */
|
||||||
|
xDisconnect, /* xDisconnect */
|
||||||
|
xDisconnect, /* xDestroy */
|
||||||
|
xOpen, /* xOpen */
|
||||||
|
xClose, /* xClose */
|
||||||
|
xFilter, /* xFilter */
|
||||||
|
xNext, /* xNext */
|
||||||
|
xEof, /* xEof */
|
||||||
|
xColumn, /* xColumn */
|
||||||
|
xRowid, /* xRowid */
|
||||||
|
NULL, /* xUpdate */
|
||||||
|
NULL, /* xBegin */
|
||||||
|
NULL, /* xSync */
|
||||||
|
NULL, /* xCommit */
|
||||||
|
NULL, /* xRollback */
|
||||||
|
NULL, /* xFindMethod */
|
||||||
|
NULL, /* xRename */
|
||||||
|
NULL, /* xSavepoint */
|
||||||
|
NULL, /* xRelease */
|
||||||
|
NULL, /* xRollbackTo */
|
||||||
|
NULL, /* xShadowName */
|
||||||
|
NULL /* xIntegrity */
|
||||||
|
};
|
||||||
|
|
||||||
|
sqlite3_module CustomTable::EPONYMOUS_MODULE = {
|
||||||
|
0, /* iVersion */
|
||||||
|
NULL, /* xCreate */
|
||||||
|
xConnect, /* xConnect */
|
||||||
|
xBestIndex, /* xBestIndex */
|
||||||
|
xDisconnect, /* xDisconnect */
|
||||||
|
xDisconnect, /* xDestroy */
|
||||||
|
xOpen, /* xOpen */
|
||||||
|
xClose, /* xClose */
|
||||||
|
xFilter, /* xFilter */
|
||||||
|
xNext, /* xNext */
|
||||||
|
xEof, /* xEof */
|
||||||
|
xColumn, /* xColumn */
|
||||||
|
xRowid, /* xRowid */
|
||||||
|
NULL, /* xUpdate */
|
||||||
|
NULL, /* xBegin */
|
||||||
|
NULL, /* xSync */
|
||||||
|
NULL, /* xCommit */
|
||||||
|
NULL, /* xRollback */
|
||||||
|
NULL, /* xFindMethod */
|
||||||
|
NULL, /* xRename */
|
||||||
|
NULL, /* xSavepoint */
|
||||||
|
NULL, /* xRelease */
|
||||||
|
NULL, /* xRollbackTo */
|
||||||
|
NULL, /* xShadowName */
|
||||||
|
NULL /* xIntegrity */
|
||||||
|
};
|
||||||
17
node_modules/better-sqlite3/src/util/data-converter.cpp
generated
vendored
Normal file
17
node_modules/better-sqlite3/src/util/data-converter.cpp
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
class DataConverter {
|
||||||
|
public:
|
||||||
|
|
||||||
|
void ThrowDataConversionError(sqlite3_context* invocation, bool isBigInt) {
|
||||||
|
if (isBigInt) {
|
||||||
|
ThrowRangeError((GetDataErrorPrefix() + " a bigint that was too big").c_str());
|
||||||
|
} else {
|
||||||
|
ThrowTypeError((GetDataErrorPrefix() + " an invalid value").c_str());
|
||||||
|
}
|
||||||
|
PropagateJSError(invocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual void PropagateJSError(sqlite3_context* invocation) = 0;
|
||||||
|
virtual std::string GetDataErrorPrefix() = 0;
|
||||||
|
};
|
||||||
194
node_modules/better-sqlite3/src/util/data.cpp
generated
vendored
Normal file
194
node_modules/better-sqlite3/src/util/data.cpp
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
#define JS_VALUE_TO_SQLITE(to, value, isolate, ...) \
|
||||||
|
if (value->IsNumber()) { \
|
||||||
|
return sqlite3_##to##_double( \
|
||||||
|
__VA_ARGS__, \
|
||||||
|
value.As<v8::Number>()->Value() \
|
||||||
|
); \
|
||||||
|
} else if (value->IsBigInt()) { \
|
||||||
|
bool lossless; \
|
||||||
|
int64_t v = value.As<v8::BigInt>()->Int64Value(&lossless); \
|
||||||
|
if (lossless) { \
|
||||||
|
return sqlite3_##to##_int64(__VA_ARGS__, v); \
|
||||||
|
} \
|
||||||
|
} else if (value->IsString()) { \
|
||||||
|
v8::String::Utf8Value utf8(isolate, value.As<v8::String>()); \
|
||||||
|
return sqlite3_##to##_text( \
|
||||||
|
__VA_ARGS__, \
|
||||||
|
*utf8, \
|
||||||
|
utf8.length(), \
|
||||||
|
SQLITE_TRANSIENT \
|
||||||
|
); \
|
||||||
|
} else if (node::Buffer::HasInstance(value)) { \
|
||||||
|
const char* data = node::Buffer::Data(value); \
|
||||||
|
return sqlite3_##to##_blob( \
|
||||||
|
__VA_ARGS__, \
|
||||||
|
data ? data : "", \
|
||||||
|
node::Buffer::Length(value), \
|
||||||
|
SQLITE_TRANSIENT \
|
||||||
|
); \
|
||||||
|
} else if (value->IsNull() || value->IsUndefined()) { \
|
||||||
|
return sqlite3_##to##_null(__VA_ARGS__); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SQLITE_VALUE_TO_JS(from, isolate, safe_ints, ...) \
|
||||||
|
switch (sqlite3_##from##_type(__VA_ARGS__)) { \
|
||||||
|
case SQLITE_INTEGER: \
|
||||||
|
if (safe_ints) { \
|
||||||
|
return v8::BigInt::New( \
|
||||||
|
isolate, \
|
||||||
|
sqlite3_##from##_int64(__VA_ARGS__) \
|
||||||
|
); \
|
||||||
|
} \
|
||||||
|
case SQLITE_FLOAT: \
|
||||||
|
return v8::Number::New( \
|
||||||
|
isolate, \
|
||||||
|
sqlite3_##from##_double(__VA_ARGS__) \
|
||||||
|
); \
|
||||||
|
case SQLITE_TEXT: \
|
||||||
|
return StringFromUtf8( \
|
||||||
|
isolate, \
|
||||||
|
reinterpret_cast<const char*>(sqlite3_##from##_text(__VA_ARGS__)), \
|
||||||
|
sqlite3_##from##_bytes(__VA_ARGS__) \
|
||||||
|
); \
|
||||||
|
case SQLITE_BLOB: \
|
||||||
|
return node::Buffer::Copy( \
|
||||||
|
isolate, \
|
||||||
|
static_cast<const char*>(sqlite3_##from##_blob(__VA_ARGS__)), \
|
||||||
|
sqlite3_##from##_bytes(__VA_ARGS__) \
|
||||||
|
).ToLocalChecked(); \
|
||||||
|
default: \
|
||||||
|
assert(sqlite3_##from##_type(__VA_ARGS__) == SQLITE_NULL); \
|
||||||
|
return v8::Null(isolate); \
|
||||||
|
} \
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
|
||||||
|
static const char FLAT = 0;
|
||||||
|
static const char PLUCK = 1;
|
||||||
|
static const char EXPAND = 2;
|
||||||
|
static const char RAW = 3;
|
||||||
|
|
||||||
|
v8::Local<v8::Value> GetValueJS(v8::Isolate* isolate, sqlite3_stmt* handle, int column, bool safe_ints) {
|
||||||
|
SQLITE_VALUE_TO_JS(column, isolate, safe_ints, handle, column);
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> GetValueJS(v8::Isolate* isolate, sqlite3_value* value, bool safe_ints) {
|
||||||
|
SQLITE_VALUE_TO_JS(value, isolate, safe_ints, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> GetExpandedRowJS(v8::Isolate* isolate, v8::Local<v8::Context> ctx, sqlite3_stmt* handle, bool safe_ints) {
|
||||||
|
v8::Local<v8::Object> row = v8::Object::New(isolate);
|
||||||
|
int column_count = sqlite3_column_count(handle);
|
||||||
|
for (int i = 0; i < column_count; ++i) {
|
||||||
|
const char* table_raw = sqlite3_column_table_name(handle, i);
|
||||||
|
v8::Local<v8::String> table = InternalizedFromUtf8(isolate, table_raw == NULL ? "$" : table_raw, -1);
|
||||||
|
v8::Local<v8::String> column = InternalizedFromUtf8(isolate, sqlite3_column_name(handle, i), -1);
|
||||||
|
v8::Local<v8::Value> value = Data::GetValueJS(isolate, handle, i, safe_ints);
|
||||||
|
if (row->HasOwnProperty(ctx, table).FromJust()) {
|
||||||
|
row->Get(ctx, table).ToLocalChecked().As<v8::Object>()->Set(ctx, column, value).FromJust();
|
||||||
|
} else {
|
||||||
|
v8::Local<v8::Object> nested = v8::Object::New(isolate);
|
||||||
|
row->Set(ctx, table, nested).FromJust();
|
||||||
|
nested->Set(ctx, column, value).FromJust();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(NODE_MODULE_VERSION) || NODE_MODULE_VERSION < 127
|
||||||
|
|
||||||
|
v8::Local<v8::Value> GetFlatRowJS(v8::Isolate* isolate, v8::Local<v8::Context> ctx, sqlite3_stmt* handle, bool safe_ints) {
|
||||||
|
v8::Local<v8::Object> row = v8::Object::New(isolate);
|
||||||
|
int column_count = sqlite3_column_count(handle);
|
||||||
|
for (int i = 0; i < column_count; ++i) {
|
||||||
|
row->Set(ctx,
|
||||||
|
InternalizedFromUtf8(isolate, sqlite3_column_name(handle, i), -1),
|
||||||
|
Data::GetValueJS(isolate, handle, i, safe_ints)
|
||||||
|
).FromJust();
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> GetRawRowJS(v8::Isolate* isolate, v8::Local<v8::Context> ctx, sqlite3_stmt* handle, bool safe_ints) {
|
||||||
|
v8::Local<v8::Array> row = v8::Array::New(isolate);
|
||||||
|
int column_count = sqlite3_column_count(handle);
|
||||||
|
for (int i = 0; i < column_count; ++i) {
|
||||||
|
row->Set(ctx, i, Data::GetValueJS(isolate, handle, i, safe_ints)).FromJust();
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> GetRowJS(v8::Isolate* isolate, v8::Local<v8::Context> ctx, sqlite3_stmt* handle, bool safe_ints, char mode) {
|
||||||
|
if (mode == FLAT) return GetFlatRowJS(isolate, ctx, handle, safe_ints);
|
||||||
|
if (mode == PLUCK) return GetValueJS(isolate, handle, 0, safe_ints);
|
||||||
|
if (mode == EXPAND) return GetExpandedRowJS(isolate, ctx, handle, safe_ints);
|
||||||
|
if (mode == RAW) return GetRawRowJS(isolate, ctx, handle, safe_ints);
|
||||||
|
assert(false);
|
||||||
|
return v8::Local<v8::Value>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
v8::Local<v8::Value> GetFlatRowJS(v8::Isolate* isolate, sqlite3_stmt* handle, bool safe_ints) {
|
||||||
|
int column_count = sqlite3_column_count(handle);
|
||||||
|
v8::LocalVector<v8::Name> keys(isolate);
|
||||||
|
v8::LocalVector<v8::Value> values(isolate);
|
||||||
|
keys.reserve(column_count);
|
||||||
|
values.reserve(column_count);
|
||||||
|
for (int i = 0; i < column_count; ++i) {
|
||||||
|
keys.emplace_back(
|
||||||
|
InternalizedFromUtf8(isolate, sqlite3_column_name(handle, i), -1).As<v8::Name>()
|
||||||
|
);
|
||||||
|
values.emplace_back(
|
||||||
|
Data::GetValueJS(isolate, handle, i, safe_ints)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return v8::Object::New(
|
||||||
|
isolate,
|
||||||
|
GET_PROTOTYPE(v8::Object::New(isolate)),
|
||||||
|
keys.data(),
|
||||||
|
values.data(),
|
||||||
|
column_count
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> GetRawRowJS(v8::Isolate* isolate, sqlite3_stmt* handle, bool safe_ints) {
|
||||||
|
int column_count = sqlite3_column_count(handle);
|
||||||
|
v8::LocalVector<v8::Value> row(isolate);
|
||||||
|
row.reserve(column_count);
|
||||||
|
for (int i = 0; i < column_count; ++i) {
|
||||||
|
row.emplace_back(Data::GetValueJS(isolate, handle, i, safe_ints));
|
||||||
|
}
|
||||||
|
return v8::Array::New(isolate, row.data(), row.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> GetRowJS(v8::Isolate* isolate, v8::Local<v8::Context> ctx, sqlite3_stmt* handle, bool safe_ints, char mode) {
|
||||||
|
if (mode == FLAT) return GetFlatRowJS(isolate, handle, safe_ints);
|
||||||
|
if (mode == PLUCK) return GetValueJS(isolate, handle, 0, safe_ints);
|
||||||
|
if (mode == EXPAND) return GetExpandedRowJS(isolate, ctx, handle, safe_ints);
|
||||||
|
if (mode == RAW) return GetRawRowJS(isolate, handle, safe_ints);
|
||||||
|
assert(false);
|
||||||
|
return v8::Local<v8::Value>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void GetArgumentsJS(v8::Isolate* isolate, v8::Local<v8::Value>* out, sqlite3_value** values, int argument_count, bool safe_ints) {
|
||||||
|
assert(argument_count > 0);
|
||||||
|
for (int i = 0; i < argument_count; ++i) {
|
||||||
|
out[i] = Data::GetValueJS(isolate, values[i], safe_ints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int BindValueFromJS(v8::Isolate* isolate, sqlite3_stmt* handle, int index, v8::Local<v8::Value> value) {
|
||||||
|
JS_VALUE_TO_SQLITE(bind, value, isolate, handle, index);
|
||||||
|
return value->IsBigInt() ? SQLITE_TOOBIG : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResultValueFromJS(v8::Isolate* isolate, sqlite3_context* invocation, v8::Local<v8::Value> value, DataConverter* converter) {
|
||||||
|
JS_VALUE_TO_SQLITE(result, value, isolate, invocation);
|
||||||
|
converter->ThrowDataConversionError(invocation, value->IsBigInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
109
node_modules/better-sqlite3/src/util/helpers.cpp
generated
vendored
Normal file
109
node_modules/better-sqlite3/src/util/helpers.cpp
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
inline v8::Local<v8::String> StringFromUtf8(v8::Isolate* isolate, const char* data, int length) {
|
||||||
|
return v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal, length).ToLocalChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline v8::Local<v8::String> InternalizedFromUtf8(v8::Isolate* isolate, const char* data, int length) {
|
||||||
|
return v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kInternalized, length).ToLocalChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline v8::Local<v8::Value> InternalizedFromUtf8OrNull(v8::Isolate* isolate, const char* data, int length) {
|
||||||
|
if (data == NULL) return v8::Null(isolate);
|
||||||
|
return InternalizedFromUtf8(isolate, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline v8::Local<v8::String> InternalizedFromLatin1(v8::Isolate* isolate, const char* str) {
|
||||||
|
return v8::String::NewFromOneByte(isolate, reinterpret_cast<const uint8_t*>(str), v8::NewStringType::kInternalized).ToLocalChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetFrozen(v8::Isolate* isolate, v8::Local<v8::Context> ctx, v8::Local<v8::Object> obj, v8::Global<v8::String>& key, v8::Local<v8::Value> value) {
|
||||||
|
obj->DefineOwnProperty(ctx, key.Get(isolate), value, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly)).FromJust();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThrowError(const char* message) { EasyIsolate; isolate->ThrowException(v8::Exception::Error(StringFromUtf8(isolate, message, -1))); }
|
||||||
|
void ThrowTypeError(const char* message) { EasyIsolate; isolate->ThrowException(v8::Exception::TypeError(StringFromUtf8(isolate, message, -1))); }
|
||||||
|
void ThrowRangeError(const char* message) { EasyIsolate; isolate->ThrowException(v8::Exception::RangeError(StringFromUtf8(isolate, message, -1))); }
|
||||||
|
|
||||||
|
// Determines whether to skip the given character at the start of an SQL string.
|
||||||
|
inline bool IS_SKIPPED(char c) {
|
||||||
|
return c == ' ' || c == ';' || (c >= '\t' && c <= '\r');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates an empty array, without calling constructors/initializers.
|
||||||
|
template<class T> inline T* ALLOC_ARRAY(size_t count) {
|
||||||
|
return static_cast<T*>(::operator new[](count * sizeof(T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deallocates an array, without calling destructors.
|
||||||
|
template<class T> inline void FREE_ARRAY(T* array_pointer) {
|
||||||
|
::operator delete[](array_pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::FunctionTemplate> NewConstructorTemplate(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::External> data,
|
||||||
|
v8::FunctionCallback func,
|
||||||
|
const char* name
|
||||||
|
) {
|
||||||
|
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate, func, data);
|
||||||
|
t->InstanceTemplate()->SetInternalFieldCount(1);
|
||||||
|
t->SetClassName(InternalizedFromLatin1(isolate, name));
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPrototypeMethod(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::External> data,
|
||||||
|
v8::Local<v8::FunctionTemplate> recv,
|
||||||
|
const char* name,
|
||||||
|
v8::FunctionCallback func
|
||||||
|
) {
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
|
recv->PrototypeTemplate()->Set(
|
||||||
|
InternalizedFromLatin1(isolate, name),
|
||||||
|
v8::FunctionTemplate::New(isolate, func, data, v8::Signature::New(isolate, recv))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPrototypeSymbolMethod(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::External> data,
|
||||||
|
v8::Local<v8::FunctionTemplate> recv,
|
||||||
|
v8::Local<v8::Symbol> symbol,
|
||||||
|
v8::FunctionCallback func
|
||||||
|
) {
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
|
recv->PrototypeTemplate()->Set(
|
||||||
|
symbol,
|
||||||
|
v8::FunctionTemplate::New(isolate, func, data, v8::Signature::New(isolate, recv))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPrototypeGetter(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::External> data,
|
||||||
|
v8::Local<v8::FunctionTemplate> recv,
|
||||||
|
const char* name,
|
||||||
|
v8::AccessorNameGetterCallback func
|
||||||
|
) {
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
|
recv->InstanceTemplate()->SetNativeDataProperty(
|
||||||
|
InternalizedFromLatin1(isolate, name),
|
||||||
|
func,
|
||||||
|
0,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(V8_ENABLE_SANDBOX)
|
||||||
|
// When V8 Sandbox is enabled (in newer Electron versions), we need to use Buffer::Copy
|
||||||
|
// instead of Buffer::New to ensure the ArrayBuffer backing store is allocated inside the sandbox
|
||||||
|
static inline v8::MaybeLocal<v8::Object> BufferSandboxNew(v8::Isolate* isolate, char* data, size_t length, void (*finalizeCallback)(char*, void*), void* finalizeHint) {
|
||||||
|
v8::MaybeLocal<v8::Object> buffer = node::Buffer::Copy(isolate, data, length);
|
||||||
|
finalizeCallback(data, finalizeHint);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
#define SAFE_NEW_BUFFER(env, data, length, finalizeCallback, finalizeHint) BufferSandboxNew(env, data, length, finalizeCallback, finalizeHint)
|
||||||
|
#else
|
||||||
|
// When V8 Sandbox is not enabled, we can use the more efficient Buffer::New
|
||||||
|
#define SAFE_NEW_BUFFER(env, data, length, finalizeCallback, finalizeHint) node::Buffer::New(env, data, length, finalizeCallback, finalizeHint)
|
||||||
|
#endif
|
||||||
70
node_modules/better-sqlite3/src/util/macros.cpp
generated
vendored
Normal file
70
node_modules/better-sqlite3/src/util/macros.cpp
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#define NODE_ARGUMENTS const v8::FunctionCallbackInfo<v8::Value>&
|
||||||
|
#define NODE_ARGUMENTS_POINTER const v8::FunctionCallbackInfo<v8::Value>*
|
||||||
|
#define NODE_METHOD(name) void name(NODE_ARGUMENTS info)
|
||||||
|
#define NODE_GETTER(name) void name(v8::Local<v8::Name> _, const v8::PropertyCallbackInfo<v8::Value>& info)
|
||||||
|
#define INIT(name) v8::Local<v8::Function> name(v8::Isolate* isolate, v8::Local<v8::External> data)
|
||||||
|
|
||||||
|
#if defined(V8_MAJOR_VERSION) && V8_MAJOR_VERSION >= 13
|
||||||
|
// v8::Object::GetPrototype has been deprecated. See http://crbug.com/333672197
|
||||||
|
#define GET_PROTOTYPE(obj) ((obj)->GetPrototypeV2())
|
||||||
|
#else
|
||||||
|
#define GET_PROTOTYPE(obj) ((obj)->GetPrototype())
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define EasyIsolate v8::Isolate* isolate = v8::Isolate::GetCurrent()
|
||||||
|
#define OnlyIsolate info.GetIsolate()
|
||||||
|
#define OnlyContext isolate->GetCurrentContext()
|
||||||
|
#define OnlyAddon static_cast<Addon*>(info.Data().As<v8::External>()->Value())
|
||||||
|
#define UseIsolate v8::Isolate* isolate = OnlyIsolate
|
||||||
|
#define UseContext v8::Local<v8::Context> ctx = OnlyContext
|
||||||
|
#define UseAddon Addon* addon = OnlyAddon
|
||||||
|
#define Unwrap node::ObjectWrap::Unwrap
|
||||||
|
|
||||||
|
#define REQUIRE_ARGUMENT_ANY(at, var) \
|
||||||
|
if (info.Length() <= (at())) \
|
||||||
|
return ThrowTypeError("Expected a "#at" argument"); \
|
||||||
|
var = info[at()]
|
||||||
|
|
||||||
|
#define _REQUIRE_ARGUMENT(at, var, Type, message, ...) \
|
||||||
|
if (info.Length() <= (at()) || !info[at()]->Is##Type()) \
|
||||||
|
return ThrowTypeError("Expected "#at" argument to be "#message); \
|
||||||
|
var = (info[at()].As<v8::Type>())__VA_ARGS__
|
||||||
|
|
||||||
|
#define REQUIRE_ARGUMENT_INT32(at, var) \
|
||||||
|
_REQUIRE_ARGUMENT(at, var, Int32, a 32-bit signed integer, ->Value())
|
||||||
|
#define REQUIRE_ARGUMENT_BOOLEAN(at, var) \
|
||||||
|
_REQUIRE_ARGUMENT(at, var, Boolean, a boolean, ->Value())
|
||||||
|
#define REQUIRE_ARGUMENT_STRING(at, var) \
|
||||||
|
_REQUIRE_ARGUMENT(at, var, String, a string)
|
||||||
|
#define REQUIRE_ARGUMENT_OBJECT(at, var) \
|
||||||
|
_REQUIRE_ARGUMENT(at, var, Object, an object)
|
||||||
|
#define REQUIRE_ARGUMENT_FUNCTION(at, var) \
|
||||||
|
_REQUIRE_ARGUMENT(at, var, Function, a function)
|
||||||
|
|
||||||
|
#define REQUIRE_DATABASE_OPEN(db) \
|
||||||
|
if (!db->open) \
|
||||||
|
return ThrowTypeError("The database connection is not open")
|
||||||
|
#define REQUIRE_DATABASE_NOT_BUSY(db) \
|
||||||
|
if (db->busy) \
|
||||||
|
return ThrowTypeError("This database connection is busy executing a query")
|
||||||
|
#define REQUIRE_DATABASE_NO_ITERATORS(db) \
|
||||||
|
if (db->iterators) \
|
||||||
|
return ThrowTypeError("This database connection is busy executing a query")
|
||||||
|
#define REQUIRE_DATABASE_NO_ITERATORS_UNLESS_UNSAFE(db) \
|
||||||
|
if (!db->unsafe_mode) { \
|
||||||
|
REQUIRE_DATABASE_NO_ITERATORS(db); \
|
||||||
|
} ((void)0)
|
||||||
|
#define REQUIRE_STATEMENT_NOT_LOCKED(stmt) \
|
||||||
|
if (stmt->locked) \
|
||||||
|
return ThrowTypeError("This statement is busy executing a query")
|
||||||
|
|
||||||
|
#define first() 0
|
||||||
|
#define second() 1
|
||||||
|
#define third() 2
|
||||||
|
#define fourth() 3
|
||||||
|
#define fifth() 4
|
||||||
|
#define sixth() 5
|
||||||
|
#define seventh() 6
|
||||||
|
#define eighth() 7
|
||||||
|
#define ninth() 8
|
||||||
|
#define tenth() 9
|
||||||
71
node_modules/better-sqlite3/src/util/query-macros.cpp
generated
vendored
Normal file
71
node_modules/better-sqlite3/src/util/query-macros.cpp
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#define STATEMENT_BIND(handle) \
|
||||||
|
Binder binder(handle); \
|
||||||
|
if (!binder.Bind(info, info.Length(), stmt)) { \
|
||||||
|
sqlite3_clear_bindings(handle); \
|
||||||
|
return; \
|
||||||
|
} ((void)0)
|
||||||
|
|
||||||
|
#define STATEMENT_THROW_LOGIC() \
|
||||||
|
db->ThrowDatabaseError(); \
|
||||||
|
if (!bound) { sqlite3_clear_bindings(handle); } \
|
||||||
|
return
|
||||||
|
|
||||||
|
#define STATEMENT_RETURN_LOGIC(return_value) \
|
||||||
|
info.GetReturnValue().Set(return_value); \
|
||||||
|
if (!bound) { sqlite3_clear_bindings(handle); } \
|
||||||
|
return
|
||||||
|
|
||||||
|
#define STATEMENT_START_LOGIC(RETURNS_DATA_CHECK, MUTATE_CHECK) \
|
||||||
|
Statement* stmt = Unwrap<Statement>(info.This()); \
|
||||||
|
RETURNS_DATA_CHECK(); \
|
||||||
|
sqlite3_stmt* handle = stmt->handle; \
|
||||||
|
Database* db = stmt->db; \
|
||||||
|
REQUIRE_DATABASE_OPEN(db->GetState()); \
|
||||||
|
REQUIRE_DATABASE_NOT_BUSY(db->GetState()); \
|
||||||
|
MUTATE_CHECK(); \
|
||||||
|
const bool bound = stmt->bound; \
|
||||||
|
if (!bound) { \
|
||||||
|
STATEMENT_BIND(handle); \
|
||||||
|
} else if (info.Length() > 0) { \
|
||||||
|
return ThrowTypeError("This statement already has bound parameters"); \
|
||||||
|
} ((void)0)
|
||||||
|
|
||||||
|
|
||||||
|
#define STATEMENT_THROW() db->GetState()->busy = false; STATEMENT_THROW_LOGIC()
|
||||||
|
#define STATEMENT_RETURN(x) db->GetState()->busy = false; STATEMENT_RETURN_LOGIC(x)
|
||||||
|
#define STATEMENT_START(x, y) \
|
||||||
|
STATEMENT_START_LOGIC(x, y); \
|
||||||
|
db->GetState()->busy = true; \
|
||||||
|
UseIsolate; \
|
||||||
|
if (db->Log(isolate, handle)) { \
|
||||||
|
STATEMENT_THROW(); \
|
||||||
|
} ((void)0)
|
||||||
|
|
||||||
|
|
||||||
|
#define DOES_NOT_MUTATE() REQUIRE_STATEMENT_NOT_LOCKED(stmt)
|
||||||
|
#define DOES_MUTATE() \
|
||||||
|
REQUIRE_STATEMENT_NOT_LOCKED(stmt); \
|
||||||
|
REQUIRE_DATABASE_NO_ITERATORS_UNLESS_UNSAFE(db->GetState())
|
||||||
|
#define DOES_ADD_ITERATOR() \
|
||||||
|
DOES_NOT_MUTATE(); \
|
||||||
|
if (db->GetState()->iterators == USHRT_MAX) \
|
||||||
|
return ThrowRangeError("Too many active database iterators")
|
||||||
|
#define REQUIRE_STATEMENT_RETURNS_DATA() \
|
||||||
|
if (!stmt->returns_data) \
|
||||||
|
return ThrowTypeError("This statement does not return data. Use run() instead")
|
||||||
|
#define ALLOW_ANY_STATEMENT() \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
|
||||||
|
#define _FUNCTION_START(type) \
|
||||||
|
type* self = static_cast<type*>(sqlite3_user_data(invocation)); \
|
||||||
|
v8::Isolate* isolate = self->isolate; \
|
||||||
|
v8::HandleScope scope(isolate)
|
||||||
|
|
||||||
|
#define FUNCTION_START() \
|
||||||
|
_FUNCTION_START(CustomFunction)
|
||||||
|
|
||||||
|
#define AGGREGATE_START() \
|
||||||
|
_FUNCTION_START(CustomAggregate); \
|
||||||
|
Accumulator* acc = self->GetAccumulator(invocation); \
|
||||||
|
if (acc->value.IsEmpty()) return
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user