Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
b885373
Zip Fix
amigin Apr 21, 2024
78ce706
Now we can deserialize Options which are not in a list yet
amigin Apr 26, 2024
dbd218b
Last version of flurl
amigin Jul 9, 2024
1cc719a
Merge branch 'current-production' of github.com:MyJetTools/my-no-sql-…
amigin Jul 9, 2024
8e3f42e
0.3.1
amigin Jul 9, 2024
f95cc03
Last version of my-json
amigin Jul 9, 2024
bd9e3e5
Added ability to do request through SSH
amigin Aug 1, 2024
2d66cf1
Made it possible to be buildable
amigin Aug 1, 2024
d8d0c9c
0.3.3 - with-ssh
amigin Aug 1, 2024
928bd0f
Exposed with-ssh feature for data-writer
amigin Aug 1, 2024
60d3392
Added Ability to connect using ssh string and SshCertCredentials
amigin Aug 1, 2024
084f602
Fixes
amigin Aug 1, 2024
bc68c53
Fixes
amigin Aug 6, 2024
32963ae
Removed with SSH
amigin Aug 12, 2024
1a75b40
Made retry natively from FlUrl
amigin Sep 12, 2024
3c20f35
Made ability to Lazy Deserialize entities
amigin Sep 20, 2024
7341d27
Made tests compilable
amigin Sep 20, 2024
19badf4
Added tests
amigin Sep 20, 2024
ecef022
Fixes master node tests
amigin Sep 21, 2024
528cac7
CI Fixes
amigin Sep 21, 2024
a53f9f7
Fixes
amigin Sep 21, 2024
777d64d
import
RomanSavh Oct 1, 2024
97a523a
Added ability to get list of Partitions
amigin Oct 3, 2024
85d8ca0
Merge branch 'current-production' of github.com:MyJetTools/my-no-sql-…
amigin Oct 3, 2024
221fd41
Get PartitionKeys
amigin Oct 3, 2024
dad249e
Fixes
amigin Oct 3, 2024
60140bf
my-json is exposed
amigin Oct 18, 2024
90216df
zip last version is on
amigin Oct 18, 2024
a34697e
Added ability to scan and find entity inside partition not copying al…
amigin Oct 20, 2024
de48eec
Default is implemented for DbTableAttributes
amigin Oct 21, 2024
4208517
Now we write error if can not find the start of Array or Json Object …
amigin Oct 21, 2024
f011811
plugged my-http-client
amigin Nov 9, 2024
acfa156
New api to set ssh credentials
amigin Nov 11, 2024
18a3611
Fixes
amigin Nov 11, 2024
408d021
Added ability to ping writer
amigin Nov 13, 2024
b6442ac
Added get_app_name and get_app_version as part of settings
amigin Nov 13, 2024
c24f714
Merge pull request #2 from MyJetTools/my-http-client
amigin Nov 13, 2024
7730936
Fixes
amigin Nov 13, 2024
657e603
Return backward compatible
amigin Nov 13, 2024
ad35369
rust-extensions:0.1.5
amigin Nov 19, 2024
80420a7
Fixes
amigin Nov 19, 2024
ba3da21
Improvements with Parsing DbEntity
amigin Nov 19, 2024
a070f21
Removed debug info
amigin Nov 19, 2024
81c8dba
DbTableName now is a structure
amigin Nov 20, 2024
59c6563
Improvements
amigin Nov 20, 2024
ea41fd2
Improvements
amigin Nov 21, 2024
4f90eb2
Improvements
amigin Nov 21, 2024
53626b5
Improved the way restoration is done
amigin Nov 21, 2024
14cc45e
Made restore method for a partition
amigin Nov 21, 2024
2dd6432
Fixes
amigin Nov 22, 2024
9f910d5
Fixes
amigin Nov 22, 2024
9605604
Removed Delay between requests
amigin Nov 24, 2024
cfdfc14
Removed delay between retries since we do not need it anymore
amigin Nov 24, 2024
c2d6564
Fixes
amigin Dec 21, 2024
a31971c
Improvements with SSH
amigin Dec 23, 2024
78d83a6
Fixes
amigin Dec 23, 2024
96d040c
Debugging
amigin Dec 24, 2024
677918f
Fixes
amigin Dec 24, 2024
467a6b5
Debugging
amigin Dec 24, 2024
ca15ce6
Removed Debug Data
amigin Dec 24, 2024
c2bec5b
Fixes
amigin Dec 26, 2024
855350d
Debugging
amigin Feb 13, 2025
1960379
Made timestamp Typed
amigin Feb 13, 2025
d604a90
Timestamp is now has types
amigin Feb 13, 2025
e0b758c
Fixing with serder_rename
amigin Feb 13, 2025
eda3c23
Added with_expires:true
amigin Feb 13, 2025
b83b09d
Made deserialization error way understandable
amigin Feb 14, 2025
cfb86e5
Added error on table
amigin Feb 14, 2025
a4d8aab
Fixes with #[serde(rename_all = "PascalCase")]
amigin Feb 15, 2025
70a78a9
Fixes
amigin Feb 15, 2025
e2c3c5f
Added server-core
amigin Mar 8, 2025
734e337
Now No Panic on Somehow we did not find the index
amigin Mar 11, 2025
2b2f501
Removed server-core for a while
amigin Mar 11, 2025
4436270
Now SDK has server-core as well
amigin Mar 11, 2025
c16637a
Fixes
amigin Mar 11, 2025
df664f1
Fixes
amigin Mar 11, 2025
1087055
Fixes
amigin Mar 11, 2025
122c8ec
Removed
amigin Mar 12, 2025
f674206
Fixes
amigin Mar 12, 2025
c75e2bc
Renaming DbTableInner
amigin Mar 12, 2025
80097dd
Added read-node
amigin Mar 12, 2025
eab7d52
Now DbTableWrapper is DbTable
amigin Mar 12, 2025
1188088
Fixes
amigin Mar 12, 2025
e546b83
Added unit tests and fixed bugs in case where we are replace_or_updat…
amigin Mar 13, 2025
97399cd
Updated FlUrl
amigin Aug 6, 2025
6c338d3
Fixes
amigin Aug 6, 2025
bd02edb
Debugging bulk_insert_or_replace
amigin Aug 6, 2025
306fdd9
Removed Debug Data
amigin Aug 6, 2025
d012ea6
Fixes
amigin Aug 16, 2025
0674964
my-json: 0.3.2
amigin Sep 5, 2025
861709f
Unix-socket support enabled
amigin Nov 24, 2025
2921aff
Added Last Updates
amigin Jan 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/build_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,11 @@ jobs:
- name: Install Protoc
uses: arduino/setup-protoc@v1

