Skip to content

Commit 7a06980

Browse files
emmaling27Convex, Inc.
authored andcommitted
Normalize AnalyzedModule (#31345)
This PR removes the `MappedModule` struct which contains duplicate data from its parent, `AnalyzedModule`. This maintains the duplicated data in `ModuleMetadata` in the db, so the data is still denormalized when it is serialized. GitOrigin-RevId: 37a34f22848f7e99e2a5ad37ed912c1dd0c94faa
1 parent a4963a6 commit 7a06980

File tree

6 files changed

+43
-195
lines changed

6 files changed

+43
-195
lines changed

crates/application/src/lib.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -876,10 +876,7 @@ impl<RT: Runtime> Application<RT> {
876876
let Some(analyze_result) = &metadata.analyze_result else {
877877
return Ok(None);
878878
};
879-
let Some(source_mapped) = &analyze_result.source_mapped else {
880-
return Ok(None);
881-
};
882-
let Some(source_index) = source_mapped.source_index else {
879+
let Some(source_index) = analyze_result.source_index else {
883880
return Ok(None);
884881
};
885882
let Some(full_source) = self.module_cache.get_module(&mut tx, path).await? else {

crates/isolate/src/environment/analyze.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ use model::{
6262
AnalyzedModule,
6363
AnalyzedSourcePosition,
6464
FullModuleSource,
65-
MappedModule,
6665
Visibility,
6766
},
6867
user_error::ModuleNotFoundError,
@@ -418,16 +417,10 @@ impl AnalyzeEnvironment {
418417
});
419418

420419
let analyzed_module = AnalyzedModule {
421-
functions: functions.clone(),
422-
http_routes: http_routes.clone(),
423-
cron_specs: cron_specs.clone(),
424-
// source_mapped should be deprecated and migrated away from in the future
425-
source_mapped: Some(MappedModule {
426-
source_index,
427-
functions,
428-
http_routes,
429-
cron_specs,
430-
}),
420+
functions,
421+
http_routes,
422+
cron_specs,
423+
source_index,
431424
};
432425
result.insert(path, analyzed_module);
433426
}

crates/isolate/src/tests/analyze.rs

Lines changed: 11 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -80,21 +80,14 @@ async fn test_analyze_module(rt: TestRuntime) -> anyhow::Result<()> {
8080
("action_in_v8", UdfType::Action, 28),
8181
];
8282
assert_eq!(module.functions.len(), expected.len());
83-
let source_mapped = module.source_mapped.as_ref().unwrap();
84-
assert_eq!(source_mapped.functions.len(), expected.len());
83+
assert!(module.source_index.is_some());
8584

8685
for (i, (name, expected_type, mapped_lineno)) in expected.iter().enumerate() {
8786
let function = &module.functions[i];
8887
assert_eq!(&function.name[..], *name);
8988
assert_eq!(&function.udf_type, expected_type);
9089

91-
let mapped_function = &source_mapped.functions[i];
92-
assert_eq!(&mapped_function.name[..], *name);
93-
assert_eq!(
94-
mapped_function.pos.as_ref().unwrap().start_lineno,
95-
*mapped_lineno
96-
);
97-
assert_eq!(&mapped_function.udf_type, expected_type);
90+
assert_eq!(function.pos.as_ref().unwrap().start_lineno, *mapped_lineno);
9891
}
9992

10093
let http_path = "http.js".parse()?;
@@ -139,20 +132,15 @@ async fn test_analyze_module(rt: TestRuntime) -> anyhow::Result<()> {
139132
.len(),
140133
expected_routes_unmapped.len()
141134
);
142-
let source_mapped = module.source_mapped.as_ref().unwrap();
143-
assert!(source_mapped.http_routes.is_some());
144-
assert_eq!(
145-
module.http_routes.as_ref().unwrap().len(),
146-
source_mapped.http_routes.as_ref().unwrap().len()
147-
);
135+
assert!(module.source_index.is_some());
148136
for (i, (path, method)) in expected_routes_unmapped.iter().enumerate() {
149137
let route = &module.http_routes.as_ref().unwrap()[i];
150138
assert_eq!(&route.route.path, path);
151139
assert_eq!(&route.route.method, method);
152140
}
153141

154142
for (i, (path, method, mapped_pos)) in expected_routes_mapped.iter().enumerate() {
155-
let mapped_route = &source_mapped
143+
let mapped_route = &module
156144
.http_routes
157145
.as_ref()
158146
.expect("no mapped http_routes found")[i];
@@ -262,46 +250,6 @@ async fn test_analyze_function(rt: TestRuntime) -> anyhow::Result<()> {
262250

263251
assert_eq!(
264252
&Vec::from(analyzed_module.functions.clone()),
265-
&[
266-
AnalyzedFunction::new(
267-
"throwsError".parse()?,
268-
// Don't check line numbers since those change on every `convex/server`
269-
// change.
270-
Some(AnalyzedSourcePosition {
271-
path: "sourceMaps.js".parse()?,
272-
start_lineno: analyzed_module.functions[0]
273-
.pos
274-
.as_ref()
275-
.unwrap()
276-
.start_lineno,
277-
start_col: analyzed_module.functions[0].pos.as_ref().unwrap().start_col,
278-
}),
279-
UdfType::Query,
280-
Some(Visibility::Public),
281-
ArgsValidator::Unvalidated,
282-
ReturnsValidator::Unvalidated,
283-
)?,
284-
AnalyzedFunction::new(
285-
"throwsErrorInDep".parse()?,
286-
Some(AnalyzedSourcePosition {
287-
path: "sourceMaps.js".parse()?,
288-
start_lineno: analyzed_module.functions[1]
289-
.pos
290-
.as_ref()
291-
.unwrap()
292-
.start_lineno,
293-
start_col: analyzed_module.functions[1].pos.as_ref().unwrap().start_col,
294-
}),
295-
UdfType::Query,
296-
Some(Visibility::Public),
297-
ArgsValidator::Unvalidated,
298-
ReturnsValidator::Unvalidated,
299-
)?,
300-
],
301-
);
302-
let source_mapped = analyzed_module.source_mapped.unwrap();
303-
assert_eq!(
304-
&Vec::from(source_mapped.functions),
305253
&[
306254
AnalyzedFunction::new(
307255
"throwsError".parse()?,
@@ -329,6 +277,7 @@ async fn test_analyze_function(rt: TestRuntime) -> anyhow::Result<()> {
329277
)?,
330278
],
331279
);
280+
analyzed_module.source_index.unwrap();
332281
Ok(())
333282
}
334283

@@ -357,50 +306,6 @@ async fn test_analyze_internal_function(rt: TestRuntime) -> anyhow::Result<()> {
357306
"myInternalQuery".parse()?,
358307
// Don't check line numbers since those change on every `convex/server`
359308
// change.
360-
analyzed_module.functions[0].pos.clone(),
361-
UdfType::Query,
362-
Some(Visibility::Internal),
363-
ArgsValidator::Unvalidated,
364-
ReturnsValidator::Unvalidated,
365-
)?,
366-
AnalyzedFunction::new(
367-
"publicQuery".parse()?,
368-
// Don't check line numbers since those change on every `convex/server`
369-
// change.
370-
analyzed_module.functions[1].pos.clone(),
371-
UdfType::Query,
372-
Some(Visibility::Public),
373-
ArgsValidator::Unvalidated,
374-
ReturnsValidator::Unvalidated,
375-
)?,
376-
AnalyzedFunction::new(
377-
"myInternalMutation".parse()?,
378-
// Don't check line numbers since those change on every `convex/server`
379-
// change.
380-
analyzed_module.functions[2].pos.clone(),
381-
UdfType::Mutation,
382-
Some(Visibility::Internal),
383-
ArgsValidator::Unvalidated,
384-
ReturnsValidator::Unvalidated,
385-
)?,
386-
AnalyzedFunction::new(
387-
"publicMutation".parse()?,
388-
// Don't check line numbers since those change on every `convex/server`
389-
// change.
390-
analyzed_module.functions[3].pos.clone(),
391-
UdfType::Mutation,
392-
Some(Visibility::Public),
393-
ArgsValidator::Unvalidated,
394-
ReturnsValidator::Unvalidated,
395-
)?,
396-
],
397-
);
398-
let source_mapped = analyzed_module.source_mapped.unwrap();
399-
assert_eq!(
400-
&Vec::from(source_mapped.functions.clone()),
401-
&[
402-
AnalyzedFunction::new(
403-
"myInternalQuery".parse()?,
404309
Some(AnalyzedSourcePosition {
405310
path: "internal.js".parse()?,
406311
start_lineno: 16,
@@ -413,6 +318,8 @@ async fn test_analyze_internal_function(rt: TestRuntime) -> anyhow::Result<()> {
413318
)?,
414319
AnalyzedFunction::new(
415320
"publicQuery".parse()?,
321+
// Don't check line numbers since those change on every `convex/server`
322+
// change.
416323
Some(AnalyzedSourcePosition {
417324
path: "internal.js".parse()?,
418325
start_lineno: 19,
@@ -425,6 +332,8 @@ async fn test_analyze_internal_function(rt: TestRuntime) -> anyhow::Result<()> {
425332
)?,
426333
AnalyzedFunction::new(
427334
"myInternalMutation".parse()?,
335+
// Don't check line numbers since those change on every `convex/server`
336+
// change.
428337
Some(AnalyzedSourcePosition {
429338
path: "internal.js".parse()?,
430339
start_lineno: 23,
@@ -437,6 +346,8 @@ async fn test_analyze_internal_function(rt: TestRuntime) -> anyhow::Result<()> {
437346
)?,
438347
AnalyzedFunction::new(
439348
"publicMutation".parse()?,
349+
// Don't check line numbers since those change on every `convex/server`
350+
// change.
440351
Some(AnalyzedSourcePosition {
441352
path: "internal.js".parse()?,
442353
start_lineno: 26,

crates/model/src/config/tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ async fn test_config(rt: TestRuntime) -> anyhow::Result<()> {
9292
functions: WithHeapSize::default(),
9393
http_routes: None,
9494
cron_specs: None,
95-
source_mapped: None,
95+
source_index: None,
9696
},
9797
p2 => AnalyzedModule {
9898
functions: WithHeapSize::default(),
9999
http_routes: None,
100100
cron_specs: None,
101-
source_mapped: None,
101+
source_index: None,
102102
},
103103
},
104104
None,
@@ -148,7 +148,7 @@ async fn test_config_large_modules(rt: TestRuntime) -> anyhow::Result<()> {
148148
functions: WithHeapSize::default(),
149149
http_routes: None,
150150
cron_specs: None,
151-
source_mapped: None,
151+
source_index: None,
152152
},
153153
)
154154
})

crates/model/src/modules/module_versions.rs

Lines changed: 22 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,16 @@ pub struct AnalyzedModule {
8282
)
8383
)]
8484
pub cron_specs: Option<WithHeapSize<BTreeMap<CronIdentifier, CronSpec>>>,
85-
pub source_mapped: Option<MappedModule>,
85+
/// Index of the module's original source in the source map.
86+
pub source_index: Option<u32>,
8687
}
8788

8889
impl HeapSize for AnalyzedModule {
8990
fn heap_size(&self) -> usize {
9091
self.functions.heap_size()
9192
+ self.http_routes.heap_size()
9293
+ self.cron_specs.heap_size()
93-
+ self.source_mapped.heap_size()
94+
+ self.source_index.heap_size()
9495
}
9596
}
9697

@@ -107,6 +108,11 @@ impl TryFrom<AnalyzedModule> for SerializedAnalyzedModule {
107108
type Error = anyhow::Error;
108109

109110
fn try_from(m: AnalyzedModule) -> anyhow::Result<Self> {
111+
let source_mapped = m
112+
.source_index
113+
.as_ref()
114+
.map(|_source_mapped| SerializedMappedModule::try_from(m.clone()))
115+
.transpose()?;
110116
Ok(Self {
111117
functions: m
112118
.functions
@@ -121,7 +127,7 @@ impl TryFrom<AnalyzedModule> for SerializedAnalyzedModule {
121127
.cron_specs
122128
.map(|specs| specs.into_iter().map(TryFrom::try_from).try_collect())
123129
.transpose()?,
124-
source_mapped: m.source_mapped.map(TryFrom::try_from).transpose()?,
130+
source_mapped,
125131
})
126132
}
127133
}
@@ -147,7 +153,9 @@ impl TryFrom<SerializedAnalyzedModule> for AnalyzedModule {
147153
.cron_specs
148154
.map(|specs| specs.into_iter().map(TryFrom::try_from).try_collect())
149155
.transpose()?,
150-
source_mapped: m.source_mapped.map(TryFrom::try_from).transpose()?,
156+
source_index: m
157+
.source_mapped
158+
.and_then(|mapped_module| mapped_module.source_index),
151159
})
152160
}
153161
}
@@ -517,43 +525,10 @@ impl Deref for AnalyzedHttpRoutes {
517525
}
518526
}
519527

520-
#[derive(Debug, Clone, PartialEq, Eq)]
521-
#[cfg_attr(any(test, feature = "testing"), derive(proptest_derive::Arbitrary))]
522-
pub struct MappedModule {
523-
// Index of the module's original source in the source map.
524-
// TODO: consider removing this or moving this out of MappedModule into AnalyzedModule and
525-
// instead just include source information. This requires a decent migration from Dashboard
526-
// schema.
527-
// See https://github.com/get-convex/convex/pull/14382/files#r1252372646 for further discussion.
528-
pub source_index: Option<u32>,
529-
#[cfg_attr(
530-
any(test, feature = "testing"),
531-
proptest(
532-
strategy = "value::heap_size::of(prop::collection::vec(any::<AnalyzedFunction>(), \
533-
0..4))"
534-
)
535-
)]
536-
pub functions: WithHeapSize<Vec<AnalyzedFunction>>,
537-
pub http_routes: Option<AnalyzedHttpRoutes>,
538-
#[cfg_attr(
539-
any(test, feature = "testing"),
540-
proptest(
541-
strategy = "prop::option::of(value::heap_size::of(prop::collection::btree_map(any::<CronIdentifier>(), \
542-
any::<CronSpec>(), 0..4)))"
543-
)
544-
)]
545-
pub cron_specs: Option<WithHeapSize<BTreeMap<CronIdentifier, CronSpec>>>,
546-
}
547-
548-
impl HeapSize for MappedModule {
549-
fn heap_size(&self) -> usize {
550-
self.source_index.heap_size()
551-
+ self.functions.heap_size()
552-
+ self.http_routes.heap_size()
553-
+ self.cron_specs.heap_size()
554-
}
555-
}
556-
528+
// TODO: consider denormalizing SerializedMappedModule into
529+
// SerializedAnalyzedModule and instead just include source information. This
530+
// requires a decent migration from Dashboard schema.
531+
// See https://github.com/get-convex/convex/pull/14382/files#r1252372646 for further discussion.
557532
#[derive(Serialize, Deserialize)]
558533
#[serde(rename_all = "camelCase")]
559534
struct SerializedMappedModule {
@@ -563,10 +538,14 @@ struct SerializedMappedModule {
563538
cron_specs: Option<Vec<SerializedNamedCronSpec>>,
564539
}
565540

566-
impl TryFrom<MappedModule> for SerializedMappedModule {
541+
impl TryFrom<AnalyzedModule> for SerializedMappedModule {
567542
type Error = anyhow::Error;
568543

569-
fn try_from(m: MappedModule) -> anyhow::Result<Self> {
544+
fn try_from(m: AnalyzedModule) -> anyhow::Result<Self> {
545+
anyhow::ensure!(
546+
m.source_index.is_some(),
547+
"source_index must be set to be serializing into SerializedMappedModule"
548+
);
570549
Ok(Self {
571550
source_index: m.source_index,
572551
functions: m
@@ -586,32 +565,6 @@ impl TryFrom<MappedModule> for SerializedMappedModule {
586565
}
587566
}
588567

589-
impl TryFrom<SerializedMappedModule> for MappedModule {
590-
type Error = anyhow::Error;
591-
592-
fn try_from(m: SerializedMappedModule) -> anyhow::Result<Self> {
593-
Ok(Self {
594-
source_index: m.source_index,
595-
functions: m
596-
.functions
597-
.into_iter()
598-
.map(TryFrom::try_from)
599-
.try_collect()?,
600-
http_routes: m
601-
.http_routes
602-
.map(|routes| {
603-
let routes = routes.into_iter().map(TryFrom::try_from).try_collect()?;
604-
anyhow::Ok(AnalyzedHttpRoutes::new(routes))
605-
})
606-
.transpose()?,
607-
cron_specs: m
608-
.cron_specs
609-
.map(|specs| specs.into_iter().map(TryFrom::try_from).try_collect())
610-
.transpose()?,
611-
})
612-
}
613-
}
614-
615568
#[cfg(test)]
616569
mod tests {
617570
use value::{

0 commit comments

Comments
 (0)