@lix-js/sdk 0.6.0-preview.2 → 0.6.0-preview.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/SKILL.md +4 -5
  2. package/dist/engine-wasm/wasm/lix_engine.js +1 -1
  3. package/dist/engine-wasm/wasm/lix_engine.wasm +0 -0
  4. package/dist/generated/builtin-schemas.d.ts +87 -162
  5. package/dist/generated/builtin-schemas.js +139 -236
  6. package/dist/open-lix.d.ts +1 -1
  7. package/dist-engine-src/src/binary_cas/types.rs +0 -6
  8. package/dist-engine-src/src/catalog/context.rs +412 -0
  9. package/dist-engine-src/src/catalog/mod.rs +10 -0
  10. package/dist-engine-src/src/catalog/schema.rs +4 -0
  11. package/dist-engine-src/src/catalog/snapshot.rs +1114 -0
  12. package/dist-engine-src/src/cel/mod.rs +1 -1
  13. package/dist-engine-src/src/cel/provider.rs +1 -1
  14. package/dist-engine-src/src/commit_graph/context.rs +328 -1015
  15. package/dist-engine-src/src/commit_graph/mod.rs +2 -3
  16. package/dist-engine-src/src/commit_graph/types.rs +7 -43
  17. package/dist-engine-src/src/commit_graph/walker.rs +57 -81
  18. package/dist-engine-src/src/commit_store/codec.rs +887 -0
  19. package/dist-engine-src/src/commit_store/context.rs +944 -0
  20. package/dist-engine-src/src/commit_store/materialization.rs +84 -0
  21. package/dist-engine-src/src/commit_store/mod.rs +16 -0
  22. package/dist-engine-src/src/commit_store/storage.rs +600 -0
  23. package/dist-engine-src/src/commit_store/types.rs +215 -0
  24. package/dist-engine-src/src/common/identity.rs +15 -5
  25. package/dist-engine-src/src/common/json_pointer.rs +67 -0
  26. package/dist-engine-src/src/common/metadata.rs +17 -12
  27. package/dist-engine-src/src/common/mod.rs +5 -5
  28. package/dist-engine-src/src/domain.rs +324 -0
  29. package/dist-engine-src/src/engine.rs +29 -43
  30. package/dist-engine-src/src/entity_identity.rs +238 -118
  31. package/dist-engine-src/src/functions/context.rs +17 -52
  32. package/dist-engine-src/src/functions/deterministic.rs +1 -1
  33. package/dist-engine-src/src/functions/mod.rs +1 -1
  34. package/dist-engine-src/src/functions/provider.rs +4 -4
  35. package/dist-engine-src/src/functions/state.rs +39 -66
  36. package/dist-engine-src/src/functions/types.rs +1 -1
  37. package/dist-engine-src/src/init.rs +204 -151
  38. package/dist-engine-src/src/json_store/context.rs +354 -60
  39. package/dist-engine-src/src/json_store/encoded.rs +6 -6
  40. package/dist-engine-src/src/json_store/mod.rs +4 -1
  41. package/dist-engine-src/src/json_store/store.rs +884 -11
  42. package/dist-engine-src/src/json_store/types.rs +166 -1
  43. package/dist-engine-src/src/lib.rs +10 -9
  44. package/dist-engine-src/src/live_state/context.rs +608 -830
  45. package/dist-engine-src/src/live_state/mod.rs +3 -3
  46. package/dist-engine-src/src/live_state/overlay.rs +7 -7
  47. package/dist-engine-src/src/live_state/reader.rs +5 -5
  48. package/dist-engine-src/src/live_state/types.rs +19 -36
  49. package/dist-engine-src/src/live_state/visibility.rs +19 -14
  50. package/dist-engine-src/src/plugin/archive.rs +3 -6
  51. package/dist-engine-src/src/plugin/install.rs +0 -18
  52. package/dist-engine-src/src/plugin/plugin_manifest.json +0 -1
  53. package/dist-engine-src/src/schema/annotations/defaults.rs +2 -7
  54. package/dist-engine-src/src/schema/builtin/lix_account.json +0 -1
  55. package/dist-engine-src/src/schema/builtin/lix_active_account.json +0 -1
  56. package/dist-engine-src/src/schema/builtin/lix_binary_blob_ref.json +0 -1
  57. package/dist-engine-src/src/schema/builtin/lix_change.json +11 -10
  58. package/dist-engine-src/src/schema/builtin/lix_change_author.json +0 -1
  59. package/dist-engine-src/src/schema/builtin/lix_commit.json +8 -46
  60. package/dist-engine-src/src/schema/builtin/lix_commit_edge.json +29 -22
  61. package/dist-engine-src/src/schema/builtin/lix_directory_descriptor.json +0 -1
  62. package/dist-engine-src/src/schema/builtin/lix_file_descriptor.json +0 -1
  63. package/dist-engine-src/src/schema/builtin/lix_key_value.json +0 -1
  64. package/dist-engine-src/src/schema/builtin/lix_label.json +10 -3
  65. package/dist-engine-src/src/schema/builtin/lix_label_assignment.json +74 -0
  66. package/dist-engine-src/src/schema/builtin/lix_registered_schema.json +2 -8
  67. package/dist-engine-src/src/schema/builtin/lix_version_descriptor.json +0 -1
  68. package/dist-engine-src/src/schema/builtin/lix_version_ref.json +0 -1
  69. package/dist-engine-src/src/schema/builtin/mod.rs +10 -59
  70. package/dist-engine-src/src/schema/compatibility.rs +787 -0
  71. package/dist-engine-src/src/schema/definition.json +47 -17
  72. package/dist-engine-src/src/schema/definition.rs +202 -96
  73. package/dist-engine-src/src/schema/key.rs +9 -77
  74. package/dist-engine-src/src/schema/mod.rs +4 -4
  75. package/dist-engine-src/src/schema/tests.rs +133 -92
  76. package/dist-engine-src/src/session/context.rs +40 -42
  77. package/dist-engine-src/src/session/create_version.rs +22 -14
  78. package/dist-engine-src/src/session/execute.rs +45 -14
  79. package/dist-engine-src/src/session/merge/apply.rs +4 -4
  80. package/dist-engine-src/src/session/merge/conflicts.rs +3 -2
  81. package/dist-engine-src/src/session/merge/stats.rs +1 -1
  82. package/dist-engine-src/src/session/merge/version.rs +35 -45
  83. package/dist-engine-src/src/session/mod.rs +4 -2
  84. package/dist-engine-src/src/session/optimization9_sql2_bench.rs +100 -0
  85. package/dist-engine-src/src/session/switch_version.rs +16 -28
  86. package/dist-engine-src/src/sql2/change_provider.rs +14 -20
  87. package/dist-engine-src/src/sql2/classify.rs +61 -26
  88. package/dist-engine-src/src/sql2/context.rs +22 -18
  89. package/dist-engine-src/src/sql2/directory_history_provider.rs +28 -20
  90. package/dist-engine-src/src/sql2/directory_provider.rs +131 -83
  91. package/dist-engine-src/src/sql2/entity_history_provider.rs +10 -14
  92. package/dist-engine-src/src/sql2/entity_provider.rs +680 -169
  93. package/dist-engine-src/src/sql2/error.rs +21 -1
  94. package/dist-engine-src/src/sql2/execute.rs +325 -264
  95. package/dist-engine-src/src/sql2/file_history_provider.rs +29 -21
  96. package/dist-engine-src/src/sql2/file_provider.rs +533 -108
  97. package/dist-engine-src/src/sql2/filesystem_planner.rs +58 -94
  98. package/dist-engine-src/src/sql2/filesystem_visibility.rs +37 -23
  99. package/dist-engine-src/src/sql2/history_projection.rs +3 -27
  100. package/dist-engine-src/src/sql2/history_provider.rs +11 -17
  101. package/dist-engine-src/src/sql2/history_route.rs +22 -8
  102. package/dist-engine-src/src/sql2/lix_state_provider.rs +178 -96
  103. package/dist-engine-src/src/sql2/mod.rs +6 -3
  104. package/dist-engine-src/src/sql2/predicate_typecheck.rs +246 -0
  105. package/dist-engine-src/src/sql2/public_bind/assignment.rs +46 -0
  106. package/dist-engine-src/src/sql2/public_bind/capability.rs +41 -0
  107. package/dist-engine-src/src/sql2/public_bind/dml.rs +166 -0
  108. package/dist-engine-src/src/sql2/public_bind/mod.rs +25 -0
  109. package/dist-engine-src/src/sql2/public_bind/table.rs +168 -0
  110. package/dist-engine-src/src/sql2/read_only.rs +10 -12
  111. package/dist-engine-src/src/sql2/session.rs +7 -10
  112. package/dist-engine-src/src/sql2/udfs/lix_timestamp.rs +76 -0
  113. package/dist-engine-src/src/sql2/udfs/mod.rs +8 -1
  114. package/dist-engine-src/src/sql2/udfs/public_call.rs +211 -0
  115. package/dist-engine-src/src/sql2/version_provider.rs +46 -31
  116. package/dist-engine-src/src/sql2/version_scope.rs +4 -4
  117. package/dist-engine-src/src/storage_bench.rs +1782 -325
  118. package/dist-engine-src/src/test_support.rs +183 -36
  119. package/dist-engine-src/src/tracked_state/by_file_index.rs +20 -24
  120. package/dist-engine-src/src/tracked_state/codec.rs +1519 -181
  121. package/dist-engine-src/src/tracked_state/context.rs +1155 -271
  122. package/dist-engine-src/src/tracked_state/diff.rs +249 -57
  123. package/dist-engine-src/src/tracked_state/materialization.rs +365 -103
  124. package/dist-engine-src/src/tracked_state/materializer.rs +488 -0
  125. package/dist-engine-src/src/tracked_state/merge.rs +37 -19
  126. package/dist-engine-src/src/tracked_state/mod.rs +8 -7
  127. package/dist-engine-src/src/tracked_state/storage.rs +138 -6
  128. package/dist-engine-src/src/tracked_state/tree.rs +695 -252
  129. package/dist-engine-src/src/tracked_state/types.rs +176 -6
  130. package/dist-engine-src/src/transaction/commit.rs +695 -435
  131. package/dist-engine-src/src/transaction/context.rs +551 -310
  132. package/dist-engine-src/src/transaction/live_state_overlay.rs +9 -8
  133. package/dist-engine-src/src/transaction/mod.rs +2 -0
  134. package/dist-engine-src/src/transaction/normalization.rs +311 -447
  135. package/dist-engine-src/src/transaction/prep.rs +37 -0
  136. package/dist-engine-src/src/transaction/schema_resolver.rs +93 -71
  137. package/dist-engine-src/src/transaction/staging.rs +701 -406
  138. package/dist-engine-src/src/transaction/types.rs +231 -122
  139. package/dist-engine-src/src/transaction/validation.rs +2717 -1698
  140. package/dist-engine-src/src/untracked_state/codec.rs +40 -96
  141. package/dist-engine-src/src/untracked_state/context.rs +21 -5
  142. package/dist-engine-src/src/untracked_state/materialization.rs +10 -104
  143. package/dist-engine-src/src/untracked_state/mod.rs +3 -5
  144. package/dist-engine-src/src/untracked_state/storage.rs +105 -57
  145. package/dist-engine-src/src/untracked_state/types.rs +63 -13
  146. package/dist-engine-src/src/version/context.rs +1 -13
  147. package/dist-engine-src/src/version/lifecycle.rs +221 -0
  148. package/dist-engine-src/src/version/mod.rs +3 -2
  149. package/dist-engine-src/src/version/refs.rs +12 -103
  150. package/dist-engine-src/src/version/stage_rows.rs +15 -19
  151. package/package.json +1 -1
  152. package/dist-engine-src/src/changelog/codec.rs +0 -321
  153. package/dist-engine-src/src/changelog/context.rs +0 -92
  154. package/dist-engine-src/src/changelog/materialization.rs +0 -121
  155. package/dist-engine-src/src/changelog/mod.rs +0 -13
  156. package/dist-engine-src/src/changelog/reader.rs +0 -20
  157. package/dist-engine-src/src/changelog/storage.rs +0 -220
  158. package/dist-engine-src/src/changelog/types.rs +0 -38
  159. package/dist-engine-src/src/schema/builtin/lix_change_set.json +0 -18
  160. package/dist-engine-src/src/schema/builtin/lix_change_set_element.json +0 -75
  161. package/dist-engine-src/src/schema/builtin/lix_entity_label.json +0 -63
  162. package/dist-engine-src/src/schema_registry.rs +0 -294
  163. package/dist-engine-src/src/sql2/commit_derived_provider.rs +0 -591
  164. package/dist-engine-src/src/tracked_state/rebuild.rs +0 -771
  165. package/dist-engine-src/src/tracked_state/tree_types.rs +0 -176
