This document describes the core data models, storage layer architecture, and database abstractions used in memos. It covers the entity structures, protocol buffer definitions, and the store abstraction pattern that enables multi-database support.
The memos application implements a three-layer storage architecture that separates API contracts, business logic, and database implementations.
Title: Storage Layer Abstraction
Sources: store/memo.go35-55 store/db/sqlite/memo.go16-52 store/db/mysql/memo.go16-60 store/db/postgres/memo.go16-49 store/store.go13-31
This separation enables:
Driver interface store/driver.go10-87The Memo is the primary entity representing a note or post. It exists in three forms across the architecture layers.
| Field | Type | Description |
|---|---|---|
ID | int32 | System-generated unique identifier store/memo.go37 |
UID | string | User-defined unique identifier store/memo.go39 |
RowStatus | RowStatus | Lifecycle state: NORMAL or ARCHIVED store/memo.go42 |
CreatorID | int32 | Foreign key to the user who created the memo store/memo.go43 |
CreatedTs | int64 | Unix timestamp of creation store/memo.go44 |
UpdatedTs | int64 | Unix timestamp of last update store/memo.go45 |
Content | string | Markdown-formatted content store/memo.go48 |
Visibility | Visibility | Access control: PUBLIC, PROTECTED, or PRIVATE store/memo.go49 |
Pinned | bool | Whether the memo is pinned to the top store/memo.go50 |
Payload | *storepb.MemoPayload | Protobuf-backed structured metadata store/memo.go51 |
ParentUID | *string | Composed field indicating parent memo for comments store/memo.go54 |
Sources: store/memo.go35-55 proto/store/memo.proto1-20
The User entity represents a system user with authentication and profile information.
| Field | Type | Description |
|---|---|---|
ID | int32 | System-generated identifier store/user.go30 |
Username | string | Unique username for login store/user.go38 |
Role | Role | User role: ADMIN or USER store/user.go39 |
Nickname | string | Display name store/user.go41 |
PasswordHash | string | Hashed password store/user.go42 |
AvatarURL | string | Profile avatar URL store/user.go43 |
Description | string | User bio/description store/user.go44 |
Sources: store/user.go29-45
The Migrator handles database schema versioning and upgrades using embedded SQL scripts.
Title: Migration Flow Logic
store/migration/{driver}/{version}/NN__description.sql store/migrator.go39-40LATEST.sql is used for fresh installations to bypass incremental steps store/migrator.go56-57Sources: store/migrator.go21-172
The Store struct provides the entry point for all data operations, utilizing a Driver for persistence and Cache for performance.
Title: Data Access Pattern
Sources: store/store.go13-31 store/driver.go10-87
base.UIDMatcher before calling the driver store/memo.go109-114memo_relation and attachment records associated with the memo ID store/memo.go140-159The Store implements an in-memory cache for user data to reduce database load.
userCache first; if missed, queries the driver and populates the cache store/user.go148-169userCreateMu to prevent concurrent first-user setup store/user.go105-124Settings are stored as key-value pairs where the value is a stringified JSON of a protobuf message store/user_setting.go14-18 The store provides helper methods for complex settings like RefreshTokens and PersonalAccessTokens store/user_setting.go149-237
Sources: store/memo.go109-159 store/user.go92-181 store/user_setting.go43-237
Each driver (SQLite, MySQL, PostgreSQL) handles SQL dialect differences, particularly for timestamps and JSON.
| Feature | SQLite | MySQL | PostgreSQL |
|---|---|---|---|
| Timestamps | Unix Integer store/db/sqlite/memo.go44 | FROM_UNIXTIME store/db/mysql/memo.go32 | Unix BigInt store/db/postgres/memo.go41 |
| JSON | protojson to String store/db/sqlite/memo.go21 | protojson to String store/db/mysql/memo.go21 | protojson to String store/db/postgres/memo.go20 |
| Placeholders | ? store/db/sqlite/memo.go18 | ? store/db/mysql/memo.go18 | $1, $2... store/db/postgres/memo.go38 |
| Identity | RETURNING id store/db/sqlite/memo.go41 | LastInsertId() store/db/mysql/memo.go47 | RETURNING id store/db/postgres/memo.go38 |
QueryRowContext with RETURNING for efficient creation store/db/sqlite/memo.go41-49GetMemo call after ExecContext because it lacks a RETURNING clause for all fields store/db/mysql/memo.go41-59QueryRowContext store/db/postgres/memo.go38-49Sources: store/db/sqlite/memo.go store/db/mysql/memo.go store/db/postgres/memo.go
Refresh this wiki
This wiki was recently refreshed. Please wait 6 days to refresh again.