An open API service indexing awesome lists of open source software.

https://github.com/evandersondev/snail

🐌 Snail is a library inspired by Spring Data JPA, designed to simplify SQLite database management in Flutter/Dart applications. Easy to use like a snail (but as functional as a rocket πŸš€)!
https://github.com/evandersondev/snail

dart flutter jpa orm snail sqflite sql

Last synced: about 2 months ago
JSON representation

🐌 Snail is a library inspired by Spring Data JPA, designed to simplify SQLite database management in Flutter/Dart applications. Easy to use like a snail (but as functional as a rocket πŸš€)!

Awesome Lists containing this project

README

          

# 🐌 Snail: A Simple ORM-like Library for Flutter/Dart 🐦

**Snail** is a library inspired by Spring Boot's JPA, designed to simplify SQLite database management in Flutter/Dart applications. Easy to use like a snail 🐌 (but as functional as a rocket πŸš€)!

## ✨ Features

- βœ… Create, Read, Update, Delete (CRUD) operations.
- πŸ” Dynamic query methods based on method naming conventions.
- πŸ› οΈ Table creation based on field definitions.
- πŸ”„ Automatic mapping of entities to database rows and vice versa.
- πŸ”— Support for snake_case and camelCase conversions.
- πŸ“œ Pagination, sorting, and filtering support.

## πŸ“₯ Installation

Add the following dependency to your `pubspec.yaml`:

```yaml
dependencies:
snail: ^1.1.4
```

## Getting Started 🏁

### Creating a Repository πŸ“¦

To create a repository for your model, extend the `SnailRepository` class:

```dart
import 'package:snail/snail.dart';

class UserRepository extends SnailRepository {
UserRepository() : super(
tableName: 'users',
primaryKeyColumn: 'id',
defineFields: {
'id': int,
'name': String,
'email': String,
'isActive': bool,
},
);

@override
Map toMap(User entity) => entity.toMap();

@override
User fromMap(Map map) => User.fromMap(map);
}

class User {
final int id;
final String name;
final String email;
final bool isActive;

User({
required this.id,
required this.name,
required this.email,
required this.isActive,
});

Map toMap() {
final result = {};

result.addAll({'id': id});
result.addAll({'name': name});
result.addAll({'email': email});
result.addAll({'isActive': isActive});

return result;
}

factory UserModel.fromMap(Map map) {
return UserModel(
id: map['id']?.toInt() ?? 0,
name: map['name'] ?? '',
email: map['email'] ?? '',
email: map['isActive'] ?? '',
);
}
}

void main() async {
WidgetsFlutterBinding.ensureInitialized();

await Snail.initialize(
repositories: [
UserRepository(),
],
);

runApp(AppWidget());
}
```

### Using the Repository πŸ”§

```dart
void main() async {
final userRepository = UserRepository();

// Save a user
await userRepository.save(User(id: 1, name: 'John Doe', email: 'john@example.com', isActive: true));

// Find a user by ID
final user = await userRepository.findById(1);

// Find all users
final users = await userRepository.findAll();

// Delete a user
await userRepository.deleteById(1);
}
```

## Dynamic Methods πŸ”

The `dynamicMethod` allows constructing SQL queries based on the method naming. The naming structure should follow standard conventions:

### Naming Structure πŸ› οΈ

- **Prefixes**: `find` or `findAll`
- **Connectors**: `And`, `Or`
- **Operators**: `Between`, `LessThan`, `GreaterThan`, `Like`, `StartingWith`, `EndingWith`, `Containing`, `In`, `NotIn`, `OrderBy`, `True`, `False`, `IsNull`, `NotNull`

### Example Naming Conventions πŸ“–

```dart
findByTitle(String title);
findById(int id);
findByTitleAndDescription(String title, String description);
findByTitleOrDescription(String title, String description);
findByTitleStartingWith(String title);
findByTitleEndingWith(String title);
findByTitleContaining(String title);
findByIdLessThan(int id);
findByIdGreaterThan(int id);
findByDateBetween(DateTime startDate, DateTime endDate);
findByTitleStartingWithAndIdLessThan(String title, int id);
findByTitleContainingOrDescriptionLike(String title, String description);
findByIdIn(List ids);
findByIdNotIn(List ids);
findByTitleOrderByDate(String title);
findByTitleOrderByDateDesc(String title);
findByTitleAndDescriptionOrderByDate(String title, String description);
findByIsActiveTrue();
findByIsActiveFalse();
findByTitleIsNull();
findByTitleNotNull();
```

