From a6524cfdc0d4d61e8ad78b052a96387e6122da26 Mon Sep 17 00:00:00 2001 From: 273* Date: Tue, 5 May 2026 23:55:07 +0900 Subject: [PATCH 01/31] =?UTF-8?q?chore:=20drizzle=E3=81=A8sqlite=E3=82=92?= =?UTF-8?q?=E5=B0=8E=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.json | 3 +- package.json | 4 + pnpm-lock.yaml | 975 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 975 insertions(+), 7 deletions(-) diff --git a/app.json b/app.json index 43fb25d..fe77076 100644 --- a/app.json +++ b/app.json @@ -35,7 +35,8 @@ "imageWidth": 76 } } - ] + ], + "expo-sqlite" ], "experiments": { "typedRoutes": true, diff --git a/package.json b/package.json index 320cd68..fa0a5fc 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,9 @@ "@react-navigation/bottom-tabs": "^7.15.5", "@react-navigation/elements": "^2.9.10", "@react-navigation/native": "^7.1.33", + "babel-plugin-inline-import": "^3.0.0", + "drizzle-kit": "^0.31.10", + "drizzle-orm": "^0.45.2", "eslint-plugin-import": "^2.32.0", "eslint-plugin-unused-imports": "^4.4.1", "expo": "~55.0.18", @@ -29,6 +32,7 @@ "expo-linking": "~55.0.14", "expo-router": "~55.0.13", "expo-splash-screen": "~55.0.19", + "expo-sqlite": "~55.0.15", "expo-status-bar": "~55.0.5", "expo-symbols": "~55.0.7", "expo-system-ui": "~55.0.16", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 85accdd..0982c60 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,15 @@ importers: '@react-navigation/native': specifier: ^7.1.33 version: 7.2.2(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + babel-plugin-inline-import: + specifier: ^3.0.0 + version: 3.0.0 + drizzle-kit: + specifier: ^0.31.10 + version: 0.31.10 + drizzle-orm: + specifier: ^0.45.2 + version: 0.45.2(expo-sqlite@55.0.15(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)) eslint-plugin-import: specifier: ^2.32.0 version: 2.32.0(@typescript-eslint/parser@8.59.1(eslint@9.39.4)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4))(eslint@9.39.4))(eslint@9.39.4) @@ -56,6 +65,9 @@ importers: expo-splash-screen: specifier: ~55.0.19 version: 55.0.19(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3))(typescript@5.9.3) + expo-sqlite: + specifier: ~55.0.15 + version: 55.0.15(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) expo-status-bar: specifier: ~55.0.5 version: 55.0.5(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) @@ -646,18 +658,473 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@drizzle-team/brocli@0.10.2': + resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + '@egjs/hammerjs@2.0.17': resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} engines: {node: '>=0.8.0'} - '@emnapi/core@1.10.0': - resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@esbuild-kit/core-utils@3.3.2': + resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + deprecated: 'Merged into tsx: https://tsx.is' + + '@esbuild-kit/esm-loader@2.6.5': + resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + deprecated: 'Merged into tsx: https://tsx.is' + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.18.20': + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.18.20': + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.18.20': + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.18.20': + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.18.20': + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.18.20': + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.18.20': + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.18.20': + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.18.20': + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.18.20': + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.18.20': + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.18.20': + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.18.20': + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.18.20': + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.18.20': + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.18.20': + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.18.20': + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.18.20': + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.18.20': + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.18.20': + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.18.20': + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] - '@emnapi/runtime@1.10.0': - resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@esbuild/win32-x64@0.18.20': + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] - '@emnapi/wasi-threads@1.2.1': - resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} @@ -1646,12 +2113,18 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + await-lock@2.2.2: + resolution: {integrity: sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==} + babel-jest@29.7.0: resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.8.0 + babel-plugin-inline-import@3.0.0: + resolution: {integrity: sha512-thnykl4FMb8QjMjVCuZoUmAM7r2mnTn5qJwrryCvDv6rugbJlTHZMctdjDtEgD0WBAXJOLJSGXN3loooEwx7UQ==} + babel-plugin-istanbul@6.1.1: resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} engines: {node: '>=8'} @@ -1995,6 +2468,102 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} + drizzle-kit@0.31.10: + resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==} + hasBin: true + + drizzle-orm@0.45.2: + resolution: {integrity: sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q==} + peerDependencies: + '@aws-sdk/client-rds-data': '>=3' + '@cloudflare/workers-types': '>=4' + '@electric-sql/pglite': '>=0.2.0' + '@libsql/client': '>=0.10.0' + '@libsql/client-wasm': '>=0.10.0' + '@neondatabase/serverless': '>=0.10.0' + '@op-engineering/op-sqlite': '>=2' + '@opentelemetry/api': ^1.4.1 + '@planetscale/database': '>=1.13' + '@prisma/client': '*' + '@tidbcloud/serverless': '*' + '@types/better-sqlite3': '*' + '@types/pg': '*' + '@types/sql.js': '*' + '@upstash/redis': '>=1.34.7' + '@vercel/postgres': '>=0.8.0' + '@xata.io/client': '*' + better-sqlite3: '>=7' + bun-types: '*' + expo-sqlite: '>=14.0.0' + gel: '>=2' + knex: '*' + kysely: '*' + mysql2: '>=2' + pg: '>=8' + postgres: '>=3' + prisma: '*' + sql.js: '>=1' + sqlite3: '>=5' + peerDependenciesMeta: + '@aws-sdk/client-rds-data': + optional: true + '@cloudflare/workers-types': + optional: true + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + '@libsql/client-wasm': + optional: true + '@neondatabase/serverless': + optional: true + '@op-engineering/op-sqlite': + optional: true + '@opentelemetry/api': + optional: true + '@planetscale/database': + optional: true + '@prisma/client': + optional: true + '@tidbcloud/serverless': + optional: true + '@types/better-sqlite3': + optional: true + '@types/pg': + optional: true + '@types/sql.js': + optional: true + '@upstash/redis': + optional: true + '@vercel/postgres': + optional: true + '@xata.io/client': + optional: true + better-sqlite3: + optional: true + bun-types: + optional: true + expo-sqlite: + optional: true + gel: + optional: true + knex: + optional: true + kysely: + optional: true + mysql2: + optional: true + pg: + optional: true + postgres: + optional: true + prisma: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -2051,6 +2620,21 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -2352,6 +2936,13 @@ packages: peerDependencies: expo: '*' + expo-sqlite@55.0.15: + resolution: {integrity: sha512-vxE5fs6l953QSIyievQ8TuSstj62eC7zUREjNzbUOwRWaHGGnhnlPJM1HLoTIv+oIt3+b1m7k2fmcDGkpK5t3w==} + peerDependencies: + expo: '*' + react: '*' + react-native: '*' + expo-status-bar@55.0.5: resolution: {integrity: sha512-qb0c3rJO2b7CC0gUVGi1JYp92oLenWdYGyk8l4YQs6U+uaXUTPv6aaFa3KkT2HON10re3AxxPNJci8rsz6kPxg==} peerDependencies: @@ -3329,6 +3920,9 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-extra@1.0.3: + resolution: {integrity: sha512-vYm3+GCkjUlT1rDvZnDVhNLXIRvwFPaN8ebHAFcuMJM/H0RBOPD7JrcldiNLd9AS3dhAyUHLa4Hny5wp1A+Ffw==} + path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -3589,6 +4183,9 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + require-resolve@0.0.2: + resolution: {integrity: sha512-eafQVaxdQsWUB8HybwognkdcIdKdQdQBwTxH48FuE6WI0owZGKp63QYr1MRp73PoX0AcyB7MDapZThYUY8FD0A==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -3925,6 +4522,11 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -4146,6 +4748,9 @@ packages: utf-8-validate: optional: true + x-path@0.0.2: + resolution: {integrity: sha512-zQ4WFI0XfJN1uEkkrB19Y4TuXOlHqKSxUJo0Yt+axPjRm8tCG6SJ6+Wo3/+Kjg4c2c8IvBXuJ0uYoshxNn4qMw==} + xcode@3.0.1: resolution: {integrity: sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==} engines: {node: '>=10.0.0'} @@ -4834,6 +5439,8 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@drizzle-team/brocli@0.10.2': {} + '@egjs/hammerjs@2.0.17': dependencies: '@types/hammerjs': 2.0.46 @@ -4854,6 +5461,238 @@ snapshots: tslib: 2.8.1 optional: true + '@esbuild-kit/core-utils@3.3.2': + dependencies: + esbuild: 0.18.20 + source-map-support: 0.5.21 + + '@esbuild-kit/esm-loader@2.6.5': + dependencies: + '@esbuild-kit/core-utils': 3.3.2 + get-tsconfig: 4.14.0 + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.18.20': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.18.20': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.18.20': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.18.20': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.18.20': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.18.20': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.18.20': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.18.20': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.18.20': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.18.20': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.18.20': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.18.20': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.18.20': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.18.20': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.18.20': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.18.20': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.18.20': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.18.20': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.18.20': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.18.20': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.18.20': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.18.20': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4)': dependencies: eslint: 9.39.4 @@ -6125,6 +6964,8 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 + await-lock@2.2.2: {} + babel-jest@29.7.0(@babel/core@7.29.0): dependencies: '@babel/core': 7.29.0 @@ -6138,6 +6979,10 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-inline-import@3.0.0: + dependencies: + require-resolve: 0.0.2 + babel-plugin-istanbul@6.1.1: dependencies: '@babel/helper-plugin-utils': 7.28.6 @@ -6535,6 +7380,17 @@ snapshots: dependencies: esutils: 2.0.3 + drizzle-kit@0.31.10: + dependencies: + '@drizzle-team/brocli': 0.10.2 + '@esbuild-kit/esm-loader': 2.6.5 + esbuild: 0.25.12 + tsx: 4.21.0 + + drizzle-orm@0.45.2(expo-sqlite@55.0.15(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)): + optionalDependencies: + expo-sqlite: 55.0.15(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -6656,6 +7512,89 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + esbuild@0.18.20: + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -7020,6 +7959,13 @@ snapshots: - supports-color - typescript + expo-sqlite@55.0.15(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + await-lock: 2.2.2 + expo: 55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + react: 19.2.0 + react-native: 0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0) + expo-status-bar@55.0.5(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): dependencies: react: 19.2.0 @@ -8127,6 +9073,8 @@ snapshots: path-exists@4.0.0: {} + path-extra@1.0.3: {} + path-is-absolute@1.0.1: {} path-key@3.1.1: {} @@ -8437,6 +9385,10 @@ snapshots: require-directory@2.1.1: {} + require-resolve@0.0.2: + dependencies: + x-path: 0.0.2 + resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -8797,6 +9749,13 @@ snapshots: tslib@2.8.1: {} + tsx@4.21.0: + dependencies: + esbuild: 0.27.7 + get-tsconfig: 4.14.0 + optionalDependencies: + fsevents: 2.3.3 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -9029,6 +9988,10 @@ snapshots: ws@8.20.0: {} + x-path@0.0.2: + dependencies: + path-extra: 1.0.3 + xcode@3.0.1: dependencies: simple-plist: 1.3.1 From df85d7cdcea3abd2e2da6901125b9d11d48e5cd4 Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 01:16:03 +0900 Subject: [PATCH 02/31] =?UTF-8?q?feat:=20db=E3=82=B9=E3=82=AD=E3=83=BC?= =?UTF-8?q?=E3=83=9E=E3=82=92=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/_layout.tsx | 17 +++++++++ src/db/schemas/entries.ts | 70 ++++++++++++++++++++++++++++++++++++++ src/db/schemas/fields.ts | 32 +++++++++++++++++ src/db/schemas/journals.ts | 31 +++++++++++++++++ 4 files changed, 150 insertions(+) create mode 100644 src/db/schemas/entries.ts create mode 100644 src/db/schemas/fields.ts create mode 100644 src/db/schemas/journals.ts diff --git a/src/app/_layout.tsx b/src/app/_layout.tsx index d82e11d..9c6452b 100644 --- a/src/app/_layout.tsx +++ b/src/app/_layout.tsx @@ -1,7 +1,24 @@ import React from "react"; +import { drizzle } from "drizzle-orm/expo-sqlite"; +import { useMigrations } from "drizzle-orm/expo-sqlite/migrator"; +import * as SQLite from "expo-sqlite"; + import AppTabs from "@/components/app-tabs"; +import migrations from "../../drizzle/migrations"; + +export * from "@/db/schemas/entries"; +export * from "@/db/schemas/fields"; +export * from "@/db/schemas/journals"; + export default function RootLayout() { + const expo = SQLite.openDatabaseSync("db.db"); + const db = drizzle(expo); + const { success, error } = useMigrations(db, migrations); + + console.log(error); + + if (!success) return null; return ; } diff --git a/src/db/schemas/entries.ts b/src/db/schemas/entries.ts new file mode 100644 index 0000000..0ab8d52 --- /dev/null +++ b/src/db/schemas/entries.ts @@ -0,0 +1,70 @@ +import { relations } from "drizzle-orm"; +import { + integer, + sqliteTable, + text, + uniqueIndex, +} from "drizzle-orm/sqlite-core"; + +import { fields } from "./fields"; +import { journals } from "./journals"; + +/** + +/** + * エントリーテーブル + */ +export const entries = sqliteTable("entries", { + id: text().primaryKey(), + journalId: text() + .notNull() + .references(() => journals.id, { onDelete: "cascade" }), + bookmark: integer("bookmark", { mode: "boolean" }).notNull().default(false), + createdAt: integer() + .notNull() + .$defaultFn(() => Date.now()), + updatedAt: integer() + .notNull() + .$defaultFn(() => Date.now()), +}); + +/** + * エントリー値テーブル + * エントリーの各フィールドに対する入力値を管理する + * valueはフィールド種別に応じてJSON文字列で格納する + */ +export const entryValues = sqliteTable( + "entry_values", + { + id: text().primaryKey(), + entryId: text() + .notNull() + .references(() => entries.id, { onDelete: "cascade" }), + fieldId: text() + .notNull() + .references(() => fields.id, { onDelete: "cascade" }), + value: text(), + }, + (t) => [uniqueIndex("entry_field_unique").on(t.entryId, t.fieldId)], // ユニーク制約 +); + +export const entriesRelations = relations(entries, ({ one, many }) => ({ + journal: one(journals, { + fields: [entries.journalId], + references: [journals.id], + }), + values: many(entryValues), +})); + +export const entryValuesRelations = relations(entryValues, ({ one }) => ({ + entry: one(entries, { + fields: [entryValues.entryId], + references: [entries.id], + }), + field: one(fields, { + fields: [entryValues.fieldId], + references: [fields.id], + }), +})); + +export type EntryObj = typeof entries.$inferSelect; diff --git a/src/db/schemas/fields.ts b/src/db/schemas/fields.ts new file mode 100644 index 0000000..d8a55a4 --- /dev/null +++ b/src/db/schemas/fields.ts @@ -0,0 +1,32 @@ +import { relations } from "drizzle-orm"; +import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; + +import type { FieldType } from "@/core/constants"; + +import { entryValues } from "./entries"; +import { journals } from "./journals"; + +/** + * フィールド定義テーブル + */ +export const fields = sqliteTable("fields", { + id: text().primaryKey(), + journalId: text() + .notNull() + .references(() => journals.id, { onDelete: "cascade" }), + /** フィールドの種別 */ + type: text().notNull().$type(), + label: text().notNull(), + /** 表示順 */ + sortOrder: integer().notNull(), +}); + +export const fieldsRelations = relations(fields, ({ one, many }) => ({ + journal: one(journals, { + fields: [fields.journalId], + references: [journals.id], + }), + entryValues: many(entryValues), +})); + +export type FieldlObj = typeof fields.$inferSelect; diff --git a/src/db/schemas/journals.ts b/src/db/schemas/journals.ts new file mode 100644 index 0000000..242f5af --- /dev/null +++ b/src/db/schemas/journals.ts @@ -0,0 +1,31 @@ +import { relations } from "drizzle-orm"; +import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; +import type { SFSymbol } from "expo-symbols"; + +import { entries } from "./entries"; +import { fields } from "./fields"; + +/** + * ジャーナルテーブル + */ +export const journals = sqliteTable("journals", { + id: text().primaryKey(), + name: text().notNull(), + /** SFSymbol名 */ + icon: text().notNull().$type(), + /** HEXカラーコード */ + color: text().notNull(), + createdAt: integer() + .notNull() + .$defaultFn(() => Date.now()), + updatedAt: integer() + .notNull() + .$defaultFn(() => Date.now()), +}); + +export const journalsRelations = relations(journals, ({ many }) => ({ + fields: many(fields), + entries: many(entries), +})); + +export type JournalObj = typeof journals.$inferSelect; From d3b708889dd2ae4191ac1acdbc1caf493ecd86bd Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 01:16:24 +0900 Subject: [PATCH 03/31] =?UTF-8?q?feat:=20db=E3=83=9E=E3=82=A4=E3=82=B0?= =?UTF-8?q?=E3=83=AC=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92=E5=AE=9F?= =?UTF-8?q?=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- drizzle.config.ts | 8 + drizzle/0000_young_bulldozer.sql | 36 +++++ drizzle/meta/0000_snapshot.json | 263 +++++++++++++++++++++++++++++++ drizzle/meta/_journal.json | 13 ++ drizzle/migrations.js | 12 ++ 5 files changed, 332 insertions(+) create mode 100644 drizzle.config.ts create mode 100644 drizzle/0000_young_bulldozer.sql create mode 100644 drizzle/meta/0000_snapshot.json create mode 100644 drizzle/meta/_journal.json create mode 100644 drizzle/migrations.js diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 0000000..5a56b52 --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,8 @@ +import type { Config } from "drizzle-kit"; + +export default { + dialect: "sqlite", + driver: "expo", + schema: "./src/db/schemas", + out: "./drizzle", +} satisfies Config; diff --git a/drizzle/0000_young_bulldozer.sql b/drizzle/0000_young_bulldozer.sql new file mode 100644 index 0000000..b92f1f3 --- /dev/null +++ b/drizzle/0000_young_bulldozer.sql @@ -0,0 +1,36 @@ +CREATE TABLE `entries` ( + `id` text PRIMARY KEY NOT NULL, + `journalId` text NOT NULL, + `bookmark` integer DEFAULT false NOT NULL, + `createdAt` integer NOT NULL, + `updatedAt` integer NOT NULL, + FOREIGN KEY (`journalId`) REFERENCES `journals`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +CREATE TABLE `entry_values` ( + `id` text PRIMARY KEY NOT NULL, + `entryId` text NOT NULL, + `fieldId` text NOT NULL, + `value` text, + FOREIGN KEY (`entryId`) REFERENCES `entries`(`id`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (`fieldId`) REFERENCES `fields`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +CREATE UNIQUE INDEX `entry_field_unique` ON `entry_values` (`entryId`,`fieldId`);--> statement-breakpoint +CREATE TABLE `fields` ( + `id` text PRIMARY KEY NOT NULL, + `journalId` text NOT NULL, + `type` text NOT NULL, + `label` text NOT NULL, + `sortOrder` integer NOT NULL, + FOREIGN KEY (`journalId`) REFERENCES `journals`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +CREATE TABLE `journals` ( + `id` text PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `icon` text NOT NULL, + `color` text NOT NULL, + `createdAt` integer NOT NULL, + `updatedAt` integer NOT NULL +); diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json new file mode 100644 index 0000000..2f87d01 --- /dev/null +++ b/drizzle/meta/0000_snapshot.json @@ -0,0 +1,263 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "3d118337-e09e-4635-9ca5-d9d5a5c94bf2", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "entries": { + "name": "entries", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "journalId": { + "name": "journalId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bookmark": { + "name": "bookmark", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "entries_journalId_journals_id_fk": { + "name": "entries_journalId_journals_id_fk", + "tableFrom": "entries", + "tableTo": "journals", + "columnsFrom": [ + "journalId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "entry_values": { + "name": "entry_values", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "entryId": { + "name": "entryId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fieldId": { + "name": "fieldId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "entry_field_unique": { + "name": "entry_field_unique", + "columns": [ + "entryId", + "fieldId" + ], + "isUnique": true + } + }, + "foreignKeys": { + "entry_values_entryId_entries_id_fk": { + "name": "entry_values_entryId_entries_id_fk", + "tableFrom": "entry_values", + "tableTo": "entries", + "columnsFrom": [ + "entryId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "entry_values_fieldId_fields_id_fk": { + "name": "entry_values_fieldId_fields_id_fk", + "tableFrom": "entry_values", + "tableTo": "fields", + "columnsFrom": [ + "fieldId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "fields": { + "name": "fields", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "journalId": { + "name": "journalId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sortOrder": { + "name": "sortOrder", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "fields_journalId_journals_id_fk": { + "name": "fields_journalId_journals_id_fk", + "tableFrom": "fields", + "tableTo": "journals", + "columnsFrom": [ + "journalId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "journals": { + "name": "journals", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json new file mode 100644 index 0000000..9af7705 --- /dev/null +++ b/drizzle/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1777997392852, + "tag": "0000_young_bulldozer", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/drizzle/migrations.js b/drizzle/migrations.js new file mode 100644 index 0000000..dbad105 --- /dev/null +++ b/drizzle/migrations.js @@ -0,0 +1,12 @@ +// This file is required for Expo/React Native SQLite migrations - https://orm.drizzle.team/quick-sqlite/expo + +import journal from './meta/_journal.json'; +import m0000 from './0000_young_bulldozer.sql'; + + export default { + journal, + migrations: { + m0000 + } + } + \ No newline at end of file From 8fb169fadf176c9073fc1e178939ce9879fc5fd0 Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 10:35:00 +0900 Subject: [PATCH 04/31] =?UTF-8?q?feat:=20drizzle=20provider=E3=82=92?= =?UTF-8?q?=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/_layout.tsx | 24 ++++++----------------- src/components/drizzle-provider.tsx | 30 +++++++++++++++++++++++++++++ src/db/schemas/index.ts | 3 +++ 3 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 src/components/drizzle-provider.tsx create mode 100644 src/db/schemas/index.ts diff --git a/src/app/_layout.tsx b/src/app/_layout.tsx index 9c6452b..5d4f83c 100644 --- a/src/app/_layout.tsx +++ b/src/app/_layout.tsx @@ -1,24 +1,12 @@ import React from "react"; -import { drizzle } from "drizzle-orm/expo-sqlite"; -import { useMigrations } from "drizzle-orm/expo-sqlite/migrator"; -import * as SQLite from "expo-sqlite"; - import AppTabs from "@/components/app-tabs"; - -import migrations from "../../drizzle/migrations"; - -export * from "@/db/schemas/entries"; -export * from "@/db/schemas/fields"; -export * from "@/db/schemas/journals"; +import { DrizzleProvider } from "@/components/drizzle-provider"; export default function RootLayout() { - const expo = SQLite.openDatabaseSync("db.db"); - const db = drizzle(expo); - const { success, error } = useMigrations(db, migrations); - - console.log(error); - - if (!success) return null; - return ; + return ( + + + + ); } diff --git a/src/components/drizzle-provider.tsx b/src/components/drizzle-provider.tsx new file mode 100644 index 0000000..120c272 --- /dev/null +++ b/src/components/drizzle-provider.tsx @@ -0,0 +1,30 @@ +import type { ReactNode } from "react"; + +import { drizzle } from "drizzle-orm/expo-sqlite"; +import { useMigrations } from "drizzle-orm/expo-sqlite/migrator"; +import { openDatabaseSync } from "expo-sqlite"; + +import * as schema from "@/db/schemas"; + +import migrations from "../../drizzle/migrations"; + +const expoDb = openDatabaseSync("db.db"); + +export const db = drizzle(expoDb, { schema }); + +type Props = { + children: ReactNode; +}; + +export function DrizzleProvider({ children }: Props) { + const { success, error: migrateError } = useMigrations(db, migrations); + + if (migrateError) { + console.error("Migration Error:", migrateError); + throw migrateError; + } + + if (!success) return null; + + return <>{children}; +} diff --git a/src/db/schemas/index.ts b/src/db/schemas/index.ts new file mode 100644 index 0000000..1090c31 --- /dev/null +++ b/src/db/schemas/index.ts @@ -0,0 +1,3 @@ +export * from "./journals"; +export * from "./fields"; +export * from "./entries"; From 049584b44650cdf8b7dfe9b307a80a448a79d3de Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 11:06:17 +0900 Subject: [PATCH 05/31] =?UTF-8?q?chore:=20claude=20init=E3=82=92=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 71 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 40e968f..dc99fad 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,16 +1,20 @@ -# Nicky - Journaling App +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview -Nicky is a React Native journaling app built with Expo and Expo Router. It features native iOS UI via `@expo/ui/swift-ui` (SwiftUI components), native tab navigation, and file-based routing. +Nicky is a React Native journaling app built with Expo and Expo Router. It features native iOS UI via `@expo/ui/swift-ui` (SwiftUI components), native tab navigation, and SQLite persistence via Drizzle ORM. ## Development Commands ```bash -pnpm expo run:ios # Build and run on iOS simulator -pnpm expo start # Start Expo dev server -pnpm lint # Run ESLint -pnpm lint-fix # Run ESLint with auto-fix +pnpm expo run:ios # Build and run on iOS simulator +pnpm expo start --clear # Start Expo dev server (clear cache) +pnpm lint # Run ESLint +pnpm lint-fix # Run ESLint with auto-fix +pnpm typecheck # TypeScript type check +pnpm drizzle-kit generate # Generate migration files from schema ``` ## Commit Convention @@ -30,7 +34,7 @@ chore: tooling / config changes ``` src/app/ - _layout.tsx # NativeTabs (root) — tab bar always visible + _layout.tsx # Root — wraps everything in DrizzleProvider + NativeTabs (journal)/ _layout.tsx # Stack — scoped to journal tab index.tsx # Journal list / @@ -45,46 +49,46 @@ src/app/ **Key rule:** `NativeTabs` is the root navigator; `Stack` lives inside `(journal)` group. This keeps the tab bar visible when pushing screens. -### Directory Structure +### Database Layer -``` -src/ - app/ # Routes (Expo Router file-based) - components/ - app-tabs.tsx # NativeTabs definition - journal/ # Journal-related components - journal-view.tsx # Grid list of journal cards - journal-card.tsx # Tappable gradient card - journal-create-view.tsx - entry/ # Entry-related components - entry-list-view.tsx # List grouped by month - entry-row.tsx # Date + title + preview row - mocks/ - journals.ts # JournalObj type + JOURNALS array - entries.ts # Entry type + ENTRIES array - constants/ - hooks/ -``` +Drizzle ORM + expo-sqlite. Schema is split by domain in `src/db/schemas/`: + +| File | Tables | +|---|---| +| `journals.ts` | `journals` | +| `fields.ts` | `fields` (field definitions per journal) | +| `entries.ts` | `entries`, `entry_values` | + +`src/db/schemas/index.ts` re-exports all schemas. `src/components/drizzle-provider.tsx` opens the DB, runs migrations via `useMigrations`, and exports `db`. + +**Adding a schema change:** edit the relevant schema file → `pnpm drizzle-kit generate` → commit the generated files in `drizzle/`. + +**Drizzle config notes:** +- Schema files must not import React Native packages (`expo-crypto`, `expo-symbols` runtime imports) — drizzle-kit runs in Node.js. Use `import type` for RN types. +- `$defaultFn` with `Crypto.randomUUID()` cannot be used in schema — generate IDs at the application layer instead. ### Key Technologies | Package | Usage | |---|---| | `expo-router` | File-based routing, `useRouter`, `useLocalSearchParams` | -| `@expo/ui/swift-ui` | SwiftUI components: `Host`, `ZStack`, `VStack`, `Grid`, `ScrollView`, `List`, `Section`, `Button`, `Image`, `Text`, `RoundedRectangle` | -| `@expo/ui/swift-ui/modifiers` | `frame`, `padding`, `font`, `foregroundStyle`, `onTapGesture`, `clipShape`, `lineLimit`, `headerProminence`, `listStyle` | +| `@expo/ui/swift-ui` | SwiftUI components: `Host`, `ZStack`, `VStack`, `Grid`, `ScrollView`, `List`, `Section`, `Button`, `Image`, `Text`, `RoundedRectangle`, `ColorPicker`, `BottomSheet` | +| `@expo/ui/swift-ui/modifiers` | `frame`, `padding`, `foregroundStyle`, `onTapGesture`, `listStyle`, `presentationDetents`, `environment`, `fixedSize` | | `expo-router/unstable-native-tabs` | `NativeTabs` — iOS native tab bar | -| `expo-symbols` | `SymbolView` — SF Symbols in RN header components | +| `expo-symbols` | `SymbolView` — SF Symbols in RN (non-SwiftUI) header components | +| `expo-sqlite` + `drizzle-orm` | Local SQLite persistence | +| `expo-crypto` | `Crypto.randomUUID()` for ID generation at the app layer | | `PlatformColor` | Adaptive system colors: `"label"`, `"systemBackground"`, `"systemIndigo"` | ### SwiftUI Component Rules - Always wrap SwiftUI components in `` with `useViewportSizeMeasurement` - Use `onTapGesture` modifier for taps — `onPress` prop does NOT work on layout components -- Gradients: `RoundedRectangle` + `foregroundStyle({ type: "linearGradient", ... })` + `clipShape` on parent `ZStack` -- Adaptive colors: use `PlatformColor("label")` directly — no need for `useColorScheme` -- Secondary text: `foregroundStyle({ type: "hierarchical", style: "secondary" })` +- `Button` inside `List` gets a blue tint by default — use `foregroundStyle({ type: "hierarchical", style: "primary" })` to keep the tap highlight without the blue color - `List` manages its own scrolling — never nest it inside `ScrollView` +- Adaptive colors: use `PlatformColor("label")` directly — no need for `useColorScheme` +- `fixedSize()` on a component prevents it from stretching in an HStack, allowing siblings to fill remaining space +- Gradients: `RoundedRectangle` + `foregroundStyle({ type: "linearGradient", ... })` + `clipShape` on parent `ZStack` ### Naming Conventions @@ -96,8 +100,7 @@ src/ ## Code Style - **Import order:** external → internal (`@/`) → relative; always separated by newlines -- **Unused imports:** auto-enforced by ESLint (`eslint-plugin-unused-imports`) - **Path alias:** `@/*` → `src/*` - **TypeScript:** strict mode enabled - **Formatter:** Prettier (enforced via ESLint) -- **React Compiler:** enabled (`reactCompiler: true` in app.json) +- **React Compiler:** enabled — do not manually add `useMemo`/`useCallback` unless there is a specific reason From 81c4836ba65bf3f58ba940898628ba1b8487e77c Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 11:08:24 +0900 Subject: [PATCH 06/31] =?UTF-8?q?feat:=20expo-drizzle-studio-plugin?= =?UTF-8?q?=E3=82=92=E5=B0=8E=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- babel.config.js | 8 ++++++++ package.json | 1 + pnpm-lock.yaml | 14 ++++++++++++++ src/components/drizzle-provider.tsx | 3 +++ 4 files changed, 26 insertions(+) create mode 100644 babel.config.js diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..6ff01f4 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,8 @@ +/** @type {import('@babel/core').TransformOptions} */ +module.exports = function (api) { + api.cache(true); + return { + presets: ["babel-preset-expo"], + plugins: [["inline-import", { extensions: [".sql"] }]], + }; +}; diff --git a/package.json b/package.json index fa0a5fc..ce7b452 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "expo-constants": "~55.0.15", "expo-crypto": "~55.0.14", "expo-device": "~55.0.15", + "expo-drizzle-studio-plugin": "^0.2.1", "expo-font": "~55.0.6", "expo-glass-effect": "~55.0.10", "expo-image": "~55.0.9", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0982c60..97f8077 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,6 +47,9 @@ importers: expo-device: specifier: ~55.0.15 version: 55.0.15(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)) + expo-drizzle-studio-plugin: + specifier: ^0.2.1 + version: 0.2.1(expo-sqlite@55.0.15(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)) expo-font: specifier: ~55.0.6 version: 55.0.6(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) @@ -2835,6 +2838,12 @@ packages: peerDependencies: expo: '*' + expo-drizzle-studio-plugin@0.2.1: + resolution: {integrity: sha512-AjMC7SOutMAv/MkeJSp/26gnHLAA17SG8EtsjIKW6tDcBkq4plDVhjMLusoGe9f0vzYK8KrOvWjEWZ/R+KvIGg==} + peerDependencies: + expo: '>=53.0.5' + expo-sqlite: '>=15.2.9' + expo-file-system@55.0.17: resolution: {integrity: sha512-d27K1cagUOt2BwxwPka9KW8Znu5kN1tnairozCzzCRZviZFtWnBxwFuJ3KU6MAbav/9UhSMkp5Ve/oZ+SR0UgQ==} peerDependencies: @@ -7841,6 +7850,11 @@ snapshots: expo: 55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) ua-parser-js: 0.7.41 + expo-drizzle-studio-plugin@0.2.1(expo-sqlite@55.0.15(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3)): + dependencies: + expo: 55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + expo-sqlite: 55.0.15(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + expo-file-system@55.0.17(expo@55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)): dependencies: expo: 55.0.18(@babel/core@7.29.0)(@expo/dom-webview@55.0.5)(@expo/metro-runtime@55.0.10)(expo-router@55.0.13)(react-dom@19.2.0(react@19.2.0))(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)(typescript@5.9.3) diff --git a/src/components/drizzle-provider.tsx b/src/components/drizzle-provider.tsx index 120c272..998263d 100644 --- a/src/components/drizzle-provider.tsx +++ b/src/components/drizzle-provider.tsx @@ -2,6 +2,7 @@ import type { ReactNode } from "react"; import { drizzle } from "drizzle-orm/expo-sqlite"; import { useMigrations } from "drizzle-orm/expo-sqlite/migrator"; +import { useDrizzleStudio } from "expo-drizzle-studio-plugin"; import { openDatabaseSync } from "expo-sqlite"; import * as schema from "@/db/schemas"; @@ -19,6 +20,8 @@ type Props = { export function DrizzleProvider({ children }: Props) { const { success, error: migrateError } = useMigrations(db, migrations); + useDrizzleStudio(expoDb); // Drizzle Studio の設定(開発環境でのみ有効) + if (migrateError) { console.error("Migration Error:", migrateError); throw migrateError; From 521a23304cf5a8350726dcba5be082974caabc59 Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 11:29:01 +0900 Subject: [PATCH 07/31] =?UTF-8?q?refactor:=20db=20provider=E3=81=AE?= =?UTF-8?q?=E3=83=AA=E3=83=95=E3=82=A1=E3=82=AF=E3=82=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/drizzle-provider.tsx | 11 ++++------- src/db/client.ts | 8 ++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 src/db/client.ts diff --git a/src/components/drizzle-provider.tsx b/src/components/drizzle-provider.tsx index 998263d..7b8e474 100644 --- a/src/components/drizzle-provider.tsx +++ b/src/components/drizzle-provider.tsx @@ -1,22 +1,19 @@ import type { ReactNode } from "react"; -import { drizzle } from "drizzle-orm/expo-sqlite"; import { useMigrations } from "drizzle-orm/expo-sqlite/migrator"; import { useDrizzleStudio } from "expo-drizzle-studio-plugin"; -import { openDatabaseSync } from "expo-sqlite"; -import * as schema from "@/db/schemas"; +import { db, expoDb } from "@/db/client"; import migrations from "../../drizzle/migrations"; -const expoDb = openDatabaseSync("db.db"); - -export const db = drizzle(expoDb, { schema }); - type Props = { children: ReactNode; }; +/** + * ローカルDBプロバイダー + */ export function DrizzleProvider({ children }: Props) { const { success, error: migrateError } = useMigrations(db, migrations); diff --git a/src/db/client.ts b/src/db/client.ts new file mode 100644 index 0000000..244b7d5 --- /dev/null +++ b/src/db/client.ts @@ -0,0 +1,8 @@ +import { drizzle } from "drizzle-orm/expo-sqlite"; +import { openDatabaseSync } from "expo-sqlite"; + +import * as schema from "@/db/schemas"; + +export const expoDb = openDatabaseSync("db.db"); + +export const db = drizzle(expoDb, { schema }); From e8bd3a94bb3a6677a27d10f0e1ab15015c8bc119 Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 11:58:18 +0900 Subject: [PATCH 08/31] =?UTF-8?q?refactor:=20db=20provider=E3=81=AE?= =?UTF-8?q?=E3=83=AA=E3=83=95=E3=82=A1=E3=82=AF=E3=82=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/drizzle-provider.tsx | 3 +++ src/db/client.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/drizzle-provider.tsx b/src/components/drizzle-provider.tsx index 7b8e474..f50ea84 100644 --- a/src/components/drizzle-provider.tsx +++ b/src/components/drizzle-provider.tsx @@ -8,6 +8,9 @@ import { db, expoDb } from "@/db/client"; import migrations from "../../drizzle/migrations"; type Props = { + /** + * React Node + */ children: ReactNode; }; diff --git a/src/db/client.ts b/src/db/client.ts index 244b7d5..354ae33 100644 --- a/src/db/client.ts +++ b/src/db/client.ts @@ -3,6 +3,6 @@ import { openDatabaseSync } from "expo-sqlite"; import * as schema from "@/db/schemas"; -export const expoDb = openDatabaseSync("db.db"); +export const expoDb = openDatabaseSync("db.db", { enableChangeListener: true }); export const db = drizzle(expoDb, { schema }); From 29774e964639141e427eab9dbf4a81948dc9d4d1 Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 12:24:38 +0900 Subject: [PATCH 09/31] =?UTF-8?q?feat:=20=E3=82=B8=E3=83=A3=E3=83=BC?= =?UTF-8?q?=E3=83=8A=E3=83=AB=E3=82=92=E5=8F=96=E5=BE=97=E3=81=99=E3=82=8B?= =?UTF-8?q?=E3=82=AF=E3=82=A8=E3=83=AA=E3=82=92=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/db/queries/journals.ts | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/db/queries/journals.ts diff --git a/src/db/queries/journals.ts b/src/db/queries/journals.ts new file mode 100644 index 0000000..63bd084 --- /dev/null +++ b/src/db/queries/journals.ts @@ -0,0 +1,42 @@ +import { db } from "@/db/client"; +import { FieldlObj, fields, JournalObj, journals } from "@/db/schemas"; + +/** + * ジャーナル一覧を取得する + */ +export const getJournals = async () => { + return db.query.journals.findMany(); +}; + +/** + * ジャーナルに紐付いたエントリー一覧を取得する + * @param journalId ジャーナルID + */ +export const getEntries = async (journalId: string) => { + return db.query.journals.findFirst({ + where: (journals, { eq }) => eq(journals.id, journalId), + with: { entries: true }, + }); +}; + +/** + * ジャーナルをフィールドと共に作成する + * @param journal ジャーナルのメタ情報 + * @param newFields フィールド一覧 + */ +export const storeJournal = async ( + journal: JournalObj, + newFields: FieldlObj[], +) => { + await db.transaction(async (tx) => { + await tx.insert(journals).values(journal); + + if (newFields.length > 0) { + await tx + .insert(fields) + .values( + newFields.map((field) => ({ ...field, journalId: journal.id })), + ); + } + }); +}; From 2ef170d8d878f31737bf9051d45f3bb82b4ee0ae Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 12:28:38 +0900 Subject: [PATCH 10/31] =?UTF-8?q?feat:=20=E3=82=B8=E3=83=A3=E3=83=BC?= =?UTF-8?q?=E3=83=8A=E3=83=AB=E3=82=92=E4=BD=9C=E6=88=90=E3=81=99=E3=82=8B?= =?UTF-8?q?=E9=96=A2=E6=95=B0=E3=82=92=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(journal)/create.tsx | 8 +++---- src/db/schemas/fields.ts | 2 +- src/hooks/journal/use-journal-field.ts | 33 +++++++++++++++++++------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/app/(journal)/create.tsx b/src/app/(journal)/create.tsx index e32f797..435bfa0 100644 --- a/src/app/(journal)/create.tsx +++ b/src/app/(journal)/create.tsx @@ -24,9 +24,9 @@ export default function JournalCreateScreen() { formDisabled, } = useJournalField(); - const handleCreate = () => { - router.push(`/(journal)/1`); - createJournal(); + const handleCreate = async () => { + const id = await createJournal(); + router.push(`/(journal)/${id}`); }; return ( @@ -35,7 +35,7 @@ export default function JournalCreateScreen() { options={{ title: "New Journal", headerRight: () => ( - + ({ entryValues: many(entryValues), })); -export type FieldlObj = typeof fields.$inferSelect; +export type FieldlObj = Omit; diff --git a/src/hooks/journal/use-journal-field.ts b/src/hooks/journal/use-journal-field.ts index ed8c566..b272368 100644 --- a/src/hooks/journal/use-journal-field.ts +++ b/src/hooks/journal/use-journal-field.ts @@ -4,6 +4,7 @@ import * as Crypto from "expo-crypto"; import type { SFSymbol } from "sf-symbols-typescript"; import { FIELD_ICONS, FieldType, JOURNAL_ICONS } from "@/core/constants"; +import { storeJournal } from "@/db/queries/journals"; /** * ジャーナルの型 @@ -50,7 +51,7 @@ export const FIELD_TYPES = Object.keys(FIELD_ICONS) as FieldType[]; * - moveField フィールドを並び替えする関数 * - meta ジャーナルのメタ情報 * - setMeta ジャーナルのメタ情報をセットする関数 - * - createJournal ジャーナルを作成する関数 + * - createJournal 新規ジャーナルを作成する関数 * - formDisabled フォームが送信可能かどうかのフラグ */ export const useJournalField = () => { @@ -122,14 +123,30 @@ export const useJournalField = () => { fields.some((field) => field.label.length === 0); /** - * ジャーナルを作成する関数 + * 新規ジャーナルをフィールドと共にDBに保存する */ - const createJournal = () => { - if (!formDisabled) { - const newJournal: JournalObj = { id: Crypto.randomUUID(), meta, fields }; - console.log(newJournal); - return newJournal; - } + const createJournal = async () => { + const now = Date.now(); + + const id = Crypto.randomUUID(); + await storeJournal( + { + id, + name: meta.name, + icon: meta.icon, + color: meta.color, + createdAt: now, + updatedAt: now, + }, + fields.map((field, i) => ({ + id: field.id, + type: field.type, + label: field.label, + sortOrder: i, + })), + ); + + return id; }; return { From 7a50df6c146fb1eb8873e77cabee6f4b5dc8afd5 Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 18:20:26 +0900 Subject: [PATCH 11/31] =?UTF-8?q?refactor:=20=E3=83=87=E3=82=A3=E3=83=AC?= =?UTF-8?q?=E3=82=AF=E3=83=88=E3=83=AA=E6=A7=8B=E6=88=90=E3=82=92=E5=A4=89?= =?UTF-8?q?=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(journal)/create.tsx | 2 +- src/components/journal/field-bottom-sheet.tsx | 2 +- src/components/journal/journal-create-view.tsx | 2 +- src/{hooks => utils}/journal/use-journal-field.ts | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename src/{hooks => utils}/journal/use-journal-field.ts (100%) diff --git a/src/app/(journal)/create.tsx b/src/app/(journal)/create.tsx index 435bfa0..75da031 100644 --- a/src/app/(journal)/create.tsx +++ b/src/app/(journal)/create.tsx @@ -4,7 +4,7 @@ import { Stack, useRouter } from "expo-router"; import { SymbolView } from "expo-symbols"; import { JournalCreateView } from "@/components/journal/journal-create-view"; -import { useJournalField } from "@/hooks/journal/use-journal-field"; +import { useJournalField } from "@/utils/journal/use-journal-field"; /** * ジャーナル作成 diff --git a/src/components/journal/field-bottom-sheet.tsx b/src/components/journal/field-bottom-sheet.tsx index ddb59d1..f316ca1 100644 --- a/src/components/journal/field-bottom-sheet.tsx +++ b/src/components/journal/field-bottom-sheet.tsx @@ -17,7 +17,7 @@ import { } from "@expo/ui/swift-ui/modifiers"; import { FIELD_ICONS, FIELD_LABELS, FieldType } from "@/core/constants"; -import { FIELD_TYPES } from "@/hooks/journal/use-journal-field"; +import { FIELD_TYPES } from "@/utils/journal/use-journal-field"; type Props = { /** ボトムシートの表示状態 */ diff --git a/src/components/journal/journal-create-view.tsx b/src/components/journal/journal-create-view.tsx index 32987c5..40b15b9 100644 --- a/src/components/journal/journal-create-view.tsx +++ b/src/components/journal/journal-create-view.tsx @@ -26,7 +26,7 @@ import { FIELD_ICONS, FieldType } from "@/core/constants"; import { JournalMetaObj, type FieldObj, -} from "@/hooks/journal/use-journal-field"; +} from "@/utils/journal/use-journal-field"; import { FieldBottomSheet } from "./field-bottom-sheet"; import { IconSelectBottomSheet } from "./icon-select-bottom-sheet"; diff --git a/src/hooks/journal/use-journal-field.ts b/src/utils/journal/use-journal-field.ts similarity index 100% rename from src/hooks/journal/use-journal-field.ts rename to src/utils/journal/use-journal-field.ts From 717c8c5bce0d0e5bbafa65eb6652b3eeed0f9c94 Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 19:20:20 +0900 Subject: [PATCH 12/31] =?UTF-8?q?feat:=20db=E3=81=8B=E3=82=89journal?= =?UTF-8?q?=E4=B8=80=E8=A6=A7=E3=82=92=E5=8F=96=E5=BE=97=E3=81=99=E3=82=8B?= =?UTF-8?q?=E5=87=A6=E7=90=86=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/journal/journal-view.tsx | 21 ++++++++++---------- src/db/queries/journals.ts | 26 +++++++++++++++---------- src/utils/chunk-array.ts | 12 ++++++++++++ 3 files changed, 38 insertions(+), 21 deletions(-) create mode 100644 src/utils/chunk-array.ts diff --git a/src/components/journal/journal-view.tsx b/src/components/journal/journal-view.tsx index 350c707..9ed1251 100644 --- a/src/components/journal/journal-view.tsx +++ b/src/components/journal/journal-view.tsx @@ -2,23 +2,22 @@ import { PlatformColor, View } from "react-native"; import { Grid, Host, ScrollView, VStack } from "@expo/ui/swift-ui"; import { padding } from "@expo/ui/swift-ui/modifiers"; +import { useLiveQuery } from "drizzle-orm/expo-sqlite"; import { JournalCard } from "@/components/journal/journal-card"; -import { JOURNALS } from "@/mocks/journals"; - -function chunkArray(arr: T[], size: number): T[][] { - const result: T[][] = []; - for (let i = 0; i < arr.length; i += size) { - result.push(arr.slice(i, i + size)); - } - return result; -} +import { getJournalsQuery } from "@/db/queries/journals"; +import { chunkArray } from "@/utils/chunk-array"; /** * ジャーナル一覧画面 */ export function JournalView() { - const rows = chunkArray(JOURNALS, 2); + const { data } = useLiveQuery(getJournalsQuery); + + const journals = data ?? []; + + // ジャーナルを2列にまとめる + const rows = chunkArray(journals, 2); return ( @@ -49,7 +48,7 @@ export function JournalView() { name={journal.name} icon={journal.icon} color={journal.color} - count={journal.count} + count={journal.entryCount} /> ))} diff --git a/src/db/queries/journals.ts b/src/db/queries/journals.ts index 63bd084..31056fa 100644 --- a/src/db/queries/journals.ts +++ b/src/db/queries/journals.ts @@ -1,26 +1,32 @@ +import { sql } from "drizzle-orm"; + import { db } from "@/db/client"; -import { FieldlObj, fields, JournalObj, journals } from "@/db/schemas"; +import { entries, FieldlObj, fields, JournalObj, journals } from "@/db/schemas"; /** - * ジャーナル一覧を取得する + * ジャーナル一覧を取得するクエリ */ -export const getJournals = async () => { - return db.query.journals.findMany(); -}; +export const getJournalsQuery = db.query.journals.findMany({ + extras: { + entryCount: + sql`(select count(*) from ${entries} where ${entries.journalId} = ${journals.id})`.as( + "entry_count", + ), + }, +}); /** - * ジャーナルに紐付いたエントリー一覧を取得する + * ジャーナルに紐付いたエントリー一覧を取得するクエリ * @param journalId ジャーナルID */ -export const getEntries = async (journalId: string) => { - return db.query.journals.findFirst({ +export const getEntriesQuery = (journalId: string) => + db.query.journals.findFirst({ where: (journals, { eq }) => eq(journals.id, journalId), with: { entries: true }, }); -}; /** - * ジャーナルをフィールドと共に作成する + * ジャーナルをフィールドと共に作成するクエリを実行 * @param journal ジャーナルのメタ情報 * @param newFields フィールド一覧 */ diff --git a/src/utils/chunk-array.ts b/src/utils/chunk-array.ts new file mode 100644 index 0000000..6ddb40c --- /dev/null +++ b/src/utils/chunk-array.ts @@ -0,0 +1,12 @@ +/** + * 配列を指定したサイズのチャンクに分割する + * @param arr 分割する配列 + * @param size チャンクのサイズ + */ +export const chunkArray = (arr: T[], size: number): T[][] => { + const result: T[][] = []; + for (let i = 0; i < arr.length; i += size) { + result.push(arr.slice(i, i + size)); + } + return result; +}; From 4ae2e0599a74c7ce93e6731d5b7415b13aabd94f Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 21:11:30 +0900 Subject: [PATCH 13/31] =?UTF-8?q?fix:=20=E8=BB=BD=E5=BE=AE=E3=81=AA?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/journal/journal-create-view.tsx | 4 ++-- src/db/client.ts | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/journal/journal-create-view.tsx b/src/components/journal/journal-create-view.tsx index 40b15b9..34b501b 100644 --- a/src/components/journal/journal-create-view.tsx +++ b/src/components/journal/journal-create-view.tsx @@ -22,7 +22,7 @@ import { padding, } from "@expo/ui/swift-ui/modifiers"; -import { FIELD_ICONS, FieldType } from "@/core/constants"; +import { FIELD_ICONS, FIELD_LABELS, FieldType } from "@/core/constants"; import { JournalMetaObj, type FieldObj, @@ -135,7 +135,7 @@ export function JournalCreateView({ modifiers={[frame({ width: 24 })]} /> renameField(field.id, value)} modifiers={[frame({ maxWidth: 9999 })]} /> diff --git a/src/db/client.ts b/src/db/client.ts index 354ae33..3037758 100644 --- a/src/db/client.ts +++ b/src/db/client.ts @@ -5,4 +5,7 @@ import * as schema from "@/db/schemas"; export const expoDb = openDatabaseSync("db.db", { enableChangeListener: true }); +// 外部キー制約を有効化 +expoDb.execSync("PRAGMA foreign_keys = ON"); + export const db = drizzle(expoDb, { schema }); From db4d6073417d5be1ffbda4f840116b9c2c863813 Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 22:51:02 +0900 Subject: [PATCH 14/31] =?UTF-8?q?feat:=20entry=E4=B8=80=E8=A6=A7=E3=82=92?= =?UTF-8?q?=E5=8F=96=E5=BE=97=E3=81=97=E3=81=A6=E8=A1=A8=E7=A4=BA=E3=81=99?= =?UTF-8?q?=E3=82=8B=E5=87=A6=E7=90=86=E3=82=92=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(journal)/[id].tsx | 9 +++----- src/components/entry/entry-list-view.tsx | 26 +++++++++++++++++++++--- src/components/journal/journal-card.tsx | 2 +- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/app/(journal)/[id].tsx b/src/app/(journal)/[id].tsx index a8f51d0..7724449 100644 --- a/src/app/(journal)/[id].tsx +++ b/src/app/(journal)/[id].tsx @@ -3,7 +3,6 @@ import { useState } from "react"; import { Stack, useLocalSearchParams } from "expo-router"; import { EntryListView } from "@/components/entry/entry-list-view"; -import { JOURNALS } from "@/mocks/journals"; /** * ソート一覧 @@ -30,17 +29,15 @@ const SORT_LABELS: Record = { * ジャーナル一覧 */ export default function JournalScreen() { - const { id } = useLocalSearchParams<{ id: string }>(); + const { id, name } = useLocalSearchParams<{ id: string; name: string }>(); const [searchText, setSearchText] = useState(""); const [sortKey, setSortKey] = useState("dateDesc"); - const journal = JOURNALS.find((journal) => journal.id === id); - return ( <> - + ); } diff --git a/src/components/entry/entry-list-view.tsx b/src/components/entry/entry-list-view.tsx index 7f15eca..92ea631 100644 --- a/src/components/entry/entry-list-view.tsx +++ b/src/components/entry/entry-list-view.tsx @@ -6,13 +6,15 @@ import { headerProminence, moveDisabled, } from "@expo/ui/swift-ui/modifiers"; +import { useLiveQuery } from "drizzle-orm/expo-sqlite"; import { GlassView } from "expo-glass-effect"; import { useRouter } from "expo-router"; import { SymbolView } from "expo-symbols"; import type { SortKey } from "@/app/(journal)/[id]"; -import { ENTRIES, type EntryObj } from "@/mocks/entries"; +import { getEntriesQuery } from "@/db/queries/entries"; import { formatYearMonth } from "@/utils/date"; +import { EntryObj } from "@/utils/journal/use-entry"; import { EntryRow } from "./entry-row"; @@ -49,21 +51,39 @@ function groupByMonth( } type Props = { + /**ジャーナル id */ + id: string; + /** 検索テキスト*/ searchText?: string; + /** ソートキー */ sortKey?: SortKey; }; export function EntryListView({ + id, searchText = "", sortKey = "dateDesc", }: Props) { const router = useRouter(); + const { data: dbEntries } = useLiveQuery(getEntriesQuery(id)); + + const entries: EntryObj[] = (dbEntries ?? []).map((entry) => ({ + id: entry.id, + date: new Date(entry.createdAt), + title: entry.values[0]?.value ?? "", + preview: entry.values + .slice(1) + .map((v) => v.value) + .join(" "), + bookmark: entry.bookmark, + })); + const filtered = searchText - ? ENTRIES.filter( + ? entries.filter( (e) => e.title.includes(searchText) || e.preview.includes(searchText), ) - : ENTRIES; + : entries; const sorted = sortEntries(filtered, sortKey); const grouped = groupByMonth(sorted); diff --git a/src/components/journal/journal-card.tsx b/src/components/journal/journal-card.tsx index db2cbeb..3b8b5c8 100644 --- a/src/components/journal/journal-card.tsx +++ b/src/components/journal/journal-card.tsx @@ -53,7 +53,7 @@ export function JournalCard({ id, name, icon, color, count }: Props) { modifiers={[ frame({ height: 85 }), clipShape("roundedRectangle", 20), - onTapGesture(() => router.push(`/(journal)/${id}`)), + onTapGesture(() => router.push(`/(journal)/${id}?name=${name}`)), ]} > Date: Wed, 6 May 2026 22:52:26 +0900 Subject: [PATCH 15/31] =?UTF-8?q?refactor:=20=E3=82=A8=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=83=AA=E3=83=BC=E5=8F=96=E5=BE=97=E5=87=A6=E7=90=86=E3=82=84?= =?UTF-8?q?=E5=9E=8B=E3=82=92=E5=88=A5=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB?= =?UTF-8?q?=E3=81=AB=E7=A7=BB=E5=8B=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/db/queries/entries.ts | 11 +++++++++++ src/db/queries/journals.ts | 10 ---------- src/mocks/entries.ts | 8 +------- src/utils/journal/use-entry.ts | 7 +++++++ 4 files changed, 19 insertions(+), 17 deletions(-) create mode 100644 src/db/queries/entries.ts create mode 100644 src/utils/journal/use-entry.ts diff --git a/src/db/queries/entries.ts b/src/db/queries/entries.ts new file mode 100644 index 0000000..a6831e7 --- /dev/null +++ b/src/db/queries/entries.ts @@ -0,0 +1,11 @@ +import { db } from "@/db/client"; + +/** + * ジャーナルに紐付いたエントリー一覧を取得するクエリ + * @param journalId ジャーナルID + */ +export const getEntriesQuery = (journalId: string) => + db.query.entries.findMany({ + where: (entries, { eq }) => eq(entries.journalId, journalId), + with: { values: true }, + }); diff --git a/src/db/queries/journals.ts b/src/db/queries/journals.ts index 31056fa..b67ee18 100644 --- a/src/db/queries/journals.ts +++ b/src/db/queries/journals.ts @@ -15,16 +15,6 @@ export const getJournalsQuery = db.query.journals.findMany({ }, }); -/** - * ジャーナルに紐付いたエントリー一覧を取得するクエリ - * @param journalId ジャーナルID - */ -export const getEntriesQuery = (journalId: string) => - db.query.journals.findFirst({ - where: (journals, { eq }) => eq(journals.id, journalId), - with: { entries: true }, - }); - /** * ジャーナルをフィールドと共に作成するクエリを実行 * @param journal ジャーナルのメタ情報 diff --git a/src/mocks/entries.ts b/src/mocks/entries.ts index c3377d6..449e207 100644 --- a/src/mocks/entries.ts +++ b/src/mocks/entries.ts @@ -1,10 +1,4 @@ -export type EntryObj = { - id: string; - date: Date; - title: string; - preview: string; - bookmark?: boolean; -}; +import { EntryObj } from "@/utils/journal/use-entry"; export const ENTRIES: EntryObj[] = [ { diff --git a/src/utils/journal/use-entry.ts b/src/utils/journal/use-entry.ts new file mode 100644 index 0000000..d6bd3dc --- /dev/null +++ b/src/utils/journal/use-entry.ts @@ -0,0 +1,7 @@ +export type EntryObj = { + id: string; + date: Date; + title: string; + preview: string; + bookmark?: boolean; +}; From c7ac630e30afbd742b1ba83774b5686a08bd190d Mon Sep 17 00:00:00 2001 From: 273* Date: Wed, 6 May 2026 23:26:25 +0900 Subject: [PATCH 16/31] =?UTF-8?q?fix:=20=E5=9E=8B=E3=81=AE=E5=91=BC?= =?UTF-8?q?=E3=81=B3=E5=87=BA=E3=81=97=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/entry/entry-detail.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/entry/entry-detail.tsx b/src/components/entry/entry-detail.tsx index 93228a9..9c92618 100644 --- a/src/components/entry/entry-detail.tsx +++ b/src/components/entry/entry-detail.tsx @@ -3,8 +3,8 @@ import { PlatformColor, View } from "react-native"; import { Host, List, Section, Text } from "@expo/ui/swift-ui"; import { frame, listStyle } from "@expo/ui/swift-ui/modifiers"; -import { EntryObj } from "@/mocks/entries"; import { formatDate } from "@/utils/date"; +import { EntryObj } from "@/utils/journal/use-entry"; /** * エントリー詳細画面 From 67e7d836eeef5151e5fc2e2d7bef707b3ae28bd6 Mon Sep 17 00:00:00 2001 From: 273* Date: Thu, 7 May 2026 00:08:12 +0900 Subject: [PATCH 17/31] =?UTF-8?q?fix:=20=E5=9E=8B=E3=81=AE=E5=91=BC?= =?UTF-8?q?=E3=81=B3=E5=87=BA=E3=81=97=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/entry/entry-row.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/entry/entry-row.tsx b/src/components/entry/entry-row.tsx index a13df4a..f083c05 100644 --- a/src/components/entry/entry-row.tsx +++ b/src/components/entry/entry-row.tsx @@ -4,8 +4,8 @@ import { Button, HStack, Image, Spacer, Text, VStack } from "@expo/ui/swift-ui"; import { font, foregroundStyle, lineLimit } from "@expo/ui/swift-ui/modifiers"; import { useRouter } from "expo-router"; -import { EntryObj } from "@/mocks/entries"; import { formatDate } from "@/utils/date"; +import { EntryObj } from "@/utils/journal/use-entry"; const secondary = foregroundStyle({ type: "hierarchical", style: "secondary" }); From 6fc82a71e0a63cd776f3d00387dad2c23c4ae944 Mon Sep 17 00:00:00 2001 From: 273* Date: Thu, 7 May 2026 22:46:16 +0900 Subject: [PATCH 18/31] =?UTF-8?q?fix:=20=E3=82=A8=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=83=AA=E3=83=BC=E8=A9=B3=E7=B4=B0=E7=94=BB=E9=9D=A2=E3=81=AE?= =?UTF-8?q?=E3=83=98=E3=83=83=E3=83=80=E3=83=BC=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(journal)/entry/[id].tsx | 4 ++-- src/components/entry/entry-row.tsx | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/app/(journal)/entry/[id].tsx b/src/app/(journal)/entry/[id].tsx index ffdcf7a..631ca00 100644 --- a/src/app/(journal)/entry/[id].tsx +++ b/src/app/(journal)/entry/[id].tsx @@ -15,8 +15,8 @@ export default function EntryDetailScreen() { <> [ { type: "menu", diff --git a/src/components/entry/entry-row.tsx b/src/components/entry/entry-row.tsx index f083c05..1155171 100644 --- a/src/components/entry/entry-row.tsx +++ b/src/components/entry/entry-row.tsx @@ -9,15 +9,22 @@ import { EntryObj } from "@/utils/journal/use-entry"; const secondary = foregroundStyle({ type: "hierarchical", style: "secondary" }); +type Props = { + /** + * エントリーデータ + * */ + entry: EntryObj; +}; + /** * エントリー行 */ -export function EntryRow({ entry }: { entry: EntryObj }) { +export function EntryRow({ entry }: Props) { const router = useRouter(); return ( ); diff --git a/src/utils/date.ts b/src/utils/date.ts index 2d3df44..c23ff59 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -3,7 +3,7 @@ * @param date フォーマットする日付 * @return フォーマットされた日付文字列 */ -export const formatDate = (date: Date): string => { +export const formatDate = (date: Date | number): string => { return new Intl.DateTimeFormat(undefined, { year: "numeric", month: "long", @@ -17,7 +17,7 @@ export const formatDate = (date: Date): string => { * @param date フォーマットする日付 * @returns フォーマットされた年月文字列 */ -export const formatYearMonth = (date: Date): string => { +export const formatYearMonth = (date: Date | number): string => { return new Intl.DateTimeFormat(undefined, { year: "numeric", month: "long", From e24c00b9369b874efc8d35f53e3d4fcfa0a7b992 Mon Sep 17 00:00:00 2001 From: 273* Date: Fri, 8 May 2026 23:41:38 +0900 Subject: [PATCH 24/31] =?UTF-8?q?refactor:=20=E9=96=A2=E6=95=B0=E3=81=AB?= =?UTF-8?q?=E8=BF=94=E3=82=8A=E5=80=A4=E3=81=AE=E5=9E=8B=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(journal)/create.tsx | 4 +-- src/utils/journal/use-journal-field.ts | 47 +++++++++++++------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/app/(journal)/create.tsx b/src/app/(journal)/create.tsx index 75da031..64f09c0 100644 --- a/src/app/(journal)/create.tsx +++ b/src/app/(journal)/create.tsx @@ -25,8 +25,8 @@ export default function JournalCreateScreen() { } = useJournalField(); const handleCreate = async () => { - const id = await createJournal(); - router.push(`/(journal)/${id}`); + const { id, name } = await createJournal(); + router.push(`/(journal)/${id}?name=${name}`); }; return ( diff --git a/src/utils/journal/use-journal-field.ts b/src/utils/journal/use-journal-field.ts index 47bf55f..2f07998 100644 --- a/src/utils/journal/use-journal-field.ts +++ b/src/utils/journal/use-journal-field.ts @@ -5,6 +5,7 @@ import type { SFSymbol } from "sf-symbols-typescript"; import { FIELD_ICONS, FieldType, JOURNAL_ICONS } from "@/core/constants"; import { storeJournal } from "@/db/queries/journals"; +import { FieldlObj, JournalObj } from "@/db/schemas"; /** * ジャーナルメタ情報の型 @@ -60,7 +61,7 @@ export const useJournalField = () => { * 新規フィールドを追加する * @param type 追加するフィールドの種別 */ - const addField = (type: FieldType) => { + const addField = (type: FieldType): void => { const newField: FieldObj = { id: Crypto.randomUUID(), type, @@ -74,7 +75,7 @@ export const useJournalField = () => { * @param id ラベルを編集する id * @param newLabel 新しいラベル */ - const renameField = (id: string, newLabel: string) => { + const renameField = (id: string, newLabel: string): void => { setFields((prev) => prev.map((field) => field.id === id ? { ...field, label: newLabel } : field, @@ -86,7 +87,7 @@ export const useJournalField = () => { * インデックス指定でフィールドを削除する(List.ForEach の onDelete 用) * @param indices 削除するインデックスの配列 */ - const deleteField = (indices: number[]) => { + const deleteField = (indices: number[]): void => { setFields((prev) => prev.filter((_, i) => !indices.includes(i))); }; @@ -95,7 +96,7 @@ export const useJournalField = () => { * @param sourceIndices 移動元のインデックス配列 * @param destination 移動先のインデックス */ - const moveField = (sourceIndices: number[], destination: number) => { + const moveField = (sourceIndices: number[], destination: number): void => { setFields((prev) => { const next = [...prev]; const moved = sourceIndices.map((i) => next[i]); @@ -116,28 +117,28 @@ export const useJournalField = () => { /** * 新規ジャーナルをフィールドと共にDBに保存する */ - const createJournal = async () => { + const createJournal = async (): Promise => { const now = Date.now(); - const id = Crypto.randomUUID(); - await storeJournal( - { - id, - name: meta.name, - icon: meta.icon, - color: meta.color, - createdAt: now, - updatedAt: now, - }, - fields.map((field, i) => ({ - id: field.id, - type: field.type, - label: field.label, - sortOrder: i, - })), - ); + const newJournal: JournalObj = { + id: Crypto.randomUUID(), + name: meta.name, + icon: meta.icon, + color: meta.color, + createdAt: now, + updatedAt: now, + }; + + const newFieldsFieldlObj: FieldlObj[] = fields.map((field, i) => ({ + id: field.id, + type: field.type, + label: field.label, + sortOrder: i, + })); + + await storeJournal(newJournal, newFieldsFieldlObj); - return id; + return newJournal; }; return { From 0c9a8e009205cda3e09a75bb9bfea774d86072a1 Mon Sep 17 00:00:00 2001 From: 273* Date: Fri, 8 May 2026 23:49:44 +0900 Subject: [PATCH 25/31] =?UTF-8?q?feat:=20=E3=82=B8=E3=83=A3=E3=83=BC?= =?UTF-8?q?=E3=83=8A=E3=83=AB=E4=BD=9C=E6=88=90=E5=BE=8C=E6=88=BB=E3=82=8B?= =?UTF-8?q?=E3=83=9C=E3=82=BF=E3=83=B3=E3=81=A7=E3=82=B8=E3=83=A3=E3=83=BC?= =?UTF-8?q?=E3=83=8A=E3=83=AB=E4=B8=80=E8=A6=A7=E3=81=AB=E6=88=BB=E3=82=8C?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(journal)/[id].tsx | 2 +- src/app/(journal)/create.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/(journal)/[id].tsx b/src/app/(journal)/[id].tsx index 7724449..4d2ecc6 100644 --- a/src/app/(journal)/[id].tsx +++ b/src/app/(journal)/[id].tsx @@ -26,7 +26,7 @@ const SORT_LABELS: Record = { }; /** - * ジャーナル一覧 + * ジャーナル詳細(エントリー一覧) */ export default function JournalScreen() { const { id, name } = useLocalSearchParams<{ id: string; name: string }>(); diff --git a/src/app/(journal)/create.tsx b/src/app/(journal)/create.tsx index 64f09c0..23c0e8a 100644 --- a/src/app/(journal)/create.tsx +++ b/src/app/(journal)/create.tsx @@ -26,7 +26,9 @@ export default function JournalCreateScreen() { const handleCreate = async () => { const { id, name } = await createJournal(); - router.push(`/(journal)/${id}?name=${name}`); + + // replace でスタックせずにジャーナル詳細画面からジャーナル一覧へ戻れるようにする + router.replace(`/(journal)/${id}?name=${name}`); }; return ( From 14b9cf5f8d3aea9a7372eb28d2c80c832d9edfd2 Mon Sep 17 00:00:00 2001 From: 273* Date: Sat, 9 May 2026 00:26:11 +0900 Subject: [PATCH 26/31] =?UTF-8?q?chore:=20=E3=83=93=E3=83=AB=E3=83=89?= =?UTF-8?q?=E3=82=B9=E3=82=AF=E3=83=AA=E3=83=97=E3=83=88=E3=81=AE=E5=AE=9F?= =?UTF-8?q?=E8=A1=8C=E3=82=92=E8=A8=B1=E5=8F=AF=E3=81=99=E3=82=8B=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index ce7b452..6ce13bb 100644 --- a/package.json +++ b/package.json @@ -57,5 +57,8 @@ "prettier": "^3.8.3", "typescript": "~5.9.2" }, - "private": true + "private": true, + "pnpm": { + "onlyBuiltDependencies": ["esbuild", "unrs-resolver"] + } } From 6188734e8a6734056c3c44b0ca7e761da2edbe07 Mon Sep 17 00:00:00 2001 From: 273* Date: Sat, 9 May 2026 00:32:28 +0900 Subject: [PATCH 27/31] =?UTF-8?q?chore:=20ci=E3=81=AEpnpm=E3=81=AE?= =?UTF-8?q?=E3=83=90=E3=83=BC=E3=82=B8=E3=83=A7=E3=83=B3=E3=82=92=E3=83=AD?= =?UTF-8?q?=E3=83=BC=E3=82=AB=E3=83=AB=E3=81=A8=E5=90=8C=E6=A7=98=E3=81=AE?= =?UTF-8?q?=E3=82=82=E3=81=AE=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 2 +- package.json | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc961d7..46a0641 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 with: - version: latest + version: 9 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 diff --git a/package.json b/package.json index 6ce13bb..b162398 100644 --- a/package.json +++ b/package.json @@ -57,8 +57,6 @@ "prettier": "^3.8.3", "typescript": "~5.9.2" }, - "private": true, - "pnpm": { - "onlyBuiltDependencies": ["esbuild", "unrs-resolver"] - } + "packageManager": "pnpm@9.11.0", + "private": true } From a199ad6d48c84d3c6085698bd460fafc5336d4b3 Mon Sep 17 00:00:00 2001 From: 273* Date: Sat, 9 May 2026 01:05:02 +0900 Subject: [PATCH 28/31] =?UTF-8?q?chore:=20=E3=83=AD=E3=83=BC=E3=82=AB?= =?UTF-8?q?=E3=83=AB=E3=81=A8ci=E3=81=AEpnpm=E3=81=AE=E3=83=90=E3=83=BC?= =?UTF-8?q?=E3=82=B8=E3=83=A7=E3=83=B3=E3=82=9211.0.0=E3=81=AB=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 2 +- package.json | 12 +++++++++--- pnpm-workspace.yaml | 3 +++ 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 pnpm-workspace.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46a0641..3bffb75 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 with: - version: 9 + version: 11 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 diff --git a/package.json b/package.json index b162398..b03d562 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,12 @@ "prettier": "^3.8.3", "typescript": "~5.9.2" }, - "packageManager": "pnpm@9.11.0", - "private": true -} + "packageManager": "pnpm@11.0.0", + "private": true, + "pnpm": { + "onlyBuiltDependencies": [ + "esbuild", + "unrs-resolver" + ] + } +} \ No newline at end of file diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..6c458ab --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +allowBuilds: + esbuild: true + unrs-resolver: true From a732b49519c2e11c28bb47866b45cdd9fafa3b7e Mon Sep 17 00:00:00 2001 From: 273* Date: Sat, 9 May 2026 01:14:19 +0900 Subject: [PATCH 29/31] =?UTF-8?q?chore:=20CI=E3=81=AEversion=E3=82=92?= =?UTF-8?q?=E5=89=8A=E9=99=A4=E3=81=97=E3=81=A6packageManager=E3=81=AB?= =?UTF-8?q?=E4=B8=80=E6=9C=AC=E5=8C=96=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3bffb75..08989f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,6 @@ jobs: steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 - with: - version: 11 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 From dc99d0d90367d7321733bee121d2134ee3f21b5f Mon Sep 17 00:00:00 2001 From: 273* Date: Sat, 9 May 2026 01:17:32 +0900 Subject: [PATCH 30/31] =?UTF-8?q?fix:=20SFSymbol=E3=81=AE=E5=91=BC?= =?UTF-8?q?=E3=81=B3=E5=87=BA=E3=81=97=E5=85=83=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/journal/icon-select-bottom-sheet.tsx | 2 +- src/utils/journal/use-journal-field.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/journal/icon-select-bottom-sheet.tsx b/src/components/journal/icon-select-bottom-sheet.tsx index 6d8ddda..47453f4 100644 --- a/src/components/journal/icon-select-bottom-sheet.tsx +++ b/src/components/journal/icon-select-bottom-sheet.tsx @@ -18,7 +18,7 @@ import { presentationDetents, presentationDragIndicator, } from "@expo/ui/swift-ui/modifiers"; -import type { SFSymbol } from "sf-symbols-typescript"; +import { SFSymbol } from "expo-symbols"; import { JOURNAL_ICONS } from "@/core/constants"; diff --git a/src/utils/journal/use-journal-field.ts b/src/utils/journal/use-journal-field.ts index 2f07998..a9eab28 100644 --- a/src/utils/journal/use-journal-field.ts +++ b/src/utils/journal/use-journal-field.ts @@ -1,7 +1,7 @@ import { useState } from "react"; import * as Crypto from "expo-crypto"; -import type { SFSymbol } from "sf-symbols-typescript"; +import { SFSymbol } from "expo-symbols"; import { FIELD_ICONS, FieldType, JOURNAL_ICONS } from "@/core/constants"; import { storeJournal } from "@/db/queries/journals"; From 1530198227bf19a308e6266b761ad32cb2bc0f99 Mon Sep 17 00:00:00 2001 From: 273* Date: Sat, 9 May 2026 01:19:22 +0900 Subject: [PATCH 31/31] =?UTF-8?q?chore:=20lefthook=E3=81=AB=E5=9E=8B?= =?UTF-8?q?=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lefthook.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lefthook.yml b/lefthook.yml index 90a1f91..7a46edf 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -10,6 +10,8 @@ pre-commit: lint-and-format-check: glob: "*.{ts,tsx,js,jsx}" run: pnpm run lint + typecheck: + run: pnpm run typecheck commit-msg: commands: