找回密码
 注册
搜索
熊猫速汇 50 元券 🔥ByBit 交易所羊毛🐑MyFin 5 欧元羊毛 🔥
人人必备的 Wise 💳最便宜的 eSIM 流量手机号 📱个人 IBAN 出金,注册送 $25 比特币 ฿
5ber eSIM 实体卡 95 折 🏷️免费领取 500M 新加坡 eSIM 流量 🎁数字货币银行卡,注册送 7 美元💲
查看: 369|回复: 0

typeorm 在 expo app 里的应用

[复制链接]

800

主题

7325

回帖

1万

积分

版主

积分
17770
HelloWorld 发表于 2024-2-23 23:58:25 | 显示全部楼层 |阅读模式

注册免广告

您需要 登录 才可以下载或查看,没有账号?注册

×
本帖最后由 HelloWorld 于 2024-2-24 10:11 编辑

最近在写个 app 需要用到 sqlite,选择 orm 时,本来打算用 Prisma,但是这个必须 node 环境,expo 用不了

另一个比较流行的是 typeorm,查了一下,他们官方提供了 expo 例子:https://github.com/typeorm/expo-example ,将这个仓库拉本地运行直接失败,毕竟 6 年前老项目,expo 版本也不兼容了

于是自己新建一个 expo-router 项目:https://docs.expo.dev/router/installation ,然后将 expo-example 的页面代码和 entities 拷贝到 expo-router 项目里
由于 typeorm 用到装饰器,所以需要在 tsconfig.json 里添加 compilerOptions.experimentalDecorators 和 compilerOptions.emitDecoratorMetadata 并且值都设为 true

然后运行,一堆报错,其中一个可能是因为 expo-example 用的类组件搬到 expo-router 里无法被 tab 识别,于是将整个页面改成 function 组件,代码会放到帖子末尾

改了 function 组件运行再次报错,将错误消息拿去问 gemini,说在 entity 里需要设置变量类型,于是设置 @Column({type: 'string'}),运行又报错,再次问 gemini,它说 sqlite 没有 string 类型,于是用了 text,运行成功:
  1. import { Entity, PrimaryGeneratedColumn, Column } from "typeorm/browser";
  2. @Entity('category')
  3. export class Category {
  4.   @PrimaryGeneratedColumn()
  5.   id!: number;

  6.   @Column({ type: 'text' })
  7.   name!: string;
  8. }
复制代码


上文提到的类组件页面代码改成函数组件:
  1. import React, { useEffect, useState } from 'react'
  2. import {
  3.   StyleSheet,
  4.   Text,
  5.   View,
  6.   Button,
  7.   Alert
  8. } from 'react-native';

  9. import { DataSource } from 'typeorm/browser';
  10. import { Category } from '@/database/entities/category';
  11. import { Author } from '@/database/entities/author';
  12. import { Post } from '@/database/entities/post';
  13. import * as FileSystem from 'expo-file-system'

  14. const database = 'test19.db' // without .db as extension is ok, but recommanded
  15. const dataSource = new DataSource({
  16.   database,
  17.   driver: require('expo-sqlite'),
  18.   entities: [
  19.     Category,
  20.     Author,
  21.     Post
  22.   ],
  23.   synchronize: true,
  24.   type: "expo",
  25. })

  26. export default function SqlitePage() {

  27.   const [progress, setProgress] = useState('')
  28.   const [loadedPost, setLoadedPost] = useState<Post>()

  29.   function connect() {
  30.     return dataSource.initialize()
  31.   }

  32.   useEffect(() => {
  33.     runDemo()
  34.   }, [])

  35.   async function runDemo() {
  36.     const source = await connect();

  37.     const category1 = new Category();
  38.     category1.name = "TypeScript";

  39.     const category2 = new Category();
  40.     category2.name = "Programming";

  41.     const author = new Author();
  42.     author.name = "Person";

  43.     const post = new Post();
  44.     post.title = "Control flow based type analysis";
  45.     post.text = "TypeScript 2.0 implements a control flow-based type analysis for local variables and parameters.";
  46.     post.categories = [category1, category2];
  47.     post.author = author;

  48.     const postRepository = source.getRepository(Post);
  49.     await postRepository.save(post);

  50.     console.log("Post has been saved");
  51.     setProgress("Post has been saved")

  52.     const loadedPost = await postRepository.findOne({ where: { id: post.id }, relations: ["author", "categories"] });

  53.     if (loadedPost) {
  54.       console.log("Post has been loaded: ", loadedPost);
  55.       setLoadedPost(loadedPost)
  56.     }
  57.   }

  58.   async function checkSqliteFile() {
  59.     const dataDirectory = FileSystem.documentDirectory || FileSystem.cacheDirectory;
  60.     const databaseFilePath = `${dataDirectory}SQLite/${database}`
  61.     console.log('databaseFilePath', databaseFilePath)
  62.     try {
  63.       const fileInfo = await FileSystem.getInfoAsync(databaseFilePath);
  64.       const fileExists = fileInfo.exists;
  65.       Alert.alert(`fileExists: ${fileExists}`, databaseFilePath)
  66.     } catch (error) {
  67.       console.error('Error getting file info:', error);
  68.     }
  69.   }

  70.   return (
  71.     <View style={styles.container}>
  72.       <Text style={styles.welcome}>
  73.         Welcome to the Expo Example for TypeORM!
  74.       </Text>
  75.       <Text style={styles.small}>
  76.         {progress}
  77.       </Text>
  78.       <Text style={styles.small}>
  79.         {JSON.stringify(loadedPost)}
  80.       </Text>

  81.       <Button title='If sqlite file exists' onPress={checkSqliteFile} />
  82.     </View>
  83.   );

  84. }

  85. const styles = StyleSheet.create({
  86.   container: {
  87.     flex: 1,
  88.     justifyContent: 'center',
  89.     alignItems: 'center',
  90.     backgroundColor: '#F5FCFF',
  91.   },
  92.   welcome: {
  93.     fontSize: 20,
  94.     textAlign: 'center',
  95.     margin: 10,
  96.   },
  97.   small: {
  98.     textAlign: 'center',
  99.     color: '#333333',
  100.     marginBottom: 5,
  101.   },
  102. });
复制代码


点击页面里的“If sqlite file exists”按钮,terminal log 会打印出 sqlite 数据库文件路径,按住 cmd 点击路径可以打开文件,如果你的 vscode 装了 SQLite Viewer 可以直接查看数据库内容
您需要登录后才可以回帖 登录 | 注册

本版积分规则

排行榜|意见建议|数字居民论坛

GMT+8, 2024-12-4 01:37

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表