본문 바로가기
CODE/Flutter

[Flutter] Supabase CRUD 해보기

by Nuridal_class 2023. 12. 21.
728x90
728x90

 Supabase stream CRUD

이전 포스팅에선 Supabase에서 실시간으로 데이터의 값을 확인하는 방법에 대해서 알아보았습니다
 

[Flutter, Supabase] Supabase RealTime Data 가져오기

RealTime Data 가져오기 이전 포스팅으로 Supabase를 flutter에 연동하는 부분까지 알아보았다 [Flutter, Supabase] supabase 연동하기 Supabase 란? 간단하게 설명하면 백엔드 서비스 플랫폼이다. 오픈소스이며 Pos

nuridal-class.tistory.com

이번 포스팅에서는 App 상에서 create, read, update, delete 이 4가지 기능확인해보려고 합니다

 

 Supbase_crud_view.dart

저번에 사용했던 dart 파일에 코드를 추가해서 예시문을 만들어보겠습니다
쿼리문 작성하듯이 하면 되니 CRUD는 아래의 예제와 같이 간단하게 수행할 수 있습니다
  //📲 추가된 코드만 작성되었습니다
  //📲 전체 코드는 github에서 확인 가능합니다
  
  final TextEditingController todoTextController = TextEditingController();

                  ...
                  
                  trailing: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      //📲 레이아웃 에러를 피하기 위한 Flexible
                      Flexible(
                        child: IconButton(
                          onPressed: () async {
                            actionTodoDialog(
                              context: context,
                              title: 'Edit a todo',
                              hintText: todos[index]['todo'],
                              textController: todoTextController,
                              onPressed: () async {
                                //👉 UPDATE 하기
                                //📲 toto table에서 toto column을 업데이트 수행
                                //📲 후에 에러가 없다면 dialog 창 종료
                                await supabase
                                    .from('todo')
                                    .update({'todo': todoTextController.text})
                                    .eq('id', todos[index]['id'])
                                    .then((value) {
                                      if (value.error != null) {
                                        todoTextController.clear();
                                        Navigator.pop(context);
                                      }
                                    });
                              },
                            );
                          },
                          icon: const Icon(Icons.edit),
                        ),
                      ),
                      Flexible(
                        child: IconButton(
                          //📲 todo talble에서 id가 맞는것을 찾아 삭제 수행
                          onPressed: () async {
                            //👉 DELETE 하기
                            await supabase
                                .from('todo')
                                .delete()
                                .eq('id', todos[index]['id']);
                          },
                          icon: const Icon(Icons.delete),
                        ),
      ...
      
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          actionTodoDialog(
              context: context,
              title: 'Add a todo',
              hintText: 'new todo',
              textController: todoTextController,
              onPressed: () async {
                //👉 INSERT 하기
                //📲 todo table에서 todo column에 textController의 text를 insert 수행
                //📲 후에 에러가 없다면 dialog 창 종료
                await Supabase.instance.client
                    .from('todo')
                    .insert({'todo': todoTextController.text}).then((value) {
                  if (value.error != null) {
                    todoTextController.clear();
                    Navigator.pop(context);
                  }
                });
              });
        },
        child: const Icon(Icons.add),
      ),
    );
  }
  
  //📲 insert와 update에서 똑같이 사용하기 때문에 한 함수로 코드를 간소화 시켰습니다
  Future<dynamic> actionTodoDialog({
    required BuildContext context,
    required String title,
    required String hintText,
    required TextEditingController textController,
    required void Function() onPressed,
  }) {
    return showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
              title: Text(title),
              content: TextField(
                controller: textController,
                decoration: InputDecoration(
                  hintText: hintText,
                ),
              ),
              actions: [
                ElevatedButton(
                  onPressed: () => Navigator.pop(context),
                  child: const Text('CANCEL'),
                ),
                ElevatedButton(
                  onPressed: onPressed,
                  child: const Text('OK'),
                )
              ]);
        });
  }
}

 

 Policy 새롭게 설정

policy에서 select만 수행가능하도록 설정했다면 
아마 App에서 read를 제외한 나머지 기능을 수행하려고 하면 제대로 수행이 안 되는 것을 볼 수 있는데
이때 아래의 사진과 같이 ALL을 클릭해 주고 policy를 새롭게 만들어 주면 된다

supabase select insert update delete policy setting

 

 Insert , Update, Delete수행 결과

아래의 영상은 오른쪽 부터 insert, update, delete입니다
중요한 점은 각각 수행했을 때에
새로고침 없이 바로 데이터가 생성, 실시간으로 감지된 것을 볼 수 있습니다

flutter supabase stream insertflutter supabase updateflutter supabase delete
왼쪽 부터 insert, update, delete

 

 💡 중요한 차이점

그런데 여기서 중요한 점이 하나 있습니다

    await supabase
        .from('todo')
        .update({'todo': todoTextController.text})
        .eq('id', todos[index]['id'])
        .then((value) {
          debugPrint('어떤 값이 들어있나 볼까?: $value');
          todoTextController.clear();
          Navigator.pop(context);
    });
이 코드에서 어떤값을 가져오는지 print를 해보았는데
아니...?? null?? Supabase에는 정상적으로 되었는데 null 이라니!!
이 부분은 Realtime을 또 다르게 감지하는 Subscribe to channel을 통해서 알아보겠습니다

 

💡 오늘 사용한 예제는 github에 업데이트가 되어있습니다
     마음껏 사용하셔도 무관합니다
 

GitHub - Jeoungeunseok/supabase: supabase connection and postgreSQL use

supabase connection and postgreSQL use. Contribute to Jeoungeunseok/supabase development by creating an account on GitHub.

github.com


오늘은 Stream을 사용해서 App에서 CRUD 하는 방법을 알아보았습니다
다음 포스팅에서는 마지막에 충격적인 null값을 도출했던 이유와
어떻게 해야 값을 받아올 수 있는지에 대해서 알아보겠습니다
그럼! 코딩이 쉬워지는 그날까지!!

728x90
300x250