@@ -0,0 +1,215 @@
1
+ use crate::entity_identity::EntityIdentity;
2
+ use crate::json_store::JsonRef;
3
+
4
+ /// Physical append/locality unit for commit metadata and derived commit SQL
5
+ /// surfaces.
6
+ #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
7
+ pub(crate) struct Commit {
8
+ pub(crate) id: String,
9
+ pub(crate) change_id: String,
10
+ pub(crate) parent_ids: Vec<String>,
11
+ pub(crate) author_account_ids: Vec<String>,
12
+ pub(crate) created_at: String,
13
+ pub(crate) change_pack_count: u32,
14
+ pub(crate) membership_pack_count: u32,
15
+ }
16
+
17
+ impl Commit {
18
+ pub(crate) fn as_ref(&self) -> StoredCommitRef<'_> {
19
+ StoredCommitRef {
20
+ id: &self.id,
21
+ change_id: &self.change_id,
22
+ parent_ids: &self.parent_ids,
23
+ author_account_ids: &self.author_account_ids,
24
+ created_at: &self.created_at,
25
+ change_pack_count: self.change_pack_count,
26
+ membership_pack_count: self.membership_pack_count,
27
+ }
28
+ }
29
+ }
30
+
31
+ /// Zero-copy view of stored [`Commit`] bytes.
32
+ #[derive(Debug, Clone, Copy)]
33
+ pub(crate) struct StoredCommitRef<'a> {
34
+ pub(crate) id: &'a str,
35
+ pub(crate) change_id: &'a str,
36
+ pub(crate) parent_ids: &'a [String],
37
+ pub(crate) author_account_ids: &'a [String],
38
+ pub(crate) created_at: &'a str,
39
+ pub(crate) change_pack_count: u32,
40
+ pub(crate) membership_pack_count: u32,
41
+ }
42
+
43
+ /// Zero-copy view of a logical commit supplied before physical packing.
44
+ #[derive(Debug, Clone, Copy)]
45
+ pub(crate) struct CommitDraftRef<'a> {
46
+ pub(crate) id: &'a str,
47
+ pub(crate) change_id: &'a str,
48
+ pub(crate) parent_ids: &'a [String],
49
+ pub(crate) author_account_ids: &'a [String],
50
+ pub(crate) created_at: &'a str,
51
+ }
52
+
53
+ /// Logical entity mutation fact stored in a commit change pack.
54
+ #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
55
+ pub(crate) struct Change {
56
+ pub(crate) id: String,
57
+ pub(crate) entity_id: EntityIdentity,
58
+ pub(crate) schema_key: String,
59
+ pub(crate) file_id: Option<String>,
60
+ pub(crate) snapshot_ref: Option<JsonRef>,
61
+ pub(crate) metadata_ref: Option<JsonRef>,
62
+ pub(crate) created_at: String,
63
+ }
64
+
65
+ /// Read-boundary view of a commit-store change with JSON refs resolved.
66
+ #[derive(Debug, Clone, PartialEq, Eq)]
67
+ pub(crate) struct MaterializedChange {
68
+ pub(crate) id: String,
69
+ pub(crate) entity_id: EntityIdentity,
70
+ pub(crate) schema_key: String,
71
+ pub(crate) file_id: Option<String>,
72
+ pub(crate) snapshot_content: Option<String>,
73
+ pub(crate) metadata: Option<String>,
74
+ pub(crate) created_at: String,
75
+ }
76
+
77
+ /// Commit-store change plus the physical pack that owns its JSON payloads.
78
+ #[derive(Debug, Clone, PartialEq, Eq)]
79
+ pub(crate) struct LocatedChange {
80
+ pub(crate) record: Change,
81
+ pub(crate) source_commit_id: String,
82
+ pub(crate) source_pack_id: u32,
83
+ }
84
+
85
+ impl Change {
86
+ pub(crate) fn as_ref(&self) -> ChangeRef<'_> {
87
+ ChangeRef {
88
+ id: &self.id,
89
+ entity_id: &self.entity_id,
90
+ schema_key: &self.schema_key,
91
+ file_id: self.file_id.as_deref(),
92
+ snapshot_ref: self.snapshot_ref.as_ref(),
93
+ metadata_ref: self.metadata_ref.as_ref(),
94
+ created_at: &self.created_at,
95
+ }
96
+ }
97
+ }
98
+
99
+ /// Zero-copy view of [`Change`].
100
+ #[derive(Debug, Clone, Copy)]
101
+ pub(crate) struct ChangeRef<'a> {
102
+ pub(crate) id: &'a str,
103
+ pub(crate) entity_id: &'a EntityIdentity,
104
+ pub(crate) schema_key: &'a str,
105
+ pub(crate) file_id: Option<&'a str>,
106
+ pub(crate) snapshot_ref: Option<&'a JsonRef>,
107
+ pub(crate) metadata_ref: Option<&'a JsonRef>,
108
+ pub(crate) created_at: &'a str,
109
+ }
110
+
111
+ /// Logical scan request for the `lix_change` SQL surface over commit_store.
112
+ #[derive(Debug, Clone, Default)]
113
+ pub(crate) struct ChangeScanRequest {
114
+ pub(crate) limit: Option<usize>,
115
+ }
116
+
117
+ /// Commit-local physical pack of newly authored change payloads.
118
+ #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
119
+ pub(crate) struct ChangePack {
120
+ pub(crate) commit_id: String,
121
+ pub(crate) pack_id: u32,
122
+ pub(crate) changes: Vec<Change>,
123
+ }
124
+
125
+ impl ChangePack {
126
+ pub(crate) fn as_view(&self) -> ChangePackView<'_> {
127
+ ChangePackView {
128
+ commit_id: &self.commit_id,
129
+ pack_id: self.pack_id,
130
+ changes: &self.changes,
131
+ }
132
+ }
133
+ }
134
+
135
+ /// Zero-copy view for a decoded [`ChangePack`].
136
+ #[derive(Debug, Clone, Copy)]
137
+ pub(crate) struct ChangePackView<'a> {
138
+ pub(crate) commit_id: &'a str,
139
+ pub(crate) pack_id: u32,
140
+ pub(crate) changes: &'a [Change],
141
+ }
142
+
143
+ /// Storage location of an existing change payload.
144
+ #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
145
+ pub(crate) struct ChangeLocator {
146
+ pub(crate) source_commit_id: String,
147
+ pub(crate) source_pack_id: u32,
148
+ pub(crate) source_ordinal: u32,
149
+ pub(crate) change_id: String,
150
+ }
151
+
152
+ impl ChangeLocator {
153
+ pub(crate) fn as_ref(&self) -> ChangeLocatorRef<'_> {
154
+ ChangeLocatorRef {
155
+ source_commit_id: &self.source_commit_id,
156
+ source_pack_id: self.source_pack_id,
157
+ source_ordinal: self.source_ordinal,
158
+ change_id: &self.change_id,
159
+ }
160
+ }
161
+ }
162
+
163
+ /// Zero-copy view of [`ChangeLocator`].
164
+ #[derive(Debug, Clone, Copy)]
165
+ pub(crate) struct ChangeLocatorRef<'a> {
166
+ pub(crate) source_commit_id: &'a str,
167
+ pub(crate) source_pack_id: u32,
168
+ pub(crate) source_ordinal: u32,
169
+ pub(crate) change_id: &'a str,
170
+ }
171
+
172
+ /// Exact lookup entry for a derived-surface-visible change id.
173
+ #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
174
+ pub(crate) enum ChangeIndexEntry {
175
+ CommitHeader {
176
+ commit_id: String,
177
+ change_id: String,
178
+ },
179
+ PackedChange {
180
+ locator: ChangeLocator,
181
+ },
182
+ }
183
+
184
+ /// Commit-local physical pack of adopted/shared membership locators.
185
+ #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
186
+ pub(crate) struct MembershipPack {
187
+ pub(crate) commit_id: String,
188
+ pub(crate) pack_id: u32,
189
+ pub(crate) members: Vec<ChangeLocator>,
190
+ }
191
+
192
+ impl MembershipPack {
193
+ pub(crate) fn as_view(&self) -> MembershipPackView<'_> {
194
+ MembershipPackView {
195
+ commit_id: &self.commit_id,
196
+ pack_id: self.pack_id,
197
+ members: &self.members,
198
+ }
199
+ }
200
+ }
201
+
202
+ /// Zero-copy view for a decoded [`MembershipPack`].
203
+ #[derive(Debug, Clone, Copy)]
204
+ pub(crate) struct MembershipPackView<'a> {
205
+ pub(crate) commit_id: &'a str,
206
+ pub(crate) pack_id: u32,
207
+ pub(crate) members: &'a [ChangeLocator],
208
+ }
209
+
210
+ /// Locators produced while staging a commit.
211
+ #[derive(Debug, Clone, PartialEq, Eq)]
212
+ pub(crate) struct StagedCommitStoreCommit {
213
+ pub(crate) authored_locators: Vec<ChangeLocator>,
214
+ pub(crate) adopted_locators: Vec<ChangeLocator>,
215
+ }
@@ -13,10 +13,7 @@ macro_rules! canonical_identity_type {
13
13
  impl $name {
14
14
  pub fn new(value: impl Into<String>) -> Result<Self, LixError> {
15
15
  let value = value.into();
16
- if value.is_empty() {
17
- return Err(LixError::unknown(format!("{} must be non-empty", $label)));
18
- }
19
- Ok(Self(value))
16
+ validate_non_empty_identity_value($label, value).map(Self)
20
17
  }
21
18
 
22
19
  pub fn as_str(&self) -> &str {
@@ -113,9 +110,22 @@ canonical_identity_type!(EntityId, "entity_id");
113
110
  canonical_identity_type!(FileId, "file_id");
114
111
  canonical_identity_type!(VersionId, "version_id");
115
112
  canonical_identity_type!(CanonicalSchemaKey, "schema_key");
116
- canonical_identity_type!(CanonicalSchemaVersion, "schema_version");
117
113
  canonical_identity_type!(CanonicalPluginKey, "plugin_key");
118
114
 
115
+ pub(crate) fn validate_non_empty_identity_value(
116
+ label: &str,
117
+ value: impl Into<String>,
118
+ ) -> Result<String, LixError> {
119
+ let value = value.into();
120
+ if value.is_empty() {
121
+ return Err(LixError::new(
122
+ LixError::CODE_INVALID_PARAM,
123
+ format!("{label} must be non-empty"),
124
+ ));
125
+ }
126
+ Ok(value)
127
+ }
128
+
119
129
  pub(crate) fn json_pointer_get<'a>(
120
130
  value: &'a serde_json::Value,
121
131
  pointer: &[String],
@@ -0,0 +1,67 @@
1
+ use crate::LixError;
2
+
3
+ pub(crate) fn parse_json_pointer(pointer: &str) -> Result<Vec<String>, LixError> {
4
+ if pointer.is_empty() {
5
+ return Ok(Vec::new());
6
+ }
7
+ if !pointer.starts_with('/') {
8
+ return Err(LixError::new(
9
+ LixError::CODE_SCHEMA_DEFINITION,
10
+ format!("invalid JSON pointer '{pointer}'"),
11
+ ));
12
+ }
13
+ pointer[1..]
14
+ .split('/')
15
+ .map(decode_json_pointer_segment)
16
+ .collect()
17
+ }
18
+
19
+ pub(crate) fn format_json_pointer(segments: &[String]) -> String {
20
+ if segments.is_empty() {
21
+ return String::new();
22
+ }
23
+ format!(
24
+ "/{}",
25
+ segments
26
+ .iter()
27
+ .map(|segment| segment.replace('~', "~0").replace('/', "~1"))
28
+ .collect::<Vec<_>>()
29
+ .join("/")
30
+ )
31
+ }
32
+
33
+ pub(crate) fn top_level_property_name(pointer: &str) -> Result<Option<String>, LixError> {
34
+ if pointer.is_empty() {
35
+ return Ok(None);
36
+ }
37
+ if !pointer.starts_with('/') {
38
+ return Err(LixError::new(
39
+ LixError::CODE_SCHEMA_DEFINITION,
40
+ format!("invalid JSON pointer '{pointer}'"),
41
+ ));
42
+ }
43
+ let segment = pointer[1..].split('/').next().unwrap_or_default();
44
+ Ok(Some(decode_json_pointer_segment(segment)?))
45
+ }
46
+
47
+ fn decode_json_pointer_segment(segment: &str) -> Result<String, LixError> {
48
+ let mut out = String::new();
49
+ let mut chars = segment.chars();
50
+ while let Some(ch) = chars.next() {
51
+ if ch != '~' {
52
+ out.push(ch);
53
+ continue;
54
+ }
55
+ match chars.next() {
56
+ Some('0') => out.push('~'),
57
+ Some('1') => out.push('/'),
58
+ _ => {
59
+ return Err(LixError::new(
60
+ LixError::CODE_SCHEMA_DEFINITION,
61
+ "invalid JSON pointer escape",
62
+ ))
63
+ }
64
+ }
65
+ }
66
+ Ok(out)
67
+ }
@@ -1,28 +1,33 @@
1
- use serde_json::Value as JsonValue;
2
-
3
1
  use crate::LixError;
4
2
 
5
- pub(crate) type RowMetadata = JsonValue;
6
-
7
3
  pub(crate) fn parse_row_metadata(
8
4
  value: &str,
9
5
  context: impl AsRef<str>,
10
- ) -> Result<RowMetadata, LixError> {
11
- let metadata = serde_json::from_str::<JsonValue>(value).map_err(|error| {
6
+ ) -> Result<String, LixError> {
7
+ let metadata = parse_row_metadata_value(value, context)?;
8
+ Ok(serde_json::to_string(&metadata).expect("serde_json::Value metadata serializes"))
9
+ }
10
+
11
+ pub(crate) fn parse_row_metadata_value(
12
+ value: &str,
13
+ context: impl AsRef<str>,
14
+ ) -> Result<serde_json::Value, LixError> {
15
+ let metadata = serde_json::from_str::<serde_json::Value>(value).map_err(|error| {
12
16
  LixError::new(
13
17
  "LIX_ERROR_INVALID_JSON",
14
18
  format!("{} metadata is invalid JSON: {error}", context.as_ref()),
15
19
  )
16
20
  })?;
17
- validate_row_metadata(metadata, context)
21
+ validate_row_metadata(&metadata, context)?;
22
+ Ok(metadata)
18
23
  }
19
24
 
20
25
  pub(crate) fn validate_row_metadata(
21
- metadata: RowMetadata,
26
+ metadata: &serde_json::Value,
22
27
  context: impl AsRef<str>,
23
- ) -> Result<RowMetadata, LixError> {
28
+ ) -> Result<(), LixError> {
24
29
  if metadata.is_object() {
25
- return Ok(metadata);
30
+ return Ok(());
26
31
  }
27
32
  Err(LixError::new(
28
33
  LixError::CODE_SCHEMA_VALIDATION,
@@ -30,6 +35,6 @@ pub(crate) fn validate_row_metadata(
30
35
  ))
31
36
  }
32
37
 
33
- pub(crate) fn serialize_row_metadata(metadata: &RowMetadata) -> String {
34
- serde_json::to_string(metadata).expect("serde_json::Value metadata serializes")
38
+ pub(crate) fn serialize_row_metadata(metadata: &String) -> String {
39
+ metadata.clone()
35
40
  }
@@ -2,6 +2,7 @@ pub(crate) mod error;
2
2
  pub(crate) mod fingerprint;
3
3
  pub(crate) mod fs_path;
4
4
  pub(crate) mod identity;
5
+ pub(crate) mod json_pointer;
5
6
  pub(crate) mod metadata;
6
7
  pub(crate) mod types;
7
8
  pub(crate) mod wire;
@@ -12,12 +13,11 @@ pub(crate) use fs_path::{
12
13
  directory_ancestor_paths, directory_name_from_path, normalize_directory_path,
13
14
  normalize_path_segment, parent_directory_path, ParsedFilePath,
14
15
  };
15
- pub(crate) use identity::json_pointer_get;
16
- pub use identity::{
17
- CanonicalPluginKey, CanonicalSchemaKey, CanonicalSchemaVersion, EntityId, FileId, VersionId,
18
- };
16
+ pub(crate) use identity::{json_pointer_get, validate_non_empty_identity_value};
17
+ pub use identity::{CanonicalPluginKey, CanonicalSchemaKey, EntityId, FileId, VersionId};
18
+ pub(crate) use json_pointer::{format_json_pointer, parse_json_pointer, top_level_property_name};
19
19
  pub(crate) use metadata::{
20
- parse_row_metadata, serialize_row_metadata, validate_row_metadata, RowMetadata,
20
+ parse_row_metadata, parse_row_metadata_value, serialize_row_metadata, validate_row_metadata,
21
21
  };
22
22
  pub use types::{LixNotice, NullableKeyFilter, SqlQueryResult, Value, WriteReceipt};
23
23
  pub use wire::{WireQueryResult, WireValue};