- name: Test default
run: cargo test

- name: Build Master-Node
run: cargo test --features master-node

- name: Build default
run: cargo build --all-features
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ members = [
"my-no-sql-sdk",
"my-no-sql-core",
"my-no-sql-tests",
"my-no-sql-server-core",
]
278 changes: 278 additions & 0 deletions MY_NO_SQL_ENTITY_DESIGN_PATTERNS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
## MyNoSql Entity Design Patterns

### Purpose
- Provide consistent guidance for defining MyNoSql entities and enum-based models used by readers/writers.
- Align with MyNoSql server concepts of `PartitionKey`, `RowKey`, `TimeStamp`, and optional `Expires`.
- Serve as an instruction set for AI agents so generated code follows established patterns without guesswork.

### Core principles
- Entities always carry partition, row, and timestamp metadata; these identify rows per the server model.
- Use `my-no-sql-macros` to autogenerate required fields and trait impls instead of hand-writing boilerplate.
- Serde names `PartitionKey`, `RowKey`, `TimeStamp`, and `Expires` are reserved; avoid collisions or custom renames that reuse them.
- Table rows are identified by `(PartitionKey, RowKey)`; partitions group related rows; `TimeStamp` tracks server-side update time.
- Writers use HTTP CRUD; readers subscribe and keep local copies—design entities to be compact and stable.

