diff --git a/sql/load_sql_context.sql b/sql/load_sql_context.sql index b6040788..5ef309c9 100644 --- a/sql/load_sql_context.sql +++ b/sql/load_sql_context.sql @@ -265,7 +265,8 @@ select ) ), 'primary_key_columns', d.directive -> 'primary_key_columns', - 'foreign_keys', d.directive -> 'foreign_keys' + 'foreign_keys', d.directive -> 'foreign_keys', + 'max_rows', (d.directive ->> 'max_rows')::int ) from directives d diff --git a/src/builder.rs b/src/builder.rs index adb23a60..67f5dd41 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1423,13 +1423,13 @@ where } }; - let max_rows: u64 = xtype + let max_rows = xtype .schema .context .schemas .values() .find(|s| s.oid == xtype.table.schema_oid) - .map(|x| x.directives.max_rows) + .map(|schema| xtype.table.max_rows(schema)) .unwrap_or(30); let before: Option = read_argument_cursor( diff --git a/src/sql_types.rs b/src/sql_types.rs index 9faff16b..0ef1bb8d 100644 --- a/src/sql_types.rs +++ b/src/sql_types.rs @@ -482,6 +482,9 @@ pub struct TableDirectives { // @graphql({"primary_key_columns": ["id"]}) pub primary_key_columns: Option>, + // @graphql({"max_rows": 20}) + pub max_rows: Option, + /* @graphql( { @@ -576,6 +579,7 @@ impl Table { pub fn is_any_column_selectable(&self) -> bool { self.columns.iter().any(|x| x.permissions.is_selectable) } + pub fn is_any_column_insertable(&self) -> bool { self.columns.iter().any(|x| x.permissions.is_insertable) } @@ -583,6 +587,14 @@ impl Table { pub fn is_any_column_updatable(&self) -> bool { self.columns.iter().any(|x| x.permissions.is_updatable) } + + /// Get the effective max_rows value for this table. + /// If table-specific max_rows is set, use that. + /// Otherwise, fall back to schema-level max_rows. + /// If neither is set, use the global default(set in load_sql_context.sql) + pub fn max_rows(&self, schema: &Schema) -> u64 { + self.directives.max_rows.unwrap_or(schema.directives.max_rows) + } } #[derive(Deserialize, Clone, Debug, Eq, PartialEq, Hash)] diff --git a/test/expected/max_rows_directive.out b/test/expected/max_rows_directive.out index 98a2734d..6627eb9c 100644 --- a/test/expected/max_rows_directive.out +++ b/test/expected/max_rows_directive.out @@ -60,4 +60,65 @@ begin; {"data": {"accountCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 2}}, {"node": {"id": 3}}, {"node": {"id": 4}}, {"node": {"id": 5}}, {"node": {"id": 6}}, {"node": {"id": 7}}, {"node": {"id": 8}}, {"node": {"id": 9}}, {"node": {"id": 10}}, {"node": {"id": 11}}, {"node": {"id": 12}}, {"node": {"id": 13}}, {"node": {"id": 14}}, {"node": {"id": 15}}, {"node": {"id": 16}}, {"node": {"id": 17}}, {"node": {"id": 18}}, {"node": {"id": 19}}, {"node": {"id": 20}}, {"node": {"id": 21}}, {"node": {"id": 22}}, {"node": {"id": 23}}, {"node": {"id": 24}}, {"node": {"id": 25}}, {"node": {"id": 26}}, {"node": {"id": 27}}, {"node": {"id": 28}}, {"node": {"id": 29}}, {"node": {"id": 30}}, {"node": {"id": 31}}, {"node": {"id": 32}}, {"node": {"id": 33}}, {"node": {"id": 34}}, {"node": {"id": 35}}, {"node": {"id": 36}}, {"node": {"id": 37}}, {"node": {"id": 38}}, {"node": {"id": 39}}, {"node": {"id": 40}}]}}} (1 row) + -- table-specific max_rows + comment on table account is e'@graphql({"max_rows": 5})'; + -- expect 5 rows on first page + select graphql.resolve($$ + { + accountCollection { + edges { + node { + id + } + } + } + } + $$); + resolve +------------------------------------------------------------------------------------------------------------------------------------------------------- + {"data": {"accountCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 2}}, {"node": {"id": 3}}, {"node": {"id": 4}}, {"node": {"id": 5}}]}}} +(1 row) + + -- view-specific max_rows + create view person as + select * from account; + comment on view person is e'@graphql({"primary_key_columns": ["id"], "max_rows": 3})'; + -- expect 3 rows on first page + select graphql.resolve($$ + { + personCollection { + edges { + node { + id + } + } + } + } + $$); + resolve +------------------------------------------------------------------------------------------------------------ + {"data": {"personCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 2}}, {"node": {"id": 3}}]}}} +(1 row) + + -- nested view with max_rows + create view parent as + select * from person; + comment on view parent is e'@graphql({"primary_key_columns": ["id"], "max_rows": 2})'; + -- expect 2 rows on first page + select graphql.resolve($$ + { + parentCollection { + edges { + node { + id + } + } + } + } + $$); + resolve +--------------------------------------------------------------------------------------- + {"data": {"parentCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 2}}]}}} +(1 row) + rollback; diff --git a/test/sql/max_rows_directive.sql b/test/sql/max_rows_directive.sql index 8f6666fd..83177146 100644 --- a/test/sql/max_rows_directive.sql +++ b/test/sql/max_rows_directive.sql @@ -52,4 +52,56 @@ begin; } $$); + -- table-specific max_rows + comment on table account is e'@graphql({"max_rows": 5})'; + + -- expect 5 rows on first page + select graphql.resolve($$ + { + accountCollection { + edges { + node { + id + } + } + } + } + $$); + + -- view-specific max_rows + create view person as + select * from account; + comment on view person is e'@graphql({"primary_key_columns": ["id"], "max_rows": 3})'; + + -- expect 3 rows on first page + select graphql.resolve($$ + { + personCollection { + edges { + node { + id + } + } + } + } + $$); + + -- nested view with max_rows + create view parent as + select * from person; + comment on view parent is e'@graphql({"primary_key_columns": ["id"], "max_rows": 2})'; + + -- expect 2 rows on first page + select graphql.resolve($$ + { + parentCollection { + edges { + node { + id + } + } + } + } + $$); + rollback;