### Usage Example πŸ“

```dart
Future> findByTitleStartingWith(String title) {
return dynamicMethod('findByTitleStartingWith', [title]);
}
```

## Filters: Pagination, Sorting, and Size πŸ“Š

Snail supports additional filtering through the `size`, `page`, and `sort` parameters:

- **`size`**: Specifies the number of records to fetch per page. Example: `size: 20`.
- **`page`**: Specifies the page number to fetch. Example: `page: 1` (fetches the first 20 records if `size` is set to 20).
- **`sort`**: Specifies the sorting order. Use the format `,`, where `` can be `asc` or `desc`. Example: `sort: 'createdAt,asc'`.

By default, Snail applies a descending sort (`createdAt,desc`) if no sorting is specified.

### Example Usage πŸ“

```dart
Future> findAllUsersWithPagination() async {
return await userRepository.findAll(
size: 20,
page: 1,
sort: 'createdAt,asc',
);
}
```

## CRUD Operations βš™οΈ

### Save or Update an Entity πŸ’Ύ

```dart
Future save(T entity);
```

### Save or Update Multiple Entities πŸ’ΎπŸ’Ύ

```dart
Future> saveAll(List entities);
```

### Find an Entity by ID πŸ”

```dart
Future findById(ID id);
```

### Find All Entities πŸ”Ž

```dart
Future> findAll({int? size, int? page, String? sort});
```

### Delete an Entity by ID πŸ—‘οΈ

```dart
Future deleteById(ID id);
```

### Delete All Entities πŸ—‘οΈπŸ—‘οΈ

```dart
Future deleteAll(List? entities);
```

### Count Entities πŸ”’

```dart
Future count();
```

## Automatic Fields: `createdAt` and `updatedAt` πŸ•’

Snail automatically adds `createdAt` and `updatedAt` fields to all models. These fields track when a record was created and last updated.

### Optional Usage in Models πŸ“Œ

If you wish to explicitly include these fields in your model, you can define them as optional:

```dart
class TodoModel {
final String id;
final String title;
final bool isCompleted;
final DateTime? createdAt;
final DateTime? updatedAt;

TodoModel({
required this.id,
required this.title,
this.isCompleted = false,
this.createdAt,
this.updatedAt,
});

Map toMap() {
return {
'id': id,
'title': title,
'isCompleted': isCompleted,
'createdAt': createdAt,
'updatedAt': updatedAt,
};
}

factory TodoModel.fromMap(Map map) {
return TodoModel(
id: map['id'] as String,
title: map['title'] as String,
isCompleted: map['isCompleted'] as bool,
createdAt: map['createdAt'] as DateTime?,
updatedAt: map['updatedAt'] as DateTime?,
);
}
}
```

## Full API πŸ“š

Below is the complete list of methods provided by Snail Repository:

| Method | Description |
| -------------------------------------------------- | ---------------------------------------------------------------- |
| `save(T entity)` | Saves or updates an entity in the database. |
| `saveAll(List entities)` | Saves or updates multiple entities in the database. |
| `findById(ID id)` | Finds an entity by its primary key. |
| `findAll({int? size, int? page, String? sort})` | Retrieves all entities with optional pagination and sorting. |
| `deleteAll(List? entities)` | Deletes all entities or a list of specified entities. |
| `count()` | Counts the total number of entities in the database. |
| `dynamicMethod(String name, List params)` | Executes a query based on the dynamic method naming conventions. |

## Contributing 🀝

Feel free to fork this repository and contribute by submitting a pull request. Your contributions are welcome! πŸ’‘

## License πŸ“œ

This project is licensed under the MIT License.

---

Made with ❀️ for Flutter developers! 🎯