### Table name validation (my-no-sql-server)
- Length: 3–63 characters.
- Allowed characters: lowercase latin letters `a`-`z`, digits `0`-`9`, and dash `-`.
- No consecutive dashes (e.g., `my--table-name` is invalid).
- Do not start or end with a dash; prefer starting with a letter (e.g., `-my-table-name` and `my-table-name-` are invalid).
- Keep names lowercase and stable; changing table names is a breaking change for both readers and writers.
- Reference: [Table Name Validation](https://github.com/MyJetTools/my-no-sql-server/wiki/Table-Name-Validation).

### Where entities live and how they flow
- Entities are stored in `my-no-sql-server`.
- Reader API: `MyNoSqlDataReader<TEntity>` subscribes to the table and keeps the latest snapshot locally in the application for fast reads.
- Writer API: `MyNoSqlDataWriter<TEntity>` is used by writers to push inserts/updates/deletes to the server.
- Design entities so they are stable over time; breaking schema changes can break both readers (subscriptions) and writers (HTTP).

### Pattern 1: Table = Model
- Use `#[my_no_sql_entity("table-name")]` on a struct that represents a single table’s rows.
- The macro injects:
- `partition_key: String`, `row_key: String`, `time_stamp: Timestamp` with proper Serde casing.
- `MyNoSqlEntity` and `MyNoSqlEntitySerializer` impls (serialize/deserialize ready for readers/writers).
- Optional `with_expires = true` adds `expires: Timestamp` with Serde name `Expires` for TTL semantics.
- Derive serde and clone/debug as needed; apply `#[serde(rename_all = "...")]` for payload fields to keep consistent casing.
- Example:
```rust
#[my_no_sql_macros::my_no_sql_entity("bidask-snapshots")]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct BidAskSnapshot {
pub unix_timestamp_with_milis: u64,
pub bid: f64,
pub ask: f64,
pub base: String,
pub quote: String,
}
```
- Example with TTL:
```rust
#[my_no_sql_macros::my_no_sql_entity("sessions", with_expires = true)]
#[derive(Serialize, Deserialize, Clone)]
pub struct SessionEntity {
pub user_id: String,
pub token: String,
pub device: String,
// `expires` is auto-added by the macro because with_expires = true
}
```

### Pattern 2: PartitionKey + RowKey = Model (enum)
- Use when each `(PartitionKey, RowKey)` pair maps to a distinct model type.
- Declare an enum with `#[enum_of_my_no_sql_entity(table_name:"<table>", generate_unwraps)]`.
- For each variant model:
- Annotate with `#[enum_model(partition_key:"...", row_key:"...")]`.
- Derive serde and other traits required by your service.
- The macros generate:
- Correct partition/row keys per variant.
- Serialization helpers plus `unwrap_caseX` accessors when `generate_unwraps` is set.
- Example:
```rust
#[enum_of_my_no_sql_entity(table_name:"Test", generate_unwraps)]
pub enum MyNoSqlEnumEntityTest {
Case1(Struct1),
Case2(Struct2),
}

#[enum_model(partition_key:"pk1", row_key:"rk1")]
#[derive(Serialize, Deserialize, Clone)]
pub struct Struct1 {
pub field1: String,
pub field2: i32,
}

#[enum_model(partition_key:"pk2", row_key:"rk2")]
#[derive(Serialize, Deserialize, Clone)]
pub struct Struct2 {
pub field3: String,
pub field4: i32,
}
```
- More elaborate enum example (mixed casing and TTL in one variant):
```rust
#[enum_of_my_no_sql_entity(table_name:"notifications", generate_unwraps)]
pub enum NotificationEntity {
#[enum_model(partition_key:"email", row_key:"welcome")]
EmailWelcome(EmailWelcomeModel),
#[enum_model(partition_key:"push", row_key:"security")]
PushSecurity(PushSecurityModel),
}

#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct EmailWelcomeModel {
pub subject: String,
pub body: String,
}

#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct PushSecurityModel {
pub title: String,
pub message: String,
pub severity: String,
}
```

### Field and serde rules
- Do not rename payload fields to reserved serde names (`PartitionKey`, `RowKey`, `TimeStamp`, `Expires`); the macro enforces uniqueness.
- When adding an `expires` field manually, use type `Timestamp`; otherwise enable `with_expires`.
- Keep `LAZY_DESERIALIZATION` as the default (`false`) unless the macro adds support for a specialized flow.
- Prefer `#[serde(rename_all = "...")]` instead of renaming individual fields when possible.
- Avoid floats for keys; keep keys ASCII-safe and stable (no trailing slashes or whitespace).

### Testing guidance
- Validate serialization/deserialization paths using the examples under `my-no-sql-tests/src/macros_tests`.
- For enums, assert `unwrap_caseX` helpers and key selection per variant.
- Add unit tests per model that:
- Serialize then deserialize and compare fields.
- For enums, confirm correct variant after round-trip and that unwrap helpers work.
- Validate `expires` presence when `with_expires = true`.

### When to choose each pattern
- Use **Table = Model** when all rows in a table share the same schema.
- Use **PartitionKey + RowKey = Model (enum)** when a table hosts heterogeneous payloads selected by keys.

### Key design guidance
- PartitionKey:
- Group data that is frequently read together.
- Keep length modest; avoid unbounded cardinality when possible.
- RowKey:
- Unique within a partition.
- Prefer stable identifiers (ids, symbols, timestamps encoded consistently).
- TimeStamp:
- Auto-managed; used by server for last-write tracking and sync ordering.
- Expires (TTL):
- Use for session-like or cache-like data; choose UTC epoch milliseconds.

### Best practices: constant keys
- When PartitionKey and/or RowKey are fixed for a table, expose them as `const` on the entity and initialize defaults with those constants. This keeps writers/readers aligned and avoids typos.
- Example:
```rust
use serde::*;

service_sdk::macros::use_my_no_sql_entity!();

#[my_no_sql_entity("atr-settings")]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AtrSettingsEntity {
pub percent: f64,
pub candles_count: i32,
}

impl AtrSettingsEntity {
pub const PARTITION_KEY: &'static str = "*";
pub const ROW_KEY: &'static str = "*";
}

impl Default for AtrSettingsEntity {
fn default() -> Self {
Self {
partition_key: Self::PARTITION_KEY.to_string(),
row_key: Self::ROW_KEY.to_string(),
time_stamp: Default::default(),
percent: 0.8,
candles_count: 365,
}
}
}
```

### Best practices: meaningful keys as helpers
- When keys encode business meaning, provide helper functions to generate and to read them back, to avoid duplicating string literals across the codebase.
- Example:
```rust
use serde::*;
use trading_robot_common::CandleType;

service_sdk::macros::use_my_no_sql_entity!();

// PartitionKey: instrument_id
// RowKey: interval ("1m", "5m", "1h", "1d", "1M")
#[my_no_sql_entity("atr-values")]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AtrValueMyNoSqlEntity {
pub value: f64,
}

impl AtrValueMyNoSqlEntity {
pub fn generate_partition_key(instrument_id: &str) -> &str {
instrument_id
}

pub fn generate_row_key(candle_type: CandleType) -> &'static str {
candle_type.as_str()
}

pub fn get_instrument(&self) -> &str {
&self.partition_key
}

pub fn get_candle_type(&self) -> CandleType {
CandleType::from_str(&self.row_key)
}
}
```

### Macro options cheat sheet
- `#[my_no_sql_entity("table", with_expires = true)]` → adds `expires`.
- `#[enum_of_my_no_sql_entity(table_name:"table", generate_unwraps)]` → generates unwrap helpers per variant.
- `#[enum_model(partition_key:"...", row_key:"...")]` → binds a variant model to fixed keys.
- The macros auto-implement:
- `MyNoSqlEntity` with `TABLE_NAME`, `LAZY_DESERIALIZATION = false`, `get_partition_key`, `get_row_key`, `get_time_stamp`.
- `MyNoSqlEntitySerializer` with standard binary serialize/deserialize.

### Minimal working template (table = model)
```rust
use my_no_sql_macros::my_no_sql_entity;
use serde::{Deserialize, Serialize};

#[my_no_sql_entity("table-name")]
#[derive(Serialize, Deserialize, Clone)]
pub struct MyEntity {
pub value: String,
pub count: i32,
}
```

### Minimal working template (enum model)
```rust
use my_no_sql_macros::{enum_model, enum_of_my_no_sql_entity};
use serde::{Deserialize, Serialize};

#[enum_of_my_no_sql_entity(table_name:"events", generate_unwraps)]
pub enum EventEntity {
Create(CreateEvent),
Delete(DeleteEvent),
}

#[enum_model(partition_key:"pk-create", row_key:"rk-create")]
#[derive(Serialize, Deserialize, Clone)]
pub struct CreateEvent {
pub id: String,
pub payload: String,
}

#[enum_model(partition_key:"pk-delete", row_key:"rk-delete")]
#[derive(Serialize, Deserialize, Clone)]
pub struct DeleteEvent {
pub id: String,
pub reason: String,
}
```

### AI generation checklist
- Choose the pattern (single model vs enum).
- Set `table_name` accurately and keep it stable.
- Apply `#[serde(rename_all = "...")]` for payload fields.
- Never introduce fields named `PartitionKey`, `RowKey`, `TimeStamp`, `Expires` manually unless following macro requirements.
- For TTL needs, prefer `with_expires = true` over a custom `expires` unless special handling is required.
- Derive `Serialize`, `Deserialize`, and `Clone`; add `Debug` when useful for logs/tests.
- Provide unit tests that round-trip entities and assert variant unwraps.

### Anti-patterns to avoid
- Manually defining partition/row/timestamp fields when using the macros (causes duplication or serde conflicts).
- Reusing the same `(partition_key, row_key)` for multiple variants in enum models.
- Using dynamic keys in enum models (keys must be compile-time constants in attributes).
- Introducing serde renames that clash with reserved casing tokens.
5 changes: 4 additions & 1 deletion my-no-sql-abstractions/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
[package]
name = "my-no-sql-abstractions"
version = "0.3.0"
version = "0.4.1"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rust-extensions = { tag = "0.1.5", git = "https://github.com/MyJetTools/rust-extensions.git" }
serde = { version = "*", features = ["derive"] }
serde_json = "*"
2 changes: 2 additions & 0 deletions my-no-sql-abstractions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ mod data_sync_period;
mod my_no_sql_entity;
pub use data_sync_period::DataSynchronizationPeriod;
pub use my_no_sql_entity::*;
mod timestamp_type;
pub use timestamp_type::*;
9 changes: 6 additions & 3 deletions my-no-sql-abstractions/src/my_no_sql_entity.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
use crate::Timestamp;

pub trait MyNoSqlEntity {
const TABLE_NAME: &'static str;
const LAZY_DESERIALIZATION: bool;
fn get_partition_key(&self) -> &str;
fn get_row_key(&self) -> &str;
fn get_time_stamp(&self) -> i64;
fn get_time_stamp(&self) -> Timestamp;
}

pub trait MyNoSqlEntitySerializer {
pub trait MyNoSqlEntitySerializer: Sized {
fn serialize_entity(&self) -> Vec<u8>;
fn deserialize_entity(src: &[u8]) -> Self;
fn deserialize_entity(src: &[u8]) -> Result<Self, String>;
}

pub trait GetMyNoSqlEntity {
Expand Down
Loading
Loading