Skip to content

Commit 556507c

Browse files
authored
Merge pull request #18 from github/optional_fields
Don't generate an index for optional fields that occur at most once
2 parents fbb075b + 547d12c commit 556507c

File tree

6 files changed

+188
-209
lines changed

6 files changed

+188
-209
lines changed

extractor/src/extractor.rs

+30-11
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,23 @@ impl Visitor<'_> {
230230
)
231231
}
232232
}
233-
Storage::Table => {
233+
Storage::Table(has_index) => {
234234
for (index, child_id) in child_ids.iter().enumerate() {
235+
if !*has_index && index > 0 {
236+
error!(
237+
"{}:{}: too many values for field: {}::{}",
238+
&self.path,
239+
node.start_position().row,
240+
node.kind(),
241+
&field.get_name()
242+
);
243+
break;
244+
}
235245
self.trap_output.push(TrapEntry::ChildOf(
236246
node_type_name(&field.parent.kind, field.parent.named),
237247
parent_id,
238248
field.get_name(),
239-
Index(index),
249+
if *has_index { Some(Index(index)) } else { None },
240250
*child_id,
241251
));
242252
}
@@ -364,7 +374,7 @@ enum TrapEntry {
364374
// @node_def(self, arg?, location)@
365375
Definition(String, Label, Vec<Arg>, Label),
366376
// @node_child(self, index, parent)@
367-
ChildOf(String, Label, String, Index, Label),
377+
ChildOf(String, Label, String, Option<Index>, Label),
368378
// @location(loc, path, r1, c1, r2, c2)
369379
Located(Vec<Arg>),
370380
Comment(String),
@@ -387,14 +397,23 @@ impl fmt::Display for TrapEntry {
387397
loc
388398
)
389399
}
390-
TrapEntry::ChildOf(pname, id, fname, idx, p) => write!(
391-
f,
392-
"{}({}, {}, {})",
393-
escape_name(&format!("{}_{}", &pname, &fname)),
394-
id,
395-
idx,
396-
p
397-
),
400+
TrapEntry::ChildOf(pname, id, fname, idx, p) => match idx {
401+
Some(idx) => write!(
402+
f,
403+
"{}({}, {}, {})",
404+
escape_name(&format!("{}_{}", &pname, &fname)),
405+
id,
406+
idx,
407+
p
408+
),
409+
None => write!(
410+
f,
411+
"{}({}, {})",
412+
escape_name(&format!("{}_{}", &pname, &fname)),
413+
id,
414+
p
415+
),
416+
},
398417
TrapEntry::Located(args) => write!(
399418
f,
400419
"location({}, {}, {}, {}, {}, {})",

generator/src/main.rs

+36-32
Original file line numberDiff line numberDiff line change
@@ -49,45 +49,49 @@ fn add_field(
4949
) {
5050
let field_name = field.get_name();
5151
let parent_name = node_types::node_type_name(&field.parent.kind, field.parent.named);
52-
match field.storage {
53-
node_types::Storage::Table { .. } => {
52+
match &field.storage {
53+
node_types::Storage::Table(has_index) => {
5454
// This field can appear zero or multiple times, so put
5555
// it in an auxiliary table.
5656
let field_type = make_field_type(&parent_name, &field_name, &field.types, entries);
57+
let parent_column = dbscheme::Column {
58+
unique: !*has_index,
59+
db_type: dbscheme::DbColumnType::Int,
60+
name: node_types::escape_name(&parent_name),
61+
ql_type: ql::Type::AtType(node_types::escape_name(&parent_name)),
62+
ql_type_is_ref: true,
63+
};
64+
let index_column = dbscheme::Column {
65+
unique: false,
66+
db_type: dbscheme::DbColumnType::Int,
67+
name: "index".to_string(),
68+
ql_type: ql::Type::Int,
69+
ql_type_is_ref: true,
70+
};
71+
let field_column = dbscheme::Column {
72+
unique: true,
73+
db_type: dbscheme::DbColumnType::Int,
74+
name: node_types::escape_name(&field_type),
75+
ql_type: ql::Type::AtType(field_type),
76+
ql_type_is_ref: true,
77+
};
5778
let field_table = dbscheme::Table {
5879
name: format!("{}_{}", parent_name, field_name),
59-
columns: vec![
60-
// First column is a reference to the parent.
61-
dbscheme::Column {
62-
unique: false,
63-
db_type: dbscheme::DbColumnType::Int,
64-
name: node_types::escape_name(&parent_name),
65-
ql_type: ql::Type::AtType(node_types::escape_name(&parent_name)),
66-
ql_type_is_ref: true,
67-
},
68-
// Then an index column.
69-
dbscheme::Column {
70-
unique: false,
71-
db_type: dbscheme::DbColumnType::Int,
72-
name: "index".to_string(),
73-
ql_type: ql::Type::Int,
74-
ql_type_is_ref: true,
75-
},
76-
// And then the field
77-
dbscheme::Column {
78-
unique: true,
79-
db_type: dbscheme::DbColumnType::Int,
80-
name: node_types::escape_name(&field_type),
81-
ql_type: ql::Type::AtType(field_type),
82-
ql_type_is_ref: true,
83-
},
84-
],
80+
columns: if *has_index {
81+
vec![parent_column, index_column, field_column]
82+
} else {
83+
vec![parent_column, field_column]
84+
},
8585
// In addition to the field being unique, the combination of
8686
// parent+index is unique, so add a keyset for them.
87-
keysets: Some(vec![
88-
node_types::escape_name(&parent_name),
89-
"index".to_string(),
90-
]),
87+
keysets: if *has_index {
88+
Some(vec![
89+
node_types::escape_name(&parent_name),
90+
"index".to_string(),
91+
])
92+
} else {
93+
None
94+
},
9195
};
9296
entries.push(dbscheme::Entry::Table(field_table));
9397
}

generator/src/ql_gen.rs

+29-13
Original file line numberDiff line numberDiff line change
@@ -339,15 +339,21 @@ fn create_get_field_expr_for_column_storage(
339339
/// all indices.
340340
fn create_get_field_expr_for_table_storage(
341341
table_name: &str,
342-
index_var_name: &str,
342+
index_var_name: Option<&str>,
343343
) -> ql::Expression {
344344
ql::Expression::Pred(
345345
table_name.to_owned(),
346-
vec![
347-
ql::Expression::Var("this".to_owned()),
348-
ql::Expression::Var(index_var_name.to_owned()),
349-
ql::Expression::Var("result".to_owned()),
350-
],
346+
match index_var_name {
347+
Some(index_var_name) => vec![
348+
ql::Expression::Var("this".to_owned()),
349+
ql::Expression::Var(index_var_name.to_owned()),
350+
ql::Expression::Var("result".to_owned()),
351+
],
352+
None => vec![
353+
ql::Expression::Var("this".to_owned()),
354+
ql::Expression::Var("result".to_owned()),
355+
],
356+
},
351357
)
352358
}
353359

@@ -400,7 +406,7 @@ fn create_field_getters(
400406
*main_table_column_index += 1;
401407
result
402408
}
403-
node_types::Storage::Table => {
409+
node_types::Storage::Table(has_index) => {
404410
let field_table_name = format!("{}_{}", parent_name, &field.get_name());
405411
(
406412
ql::Predicate {
@@ -410,13 +416,23 @@ fn create_field_getters(
410416
),
411417
overridden: false,
412418
return_type: Some(ql::Type::Normal(dbscheme_name_to_class_name(field_type))),
413-
formal_parameters: vec![ql::FormalParameter {
414-
name: "i".to_owned(),
415-
param_type: ql::Type::Int,
416-
}],
417-
body: create_get_field_expr_for_table_storage(&field_table_name, "i"),
419+
formal_parameters: if *has_index {
420+
vec![ql::FormalParameter {
421+
name: "i".to_owned(),
422+
param_type: ql::Type::Int,
423+
}]
424+
} else {
425+
vec![]
426+
},
427+
body: create_get_field_expr_for_table_storage(
428+
&field_table_name,
429+
if *has_index { Some("i") } else { None },
430+
),
418431
},
419-
create_get_field_expr_for_table_storage(&field_table_name, "_"),
432+
create_get_field_expr_for_table_storage(
433+
&field_table_name,
434+
if *has_index { Some("_") } else { None },
435+
),
420436
)
421437
}
422438
}

node-types/src/lib.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ impl Field {
4646
pub enum Storage {
4747
/// the field is stored as a column in the parent table
4848
Column,
49-
// the field is store in a link table
50-
Table,
49+
/// the field is stored in a link table, and may or may not have an
50+
/// associated index column
51+
Table(bool),
5152
}
5253

5354
pub fn read_node_types(node_types_path: &Path) -> std::io::Result<Vec<Entry>> {
@@ -122,16 +123,19 @@ fn add_field(
122123
field_info: &FieldInfo,
123124
fields: &mut Vec<Field>,
124125
) {
125-
let storage;
126-
if !field_info.multiple && field_info.required {
126+
let storage = if !field_info.multiple && field_info.required {
127127
// This field must appear exactly once, so we add it as
128128
// a column to the main table for the node type.
129-
storage = Storage::Column;
129+
Storage::Column
130+
} else if !field_info.multiple {
131+
// This field is optional but can occur at most once. Put it in an
132+
// auxiliary table without an index.
133+
Storage::Table(false)
130134
} else {
131-
// This field can appear zero or multiple times, so put
132-
// it in an auxiliary table.
133-
storage = Storage::Table;
134-
}
135+
// This field can occur multiple times. Put it in an auxiliary table
136+
// with an associated index.
137+
Storage::Table(true)
138+
};
135139
fields.push(Field {
136140
parent: TypeName {
137141
kind: parent_type_name.kind.to_string(),

0 commit comments

Comments
 (0)