├── .Rbuildignore ├── .github ├── .gitignore ├── CONTRIBUTING.md ├── odbc │ ├── install-mariadb-driver.sh │ ├── odbc.ini │ └── odbcinst.ini ├── versions-matrix.R └── workflows │ ├── R-CMD-check-dev.yaml │ ├── R-CMD-check-status.yaml │ ├── R-CMD-check.yaml │ ├── check │ └── action.yml │ ├── commit │ └── action.yml │ ├── covr │ └── action.yml │ ├── custom │ ├── after-install │ │ └── action.yml │ └── before-install │ │ └── action.yml │ ├── dep-matrix │ └── action.yml │ ├── dep-suggests-matrix │ ├── action.R │ └── action.yml │ ├── fledge.yaml │ ├── get-extra │ └── action.yml │ ├── ghcr.yaml │ ├── git-identity │ └── action.yml │ ├── install │ └── action.yml │ ├── lock.yaml │ ├── matrix-check │ └── action.yml │ ├── pkgdown-build │ └── action.yml │ ├── pkgdown-deploy │ └── action.yml │ ├── pkgdown.yaml │ ├── pr-commands.yaml │ ├── rate-limit │ └── action.yml │ ├── revdep.yaml │ ├── roxygenize │ └── action.yml │ ├── style │ └── action.yml │ ├── unblock.yaml │ ├── update-snapshots │ └── action.yml │ └── versions-matrix │ ├── action.R │ └── action.yml ├── .gitignore ├── .gitpod.yml ├── CODE_OF_CONDUCT.md ├── DESCRIPTION ├── Dockerfile ├── LICENSE ├── LICENSE.md ├── Makefile ├── NAMESPACE ├── NEWS.md ├── R ├── aaa-dbplyr.R ├── aaa-dplyr.R ├── add-tbl.R ├── bind.R ├── build_copy_queries.R ├── cache.R ├── check-cardinalities.R ├── code-generation.R ├── colors.R ├── data-model-helpers.R ├── datamodelr-code.R ├── db-helpers.R ├── db-interface.R ├── deconstruct.R ├── deprecated.R ├── descriptions.R ├── disambiguate.R ├── disentangle.R ├── dm-package.R ├── dm.R ├── dm_deconstruct.R ├── dm_from_con.R ├── dm_get_con.R ├── dm_get_tables.R ├── dm_gui.R ├── dm_nest_tbl.R ├── dm_sql.R ├── dm_unnest_tbl.R ├── dm_wrap.R ├── dplyr-src.R ├── dplyr.R ├── draw-dm.R ├── enum_ops.R ├── enumerate_all_paths.R ├── error-helpers.R ├── examine-cardinalities.R ├── examine-constraints.R ├── filter-dm.R ├── filter-helpers.R ├── financial-db-con.R ├── financial.R ├── flatten.R ├── foreign-keys.R ├── format.R ├── globals.R ├── graph.R ├── gui-check.R ├── gui-dm.R ├── gui-dmSVG.R ├── gui-dm_to_svg.R ├── gui-expect_mw_cg_snapshot.R ├── gui-gui_global.R ├── gui-gui_run.R ├── gui-gui_server.R ├── gui-gui_ui.R ├── gui-mw_cg.R ├── gui-mw_cg_enum_dm_add_fk.R ├── gui-mw_cg_make_dm_add_fk.R ├── gui-mw_cg_make_dm_add_pk.R ├── gui-mw_cg_make_dm_disentangle.R ├── gui-mw_cg_make_dm_rename.R ├── gui-mw_cg_make_dm_rm_fk.R ├── gui-mw_cg_make_dm_select.R ├── gui-mw_cg_make_dm_select_tbl.R ├── gui-mw_cg_make_dm_set_colors.R ├── gui-ops_stack.R ├── gui-shiny_input.R ├── gui-zzz.R ├── json_nest.R ├── json_nest_join.R ├── json_pack.R ├── json_pack_join.R ├── json_unnest.R ├── json_unpack.R ├── key-helpers.R ├── keys.R ├── learn.R ├── mariadb.R ├── meta.R ├── mssql.R ├── nest.R ├── new_ticker.R ├── nycflights13.R ├── pack_join.R ├── paste.R ├── pixarfilms.R ├── pkgdown.R ├── postgres.R ├── primary-keys.R ├── ptype.R ├── reexport.R ├── rows-dm.R ├── schema.R ├── select-tbl.R ├── select.R ├── standalone-check_suggested.R ├── strict.R ├── table-surgery.R ├── test-dm.R ├── testthat-wrappers.R ├── tidyr.R ├── tidyselect.R ├── unique-keys.R ├── unjson_nested.R ├── unnest.R ├── upgrade.R ├── utils.R ├── validate.R ├── waldo.R ├── zoom.R ├── zzx-deprecated.R └── zzz.R ├── README.Rmd ├── README.md ├── TODO.md ├── codecov.yml ├── cran-comments.md ├── data-raw └── nycflights13-small.R ├── demo ├── 00Index ├── basel.R ├── berlin.R ├── hamburg.R ├── milano.R ├── neuchatel.R ├── nyc.R ├── seattle.R ├── zurich.R └── zurich2.R ├── dm.Rproj ├── docker-compose.yml ├── example └── rows-d.R ├── index.md ├── inst ├── WORDLIST ├── cheatsheet-template.html ├── cheatsheet.css ├── extdata │ └── nycflights13-small.rds ├── htmlwidgets │ ├── css │ │ └── styles.css │ ├── custom.js │ ├── dmSVG.js │ ├── dmSVG.yaml │ └── lib │ │ ├── hammer │ │ ├── LICENSE.md │ │ ├── README.md │ │ └── hammer.min.js │ │ ├── jquery │ │ ├── .bower.json │ │ ├── AUTHORS.txt │ │ ├── LICENSE.txt │ │ ├── README.md │ │ ├── bower.json │ │ ├── dist │ │ │ ├── jquery.js │ │ │ ├── jquery.min.js │ │ │ ├── jquery.min.map │ │ │ ├── jquery.slim.js │ │ │ ├── jquery.slim.min.js │ │ │ └── jquery.slim.min.map │ │ ├── external │ │ │ └── sizzle │ │ │ │ ├── LICENSE.txt │ │ │ │ └── dist │ │ │ │ ├── sizzle.js │ │ │ │ ├── sizzle.min.js │ │ │ │ └── sizzle.min.map │ │ └── src │ │ │ ├── ajax.js │ │ │ ├── ajax │ │ │ ├── jsonp.js │ │ │ ├── load.js │ │ │ ├── script.js │ │ │ ├── var │ │ │ │ ├── location.js │ │ │ │ ├── nonce.js │ │ │ │ └── rquery.js │ │ │ └── xhr.js │ │ │ ├── attributes.js │ │ │ ├── attributes │ │ │ ├── attr.js │ │ │ ├── classes.js │ │ │ ├── prop.js │ │ │ ├── support.js │ │ │ └── val.js │ │ │ ├── callbacks.js │ │ │ ├── core.js │ │ │ ├── core │ │ │ ├── DOMEval.js │ │ │ ├── access.js │ │ │ ├── camelCase.js │ │ │ ├── init.js │ │ │ ├── isAttached.js │ │ │ ├── nodeName.js │ │ │ ├── parseHTML.js │ │ │ ├── parseXML.js │ │ │ ├── ready-no-deferred.js │ │ │ ├── ready.js │ │ │ ├── readyException.js │ │ │ ├── stripAndCollapse.js │ │ │ ├── support.js │ │ │ ├── toType.js │ │ │ └── var │ │ │ │ └── rsingleTag.js │ │ │ ├── css.js │ │ │ ├── css │ │ │ ├── addGetHookIf.js │ │ │ ├── adjustCSS.js │ │ │ ├── curCSS.js │ │ │ ├── finalPropName.js │ │ │ ├── hiddenVisibleSelectors.js │ │ │ ├── showHide.js │ │ │ ├── support.js │ │ │ └── var │ │ │ │ ├── cssExpand.js │ │ │ │ ├── getStyles.js │ │ │ │ ├── isHiddenWithinTree.js │ │ │ │ ├── rboxStyle.js │ │ │ │ ├── rnumnonpx.js │ │ │ │ └── swap.js │ │ │ ├── data.js │ │ │ ├── data │ │ │ ├── Data.js │ │ │ └── var │ │ │ │ ├── acceptData.js │ │ │ │ ├── dataPriv.js │ │ │ │ └── dataUser.js │ │ │ ├── deferred.js │ │ │ ├── deferred │ │ │ └── exceptionHook.js │ │ │ ├── deprecated.js │ │ │ ├── deprecated │ │ │ ├── ajax-event-alias.js │ │ │ └── event.js │ │ │ ├── dimensions.js │ │ │ ├── effects.js │ │ │ ├── effects │ │ │ ├── Tween.js │ │ │ └── animatedSelector.js │ │ │ ├── event.js │ │ │ ├── event │ │ │ ├── focusin.js │ │ │ ├── support.js │ │ │ └── trigger.js │ │ │ ├── exports │ │ │ ├── amd.js │ │ │ └── global.js │ │ │ ├── jquery.js │ │ │ ├── manipulation.js │ │ │ ├── manipulation │ │ │ ├── _evalUrl.js │ │ │ ├── buildFragment.js │ │ │ ├── getAll.js │ │ │ ├── setGlobalEval.js │ │ │ ├── support.js │ │ │ ├── var │ │ │ │ ├── rscriptType.js │ │ │ │ └── rtagName.js │ │ │ └── wrapMap.js │ │ │ ├── offset.js │ │ │ ├── queue.js │ │ │ ├── queue │ │ │ └── delay.js │ │ │ ├── selector-native.js │ │ │ ├── selector-sizzle.js │ │ │ ├── selector.js │ │ │ ├── serialize.js │ │ │ ├── traversing.js │ │ │ ├── traversing │ │ │ ├── findFilter.js │ │ │ └── var │ │ │ │ ├── dir.js │ │ │ │ ├── rneedsContext.js │ │ │ │ └── siblings.js │ │ │ ├── var │ │ │ ├── ObjectFunctionString.js │ │ │ ├── arr.js │ │ │ ├── class2type.js │ │ │ ├── document.js │ │ │ ├── documentElement.js │ │ │ ├── flat.js │ │ │ ├── fnToString.js │ │ │ ├── getProto.js │ │ │ ├── hasOwn.js │ │ │ ├── indexOf.js │ │ │ ├── isFunction.js │ │ │ ├── isWindow.js │ │ │ ├── pnum.js │ │ │ ├── push.js │ │ │ ├── rcheckableType.js │ │ │ ├── rcssNum.js │ │ │ ├── rnothtmlwhite.js │ │ │ ├── slice.js │ │ │ ├── support.js │ │ │ └── toString.js │ │ │ └── wrap.js │ │ └── svg-pan-zoom │ │ ├── LICENSE_svg-pan-zoom │ │ └── dist │ │ ├── svg-pan-zoom.js │ │ └── svg-pan-zoom.min.js └── make-cheatsheet.R ├── man ├── check_key.Rd ├── check_set_equality.Rd ├── check_subset.Rd ├── copy_dm_to.Rd ├── db_schema_create.Rd ├── db_schema_drop.Rd ├── db_schema_exists.Rd ├── db_schema_list.Rd ├── decompose_table.Rd ├── deprecated.Rd ├── dm-package.Rd ├── dm.Rd ├── dm_add_fk.Rd ├── dm_add_pk.Rd ├── dm_add_uk.Rd ├── dm_deconstruct.Rd ├── dm_disambiguate_cols.Rd ├── dm_draw.Rd ├── dm_enum_fk_candidates.Rd ├── dm_enum_pk_candidates.Rd ├── dm_examine_cardinalities.Rd ├── dm_examine_constraints.Rd ├── dm_filter.Rd ├── dm_financial.Rd ├── dm_flatten_to_tbl.Rd ├── dm_from_con.Rd ├── dm_from_src.Rd ├── dm_get_all_fks.Rd ├── dm_get_all_pks.Rd ├── dm_get_all_uks.Rd ├── dm_get_con.Rd ├── dm_get_pk.Rd ├── dm_get_tables.Rd ├── dm_gui.Rd ├── dm_has_fk.Rd ├── dm_has_pk.Rd ├── dm_mutate_tbl.Rd ├── dm_nest_tbl.Rd ├── dm_nrow.Rd ├── dm_nycflights13.Rd ├── dm_pack_tbl.Rd ├── dm_paste.Rd ├── dm_pixarfilms.Rd ├── dm_ptype.Rd ├── dm_rename.Rd ├── dm_rm_fk.Rd ├── dm_rm_pk.Rd ├── dm_rm_uk.Rd ├── dm_select.Rd ├── dm_select_tbl.Rd ├── dm_set_colors.Rd ├── dm_set_table_description.Rd ├── dm_sql.Rd ├── dm_unnest_tbl.Rd ├── dm_unpack_tbl.Rd ├── dm_unwrap_tbl.Rd ├── dm_validate.Rd ├── dm_wrap_tbl.Rd ├── dm_zoom_to.Rd ├── dplyr_join.Rd ├── dplyr_src.Rd ├── dplyr_table_manipulation.Rd ├── examine_cardinality.Rd ├── figures │ ├── README-draw.svg │ ├── cynkra-72.png │ ├── energie-72.png │ ├── lifecycle-archived.svg │ ├── lifecycle-defunct.svg │ ├── lifecycle-deprecated.svg │ ├── lifecycle-experimental.svg │ ├── lifecycle-maturing.svg │ ├── lifecycle-questioning.svg │ ├── lifecycle-soft-deprecated.svg │ ├── lifecycle-stable.svg │ ├── lifecycle-superseded.svg │ └── logo.png ├── glimpse.dm.Rd ├── json_nest.Rd ├── json_nest_join.Rd ├── json_pack.Rd ├── json_pack_join.Rd ├── json_unnest.Rd ├── json_unpack.Rd ├── materialize.Rd ├── pack_join.Rd ├── pull_tbl.Rd ├── reexports.Rd ├── reunite_parent_child.Rd ├── rows-dm.Rd ├── tidyr_table_manipulation.Rd └── utils_table_manipulation.Rd ├── pkgdown ├── _pkgdown.yml ├── assets │ └── reference │ │ └── figures │ │ ├── cynkra-72.png │ │ └── energie-72.png ├── extra.css └── favicon │ └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico ├── renovate.json ├── revdep └── .gitignore ├── scratch ├── clean.R ├── code_generation_examples.R ├── code_generation_middleware.R ├── code_generation_middleware_2.R ├── code_generation_middleware_3.R ├── code_generation_middleware_4.R ├── demo-deconstruct.R ├── demo-gui-0.R ├── demo-gui-1.R ├── demo-gui-2.R ├── demo-gui-3.R ├── dm-overview.Rmd ├── enum.R ├── filter.R ├── info.R ├── other_test.R ├── test.R ├── vendor-gui-back.R └── vendor-gui.R ├── tests ├── testthat.R └── testthat │ ├── _snaps │ ├── add-tbl.md │ ├── autoincrement.md │ ├── bind.md │ ├── check-cardinalities.md │ ├── code-generation.md │ ├── datamodelr-code.md │ ├── datamodelr-code │ │ ├── nycflights13.dot │ │ ├── nycflights13_draw_uk_1.dot │ │ ├── nycflights13_draw_uk_2.dot │ │ ├── nycflights13_draw_uk_3.dot │ │ ├── nycflights13_table_desc_1.dot │ │ ├── nycflights13_table_desc_2.dot │ │ └── weird.dot │ ├── db-interface.md │ ├── deconstruct.md │ ├── df │ │ ├── build_copy_queries.md │ │ ├── flatten.md │ │ └── rows-dm.md │ ├── disambiguate.md │ ├── disentangle.md │ ├── dm.md │ ├── dm_deconstruct.md │ ├── dm_nest_tbl.md │ ├── dm_pixarfilms.md │ ├── dm_sql.md │ ├── dm_wrap.md │ ├── dplyr.md │ ├── draw-dm.md │ ├── draw-dm │ │ ├── empty-table-in-dm.svg │ │ ├── nycflight-dm-types.svg │ │ ├── nycflight-dm.svg │ │ ├── single-empty-table-dm.svg │ │ ├── table-desc-1-dm.svg │ │ ├── table-desc-2-dm.svg │ │ ├── table-desc-3-dm.svg │ │ ├── table-desc-4-dm.svg │ │ ├── table-uk-1-dm.svg │ │ └── table-uk-2-dm.svg │ ├── duckdb.md │ ├── duckdb │ │ ├── build_copy_queries.md │ │ └── flatten.md │ ├── enum-ops.md │ ├── enumerate_all_paths.md │ ├── error-helpers.md │ ├── examine-cardinalities.md │ ├── examine-constraints.md │ ├── filter-dm.md │ ├── foreign-keys.md │ ├── format.md │ ├── graph.md │ ├── json.md │ ├── json_nest.md │ ├── json_pack.md │ ├── key-helpers.md │ ├── learn.md │ ├── maria.md │ ├── maria │ │ ├── build_copy_queries.md │ │ └── flatten.md │ ├── meta.md │ ├── mssql.md │ ├── mssql │ │ ├── build_copy_queries.md │ │ ├── flatten.md │ │ ├── json_nest.md │ │ ├── json_pack.md │ │ ├── meta.md │ │ └── rows-dm.md │ ├── pack_join.md │ ├── paste.md │ ├── postgres.md │ ├── postgres │ │ ├── build_copy_queries.md │ │ ├── flatten.md │ │ ├── json_nest.md │ │ ├── json_pack.md │ │ └── rows-dm.md │ ├── primary-keys.md │ ├── rows-dm.md │ ├── select-tbl.md │ ├── select.md │ ├── sqlite.md │ ├── sqlite │ │ ├── build_copy_queries.md │ │ ├── flatten.md │ │ └── rows-dm.md │ ├── standalone-check_suggested.md │ ├── testthat-legacy │ │ └── draw-dm.md │ ├── testthat-new │ │ └── draw-dm.md │ ├── tidyr.md │ ├── tidyselect.md │ ├── unique-keys.md │ ├── upgrade.md │ ├── waldo.md │ ├── zoom.md │ └── zzx-deprecated.md │ ├── dm │ ├── v1.rds │ ├── v1_zoomed.rds │ ├── v2.rds │ ├── v2_zoomed.rds │ ├── v3.rds │ ├── v3_zoomed.rds │ ├── v4.rds │ └── v4_zoomed.rds │ ├── helper-config-db.R │ ├── helper-expectations.R │ ├── helper-filter-dm.R │ ├── helper-jsonlite.R │ ├── helper-print.R │ ├── helper-skip.R │ ├── helper-src.R │ ├── helper-sync.R │ ├── helper-testthat.R │ ├── helper-zoom.R │ ├── setup.R │ ├── test-add-tbl.R │ ├── test-autoincrement.R │ ├── test-bind.R │ ├── test-build_copy_queries.R │ ├── test-check-cardinalities.R │ ├── test-code-generation.R │ ├── test-colors.R │ ├── test-datamodelr-code.R │ ├── test-db-helpers.R │ ├── test-db-interface.R │ ├── test-deconstruct.R │ ├── test-descriptions.R │ ├── test-disambiguate.R │ ├── test-disentangle.R │ ├── test-dm.R │ ├── test-dm_deconstruct.R │ ├── test-dm_nest_tbl.R │ ├── test-dm_pixarfilms.R │ ├── test-dm_sql.R │ ├── test-dm_unnest_tbl.R │ ├── test-dm_wrap.R │ ├── test-dplyr-src.R │ ├── test-dplyr.R │ ├── test-draw-dm.R │ ├── test-duckdb.R │ ├── test-enum-ops.R │ ├── test-enumerate_all_paths.R │ ├── test-error-helpers.R │ ├── test-examine-cardinalities.R │ ├── test-examine-constraints.R │ ├── test-filter-dm.R │ ├── test-filter-helpers.R │ ├── test-flatten.R │ ├── test-foreign-keys.R │ ├── test-format.R │ ├── test-graph.R │ ├── test-json.R │ ├── test-json_nest.R │ ├── test-json_pack.R │ ├── test-key-helpers.R │ ├── test-learn.R │ ├── test-maria.R │ ├── test-meta.R │ ├── test-mssql.R │ ├── test-nest.R │ ├── test-pack_join.R │ ├── test-paste.R │ ├── test-pool-support.R │ ├── test-postgres.R │ ├── test-primary-keys.R │ ├── test-rows-dm.R │ ├── test-schema.R │ ├── test-select-tbl.R │ ├── test-select.R │ ├── test-sqlite.R │ ├── test-standalone-check_suggested.R │ ├── test-table-surgery.R │ ├── test-test-dm.R │ ├── test-testthat-wrappers.R │ ├── test-tidyr.R │ ├── test-tidyselect.R │ ├── test-unique-keys.R │ ├── test-upgrade.R │ ├── test-utils.R │ ├── test-validate.R │ ├── test-waldo.R │ ├── test-zoom.R │ ├── test-zzx-deprecated.R │ └── test_dm_from_con.R └── vignettes ├── .gitignore ├── abstracts ├── erum-2020.md ├── rstudio-conf-2020.md └── user-2019.md ├── articles ├── cheatsheet-figures │ ├── copy_dm.svg │ ├── copy_to_dm.svg │ ├── db.svg │ ├── deconstruct.svg │ ├── df-pk-fk-col.svg │ ├── df-pk-fk.svg │ ├── df-pk.svg │ ├── df.svg │ ├── dm-df.svg │ ├── dm-dm.svg │ ├── dm.svg │ ├── dm_from_con.svg │ ├── dm_nycflights13-select-col.svg │ ├── dm_nycflights13-select.svg │ ├── dm_nycflights13.svg │ ├── dm_select.svg │ ├── dm_wrap_tbl.svg │ ├── draw-all.svg │ ├── draw-default.svg │ ├── draw-title_only.svg │ ├── filter.svg │ ├── fk.svg │ ├── flatten.svg │ ├── glyphicons-halflings-regular.svg │ ├── in_place_FALSE.svg │ ├── in_place_TRUE.svg │ ├── insert1.svg │ ├── insert2.svg │ ├── insert3.svg │ ├── insert4.svg │ ├── logo.png │ ├── logo.svg │ ├── mutate.svg │ ├── primary-keys.svg │ ├── pull-keyed.svg │ ├── pull.svg │ ├── pull2.svg │ ├── reconstruct.svg │ ├── select_tbl.svg │ ├── shiny.png │ ├── squash.svg │ ├── zoom1.svg │ ├── zoom2.svg │ └── zoom3.svg └── cheatsheet.Rmd ├── dm.Rmd ├── flights_dm_w_many_keys_and_color.svg ├── howto-dm-copy.Rmd ├── howto-dm-db.Rmd ├── howto-dm-df.Rmd ├── howto-dm-rows.Rmd ├── howto-dm-theory.Rmd ├── out ├── dm.md ├── dm_files │ └── figure-gfm │ │ └── visualize_keys-1.png ├── howto-dm-copy.md ├── howto-dm-copy_files │ └── figure-gfm │ │ └── unnamed-chunk-9-1.png ├── howto-dm-db.md ├── howto-dm-db_files │ └── figure-gfm │ │ ├── unnamed-chunk-4-1.png │ │ └── unnamed-chunk-9-1.png ├── howto-dm-df.md ├── howto-dm-df_files │ └── figure-gfm │ │ ├── unnamed-chunk-6-1.png │ │ ├── unnamed-chunk-6-2.png │ │ ├── unnamed-chunk-6-3.png │ │ └── unnamed-chunk-6-4.png ├── howto-dm-rows.md ├── howto-dm-rows_files │ └── figure-gfm │ │ └── unnamed-chunk-1-1.png ├── howto-dm-theory.md ├── howto-dm-theory_files │ └── figure-gfm │ │ └── unnamed-chunk-2-1.png ├── tech-dm-cdm.md ├── tech-dm-class.md ├── tech-dm-draw.md ├── tech-dm-draw_files │ └── figure-gfm │ │ ├── unnamed-chunk-2-1.png │ │ ├── unnamed-chunk-5-1.png │ │ ├── unnamed-chunk-7-1.png │ │ └── unnamed-chunk-8-1.png ├── tech-dm-filter.md ├── tech-dm-filter_files │ └── figure-gfm │ │ └── unnamed-chunk-4-1.png ├── tech-dm-join.md ├── tech-dm-join_files │ └── figure-gfm │ │ └── unnamed-chunk-3-1.png ├── tech-dm-low-level.md ├── tech-dm-naming.md ├── tech-dm-zoom.md ├── tech-dm-zoom_files │ └── figure-gfm │ │ ├── unnamed-chunk-1-1.png │ │ ├── unnamed-chunk-2-1.png │ │ ├── unnamed-chunk-3-1.png │ │ ├── unnamed-chunk-4-1.png │ │ ├── unnamed-chunk-5-1.png │ │ └── zoom-1.png └── wip │ ├── dm-insert.md │ ├── dm-readme-old.md │ ├── dm-shiny-dynafilter.md │ └── dm-tips-and-tricks.md ├── setup └── setup.R ├── tech-dm-cdm.Rmd ├── tech-dm-class.Rmd ├── tech-dm-draw.Rmd ├── tech-dm-filter.Rmd ├── tech-dm-join.Rmd ├── tech-dm-keyed.Rmd ├── tech-dm-low-level.Rmd ├── tech-dm-naming.Rmd ├── tech-dm-zoom.Rmd └── wip ├── dm-insert.Rmd ├── dm-readme-old.Rmd ├── dm-shiny-dynafilter.Rmd └── dm-tips-and-tricks.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^docs$ 2 | ^README\.Rmd$ 3 | ^LICENSE\.md$ 4 | ^dm\.Rproj$ 5 | ^\.Rproj\.user$ 6 | ^scratch$ 7 | ^CODE_OF_CONDUCT\.md$ 8 | ^pkgdown$ 9 | ^\.travis\.yml$ 10 | ^appveyor\.yml$ 11 | ^tic\.R$ 12 | ^codecov\.yml$ 13 | ^dm\.Rcheck$ 14 | ^dm.*\.tar\.gz$ 15 | ^dm.*\.tgz$ 16 | ^cran-comments\.md$ 17 | ^man/figures/logo\.png$ 18 | ^CRAN-RELEASE$ 19 | ^vignettes/wip$ 20 | ^Makefile$ 21 | ^\.ccache$ 22 | ^\.github$ 23 | ^example$ 24 | ^vignettes/abstracts$ 25 | ^vignettes/out$ 26 | ^TODO\.md$ 27 | ^data-raw$ 28 | ^CRAN-SUBMISSION$ 29 | ^\.gitpod\.Dockerfile$ 30 | ^\.gitpod\.yml$ 31 | ^inst/htmlwidgets/lib/jquery/\.bower\.json$ 32 | ^docker-compose\.yml$ 33 | ^Dockerfile$ 34 | ^\.vscode$ 35 | ^renovate\.json$ 36 | ^tests/testthat/helper-sync\.R$ 37 | ^index\.md$ 38 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | /pkg.lock 2 | *.html 3 | -------------------------------------------------------------------------------- /.github/odbc/install-mariadb-driver.sh: -------------------------------------------------------------------------------- 1 | # from https://mariadb.com/kb/en/about-mariadb-connector-odbc/#installing-mariadb-connectorodbc-on-debianubuntu 2 | mkdir odbc_package 3 | pushd odbc_package 4 | wget https://downloads.mariadb.com/Connectors/odbc/connector-odbc-3.1.7/mariadb-connector-odbc-3.1.7-ga-debian-x86_64.tar.gz 5 | tar -xvzf mariadb-connector-odbc-3.1.7-ga-debian-x86_64.tar.gz 6 | sudo install lib/libmaodbc.so /usr/lib/ 7 | sudo install -d /usr/lib/mariadb/ 8 | sudo install -d /usr/lib/mariadb/plugin/ 9 | sudo install lib/mariadb/plugin/auth_gssapi_client.so /usr/lib/mariadb/plugin/ 10 | sudo install lib/mariadb/plugin/caching_sha2_password.so /usr/lib/mariadb/plugin/ 11 | sudo install lib/mariadb/plugin/client_ed25519.so /usr/lib/mariadb/plugin/ 12 | sudo install lib/mariadb/plugin/dialog.so /usr/lib/mariadb/plugin/ 13 | sudo install lib/mariadb/plugin/mysql_clear_password.so /usr/lib/mariadb/plugin/ 14 | sudo install lib/mariadb/plugin/sha256_password.so /usr/lib/mariadb/plugin/ 15 | popd 16 | rm -r odbc_package 17 | -------------------------------------------------------------------------------- /.github/odbc/odbc.ini: -------------------------------------------------------------------------------- 1 | [ODBC Data Sources] 2 | PostgreSQL = My Cool Database 3 | 4 | [PostgreSQL] 5 | Driver = PostgreSQL Driver 6 | Database = test 7 | Servername = localhost 8 | UserName = postgres 9 | Password = password 10 | Port = 5432 11 | UseServerSidePrepare = 1 12 | ReadOnly = No 13 | RowVersioning = No 14 | ShowSystemTables = No 15 | ShowOidColumn = No 16 | FakeOidIndex = No 17 | BoolsAsChar = No 18 | ConnSettings = set time zone 'UTC'; set client_encoding to 'UTF-8'; 19 | UseDeclareFetch = 1 20 | 21 | [MySQL] 22 | Driver = MySQL Driver 23 | Database = test 24 | Server = 127.0.0.1 25 | User = root 26 | password = root 27 | Port = 3306 28 | charset=utf8mb4 29 | 30 | [SQLite] 31 | Description = Test db 32 | Driver = SQLite Driver 33 | Database = /tmp/test 34 | Timeout = 2000 35 | 36 | [mssql-test] 37 | Driver = ODBC Driver 17 for SQL Server 38 | Server = localhost 39 | Port = 1433 40 | -------------------------------------------------------------------------------- /.github/odbc/odbcinst.ini: -------------------------------------------------------------------------------- 1 | [ODBC Drivers] 2 | PostgreSQL Driver=Installed 3 | 4 | [PostgreSQL Driver] 5 | Driver = /usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so 6 | FileUsage=1 7 | Threading=2 8 | 9 | [SQLite Driver] 10 | Driver=/usr/lib/x86_64-linux-gnu/odbc/libsqlite3odbc.so 11 | 12 | [ODBC Driver 17 for SQL Server] 13 | Description=Microsoft ODBC Driver 17 for SQL Server 14 | Driver=/opt/microsoft/msodbcsql17/lib64/libmsodbcsql-17.so 15 | UsageCount=1 16 | -------------------------------------------------------------------------------- /.github/versions-matrix.R: -------------------------------------------------------------------------------- 1 | data.frame( 2 | os = "ubuntu-22.04", 3 | r = "release", 4 | test_src = c( 5 | "test-mssql", 6 | "test-postgres", 7 | "test-maria", 8 | "test-mysql-maria", 9 | "test-duckdb", 10 | "test-sqlite" 11 | ), 12 | covr = "true", 13 | desc = c( 14 | "SQL Server with covr", 15 | "Postgres with covr", 16 | "MariaDB with covr", 17 | "MySQL with covr", 18 | "DuckDB with covr", 19 | "SQLite with covr" 20 | ) 21 | ) 22 | -------------------------------------------------------------------------------- /.github/workflows/check/action.yml: -------------------------------------------------------------------------------- 1 | name: "Actions to check an R package" 2 | inputs: 3 | results: 4 | description: Slug for check results 5 | required: true 6 | 7 | runs: 8 | using: "composite" 9 | steps: 10 | - uses: r-lib/actions/check-r-package@v2 11 | with: 12 | # Fails on R 3.6 on Windows, remove when this job is removed? 13 | args: 'c("--no-manual", "--as-cran", "--no-multiarch")' 14 | error-on: ${{ env.RCMDCHECK_ERROR_ON || '"note"' }} 15 | 16 | - name: Show test output 17 | if: always() 18 | run: | 19 | ## -- Show test output -- 20 | echo "::group::Test output" 21 | find check -name '*.Rout*' -exec head -n 1000000 '{}' \; || true 22 | echo "::endgroup::" 23 | shell: bash 24 | 25 | - name: Upload check results 26 | if: failure() 27 | uses: actions/upload-artifact@main 28 | with: 29 | name: ${{ inputs.results }}-results 30 | path: check 31 | -------------------------------------------------------------------------------- /.github/workflows/covr/action.yml: -------------------------------------------------------------------------------- 1 | name: "Actions to run covr for an R package" 2 | inputs: 3 | token: 4 | description: codecov token 5 | required: false 6 | 7 | runs: 8 | using: "composite" 9 | steps: 10 | - name: Run coverage check 11 | run: | 12 | if (dir.exists("tests/testthat")) { 13 | cov <- covr::package_coverage( 14 | quiet = FALSE, 15 | clean = FALSE, 16 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 17 | ) 18 | covr::to_cobertura(cov) 19 | } else { 20 | message("No tests found, coverage not tested.") 21 | } 22 | shell: Rscript {0} 23 | 24 | - uses: codecov/codecov-action@v5 25 | with: 26 | # Fail if token is given 27 | fail_ci_if_error: ${{ inputs.token != '' }} 28 | files: ./cobertura.xml 29 | plugins: noop 30 | disable_search: true 31 | token: ${{ inputs.token }} 32 | 33 | - name: Show testthat output 34 | if: always() 35 | run: | 36 | ## -------------------------------------------------------------------- 37 | find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true 38 | shell: bash 39 | 40 | - name: Upload test results 41 | if: failure() 42 | uses: actions/upload-artifact@v4 43 | with: 44 | name: coverage-test-failures 45 | path: ${{ runner.temp }}/package 46 | -------------------------------------------------------------------------------- /.github/workflows/custom/before-install/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Custom steps to run before R packages are installed' 2 | 3 | runs: 4 | using: "composite" 5 | steps: 6 | - name: Define _R_CHECK_PKG_SIZES_THRESHOLD_ 7 | run: | 8 | echo '_R_CHECK_PKG_SIZES_THRESHOLD_=10' | tee -a $GITHUB_ENV 9 | shell: bash 10 | 11 | - name: Define DM_TEST_SRC 12 | run: | 13 | echo "DM_TEST_SRC=${{ matrix.config.test-src }}" | tee -a $GITHUB_ENV 14 | shell: bash 15 | 16 | - name: Clean up broken mysql apt 17 | # FIXME: Remove if package becomes unavailable 18 | if: runner.os == 'Linux' 19 | run: | 20 | sudo apt-get update 21 | if [ $(lsb_release --short --codename) == 'focal' ]; then 22 | sudo apt-get install mysql-common=5.8+1.0.5ubuntu2 --allow-downgrades 23 | fi 24 | shell: bash 25 | -------------------------------------------------------------------------------- /.github/workflows/dep-suggests-matrix/action.yml: -------------------------------------------------------------------------------- 1 | name: "Actions to compute a matrix with all suggested packages" 2 | outputs: 3 | matrix: 4 | description: "Generated matrix" 5 | value: ${{ steps.set-matrix.outputs.matrix }} 6 | 7 | runs: 8 | using: "composite" 9 | steps: 10 | - id: set-matrix 11 | run: | 12 | Rscript ./.github/workflows/dep-suggests-matrix/action.R 13 | shell: bash 14 | -------------------------------------------------------------------------------- /.github/workflows/get-extra/action.yml: -------------------------------------------------------------------------------- 1 | name: "Action to determine extra packages to be installed" 2 | outputs: 3 | packages: 4 | description: "List of extra packages" 5 | value: ${{ steps.get-extra.outputs.packages }} 6 | 7 | runs: 8 | using: "composite" 9 | steps: 10 | - name: Get extra packages 11 | id: get-extra 12 | run: | 13 | set -x 14 | packages=$( ( grep Config/gha/extra-packages DESCRIPTION || true ) | cut -d " " -f 2) 15 | echo packages=$packages >> $GITHUB_OUTPUT 16 | shell: bash 17 | -------------------------------------------------------------------------------- /.github/workflows/git-identity/action.yml: -------------------------------------------------------------------------------- 1 | name: "Actions to set up a Git identity" 2 | 3 | runs: 4 | using: "composite" 5 | steps: 6 | - name: Configure Git identity 7 | run: | 8 | env | sort 9 | git config --local user.name "$GITHUB_ACTOR" 10 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 11 | shell: bash 12 | -------------------------------------------------------------------------------- /.github/workflows/lock.yaml: -------------------------------------------------------------------------------- 1 | name: "Lock threads" 2 | permissions: 3 | issues: write 4 | pull-requests: write 5 | discussions: write 6 | on: 7 | workflow_dispatch: 8 | schedule: 9 | - cron: "37 2 * * *" 10 | 11 | jobs: 12 | lock: 13 | runs-on: ubuntu-24.04 14 | steps: 15 | - uses: krlmlr/lock-threads@patch-1 16 | with: 17 | github-token: ${{ github.token }} 18 | issue-inactive-days: "365" 19 | issue-lock-reason: "" 20 | issue-comment: > 21 | This old thread has been automatically locked. If you think you have 22 | found something related to this, please open a new issue and link to this 23 | old issue if necessary. 24 | -------------------------------------------------------------------------------- /.github/workflows/matrix-check/action.yml: -------------------------------------------------------------------------------- 1 | name: "Actions to check a matrix with all R and OS versions, computed with the versions-matrix action" 2 | inputs: 3 | matrix: 4 | description: "Generated matrix" 5 | required: true 6 | 7 | runs: 8 | using: "composite" 9 | steps: 10 | - name: Install json2yaml 11 | run: | 12 | sudo npm install -g json2yaml 13 | shell: bash 14 | 15 | - run: | 16 | matrix='${{ inputs.matrix }}' 17 | if [ -n "${matrix}" ]; then 18 | echo $matrix | jq . 19 | echo $matrix | json2yaml 20 | else 21 | echo "No matrix found" 22 | fi 23 | shell: bash 24 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown-build/action.yml: -------------------------------------------------------------------------------- 1 | name: "Action to build a pkgdown website" 2 | 3 | runs: 4 | using: "composite" 5 | steps: 6 | - name: Build site 7 | run: | 8 | pkgdown::build_site() 9 | shell: Rscript {0} 10 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown-deploy/action.yml: -------------------------------------------------------------------------------- 1 | name: "Action to deploy a pkgdown website" 2 | 3 | runs: 4 | using: "composite" 5 | steps: 6 | - name: Deploy site 7 | uses: nick-fields/retry@v3 8 | with: 9 | timeout_minutes: 15 10 | max_attempts: 10 11 | command: | 12 | R -q -e 'pkgdown::deploy_to_branch(new_process = FALSE)' 13 | -------------------------------------------------------------------------------- /.github/workflows/rate-limit/action.yml: -------------------------------------------------------------------------------- 1 | name: "Check GitHub rate limits" 2 | inputs: 3 | token: # id of input 4 | description: GitHub token, pass secrets.GITHUB_TOKEN 5 | required: true 6 | 7 | runs: 8 | using: "composite" 9 | steps: 10 | - name: Check rate limits 11 | run: | 12 | curl -s --header "authorization: Bearer ${{ inputs.token }}" https://api.github.com/rate_limit 13 | shell: bash 14 | -------------------------------------------------------------------------------- /.github/workflows/roxygenize/action.yml: -------------------------------------------------------------------------------- 1 | name: "Action to create documentation with roxygen2" 2 | 3 | runs: 4 | using: "composite" 5 | steps: 6 | - name: Roxygenize 7 | run: | 8 | try(roxygen2::roxygenize()) 9 | shell: Rscript {0} 10 | -------------------------------------------------------------------------------- /.github/workflows/unblock.yaml: -------------------------------------------------------------------------------- 1 | name: unblock 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - .github/workflows/unblock.yaml 9 | # for manual triggers 10 | workflow_dispatch: 11 | # daily run 12 | schedule: 13 | - cron: "30 1/3 * * *" 14 | 15 | concurrency: 16 | group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || github.sha }}-${{ github.base_ref || '' }} 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | unblock: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - name: Remove blocked label from all PRs 26 | env: 27 | GH_TOKEN: ${{ github.token }} 28 | run: | 29 | gh pr list --json number -q '.[].number' | xargs -n 1 gh pr edit --remove-label blocked 30 | -------------------------------------------------------------------------------- /.github/workflows/versions-matrix/action.yml: -------------------------------------------------------------------------------- 1 | name: "Actions to compute a matrix with all R and OS versions" 2 | 3 | outputs: 4 | matrix: 5 | description: "Generated matrix" 6 | value: ${{ steps.set-matrix.outputs.matrix }} 7 | 8 | runs: 9 | using: "composite" 10 | steps: 11 | - name: Install json2yaml 12 | run: | 13 | sudo npm install -g json2yaml 14 | shell: bash 15 | 16 | - id: set-matrix 17 | run: | 18 | Rscript ./.github/workflows/versions-matrix/action.R 19 | shell: bash 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | inst/doc 2 | .Rhistory 3 | .RData 4 | .Rproj.user 5 | .Rprofile.local 6 | docs/ 7 | .Rprofile 8 | dm.Rcheck/ 9 | dm*.tar.gz 10 | dm*.tgz 11 | .ccache 12 | CRAN-RELEASE 13 | *.log 14 | CRAN-SUBMISSION 15 | .vscode 16 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who 4 | contribute through reporting issues, posting feature requests, updating documentation, 5 | submitting pull requests or patches, and other activities. 6 | 7 | We are committed to making participation in this project a harassment-free experience for 8 | everyone, regardless of level of experience, gender, gender identity and expression, 9 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 10 | 11 | Examples of unacceptable behavior by participants include the use of sexual language or 12 | imagery, derogatory comments or personal attacks, trolling, public or private harassment, 13 | insults, or other unprofessional conduct. 14 | 15 | Project maintainers have the right and responsibility to remove, edit, or reject comments, 16 | commits, code, wiki edits, issues, and other contributions that are not aligned to this 17 | Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed 18 | from the project team. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by 21 | opening an issue or contacting one or more of the project maintainers. 22 | 23 | This Code of Conduct is adapted from the Contributor Covenant 24 | (https://www.contributor-covenant.org), version 1.0.0, available at 25 | https://contributor-covenant.org/version/1/0/0/. 26 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cynkra/rig-ubuntu:main 2 | 3 | RUN mkdir -p /root/workspace 4 | 5 | COPY DESCRIPTION /root/workspace 6 | 7 | RUN R -q -e 'pak::pak()' 8 | 9 | RUN apt-get install -y gnupg lsb-release time 10 | 11 | # https://learn.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver16&tabs=ubuntu18-install%2Calpine17-install%2Cdebian8-install%2Credhat7-13-install%2Crhel7-offline 12 | RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - 13 | 14 | RUN curl https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list > /etc/apt/sources.list.d/mssql-release.list 15 | 16 | RUN apt-get update 17 | 18 | RUN ACCEPT_EULA=Y apt-get install -y msodbcsql18 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2022 2 | COPYRIGHT HOLDER: cynkra 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2022 cynkra GmbH. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /R/aaa-dplyr.R: -------------------------------------------------------------------------------- 1 | # nocov start 2 | replace_if_dplyr_has <- function(fun) { 3 | dplyr_ns <- asNamespace("dplyr") 4 | 5 | fun <- as_string(ensym(fun)) 6 | value <- mget(fun, dplyr_ns, mode = "function", ifnotfound = list(NULL))[[1]] 7 | if (!is.null(value)) { 8 | assign(fun, value, inherits = TRUE) 9 | "dplyr" 10 | } else { 11 | "dm" 12 | } 13 | } 14 | 15 | register_if_dplyr_hasnt <- function(...) { 16 | dplyr_ns <- asNamespace("dplyr") 17 | 18 | # Register our method implementations only if dplyr doesn't provide them 19 | methods <- enquos(..., .named = TRUE) 20 | dplyr_methods <- mget(names(methods), dplyr_ns, mode = "function", ifnotfound = list(NULL)) 21 | methods <- methods[map_lgl(dplyr_methods, is.null)] 22 | 23 | if (is_empty(methods)) { 24 | return() 25 | } 26 | 27 | methods <- map(methods, eval_tidy) 28 | classes <- sub("^[^.]*.", "", names(methods)) 29 | fun <- sub("[.].*$", "", names(methods)[[1]]) 30 | 31 | map2(classes, methods, s3_register, generic = paste0("dm::", fun)) 32 | invisible() 33 | } 34 | # nocov end 35 | -------------------------------------------------------------------------------- /R/cache.R: -------------------------------------------------------------------------------- 1 | cache_attach <- function(algo = "sha512", base_attach = attach, name = paste0(utils::packageName(), "_cache")) { 2 | force(algo) 3 | 4 | if (!rlang::is_attached(name)) { 5 | env <- rlang::new_environment(list(...cache = rlang::new_environment())) 6 | base_attach(env, pos = length(search()) - 1, name = name) 7 | } 8 | cache <- rlang::search_env(name)$...cache 9 | 10 | cache_reset <- function() { 11 | rm(list = ls(cache), envir = cache) 12 | } 13 | 14 | cache_set <- function(key, value) { 15 | assign(key, value, envir = cache) 16 | } 17 | 18 | cache_get <- function(key) { 19 | get(key, envir = cache, inherits = FALSE) 20 | } 21 | 22 | cache_has_key <- function(key) { 23 | exists(key, envir = cache, inherits = FALSE) 24 | } 25 | 26 | list( 27 | digest = function(...) digest::digest(..., algo = algo), 28 | reset = cache_reset, 29 | set = cache_set, 30 | get = cache_get, 31 | has_key = cache_has_key, 32 | keys = function() ls(cache) 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /R/data-model-helpers.R: -------------------------------------------------------------------------------- 1 | new_data_model <- function(tables, columns, references) { 2 | empty_tables <- setdiff(tables$table, columns$table) 3 | if (length(empty_tables)) { 4 | empty_table_columns <- tibble(table = empty_tables, column = "", key = 0) 5 | columns <- bind_rows(columns, empty_table_columns) 6 | } 7 | stopifnot(nrow(tables) > 0) 8 | stopifnot(nrow(columns) > 0) 9 | 10 | structure( 11 | list( 12 | tables = tables, 13 | columns = columns, 14 | references = references 15 | ), 16 | class = "data_model" 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /R/disentangle.R: -------------------------------------------------------------------------------- 1 | #' @autoglobal 2 | dm_disentangle <- function(dm, start, quiet = FALSE) { 3 | check_not_zoomed(dm) 4 | start <- dm_tbl_name(dm, {{ start }}) 5 | recipes <- enumerate_all_paths(dm, start) 6 | changed <- arrange(recipes$table_mapping, table, new_table) 7 | 8 | if (!quiet) { 9 | msgs <- 10 | changed %>% 11 | group_by(table) %>% 12 | summarize( 13 | msg = glue::glue("Replaced table {tick(unique(table))} with {commas(tick(new_table))}.") 14 | ) %>% 15 | ungroup() 16 | 17 | walk(msgs$msg, message) 18 | } 19 | fk_table <- fk_table_to_def_fks( 20 | recipes$new_fks, 21 | child_table = "new_child_table", 22 | child_fk_cols = "child_cols", 23 | parent_table = "new_parent_table", 24 | parent_key_cols = "parent_cols" 25 | ) %>% 26 | rename(new_fks = fks) 27 | 28 | dm_get_def(dm) %>% 29 | left_join(changed, by = "table", multiple = "all") %>% 30 | mutate(table = coalesce(new_table, table)) %>% 31 | select(-new_table) %>% 32 | left_join(fk_table, by = c("table" = "new_parent_table")) %>% 33 | select(-fks) %>% 34 | relocate(fks = new_fks, .after = uks) %>% 35 | mutate(fks = vctrs::as_list_of(map(fks, ~ .x %||% new_fk()))) %>% 36 | dm_from_def() 37 | } 38 | -------------------------------------------------------------------------------- /R/dm-package.R: -------------------------------------------------------------------------------- 1 | #' @keywords internal 2 | #' @aliases NULL dm-package 3 | "_PACKAGE" 4 | 5 | #' @import rlang 6 | #' @import cli 7 | #' @import glue 8 | #' @import lifecycle 9 | #' @import vctrs 10 | #' @rawNamespace import(tibble, except = c(data_frame)) 11 | #' @rawNamespace import(dplyr, except = c(data_frame)) 12 | #' @rawNamespace import(purrr, except = c(list_along, rep_along, invoke, modify, as_function, flatten_dbl, flatten_lgl, flatten_int, flatten_raw, flatten_chr, splice, flatten, prepend, `%@%`, `%||%`)) 13 | #' @rawNamespace import(tidyr, except = c(extract)) 14 | ## usethis namespace: start 15 | #' @importFrom methods is 16 | #' @importFrom igraph V E 17 | #' @importFrom utils head tail str packageVersion 18 | #' @importFrom grDevices col2rgb colors rgb 19 | ## usethis namespace: end 20 | NULL 21 | -------------------------------------------------------------------------------- /R/dm_get_con.R: -------------------------------------------------------------------------------- 1 | #' Get connection 2 | #' 3 | #' @description 4 | #' `dm_get_con()` returns the DBI connection for a `dm` object. 5 | #' This works only if the tables are stored on a database, otherwise an error 6 | #' is thrown. 7 | #' 8 | #' @details 9 | #' All lazy tables in a dm object must be stored on the same database server 10 | #' and accessed through the same connection, because a large part 11 | #' of the package's functionality relies on efficient joins. 12 | #' 13 | #' @inheritParams dm_add_pk 14 | #' 15 | #' @return The [`DBI::DBIConnection-class`] object for a `dm` object. 16 | #' 17 | #' @export 18 | #' @examplesIf dm:::dm_has_financial() 19 | #' dm_financial() %>% 20 | #' dm_get_con() 21 | dm_get_con <- function(dm) { 22 | check_not_zoomed(dm) 23 | src <- dm_get_src_impl(dm) 24 | if (!inherits(src, "src_dbi")) abort_con_only_for_dbi() 25 | src$con 26 | } 27 | 28 | dm_get_src_impl <- function(x) { 29 | tables <- dm_get_tables_impl(x) 30 | tbl_src(tables[1][[1]]) 31 | } 32 | -------------------------------------------------------------------------------- /R/financial-db-con.R: -------------------------------------------------------------------------------- 1 | #' Connection to SQL Financial Database 2 | #' @description Connects to relational.fel.cvut.cz unless the service is 3 | #' unavailable, in which case databases.pacha.dev is used as a fallback 4 | #' @return A `MariaDBConnection` object 5 | #' @noRd 6 | financial_db_con <- function() { 7 | if (Sys.getenv("DM_OFFLINE") != "") { 8 | abort("Offline") 9 | } 10 | 11 | err_relational <- tryCatch(return(relational_con()), error = identity) 12 | err_dbedu <- tryCatch(return(dbedu_con()), error = identity) 13 | 14 | abort(paste0( 15 | "Can't connect to relational.fel.cvut.cz or databases.pacha.dev:\n", 16 | conditionMessage(err_relational), "\n", 17 | conditionMessage(err_dbedu) 18 | )) 19 | } 20 | 21 | relational_con <- function() { 22 | DBI::dbConnect( 23 | RMariaDB::MariaDB(), 24 | username = "guest", 25 | password = "ctu-relational", 26 | dbname = "Financial_ijs", 27 | host = "relational.fel.cvut.cz" 28 | ) 29 | } 30 | 31 | dbedu_con <- function() { 32 | DBI::dbConnect( 33 | RMariaDB::MariaDB(), 34 | username = "student", 35 | password = "uQCy30sNP5arqMBGHVLZ", 36 | dbname = "financial", 37 | host = "databases.pacha.dev" 38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /R/gui-check.R: -------------------------------------------------------------------------------- 1 | check_is_character_vec <- function(x, arg = caller_arg(x), call = caller_env()) { 2 | if (!is_character(x)) { 3 | cli::cli_abort("{.arg {arg}} must be a character vector.", call = call) 4 | } 5 | } 6 | 7 | check_tbl_in_dm <- function(x, 8 | y, 9 | arg_x = caller_arg(x), 10 | arg_y = caller_arg(y), 11 | call = caller_env()) { 12 | not_in_dm <- setdiff(y, names(x)) 13 | if (length(not_in_dm) != 0) { 14 | cli::cli_abort("Table {.arg_y {not_in_dm}} is not in {.arg_x {names(x)}}.", call = call) 15 | } 16 | } 17 | 18 | check_at_least_one_col <- function(cols, call = current_call()) { 19 | if (length(cols) < 1) { 20 | abort("Hey, you should select at least one column!", call = call) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /R/gui-dm.R: -------------------------------------------------------------------------------- 1 | get_dm <- function(name) { 2 | if (name == "nycflights13") { 3 | return(dm::dm_nycflights13()) 4 | } 5 | 6 | basename <- paste0(name, ".R") 7 | path <- system.file("relational", basename, package = utils::packageName(), mustWork = TRUE) 8 | source(path, local = TRUE)$value 9 | } 10 | -------------------------------------------------------------------------------- /R/gui-dm_to_svg.R: -------------------------------------------------------------------------------- 1 | dm_to_svg <- function(dm) { 2 | svg <- 3 | dm %>% 4 | dm::dm_draw(graph_attrs = 'bgcolor="transparent"', node_attrs = 'fontname="Helvetica"') %>% 5 | DiagrammeRsvg::export_svg() 6 | 7 | gsub('( class="(edge|node)")', '\\1 onclick="\\2Style(this.id)"', svg) 8 | } 9 | -------------------------------------------------------------------------------- /R/gui-expect_mw_cg_snapshot.R: -------------------------------------------------------------------------------- 1 | # Create a snapshot of the code and of the resulting dm object 2 | # This requires a certain of the code. 3 | expect_mw_cg_snapshot <- function(...) { 4 | testthat::expect_snapshot(...) 5 | quo <- enquos(...)[[1]] 6 | out <- eval_tidy(quo) 7 | 8 | expr <- quo_get_expr(quo) 9 | if (!identical(expr[[1]], quote(`{`)) || length(expr) != 2) { 10 | result <- glue::as_glue("expect_mw_cg_snapshot(): check structure of your code block") 11 | testthat::expect_snapshot(result) 12 | return() 13 | } 14 | 15 | dm_expr <- expr[[2]][[2]] 16 | 17 | dm <- eval_tidy(dm_expr, env = quo_get_env(quo)) 18 | 19 | result <- 20 | new_cg_block(dm) %>% 21 | cg_add_call(!!out$call) %>% 22 | cg_eval_block() 23 | 24 | testthat::expect_snapshot(result) 25 | } 26 | -------------------------------------------------------------------------------- /R/gui-gui_run.R: -------------------------------------------------------------------------------- 1 | gui_run <- function(dm = dm_nycflights13(), select_tables = TRUE, debug = FALSE) { 2 | stopifnot(is_dm(dm)) 3 | local_options(dm.gui_init_dm = dm) 4 | 5 | app <- shiny::shinyApp(ui = gui_ui(select_tables = select_tables), server = gui_server) 6 | 7 | if (debug) { 8 | local_options(shiny.fullstacktrace = debug) 9 | } 10 | 11 | code <- shiny::runApp(app) 12 | rstudioapi::sendToConsole(code, execute = FALSE) 13 | } 14 | -------------------------------------------------------------------------------- /R/gui-mw_cg_enum_dm_add_fk.R: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/R/gui-mw_cg_enum_dm_add_fk.R -------------------------------------------------------------------------------- /R/gui-mw_cg_make_dm_add_pk.R: -------------------------------------------------------------------------------- 1 | mw_cg_make_dm_add_pk <- function(dm, ..., table_names = NULL, column_names = NULL) { 2 | # Checks 3 | check_dots_empty() 4 | stopifnot(length(table_names) == 1) 5 | table <- dm[[table_names]] 6 | 7 | check_at_least_one_col(column_names) 8 | stopifnot(column_names %in% colnames(table)) 9 | 10 | # Call generation 11 | if (length(column_names) == 1) { 12 | column_names_sym <- sym(column_names) 13 | } else { 14 | column_names_sym <- expr(c(!!!syms(column_names))) 15 | } 16 | 17 | if (dm_has_pk(dm, !!table_names)) { 18 | # FIXME: Include confirmation message 19 | list( 20 | call = expr(dm_add_pk( 21 | ., 22 | !!sym(table_names), 23 | !!column_names_sym, 24 | force = TRUE # we want to change the pks interactively, otherwise error 25 | )) 26 | ) 27 | } else { 28 | list( 29 | call = expr(dm_add_pk( 30 | ., 31 | !!sym(table_names), 32 | !!column_names_sym 33 | )) 34 | ) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /R/gui-mw_cg_make_dm_disentangle.R: -------------------------------------------------------------------------------- 1 | # FIXME: Adapt argument list as provided/required by the Shiny app 2 | mw_cg_make_dm_disentangle <- function(dm, ..., table_names = NULL) { 3 | check_dots_empty() 4 | 5 | # Checks 6 | stopifnot(is.character(table_names)) 7 | stopifnot(table_names %in% names(dm)) 8 | stopifnot(length(table_names) == 1) 9 | 10 | # Return call object 11 | list( 12 | call = expr(dm_disentangle( 13 | ., 14 | # FIXME: Adapt signature 15 | !!sym(table_names) 16 | )) 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /R/gui-mw_cg_make_dm_rename.R: -------------------------------------------------------------------------------- 1 | mw_cg_make_dm_rename <- function(dm, ..., table_names = NULL, column_names = NULL, new_column_names = NULL) { 2 | check_dots_empty() 3 | 4 | # Checks 5 | stopifnot(!is.null(table_names)) 6 | stopifnot(length(table_names) == 1) 7 | stopifnot(table_names %in% names(dm)) 8 | stopifnot(inherits(column_names, "character")) 9 | stopifnot(length(column_names) == 1) 10 | stopifnot(inherits(new_column_names, "character")) 11 | stopifnot(length(new_column_names) == 1) 12 | 13 | rename_col <- set_names(column_names, new_column_names) 14 | 15 | # Return call object 16 | list( 17 | call = expr(dm_rename( 18 | ., 19 | !!sym(table_names), 20 | !!!syms(rename_col) 21 | )) 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /R/gui-mw_cg_make_dm_rm_fk.R: -------------------------------------------------------------------------------- 1 | # FIXME: Adapt argument list as provided/required by the Shiny app 2 | mw_cg_make_dm_rm_fk <- function(dm, ..., edge_table) { 3 | check_dots_empty() 4 | 5 | # Checks 6 | stopifnot(is.character(edge_table$child_table)) 7 | stopifnot(is.character(edge_table$parent_table)) 8 | stopifnot(edge_table$child_table %in% names(dm)) 9 | stopifnot(edge_table$parent_table %in% names(dm)) 10 | 11 | # FIXME: check also cols 12 | purrr::pmap( 13 | edge_table, 14 | function(child_table, child_fk_cols, parent_table, parent_key_cols) { 15 | if (length(child_fk_cols) > 1) { 16 | call <- expr(dm_rm_fk( 17 | ., 18 | table = !!sym(child_table), 19 | columns = c(!!!syms(child_fk_cols)), 20 | ref_table = !!sym(parent_table), 21 | ref_columns = c(!!!syms(parent_key_cols)) 22 | )) 23 | } else { 24 | call <- expr(dm_rm_fk( 25 | ., 26 | table = !!sym(child_table), 27 | columns = !!sym(child_fk_cols), 28 | ref_table = !!sym(parent_table), 29 | ref_columns = !!sym(parent_key_cols) 30 | )) 31 | } 32 | } 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /R/gui-mw_cg_make_dm_select.R: -------------------------------------------------------------------------------- 1 | # FIXME: Adapt argument list as provided/required by the Shiny app 2 | mw_cg_make_dm_select <- function(dm, ..., table_names = NULL, column_names = NULL, rm = FALSE) { 3 | check_dots_empty() 4 | 5 | # Checks 6 | stopifnot(is.character(table_names)) 7 | stopifnot(table_names %in% names(dm)) 8 | stopifnot(length(table_names) == 1) 9 | 10 | col_names_sel_rm <- if (rm) { 11 | sapply(syms(column_names), function(x) { 12 | call("-", x) 13 | }) 14 | } else { 15 | syms(column_names) 16 | } 17 | 18 | list( 19 | call = expr(dm_select( 20 | ., 21 | !!sym(table_names), 22 | !!!col_names_sel_rm 23 | )) 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /R/gui-mw_cg_make_dm_select_tbl.R: -------------------------------------------------------------------------------- 1 | mw_cg_make_dm_select_tbl <- function(dm, ..., table_names = NULL, rm = FALSE) { 2 | check_dots_empty() 3 | 4 | # Checks 5 | check_is_character_vec(table_names) 6 | check_tbl_in_dm(dm, table_names) 7 | 8 | tbl_names_sel_rm <- syms(table_names) 9 | 10 | if (rm) { 11 | if (length(tbl_names_sel_rm) == 1) { 12 | tbl_names_sel_rm <- exprs(-!!tbl_names_sel_rm[[1]]) 13 | } else { 14 | tbl_names_sel_rm <- exprs(-c(!!!tbl_names_sel_rm)) 15 | } 16 | } 17 | 18 | # Return call object 19 | list( 20 | call = expr(dm_select_tbl( 21 | ., 22 | !!!tbl_names_sel_rm 23 | )) 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /R/gui-mw_cg_make_dm_set_colors.R: -------------------------------------------------------------------------------- 1 | # FIXME: Adapt argument list as provided/required by the Shiny app 2 | mw_cg_make_dm_set_colors <- function(dm, ..., table_names = NULL, color_name = NULL) { 3 | check_dots_empty() 4 | # Checks 5 | stopifnot(is.character(table_names)) 6 | stopifnot(table_names %in% names(dm)) 7 | 8 | if (length(table_names) == 1) { 9 | table_sym <- sym(table_names) 10 | } else { 11 | table_sym <- expr(c(!!!syms(table_names))) 12 | } 13 | 14 | table_syms <- exprs(!!sym(color_name) := !!table_sym) 15 | 16 | list( 17 | call = expr(dm_set_colors( 18 | ., 19 | !!!table_syms 20 | )) 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /R/gui-ops_stack.R: -------------------------------------------------------------------------------- 1 | ops_stack <- function(x) { 2 | new_ops_stack(list(x), 1) 3 | } 4 | 5 | new_ops_stack <- function(list, pos) { 6 | stopifnot(is.list(list)) 7 | stopifnot(pos >= 1) 8 | stopifnot(pos <= length(list)) 9 | list( 10 | list = list, 11 | pos = pos 12 | ) 13 | } 14 | 15 | ops_stack_current <- function(stack) { 16 | stack$list[[stack$pos]] 17 | } 18 | 19 | ops_stack_append <- function(stack, x) { 20 | pos <- stack$pos 21 | new_ops_stack( 22 | c(stack$list[seq_len(pos)], list(x)), 23 | pos + 1 24 | ) 25 | } 26 | 27 | ops_stack_undo <- function(stack) { 28 | pos <- stack$pos 29 | new_ops_stack( 30 | stack$list, 31 | max(pos - 1, 1) 32 | ) 33 | } 34 | 35 | ops_stack_redo <- function(stack) { 36 | pos <- stack$pos 37 | new_ops_stack( 38 | stack$list, 39 | min(pos + 1, length(stack$list)) 40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /R/gui-shiny_input.R: -------------------------------------------------------------------------------- 1 | shiny_input_dm_nodes_edges <- function(x, session, name) { 2 | # The client shouldn't have to deal with that (and I wonder why we need to 3 | # do this here even). 4 | x$nodes <- unlist(x$nodes) 5 | x$edges <- unlist(x$edges) 6 | x 7 | } 8 | -------------------------------------------------------------------------------- /R/gui-zzz.R: -------------------------------------------------------------------------------- 1 | rlang::on_load({ 2 | if (rlang::is_installed("shiny")) { 3 | shiny::registerInputHandler("dm_nodes_edges", force = TRUE, shiny_input_dm_nodes_edges) 4 | } 5 | }) 6 | 7 | utils::globalVariables(c( 8 | ".", 9 | "child_table", 10 | "id", 11 | "name", 12 | "on_delete", 13 | "op", 14 | "parent_table", 15 | "pk_col", 16 | NULL 17 | )) 18 | 19 | "%:::%" <- function(p, f) { 20 | get(f, envir = asNamespace(p)) 21 | } 22 | -------------------------------------------------------------------------------- /R/json_nest_join.R: -------------------------------------------------------------------------------- 1 | #' JSON nest join 2 | #' 3 | #' @description 4 | #' `r lifecycle::badge("experimental")` 5 | #' 6 | #' A wrapper around [dplyr::nest_join()] which stores the joined data into a JSON column. 7 | #' `json_nest_join()` returns all rows and columns in `x` with a new JSON columns that contains all nested matches from `y`. 8 | #' 9 | #' @inheritParams dplyr::nest_join 10 | #' @param x,y A pair of data frames or data frame extensions (e.g. a tibble). 11 | #' @seealso [dplyr::nest_join()], [json_pack_join()] 12 | #' @export 13 | #' @examples 14 | #' df1 <- tibble::tibble(x = 1:3) 15 | #' df2 <- tibble::tibble(x = c(1, 1, 2), y = c("first", "second", "third")) 16 | #' df3 <- json_nest_join(df1, df2) 17 | #' df3 18 | #' df3$df2 19 | json_nest_join <- function(x, y, by = NULL, ..., copy = FALSE, keep = FALSE, name = NULL) { 20 | UseMethod("json_nest_join") 21 | } 22 | 23 | #' @export 24 | json_nest_join.data.frame <- function(x, y, by = NULL, ..., copy = FALSE, keep = FALSE, name = NULL) { 25 | check_suggested("jsonlite", "json_nest_join") 26 | check_dots_empty() 27 | 28 | name_var <- name %||% as_label(enexpr(y)) 29 | dplyr::nest_join(x, y, by, copy = copy, keep = keep, name = name_var) %>% 30 | mutate(!!name_var := map(!!sym(name_var), jsonlite::toJSON, digits = NA)) 31 | } 32 | -------------------------------------------------------------------------------- /R/json_pack_join.R: -------------------------------------------------------------------------------- 1 | #' JSON pack join 2 | #' 3 | #' @description 4 | #' `r lifecycle::badge("experimental")` 5 | #' 6 | #' A wrapper around [pack_join()] which stores the joined data into a JSON column. 7 | #' `json_pack_join()` returns all rows and columns in `x` with a new JSON columns that contains all packed matches from `y`. 8 | #' 9 | #' @inheritParams dplyr::nest_join 10 | #' @param x,y A pair of data frames or data frame extensions (e.g. a tibble). 11 | #' @seealso [pack_join()], [json_nest_join()] 12 | #' @export 13 | #' @examples 14 | #' df1 <- tibble::tibble(x = 1:3) 15 | #' df2 <- tibble::tibble(x = c(1, 1, 2), y = c("first", "second", "third")) 16 | #' df3 <- json_pack_join(df1, df2) 17 | #' df3 18 | #' df3$df2 19 | json_pack_join <- function(x, y, by = NULL, ..., copy = FALSE, keep = FALSE, name = NULL) { 20 | UseMethod("json_pack_join") 21 | } 22 | 23 | #' @export 24 | json_pack_join.data.frame <- function(x, y, by = NULL, ..., copy = FALSE, keep = FALSE, name = NULL) { 25 | check_suggested("jsonlite", "json_pack_join") 26 | check_dots_empty() 27 | 28 | name_var <- name %||% as_label(enexpr(y)) 29 | pack_join(x, y, by, ..., copy = copy, keep = keep, name = name_var) %>% 30 | mutate( 31 | !!name_var := map( 32 | unname(split(!!sym(name_var), seq.int(n()))), 33 | jsonlite::toJSON, 34 | digits = NA 35 | ) 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /R/keys.R: -------------------------------------------------------------------------------- 1 | new_keys <- function(x = list()) { 2 | # both c("a", "b") and list("a", "b") is accepted 3 | if (!is.list(x)) { 4 | x <- as.list(as.character(x)) 5 | } 6 | new_list_of(x, character(), class = "dm_keys") 7 | } 8 | 9 | #' @export 10 | vec_ptype2.dm_keys.dm_keys <- function(x, y, ...) new_keys() 11 | 12 | #' @export 13 | vec_cast.dm_keys.dm_keys <- function(x, to, ...) x 14 | 15 | #' @export 16 | vec_ptype_abbr.dm_keys <- function(x, ..., prefix_named, suffix_shape) { 17 | "keys" 18 | } 19 | 20 | #' @export 21 | vec_proxy_compare.dm_keys <- function(x, ...) { 22 | # Not called: https://github.com/r-lib/vctrs/issues/1373 23 | x_raw <- vec_data(x) 24 | 25 | if (length(x_raw) > 0) { 26 | # First figure out the maximum length 27 | n <- max(lengths(x_raw)) 28 | 29 | # Then expand all vectors to this length by filling in with zeros 30 | full <- map(x_raw, function(x) c(x, rep("", n - length(x)))) 31 | } else { 32 | full <- list() 33 | } 34 | 35 | # Then turn into a data frame 36 | as.data.frame(do.call(rbind, full)) 37 | } 38 | 39 | pillar_shaft.dm_keys <- function(x, ...) { 40 | x <- map_chr(x, commas, max_commas = 3) 41 | pillar::pillar_shaft(x) 42 | } 43 | on_load({ 44 | s3_register("pillar::pillar_shaft", "dm_keys", pillar_shaft.dm_keys) 45 | }) 46 | 47 | #' @export 48 | format.dm_keys <- function(x, ...) { 49 | map_chr(x, commas, max_commas = Inf) 50 | } 51 | 52 | get_key_cols <- function(x) { 53 | stopifnot(length(x) == 1) 54 | x[[1]] 55 | } 56 | -------------------------------------------------------------------------------- /R/mariadb.R: -------------------------------------------------------------------------------- 1 | # No longer needed for dbplyr >= 2.4.0 2 | # https://github.com/tidyverse/dbplyr/pull/1190 3 | rlang::on_load({ 4 | if (rlang::is_installed("dbplyr") && getNamespaceInfo("dbplyr", "spec")["version"] <= "2.3.4") { 5 | dbplyr <- asNamespace("dbplyr") 6 | rlang::env_binding_unlock(dbplyr, "sql_values_subquery.MariaDBConnection") 7 | try(dbplyr$sql_values_subquery.MariaDBConnection <- dbplyr$sql_values_subquery.DBIConnection, silent = TRUE) 8 | rlang::env_binding_lock(dbplyr, "sql_values_subquery.MariaDBConnection") 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /R/new_ticker.R: -------------------------------------------------------------------------------- 1 | new_ticker <- function(label, n, progress = NA, top_level_fun = NULL) { 2 | stopifnot(is_bare_string(label)) 3 | stopifnot(is_bare_integerish(n, 1)) 4 | 5 | suggested <- check_suggested("progress", top_level_fun, use = progress) 6 | if (!suggested) { 7 | return(identity) 8 | } 9 | 10 | # pb to be updated by reference by output function 11 | pb <- progress::progress_bar$new( 12 | format = sprintf( 13 | " %s [:bar] :percent in :elapsed", 14 | label 15 | ), 16 | total = n, clear = FALSE 17 | ) 18 | # output a function that curries f to tick, updating pb 19 | function(f) { 20 | f <- purrr::as_mapper(f) 21 | function(...) { 22 | pb$tick() 23 | f(...) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /R/pkgdown.R: -------------------------------------------------------------------------------- 1 | replay_html_dm_draw <- function(x, ...) { 2 | unclass(x) 3 | } 4 | 5 | # Use custom name to avoid clash if pkgload is active 6 | pkgdown_print_grViz <- function(x, ...) { 7 | structure(DiagrammeRsvg::export_svg(x), class = "dm_draw") 8 | } 9 | 10 | register_pkgdown_methods <- function() { 11 | if (Sys.getenv("IN_PKGDOWN") == "") { 12 | return() 13 | } 14 | 15 | # FIXME Should we use Config/Needs/website in DESCRIPTION instead? 16 | check_suggested(c("DiagrammeR", "DiagrammeRsvg"), "register_pkgdown_methods") 17 | 18 | # For dev pkgdown 19 | s3_register("downlit::replay_html", "dm_draw", replay_html_dm_draw) 20 | s3_register("pkgdown::pkgdown_print", "grViz", pkgdown_print_grViz) 21 | } 22 | -------------------------------------------------------------------------------- /R/ptype.R: -------------------------------------------------------------------------------- 1 | #' Prototype for a dm object 2 | #' 3 | #' @description 4 | #' The prototype contains all tables, all primary and foreign keys, 5 | #' but no data. 6 | #' All tables are truncated and converted to zero-row tibbles, 7 | #' also for remote data models. 8 | #' Columns retain their type. 9 | #' This is useful for performing creation and population of a database 10 | #' in separate steps. 11 | #' 12 | #' @inheritParams dm_has_fk 13 | #' @export 14 | #' @examplesIf dm:::dm_has_financial() 15 | #' dm_financial() %>% 16 | #' dm_ptype() 17 | #' 18 | #' dm_financial() %>% 19 | #' dm_ptype() %>% 20 | #' dm_nrow() 21 | dm_ptype <- function(dm) { 22 | check_not_zoomed(dm) 23 | 24 | # collect() doesn't support n argument for data frames 25 | # collect() requires n > 0: https://github.com/tidyverse/dbplyr/issues/415 26 | dm %>% 27 | dm_get_def() %>% 28 | mutate(data = map(data, ~ head(.x, 0))) %>% 29 | dm_from_def() %>% 30 | collect() 31 | } 32 | -------------------------------------------------------------------------------- /R/reexport.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | dplyr::`%>%` 3 | 4 | #' @export 5 | dplyr::filter 6 | 7 | #' @export 8 | dplyr::mutate 9 | 10 | #' @export 11 | dplyr::transmute 12 | 13 | #' @export 14 | dplyr::summarise 15 | 16 | #' @export 17 | dplyr::summarize 18 | 19 | #' @export 20 | dplyr::select 21 | 22 | #' @export 23 | dplyr::rename 24 | 25 | #' @export 26 | dplyr::group_by 27 | 28 | #' @export 29 | dplyr::ungroup 30 | 31 | #' @export 32 | dplyr::left_join 33 | 34 | #' @export 35 | dplyr::inner_join 36 | 37 | #' @export 38 | dplyr::full_join 39 | 40 | #' @export 41 | dplyr::semi_join 42 | 43 | #' @export 44 | dplyr::anti_join 45 | 46 | #' @export 47 | dplyr::right_join 48 | 49 | #' @export 50 | dplyr::collect 51 | 52 | #' @export 53 | dplyr::compute 54 | 55 | #' @export 56 | dplyr::copy_to 57 | 58 | #' @export 59 | dplyr::src_tbls 60 | 61 | #' @export 62 | dplyr::tbl 63 | 64 | #' @export 65 | dplyr::arrange 66 | 67 | #' @export 68 | dplyr::rows_insert 69 | 70 | #' @export 71 | dplyr::rows_append 72 | 73 | #' @export 74 | dplyr::rows_update 75 | 76 | #' @export 77 | dplyr::rows_patch 78 | 79 | #' @export 80 | dplyr::rows_upsert 81 | 82 | #' @export 83 | dplyr::rows_delete 84 | 85 | #' @export 86 | tibble::glimpse 87 | 88 | #' @export 89 | tibble::tibble 90 | 91 | #' @export 92 | tidyr::unite 93 | 94 | #' @export 95 | tidyr::separate 96 | -------------------------------------------------------------------------------- /R/strict.R: -------------------------------------------------------------------------------- 1 | # Infrastructure for "strict mode" of a dm 2 | # where re-adding existing keys gives an error 3 | # 4 | # Idea: "strict mode" is set during construction of a dm 5 | # 6 | # For now, strict mode only, easier to relax later 7 | # than to strengthen after the fact 8 | 9 | dm_is_strict_keys <- function(dm) { 10 | TRUE 11 | } 12 | -------------------------------------------------------------------------------- /R/unjson_nested.R: -------------------------------------------------------------------------------- 1 | # FIXME: make more robust as we implement all json functions 2 | unjson_nested <- function(data) { 3 | safe_fromJSON <- function(x) { 4 | tryCatch(map(x, jsonlite::fromJSON), error = function(e) x) 5 | } 6 | mutate(data, across(where(is.character), safe_fromJSON)) 7 | } 8 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | #' \pkg{utils} table manipulation methods for `dm_zoomed` objects 2 | #' 3 | #' @description 4 | #' Extract the first or last rows from a table. 5 | #' Use these methods without the '.dm_zoomed' suffix (see examples). 6 | #' The methods for regular `dm` objects extract the first or last tables. 7 | #' 8 | #' @param x object of class `dm_zoomed` 9 | #' @inheritParams utils::head 10 | #' @rdname utils_table_manipulation 11 | #' 12 | #' @return A `dm_zoomed` object. 13 | #' 14 | #' @details see manual for the corresponding functions in \pkg{utils}. 15 | #' 16 | #' @examplesIf rlang::is_installed("nycflights13") 17 | #' zoomed <- dm_nycflights13() %>% 18 | #' dm_zoom_to(flights) %>% 19 | #' head(4) 20 | #' zoomed 21 | #' dm_insert_zoomed(zoomed, new_tbl_name = "head_flights") 22 | #' @export 23 | head.dm_zoomed <- function(x, n = 6L, ...) { 24 | # dm method provided by utils 25 | replace_zoomed_tbl(x, head(tbl_zoomed(x), n, ...)) 26 | } 27 | 28 | #' @rdname utils_table_manipulation 29 | #' @export 30 | tail.dm_zoomed <- function(x, n = 6L, ...) { 31 | # dm method provided by utils 32 | replace_zoomed_tbl(x, tail(tbl_zoomed(x), n, ...)) 33 | } 34 | 35 | fast_tibble <- function(...) { 36 | out <- vctrs::df_list(...) 37 | tibble::new_tibble(out) 38 | } 39 | 40 | recode_compat <- function(x, y) { 41 | x <- unname(x) 42 | idx <- vctrs::vec_match(names(y), x) 43 | vctrs::vec_assign(x, idx, y) 44 | } 45 | -------------------------------------------------------------------------------- /R/waldo.R: -------------------------------------------------------------------------------- 1 | # Registered in .onLoad() 2 | compare_proxy.dm <- function(x, path = NULL, ...) { 3 | list( 4 | object = 5 | x %>% 6 | dm_get_def() %>% 7 | mutate(., data = transpose(select(., -table))) %>% 8 | select(table, data) %>% 9 | deframe() %>% 10 | map(as.list) %>% 11 | map(~ { 12 | .x$pks <- as.list(.x$pks) 13 | fk_data <- 14 | .x$fks %>% 15 | select(-table) %>% 16 | transpose() 17 | .x$fks <- set_names(fk_data, .x$fks$table) 18 | .x 19 | }), 20 | path = path 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # FIXME NEXT 2 | 3 | - un-skip tests 4 | 5 | # Later 6 | 7 | - Store `keys` objects in dm, much easier for debugging 8 | - Add "strict mode" to GitHub Actions: validation in `dm_from_def()` 9 | - Named PK and unique constraints: https://github.com/r-dbi/DBI/pull/351#issuecomment-833438890 10 | - `dm_paste()`: remove `select` argument from documentation, via `_impl()` function that takes dots and this argument, like `dm_rm_pk()` 11 | - Persistent test dm objects 12 | - Use `copy_to(temporary = FALSE)` 13 | - sqlite and duckdb: use file that can be discarded 14 | - Requires schema support for all databases 15 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | patch: 10 | default: 11 | target: auto 12 | threshold: 1% 13 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | dm 1.0.11 2 | 3 | ## Cran Repository Policy 4 | 5 | - [x] Reviewed CRP last edited 2024-08-27. 6 | -------------------------------------------------------------------------------- /data-raw/nycflights13-small.R: -------------------------------------------------------------------------------- 1 | flights <- 2 | nycflights13::flights %>% 3 | filter(day == 10, month %in% c(1, 2)) 4 | 5 | weather <- 6 | nycflights13::weather %>% 7 | filter(day == 10, month %in% c(1, 2)) 8 | 9 | airlines <- 10 | nycflights13::airlines %>% 11 | semi_join(flights, by = "carrier") 12 | 13 | airports <- 14 | nycflights13::airports %>% 15 | left_join(flights %>% select(origin, origin_day = day), by = c("faa" = "origin")) %>% 16 | left_join(flights %>% select(dest, dest_day = day), by = c("faa" = "dest")) %>% 17 | filter(!is.na(origin_day) | !is.na(dest_day)) %>% 18 | select(-origin_day, -dest_day) %>% 19 | distinct() 20 | 21 | planes <- 22 | nycflights13::planes %>% 23 | semi_join(flights, by = "tailnum") 24 | 25 | data <- tibble::lst(flights, weather, airlines, airports, planes) 26 | 27 | dir.create("inst/extdata", showWarnings = FALSE) 28 | saveRDS(data, "inst/extdata/nycflights13-small.rds", compress = "gzip", version = 2) 29 | -------------------------------------------------------------------------------- /demo/00Index: -------------------------------------------------------------------------------- 1 | berlin Demo for presentation at the 16th Berlin R meetup, July 2019 2 | zurich Demo for presentation at the Zurich R meetup, September 2019 3 | zurich2 Demo for presentation at Energie360, November 2019 4 | basel Demo for presentation at BaselR, December 2019 5 | hamburg Demo for presentation at the Hamburg R user group, January 2020 6 | seattle Demo for presentation at the Seattle R user group, February 2020 7 | nyc Demo for presentation at the New York Open Statistical Programming Meetup, February 2020 8 | neuchatel Demo for presentation at the satRday Neuchâtel, March 2020 9 | milano Demo for presentation at e-Rum Milano, June 2020 10 | -------------------------------------------------------------------------------- /dm.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | ProjectId: 1b8bc487-1b33-4dff-8d94-7bb130ab23c9 3 | 4 | RestoreWorkspace: No 5 | SaveWorkspace: No 6 | AlwaysSaveHistory: Default 7 | 8 | EnableCodeIndexing: Yes 9 | UseSpacesForTab: Yes 10 | NumSpacesForTab: 2 11 | Encoding: UTF-8 12 | 13 | RnwWeave: Sweave 14 | LaTeX: pdfLaTeX 15 | 16 | AutoAppendNewline: Yes 17 | StripTrailingWhitespace: Yes 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | PackageRoxygenize: rd,collate,namespace,roxyglobals::global_roclet 23 | -------------------------------------------------------------------------------- /example/rows-d.R: -------------------------------------------------------------------------------- 1 | data <- tibble(a = 1:3, b = letters[c(1:2, NA)], c = 0.5 + 0:2) 2 | data 3 | 4 | rows_insert(data, tibble(a = 4, b = "z")) 5 | rows_update(data, tibble(a = 2:3, b = "z")) 6 | rows_update(data, tibble(b = "z", a = 2:3), by = "a") 7 | rows_patch(data, tibble(a = 2:3, b = "z")) 8 | rows_upsert(data, tibble(a = 2:4, b = "z")) 9 | rows_delete(data, tibble(a = 2:4)) 10 | rows_delete(data, tibble(a = 2:4, b = "b")) 11 | rows_delete(data, tibble(a = 2:4, b = "b"), by = c("a", "b")) 12 | rows_truncate(data) 13 | -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | arg 2 | atributes 3 | bijective 4 | BT 5 | cardinalities 6 | cardinality 7 | cdm 8 | CMD 9 | Codecov 10 | csv 11 | cvut 12 | cynkra 13 | cz 14 | datamodelr 15 | DBMSs 16 | dbplyr 17 | DBs 18 | denormalized 19 | dev 20 | dimensioned 21 | disambiguated 22 | disambiguates 23 | disambiguations 24 | dm's 25 | dm’ 26 | dplyr 27 | dplyr's 28 | DT 29 | dynafilter 30 | energie 31 | FIXME 32 | fk 33 | FK 34 | GmbH 35 | hexcoded 36 | injective 37 | lifecycle 38 | Lifecycle 39 | memoizes 40 | MSSQL 41 | NSE 42 | nycflights 43 | onwards 44 | pipeable 45 | pkgdown 46 | polyply 47 | postgres 48 | Postgres 49 | pre 50 | programmatically 51 | RDBMS 52 | RDBMSs 53 | readme 54 | README 55 | RMariaDB 56 | RPostgres 57 | RPostgreSQL 58 | rquery 59 | RSQLite 60 | rstudio 61 | RStudio 62 | schemas 63 | sqlite 64 | src 65 | stringr 66 | surjective 67 | tbls 68 | th 69 | tibble 70 | tibbles 71 | tidygraph 72 | tidyr 73 | tidyselect 74 | tidyverse 75 | unevaluated 76 | Unexport 77 | unzooming 78 | validators 79 | Validators 80 | vals 81 | -------------------------------------------------------------------------------- /inst/extdata/nycflights13-small.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/inst/extdata/nycflights13-small.rds -------------------------------------------------------------------------------- /inst/htmlwidgets/css/styles.css: -------------------------------------------------------------------------------- 1 | 2 | .on { 3 | stroke-dasharray: 2; 4 | } 5 | 6 | .node:hover polygon { 7 | stroke-width: 3; 8 | } 9 | .edge:hover path { 10 | stroke-width: 3; 11 | } 12 | .edge:hover polygon { 13 | stroke-width: 4; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /inst/htmlwidgets/dmSVG.yaml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: jquery 3 | version: 3.6.0 4 | src: htmlwidgets/lib/jquery 5 | script: dist/jquery.min.js 6 | - name: customjs 7 | version: 1.0.0 8 | src: htmlwidgets 9 | script: custom.js 10 | stylesheet: css/styles.css 11 | - name: hammer 12 | version: 2.0.8 13 | src: htmlwidgets/lib/hammer 14 | script: hammer.min.js 15 | - name: svg-pan-zoom 16 | version: 3.6.1 17 | src: htmlwidgets/lib/svg-pan-zoom 18 | script: dist/svg-pan-zoom.min.js 19 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/hammer/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (C) 2011-2014 by Jorik Tangelder (Eight Media) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/hammer/README.md: -------------------------------------------------------------------------------- 1 | # Hammer.js 2.0 [![Build Status](https://travis-ci.org/hammerjs/hammer.js.svg)](https://travis-ci.org/hammerjs/hammer.js/) 2 | 3 | Visit [hammerjs.github.io](http://hammerjs.github.io) for documentation. 4 | 5 | You can get the pre-build versions from the Hammer.js website, or do this by yourself running 6 | `npm install -g grunt-cli && npm install && grunt build` 7 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "main": "dist/jquery.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "package.json" 7 | ], 8 | "keywords": [ 9 | "jquery", 10 | "javascript", 11 | "browser", 12 | "library" 13 | ], 14 | "homepage": "https://github.com/jquery/jquery-dist", 15 | "version": "3.6.0", 16 | "_release": "3.6.0", 17 | "_resolution": { 18 | "type": "version", 19 | "tag": "3.6.0", 20 | "commit": "e786e3d9707ffd9b0dd330ca135b66344dcef85a" 21 | }, 22 | "_source": "https://github.com/jquery/jquery-dist.git", 23 | "_target": "^3.6.0", 24 | "_originalSource": "jquery", 25 | "_direct": true 26 | } -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright OpenJS Foundation and other contributors, https://openjsf.org/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "main": "dist/jquery.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "package.json" 7 | ], 8 | "keywords": [ 9 | "jquery", 10 | "javascript", 11 | "browser", 12 | "library" 13 | ] 14 | } -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/ajax/var/location.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return window.location; 5 | } ); 6 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/ajax/var/nonce.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return { guid: Date.now() }; 5 | } ); 6 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/ajax/var/rquery.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return ( /\?/ ); 5 | } ); 6 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/attributes.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./core", 3 | "./attributes/attr", 4 | "./attributes/prop", 5 | "./attributes/classes", 6 | "./attributes/val" 7 | ], function( jQuery ) { 8 | 9 | "use strict"; 10 | 11 | // Return jQuery for attributes-only inclusion 12 | return jQuery; 13 | } ); 14 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/attributes/support.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../var/document", 3 | "../var/support" 4 | ], function( document, support ) { 5 | 6 | "use strict"; 7 | 8 | ( function() { 9 | var input = document.createElement( "input" ), 10 | select = document.createElement( "select" ), 11 | opt = select.appendChild( document.createElement( "option" ) ); 12 | 13 | input.type = "checkbox"; 14 | 15 | // Support: Android <=4.3 only 16 | // Default value for a checkbox should be "on" 17 | support.checkOn = input.value !== ""; 18 | 19 | // Support: IE <=11 only 20 | // Must access selectedIndex to make default options select 21 | support.optSelected = opt.selected; 22 | 23 | // Support: IE <=11 only 24 | // An input loses its value after becoming a radio 25 | input = document.createElement( "input" ); 26 | input.value = "t"; 27 | input.type = "radio"; 28 | support.radioValue = input.value === "t"; 29 | } )(); 30 | 31 | return support; 32 | 33 | } ); 34 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/core/DOMEval.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../var/document" 3 | ], function( document ) { 4 | "use strict"; 5 | 6 | var preservedScriptAttributes = { 7 | type: true, 8 | src: true, 9 | nonce: true, 10 | noModule: true 11 | }; 12 | 13 | function DOMEval( code, node, doc ) { 14 | doc = doc || document; 15 | 16 | var i, val, 17 | script = doc.createElement( "script" ); 18 | 19 | script.text = code; 20 | if ( node ) { 21 | for ( i in preservedScriptAttributes ) { 22 | 23 | // Support: Firefox 64+, Edge 18+ 24 | // Some browsers don't support the "nonce" property on scripts. 25 | // On the other hand, just using `getAttribute` is not enough as 26 | // the `nonce` attribute is reset to an empty string whenever it 27 | // becomes browsing-context connected. 28 | // See https://github.com/whatwg/html/issues/2369 29 | // See https://html.spec.whatwg.org/#nonce-attributes 30 | // The `node.getAttribute` check was added for the sake of 31 | // `jQuery.globalEval` so that it can fake a nonce-containing node 32 | // via an object. 33 | val = node[ i ] || node.getAttribute && node.getAttribute( i ); 34 | if ( val ) { 35 | script.setAttribute( i, val ); 36 | } 37 | } 38 | } 39 | doc.head.appendChild( script ).parentNode.removeChild( script ); 40 | } 41 | 42 | return DOMEval; 43 | } ); 44 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/core/camelCase.js: -------------------------------------------------------------------------------- 1 | define( [], function() { 2 | 3 | "use strict"; 4 | 5 | // Matches dashed string for camelizing 6 | var rmsPrefix = /^-ms-/, 7 | rdashAlpha = /-([a-z])/g; 8 | 9 | // Used by camelCase as callback to replace() 10 | function fcamelCase( _all, letter ) { 11 | return letter.toUpperCase(); 12 | } 13 | 14 | // Convert dashed to camelCase; used by the css and data modules 15 | // Support: IE <=9 - 11, Edge 12 - 15 16 | // Microsoft forgot to hump their vendor prefix (#9572) 17 | function camelCase( string ) { 18 | return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); 19 | } 20 | 21 | return camelCase; 22 | 23 | } ); 24 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/core/isAttached.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../core", 3 | "../var/documentElement", 4 | "../selector" // jQuery.contains 5 | ], function( jQuery, documentElement ) { 6 | "use strict"; 7 | 8 | var isAttached = function( elem ) { 9 | return jQuery.contains( elem.ownerDocument, elem ); 10 | }, 11 | composed = { composed: true }; 12 | 13 | // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only 14 | // Check attachment across shadow DOM boundaries when possible (gh-3504) 15 | // Support: iOS 10.0-10.2 only 16 | // Early iOS 10 versions support `attachShadow` but not `getRootNode`, 17 | // leading to errors. We need to check for `getRootNode`. 18 | if ( documentElement.getRootNode ) { 19 | isAttached = function( elem ) { 20 | return jQuery.contains( elem.ownerDocument, elem ) || 21 | elem.getRootNode( composed ) === elem.ownerDocument; 22 | }; 23 | } 24 | 25 | return isAttached; 26 | } ); 27 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/core/nodeName.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | 3 | "use strict"; 4 | 5 | function nodeName( elem, name ) { 6 | 7 | return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); 8 | 9 | } 10 | 11 | return nodeName; 12 | 13 | } ); 14 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/core/parseXML.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../core" 3 | ], function( jQuery ) { 4 | 5 | "use strict"; 6 | 7 | // Cross-browser xml parsing 8 | jQuery.parseXML = function( data ) { 9 | var xml, parserErrorElem; 10 | if ( !data || typeof data !== "string" ) { 11 | return null; 12 | } 13 | 14 | // Support: IE 9 - 11 only 15 | // IE throws on parseFromString with invalid input. 16 | try { 17 | xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); 18 | } catch ( e ) {} 19 | 20 | parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; 21 | if ( !xml || parserErrorElem ) { 22 | jQuery.error( "Invalid XML: " + ( 23 | parserErrorElem ? 24 | jQuery.map( parserErrorElem.childNodes, function( el ) { 25 | return el.textContent; 26 | } ).join( "\n" ) : 27 | data 28 | ) ); 29 | } 30 | return xml; 31 | }; 32 | 33 | return jQuery.parseXML; 34 | 35 | } ); 36 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/core/readyException.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../core" 3 | ], function( jQuery ) { 4 | 5 | "use strict"; 6 | 7 | jQuery.readyException = function( error ) { 8 | window.setTimeout( function() { 9 | throw error; 10 | } ); 11 | }; 12 | 13 | } ); 14 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/core/stripAndCollapse.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../var/rnothtmlwhite" 3 | ], function( rnothtmlwhite ) { 4 | "use strict"; 5 | 6 | // Strip and collapse whitespace according to HTML spec 7 | // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace 8 | function stripAndCollapse( value ) { 9 | var tokens = value.match( rnothtmlwhite ) || []; 10 | return tokens.join( " " ); 11 | } 12 | 13 | return stripAndCollapse; 14 | } ); 15 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/core/support.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../var/document", 3 | "../var/support" 4 | ], function( document, support ) { 5 | 6 | "use strict"; 7 | 8 | // Support: Safari 8 only 9 | // In Safari 8 documents created via document.implementation.createHTMLDocument 10 | // collapse sibling forms: the second one becomes a child of the first one. 11 | // Because of that, this security measure has to be disabled in Safari 8. 12 | // https://bugs.webkit.org/show_bug.cgi?id=137337 13 | support.createHTMLDocument = ( function() { 14 | var body = document.implementation.createHTMLDocument( "" ).body; 15 | body.innerHTML = "
"; 16 | return body.childNodes.length === 2; 17 | } )(); 18 | 19 | return support; 20 | } ); 21 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/core/toType.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../var/class2type", 3 | "../var/toString" 4 | ], function( class2type, toString ) { 5 | 6 | "use strict"; 7 | 8 | function toType( obj ) { 9 | if ( obj == null ) { 10 | return obj + ""; 11 | } 12 | 13 | // Support: Android <=2.3 only (functionish RegExp) 14 | return typeof obj === "object" || typeof obj === "function" ? 15 | class2type[ toString.call( obj ) ] || "object" : 16 | typeof obj; 17 | } 18 | 19 | return toType; 20 | } ); 21 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/core/var/rsingleTag.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | // rsingleTag matches a string consisting of a single HTML element with no attributes 5 | // and captures the element's name 6 | return ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/css/addGetHookIf.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | 3 | "use strict"; 4 | 5 | function addGetHookIf( conditionFn, hookFn ) { 6 | 7 | // Define the hook, we'll check on the first run if it's really needed. 8 | return { 9 | get: function() { 10 | if ( conditionFn() ) { 11 | 12 | // Hook not needed (or it's not possible to use it due 13 | // to missing dependency), remove it. 14 | delete this.get; 15 | return; 16 | } 17 | 18 | // Hook needed; redefine it so that the support test is not executed again. 19 | return ( this.get = hookFn ).apply( this, arguments ); 20 | } 21 | }; 22 | } 23 | 24 | return addGetHookIf; 25 | 26 | } ); 27 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/css/finalPropName.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../var/document", 3 | "../core" 4 | ], function( document, jQuery ) { 5 | 6 | "use strict"; 7 | 8 | var cssPrefixes = [ "Webkit", "Moz", "ms" ], 9 | emptyStyle = document.createElement( "div" ).style, 10 | vendorProps = {}; 11 | 12 | // Return a vendor-prefixed property or undefined 13 | function vendorPropName( name ) { 14 | 15 | // Check for vendor prefixed names 16 | var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), 17 | i = cssPrefixes.length; 18 | 19 | while ( i-- ) { 20 | name = cssPrefixes[ i ] + capName; 21 | if ( name in emptyStyle ) { 22 | return name; 23 | } 24 | } 25 | } 26 | 27 | // Return a potentially-mapped jQuery.cssProps or vendor prefixed property 28 | function finalPropName( name ) { 29 | var final = jQuery.cssProps[ name ] || vendorProps[ name ]; 30 | 31 | if ( final ) { 32 | return final; 33 | } 34 | if ( name in emptyStyle ) { 35 | return name; 36 | } 37 | return vendorProps[ name ] = vendorPropName( name ) || name; 38 | } 39 | 40 | return finalPropName; 41 | 42 | } ); 43 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/css/hiddenVisibleSelectors.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../core", 3 | "../selector" 4 | ], function( jQuery ) { 5 | 6 | "use strict"; 7 | 8 | jQuery.expr.pseudos.hidden = function( elem ) { 9 | return !jQuery.expr.pseudos.visible( elem ); 10 | }; 11 | jQuery.expr.pseudos.visible = function( elem ) { 12 | return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); 13 | }; 14 | 15 | } ); 16 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/css/var/cssExpand.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return [ "Top", "Right", "Bottom", "Left" ]; 5 | } ); 6 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/css/var/getStyles.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return function( elem ) { 5 | 6 | // Support: IE <=11 only, Firefox <=30 (#15098, #14150) 7 | // IE throws on elements created in popups 8 | // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" 9 | var view = elem.ownerDocument.defaultView; 10 | 11 | if ( !view || !view.opener ) { 12 | view = window; 13 | } 14 | 15 | return view.getComputedStyle( elem ); 16 | }; 17 | } ); 18 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/css/var/isHiddenWithinTree.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../../core", 3 | "../../core/isAttached" 4 | 5 | // css is assumed 6 | ], function( jQuery, isAttached ) { 7 | "use strict"; 8 | 9 | // isHiddenWithinTree reports if an element has a non-"none" display style (inline and/or 10 | // through the CSS cascade), which is useful in deciding whether or not to make it visible. 11 | // It differs from the :hidden selector (jQuery.expr.pseudos.hidden) in two important ways: 12 | // * A hidden ancestor does not force an element to be classified as hidden. 13 | // * Being disconnected from the document does not force an element to be classified as hidden. 14 | // These differences improve the behavior of .toggle() et al. when applied to elements that are 15 | // detached or contained within hidden ancestors (gh-2404, gh-2863). 16 | return function( elem, el ) { 17 | 18 | // isHiddenWithinTree might be called from jQuery#filter function; 19 | // in that case, element will be second argument 20 | elem = el || elem; 21 | 22 | // Inline style trumps all 23 | return elem.style.display === "none" || 24 | elem.style.display === "" && 25 | 26 | // Otherwise, check computed style 27 | // Support: Firefox <=43 - 45 28 | // Disconnected elements can have computed display: none, so first confirm that elem is 29 | // in the document. 30 | isAttached( elem ) && 31 | 32 | jQuery.css( elem, "display" ) === "none"; 33 | }; 34 | } ); 35 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/css/var/rboxStyle.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./cssExpand" 3 | ], function( cssExpand ) { 4 | "use strict"; 5 | 6 | return new RegExp( cssExpand.join( "|" ), "i" ); 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/css/var/rnumnonpx.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../../var/pnum" 3 | ], function( pnum ) { 4 | "use strict"; 5 | 6 | return new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/css/var/swap.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | 3 | "use strict"; 4 | 5 | // A method for quickly swapping in/out CSS properties to get correct calculations. 6 | return function( elem, options, callback ) { 7 | var ret, name, 8 | old = {}; 9 | 10 | // Remember the old values, and insert the new ones 11 | for ( name in options ) { 12 | old[ name ] = elem.style[ name ]; 13 | elem.style[ name ] = options[ name ]; 14 | } 15 | 16 | ret = callback.call( elem ); 17 | 18 | // Revert the old values 19 | for ( name in options ) { 20 | elem.style[ name ] = old[ name ]; 21 | } 22 | 23 | return ret; 24 | }; 25 | 26 | } ); 27 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/data/var/acceptData.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | 3 | "use strict"; 4 | 5 | /** 6 | * Determines whether an object can have data 7 | */ 8 | return function( owner ) { 9 | 10 | // Accepts only: 11 | // - Node 12 | // - Node.ELEMENT_NODE 13 | // - Node.DOCUMENT_NODE 14 | // - Object 15 | // - Any 16 | return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); 17 | }; 18 | 19 | } ); 20 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/data/var/dataPriv.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../Data" 3 | ], function( Data ) { 4 | "use strict"; 5 | 6 | return new Data(); 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/data/var/dataUser.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../Data" 3 | ], function( Data ) { 4 | "use strict"; 5 | 6 | return new Data(); 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/deferred/exceptionHook.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../core", 3 | "../deferred" 4 | ], function( jQuery ) { 5 | 6 | "use strict"; 7 | 8 | // These usually indicate a programmer mistake during development, 9 | // warn about them ASAP rather than swallowing them by default. 10 | var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; 11 | 12 | jQuery.Deferred.exceptionHook = function( error, stack ) { 13 | 14 | // Support: IE 8 - 9 only 15 | // Console exists when dev tools are open, which can happen at any time 16 | if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { 17 | window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); 18 | } 19 | }; 20 | 21 | } ); 22 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/deprecated/ajax-event-alias.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../core", 3 | "../ajax", 4 | "../event" 5 | ], function( jQuery ) { 6 | 7 | "use strict"; 8 | 9 | jQuery.each( [ 10 | "ajaxStart", 11 | "ajaxStop", 12 | "ajaxComplete", 13 | "ajaxError", 14 | "ajaxSuccess", 15 | "ajaxSend" 16 | ], function( _i, type ) { 17 | jQuery.fn[ type ] = function( fn ) { 18 | return this.on( type, fn ); 19 | }; 20 | } ); 21 | 22 | } ); 23 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/deprecated/event.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../core", 3 | 4 | "../event", 5 | "../event/trigger" 6 | ], function( jQuery ) { 7 | 8 | "use strict"; 9 | 10 | jQuery.fn.extend( { 11 | 12 | bind: function( types, data, fn ) { 13 | return this.on( types, null, data, fn ); 14 | }, 15 | unbind: function( types, fn ) { 16 | return this.off( types, null, fn ); 17 | }, 18 | 19 | delegate: function( selector, types, data, fn ) { 20 | return this.on( types, selector, data, fn ); 21 | }, 22 | undelegate: function( selector, types, fn ) { 23 | 24 | // ( namespace ) or ( selector, types [, fn] ) 25 | return arguments.length === 1 ? 26 | this.off( selector, "**" ) : 27 | this.off( types, selector || "**", fn ); 28 | }, 29 | 30 | hover: function( fnOver, fnOut ) { 31 | return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); 32 | } 33 | } ); 34 | 35 | jQuery.each( 36 | ( "blur focus focusin focusout resize scroll click dblclick " + 37 | "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + 38 | "change select submit keydown keypress keyup contextmenu" ).split( " " ), 39 | function( _i, name ) { 40 | 41 | // Handle event binding 42 | jQuery.fn[ name ] = function( data, fn ) { 43 | return arguments.length > 0 ? 44 | this.on( name, null, data, fn ) : 45 | this.trigger( name ); 46 | }; 47 | } 48 | ); 49 | 50 | } ); 51 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/effects/animatedSelector.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../core", 3 | "../selector", 4 | "../effects" 5 | ], function( jQuery ) { 6 | 7 | "use strict"; 8 | 9 | jQuery.expr.pseudos.animated = function( elem ) { 10 | return jQuery.grep( jQuery.timers, function( fn ) { 11 | return elem === fn.elem; 12 | } ).length; 13 | }; 14 | 15 | } ); 16 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/event/support.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../var/support" 3 | ], function( support ) { 4 | 5 | "use strict"; 6 | 7 | support.focusin = "onfocusin" in window; 8 | 9 | return support; 10 | 11 | } ); 12 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/exports/amd.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../core" 3 | ], function( jQuery ) { 4 | 5 | "use strict"; 6 | 7 | // Register as a named AMD module, since jQuery can be concatenated with other 8 | // files that may use define, but not via a proper concatenation script that 9 | // understands anonymous AMD modules. A named AMD is safest and most robust 10 | // way to register. Lowercase jquery is used because AMD module names are 11 | // derived from file names, and jQuery is normally delivered in a lowercase 12 | // file name. Do this after creating the global so that if an AMD module wants 13 | // to call noConflict to hide this version of jQuery, it will work. 14 | 15 | // Note that for maximum portability, libraries that are not jQuery should 16 | // declare themselves as anonymous modules, and avoid setting a global if an 17 | // AMD loader is present. jQuery is a special case. For more information, see 18 | // https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon 19 | 20 | if ( typeof define === "function" && define.amd ) { 21 | define( "jquery", [], function() { 22 | return jQuery; 23 | } ); 24 | } 25 | 26 | } ); 27 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/exports/global.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../core" 3 | ], function( jQuery ) { 4 | 5 | "use strict"; 6 | 7 | var 8 | 9 | // Map over jQuery in case of overwrite 10 | _jQuery = window.jQuery, 11 | 12 | // Map over the $ in case of overwrite 13 | _$ = window.$; 14 | 15 | jQuery.noConflict = function( deep ) { 16 | if ( window.$ === jQuery ) { 17 | window.$ = _$; 18 | } 19 | 20 | if ( deep && window.jQuery === jQuery ) { 21 | window.jQuery = _jQuery; 22 | } 23 | 24 | return jQuery; 25 | }; 26 | 27 | // Expose jQuery and $ identifiers, even in AMD 28 | // (#7102#comment:10, https://github.com/jquery/jquery/pull/557) 29 | // and CommonJS for browser emulators (#13566) 30 | if ( typeof noGlobal === "undefined" ) { 31 | window.jQuery = window.$ = jQuery; 32 | } 33 | 34 | } ); 35 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/jquery.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./core", 3 | "./selector", 4 | "./traversing", 5 | "./callbacks", 6 | "./deferred", 7 | "./deferred/exceptionHook", 8 | "./core/ready", 9 | "./data", 10 | "./queue", 11 | "./queue/delay", 12 | "./attributes", 13 | "./event", 14 | "./event/focusin", 15 | "./manipulation", 16 | "./manipulation/_evalUrl", 17 | "./wrap", 18 | "./css", 19 | "./css/hiddenVisibleSelectors", 20 | "./serialize", 21 | "./ajax", 22 | "./ajax/xhr", 23 | "./ajax/script", 24 | "./ajax/jsonp", 25 | "./ajax/load", 26 | "./core/parseXML", 27 | "./core/parseHTML", 28 | "./effects", 29 | "./effects/animatedSelector", 30 | "./offset", 31 | "./dimensions", 32 | "./deprecated", 33 | "./exports/amd", 34 | "./exports/global" 35 | ], function( jQuery ) { 36 | 37 | "use strict"; 38 | 39 | return jQuery; 40 | 41 | } ); 42 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/manipulation/_evalUrl.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../ajax" 3 | ], function( jQuery ) { 4 | 5 | "use strict"; 6 | 7 | jQuery._evalUrl = function( url, options, doc ) { 8 | return jQuery.ajax( { 9 | url: url, 10 | 11 | // Make this explicit, since user can override this through ajaxSetup (#11264) 12 | type: "GET", 13 | dataType: "script", 14 | cache: true, 15 | async: false, 16 | global: false, 17 | 18 | // Only evaluate the response if it is successful (gh-4126) 19 | // dataFilter is not invoked for failure responses, so using it instead 20 | // of the default converter is kludgy but it works. 21 | converters: { 22 | "text script": function() {} 23 | }, 24 | dataFilter: function( response ) { 25 | jQuery.globalEval( response, options, doc ); 26 | } 27 | } ); 28 | }; 29 | 30 | return jQuery._evalUrl; 31 | 32 | } ); 33 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/manipulation/getAll.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../core", 3 | "../core/nodeName" 4 | ], function( jQuery, nodeName ) { 5 | 6 | "use strict"; 7 | 8 | function getAll( context, tag ) { 9 | 10 | // Support: IE <=9 - 11 only 11 | // Use typeof to avoid zero-argument method invocation on host objects (#15151) 12 | var ret; 13 | 14 | if ( typeof context.getElementsByTagName !== "undefined" ) { 15 | ret = context.getElementsByTagName( tag || "*" ); 16 | 17 | } else if ( typeof context.querySelectorAll !== "undefined" ) { 18 | ret = context.querySelectorAll( tag || "*" ); 19 | 20 | } else { 21 | ret = []; 22 | } 23 | 24 | if ( tag === undefined || tag && nodeName( context, tag ) ) { 25 | return jQuery.merge( [ context ], ret ); 26 | } 27 | 28 | return ret; 29 | } 30 | 31 | return getAll; 32 | } ); 33 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/manipulation/setGlobalEval.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../data/var/dataPriv" 3 | ], function( dataPriv ) { 4 | 5 | "use strict"; 6 | 7 | // Mark scripts as having already been evaluated 8 | function setGlobalEval( elems, refElements ) { 9 | var i = 0, 10 | l = elems.length; 11 | 12 | for ( ; i < l; i++ ) { 13 | dataPriv.set( 14 | elems[ i ], 15 | "globalEval", 16 | !refElements || dataPriv.get( refElements[ i ], "globalEval" ) 17 | ); 18 | } 19 | } 20 | 21 | return setGlobalEval; 22 | } ); 23 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/manipulation/support.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../var/document", 3 | "../var/support" 4 | ], function( document, support ) { 5 | 6 | "use strict"; 7 | 8 | ( function() { 9 | var fragment = document.createDocumentFragment(), 10 | div = fragment.appendChild( document.createElement( "div" ) ), 11 | input = document.createElement( "input" ); 12 | 13 | // Support: Android 4.0 - 4.3 only 14 | // Check state lost if the name is set (#11217) 15 | // Support: Windows Web Apps (WWA) 16 | // `name` and `type` must use .setAttribute for WWA (#14901) 17 | input.setAttribute( "type", "radio" ); 18 | input.setAttribute( "checked", "checked" ); 19 | input.setAttribute( "name", "t" ); 20 | 21 | div.appendChild( input ); 22 | 23 | // Support: Android <=4.1 only 24 | // Older WebKit doesn't clone checked state correctly in fragments 25 | support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; 26 | 27 | // Support: IE <=11 only 28 | // Make sure textarea (and checkbox) defaultValue is properly cloned 29 | div.innerHTML = ""; 30 | support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; 31 | 32 | // Support: IE <=9 only 33 | // IE <=9 replaces "; 36 | support.option = !!div.lastChild; 37 | } )(); 38 | 39 | return support; 40 | 41 | } ); 42 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/manipulation/var/rscriptType.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return ( /^$|^module$|\/(?:java|ecma)script/i ); 5 | } ); 6 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/manipulation/var/rtagName.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | // rtagName captures the name from the first start tag in a string of HTML 5 | // https://html.spec.whatwg.org/multipage/syntax.html#tag-open-state 6 | // https://html.spec.whatwg.org/multipage/syntax.html#tag-name-state 7 | return ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); 8 | } ); 9 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/manipulation/wrapMap.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./support" 3 | ], function( support ) { 4 | 5 | "use strict"; 6 | 7 | // We have to close these tags to support XHTML (#13200) 8 | var wrapMap = { 9 | 10 | // XHTML parsers do not magically insert elements in the 11 | // same way that tag soup parsers do. So we cannot shorten 12 | // this by omitting or other required elements. 13 | thead: [ 1, "", "
" ], 14 | col: [ 2, "", "
" ], 15 | tr: [ 2, "", "
" ], 16 | td: [ 3, "", "
" ], 17 | 18 | _default: [ 0, "", "" ] 19 | }; 20 | 21 | wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; 22 | wrapMap.th = wrapMap.td; 23 | 24 | // Support: IE <=9 only 25 | if ( !support.option ) { 26 | wrapMap.optgroup = wrapMap.option = [ 1, "" ]; 27 | } 28 | 29 | return wrapMap; 30 | } ); 31 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/queue/delay.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../core", 3 | "../queue", 4 | "../effects" // Delay is optional because of this dependency 5 | ], function( jQuery ) { 6 | 7 | "use strict"; 8 | 9 | // Based off of the plugin by Clint Helfers, with permission. 10 | // https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ 11 | jQuery.fn.delay = function( time, type ) { 12 | time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; 13 | type = type || "fx"; 14 | 15 | return this.queue( type, function( next, hooks ) { 16 | var timeout = window.setTimeout( next, time ); 17 | hooks.stop = function() { 18 | window.clearTimeout( timeout ); 19 | }; 20 | } ); 21 | }; 22 | 23 | return jQuery.fn.delay; 24 | } ); 25 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/selector-sizzle.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./core", 3 | "../external/sizzle/dist/sizzle" 4 | ], function( jQuery, Sizzle ) { 5 | 6 | "use strict"; 7 | 8 | jQuery.find = Sizzle; 9 | jQuery.expr = Sizzle.selectors; 10 | 11 | // Deprecated 12 | jQuery.expr[ ":" ] = jQuery.expr.pseudos; 13 | jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; 14 | jQuery.text = Sizzle.getText; 15 | jQuery.isXMLDoc = Sizzle.isXML; 16 | jQuery.contains = Sizzle.contains; 17 | jQuery.escapeSelector = Sizzle.escape; 18 | 19 | } ); 20 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/selector.js: -------------------------------------------------------------------------------- 1 | define( [ "./selector-sizzle" ], function() { 2 | "use strict"; 3 | } ); 4 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/traversing/var/dir.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../../core" 3 | ], function( jQuery ) { 4 | 5 | "use strict"; 6 | 7 | return function( elem, dir, until ) { 8 | var matched = [], 9 | truncate = until !== undefined; 10 | 11 | while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { 12 | if ( elem.nodeType === 1 ) { 13 | if ( truncate && jQuery( elem ).is( until ) ) { 14 | break; 15 | } 16 | matched.push( elem ); 17 | } 18 | } 19 | return matched; 20 | }; 21 | 22 | } ); 23 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/traversing/var/rneedsContext.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../../core", 3 | "../../selector" 4 | ], function( jQuery ) { 5 | "use strict"; 6 | 7 | return jQuery.expr.match.needsContext; 8 | } ); 9 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/traversing/var/siblings.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | 3 | "use strict"; 4 | 5 | return function( n, elem ) { 6 | var matched = []; 7 | 8 | for ( ; n; n = n.nextSibling ) { 9 | if ( n.nodeType === 1 && n !== elem ) { 10 | matched.push( n ); 11 | } 12 | } 13 | 14 | return matched; 15 | }; 16 | 17 | } ); 18 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/ObjectFunctionString.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./fnToString" 3 | ], function( fnToString ) { 4 | "use strict"; 5 | 6 | return fnToString.call( Object ); 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/arr.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return []; 5 | } ); 6 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/class2type.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | // [[Class]] -> type pairs 5 | return {}; 6 | } ); 7 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/document.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return window.document; 5 | } ); 6 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/documentElement.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./document" 3 | ], function( document ) { 4 | "use strict"; 5 | 6 | return document.documentElement; 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/flat.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./arr" 3 | ], function( arr ) { 4 | 5 | "use strict"; 6 | 7 | // Support: IE 9 - 11+, Edge 18+, Android Browser 4.0 - 4.3 only, iOS 7 - 11 only, Safari 11 only, 8 | // Firefox <= 61 only 9 | // Provide fallback for browsers without Array#flat. 10 | return arr.flat ? function( array ) { 11 | return arr.flat.call( array ); 12 | } : function( array ) { 13 | return arr.concat.apply( [], array ); 14 | }; 15 | 16 | } ); 17 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/fnToString.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./hasOwn" 3 | ], function( hasOwn ) { 4 | "use strict"; 5 | 6 | return hasOwn.toString; 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/getProto.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return Object.getPrototypeOf; 5 | } ); 6 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/hasOwn.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./class2type" 3 | ], function( class2type ) { 4 | "use strict"; 5 | 6 | return class2type.hasOwnProperty; 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/indexOf.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./arr" 3 | ], function( arr ) { 4 | "use strict"; 5 | 6 | return arr.indexOf; 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/isFunction.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return function isFunction( obj ) { 5 | 6 | // Support: Chrome <=57, Firefox <=52 7 | // In some browsers, typeof returns "function" for HTML elements 8 | // (i.e., `typeof document.createElement( "object" ) === "function"`). 9 | // We don't want to classify *any* DOM node as a function. 10 | // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 11 | // Plus for old WebKit, typeof returns "function" for HTML collections 12 | // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) 13 | return typeof obj === "function" && typeof obj.nodeType !== "number" && 14 | typeof obj.item !== "function"; 15 | }; 16 | 17 | } ); 18 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/isWindow.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return function isWindow( obj ) { 5 | return obj != null && obj === obj.window; 6 | }; 7 | 8 | } ); 9 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/pnum.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; 5 | } ); 6 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/push.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./arr" 3 | ], function( arr ) { 4 | "use strict"; 5 | 6 | return arr.push; 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/rcheckableType.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | return ( /^(?:checkbox|radio)$/i ); 5 | } ); 6 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/rcssNum.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "../var/pnum" 3 | ], function( pnum ) { 4 | 5 | "use strict"; 6 | 7 | return new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); 8 | 9 | } ); 10 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/rnothtmlwhite.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | // Only count HTML whitespace 5 | // Other whitespace should count in values 6 | // https://infra.spec.whatwg.org/#ascii-whitespace 7 | return ( /[^\x20\t\r\n\f]+/g ); 8 | } ); 9 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/slice.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./arr" 3 | ], function( arr ) { 4 | "use strict"; 5 | 6 | return arr.slice; 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/support.js: -------------------------------------------------------------------------------- 1 | define( function() { 2 | "use strict"; 3 | 4 | // All support tests are defined in their respective modules. 5 | return {}; 6 | } ); 7 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/jquery/src/var/toString.js: -------------------------------------------------------------------------------- 1 | define( [ 2 | "./class2type" 3 | ], function( class2type ) { 4 | "use strict"; 5 | 6 | return class2type.toString; 7 | } ); 8 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/svg-pan-zoom/LICENSE_svg-pan-zoom: -------------------------------------------------------------------------------- 1 | Copyright 2009-2010 Andrea Leofreddi 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /man/check_key.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/key-helpers.R 3 | \name{check_key} 4 | \alias{check_key} 5 | \title{Check if column(s) can be used as keys} 6 | \usage{ 7 | check_key(x, ..., .data = deprecated()) 8 | } 9 | \arguments{ 10 | \item{x}{The data frame whose columns should be tested for key properties.} 11 | 12 | \item{...}{The names of the columns to be checked, processed with 13 | \code{\link[dplyr:select]{dplyr::select()}}. If omitted, all columns will be checked.} 14 | 15 | \item{.data}{Deprecated.} 16 | } 17 | \value{ 18 | Returns \code{x}, invisibly, if the check is passed. 19 | Otherwise an error is thrown and the reason for it is explained. 20 | } 21 | \description{ 22 | \code{check_key()} accepts a data frame and, optionally, columns. 23 | It throws an error 24 | if the specified columns are NOT a unique key of the data frame. 25 | If the columns given in the ellipsis ARE a key, the data frame itself is returned silently, so that it can be used for piping. 26 | } 27 | \examples{ 28 | data <- tibble::tibble(a = c(1, 2, 1), b = c(1, 4, 1), c = c(5, 6, 7)) 29 | # this is failing: 30 | try(check_key(data, a, b)) 31 | 32 | # this is passing: 33 | check_key(data, a, c) 34 | check_key(data) 35 | } 36 | -------------------------------------------------------------------------------- /man/db_schema_exists.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/schema.R 3 | \name{db_schema_exists} 4 | \alias{db_schema_exists} 5 | \title{Check for existence of a schema on a database} 6 | \usage{ 7 | db_schema_exists(con, schema, ...) 8 | } 9 | \arguments{ 10 | \item{con}{An object of class \code{"src"} or \code{"DBIConnection"}.} 11 | 12 | \item{schema}{Class \code{character} or \code{SQL}, name of the schema} 13 | 14 | \item{...}{Passed on to the individual methods.} 15 | } 16 | \value{ 17 | A boolean: \code{TRUE} if schema exists, \code{FALSE} otherwise. 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 21 | 22 | \code{db_schema_exists()} checks, if a schema exists on the database. 23 | } 24 | \details{ 25 | Methods are not available for all DBMS. 26 | 27 | Additional arguments are: 28 | \itemize{ 29 | \item \code{dbname}: supported for MSSQL. Check if a schema exists on a different 30 | database on the connected MSSQL-server; default: database addressed by \code{con}. 31 | } 32 | } 33 | \seealso{ 34 | Other schema handling functions: 35 | \code{\link{db_schema_create}()}, 36 | \code{\link{db_schema_drop}()}, 37 | \code{\link{db_schema_list}()} 38 | } 39 | \concept{schema handling functions} 40 | -------------------------------------------------------------------------------- /man/dm_financial.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/financial.R 3 | \name{dm_financial} 4 | \alias{dm_financial} 5 | \alias{dm_financial_sqlite} 6 | \title{Creates a dm object for the Financial data} 7 | \usage{ 8 | dm_financial() 9 | 10 | dm_financial_sqlite() 11 | } 12 | \value{ 13 | A \code{dm} object. 14 | } 15 | \description{ 16 | \code{dm_financial()} creates an example \code{\link{dm}} object from the tables at 17 | https://relational.fel.cvut.cz/dataset/Financial. 18 | The connection is established once per session, 19 | subsequent calls return the same connection. 20 | 21 | \code{dm_financial_sqlite()} copies the data to a temporary SQLite database. 22 | The data is downloaded once per session, subsequent calls return the same database. 23 | The \code{trans} table is excluded due to its size. 24 | } 25 | \examples{ 26 | \dontshow{if (dm:::dm_has_financial() && rlang::is_installed("DiagrammeR")) withAutoprint(\{ # examplesIf} 27 | dm_financial() \%>\% 28 | dm_draw() 29 | \dontshow{\}) # examplesIf} 30 | } 31 | -------------------------------------------------------------------------------- /man/dm_get_con.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dm_get_con.R 3 | \name{dm_get_con} 4 | \alias{dm_get_con} 5 | \title{Get connection} 6 | \usage{ 7 | dm_get_con(dm) 8 | } 9 | \arguments{ 10 | \item{dm}{A \code{dm} object.} 11 | } 12 | \value{ 13 | The \code{\link[DBI:DBIConnection-class]{DBI::DBIConnection}} object for a \code{dm} object. 14 | } 15 | \description{ 16 | \code{dm_get_con()} returns the DBI connection for a \code{dm} object. 17 | This works only if the tables are stored on a database, otherwise an error 18 | is thrown. 19 | } 20 | \details{ 21 | All lazy tables in a dm object must be stored on the same database server 22 | and accessed through the same connection, because a large part 23 | of the package's functionality relies on efficient joins. 24 | } 25 | \examples{ 26 | \dontshow{if (dm:::dm_has_financial()) withAutoprint(\{ # examplesIf} 27 | dm_financial() \%>\% 28 | dm_get_con() 29 | \dontshow{\}) # examplesIf} 30 | } 31 | -------------------------------------------------------------------------------- /man/dm_get_pk.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/primary-keys.R 3 | \name{dm_get_pk} 4 | \alias{dm_get_pk} 5 | \title{Primary key column names} 6 | \usage{ 7 | dm_get_pk(dm, table, ...) 8 | } 9 | \description{ 10 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 11 | 12 | This function is deprecated because of its limited use 13 | and its unintuitive return value. 14 | Use \code{\link[=dm_get_all_pks]{dm_get_all_pks()}} instead. 15 | } 16 | \keyword{internal} 17 | -------------------------------------------------------------------------------- /man/dm_gui.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dm_gui.R 3 | \name{dm_gui} 4 | \alias{dm_gui} 5 | \title{Shiny app for defining dm objects} 6 | \usage{ 7 | dm_gui(..., dm = NULL, select_tables = TRUE, debug = FALSE) 8 | } 9 | \arguments{ 10 | \item{...}{These dots are for future extensions and must be empty.} 11 | 12 | \item{dm}{An initial dm object, currently required.} 13 | 14 | \item{select_tables}{Show selectize input to select tables?} 15 | 16 | \item{debug}{Set to \code{TRUE} to simplify debugging of the app.} 17 | } 18 | \description{ 19 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 20 | 21 | This function starts a Shiny application that allows to define \code{dm} objects 22 | from a database or from local data frames. 23 | The application generates R code that can be inserted or copy-pasted 24 | into an R script or function. 25 | } 26 | \details{ 27 | In a future release, the app will also allow composing \code{dm} objects directly 28 | from database connections or data frames. 29 | 30 | The signature of this function is subject to change without notice. 31 | This should not pose too many problems, because it will usually be run 32 | interactively. 33 | } 34 | \examples{ 35 | \dontrun{ 36 | dm <- dm_nycflights13(cycle = TRUE) 37 | dm_gui(dm = dm) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /man/dm_has_fk.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/foreign-keys.R 3 | \name{dm_has_fk} 4 | \alias{dm_has_fk} 5 | \alias{dm_get_fk} 6 | \title{Check if foreign keys exists} 7 | \usage{ 8 | dm_has_fk(dm, table, ref_table, ...) 9 | 10 | dm_get_fk(dm, table, ref_table, ...) 11 | } 12 | \arguments{ 13 | \item{dm}{A \code{dm} object.} 14 | 15 | \item{table}{A table in the \code{dm}.} 16 | 17 | \item{ref_table}{The table which \code{table} will be referencing.} 18 | 19 | \item{...}{These dots are for future extensions and must be empty.} 20 | } 21 | \description{ 22 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 23 | 24 | These functions are deprecated because of their limited use 25 | since the introduction of foreign keys to arbitrary columns in dm 0.2.1. 26 | Use \code{\link[=dm_get_all_fks]{dm_get_all_fks()}} with table manipulation functions instead. 27 | } 28 | \keyword{internal} 29 | -------------------------------------------------------------------------------- /man/dm_has_pk.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/primary-keys.R 3 | \name{dm_has_pk} 4 | \alias{dm_has_pk} 5 | \title{Check for primary key} 6 | \usage{ 7 | dm_has_pk(dm, table, ...) 8 | } 9 | \arguments{ 10 | \item{dm}{A \code{dm} object.} 11 | 12 | \item{table}{A table in the \code{dm}.} 13 | 14 | \item{...}{These dots are for future extensions and must be empty.} 15 | } 16 | \value{ 17 | A logical value: \code{TRUE} if the given table has a primary key, \code{FALSE} otherwise. 18 | } 19 | \description{ 20 | \code{dm_has_pk()} checks if a given table has columns marked as its primary key. 21 | } 22 | \examples{ 23 | \dontshow{if (rlang::is_installed("nycflights13")) withAutoprint(\{ # examplesIf} 24 | dm_nycflights13() \%>\% 25 | dm_has_pk(flights) 26 | dm_nycflights13() \%>\% 27 | dm_has_pk(planes) 28 | \dontshow{\}) # examplesIf} 29 | } 30 | \seealso{ 31 | Other primary key functions: 32 | \code{\link{dm_add_pk}()}, 33 | \code{\link{dm_add_uk}()}, 34 | \code{\link{dm_get_all_pks}()}, 35 | \code{\link{dm_get_all_uks}()}, 36 | \code{\link{dm_rm_pk}()}, 37 | \code{\link{dm_rm_uk}()}, 38 | \code{\link{enum_pk_candidates}()} 39 | } 40 | \concept{primary key functions} 41 | -------------------------------------------------------------------------------- /man/dm_mutate_tbl.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/add-tbl.R 3 | \name{dm_mutate_tbl} 4 | \alias{dm_mutate_tbl} 5 | \title{Update tables in a \code{\link{dm}}} 6 | \usage{ 7 | dm_mutate_tbl(dm, ...) 8 | } 9 | \arguments{ 10 | \item{dm}{A \code{\link{dm}} object.} 11 | 12 | \item{...}{One or more tables to update in the \code{dm}. 13 | Must be named.} 14 | } 15 | \description{ 16 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 17 | 18 | Updates one or more existing tables in a \code{\link{dm}}. 19 | For now, the column names must be identical. 20 | This restriction may be levied optionally in the future. 21 | } 22 | \examples{ 23 | \dontshow{if (rlang::is_installed("nycflights13")) withAutoprint(\{ # examplesIf} 24 | dm_nycflights13() \%>\% 25 | dm_mutate_tbl(flights = nycflights13::flights[1:3, ]) 26 | \dontshow{\}) # examplesIf} 27 | } 28 | \seealso{ 29 | \code{\link[=dm]{dm()}}, \code{\link[=dm_select_tbl]{dm_select_tbl()}} 30 | } 31 | -------------------------------------------------------------------------------- /man/dm_nest_tbl.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dm_nest_tbl.R 3 | \name{dm_nest_tbl} 4 | \alias{dm_nest_tbl} 5 | \title{Nest a table inside its dm} 6 | \usage{ 7 | dm_nest_tbl(dm, child_table, into = NULL) 8 | } 9 | \arguments{ 10 | \item{dm}{A dm.} 11 | 12 | \item{child_table}{A terminal table with one parent table.} 13 | 14 | \item{into}{The table to nest \code{child_tables} into, optional as it can be guessed 15 | from the foreign keys unambiguously but useful to be explicit.} 16 | } 17 | \description{ 18 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 19 | 20 | \code{dm_nest_tbl()} converts a child table to a nested column in its parent 21 | table. 22 | The child table should not have children itself (i.e. it needs to be a 23 | \emph{terminal child table}). 24 | } 25 | \examples{ 26 | nested_dm <- 27 | dm_nycflights13() \%>\% 28 | dm_select_tbl(airlines, flights) \%>\% 29 | dm_nest_tbl(flights) 30 | 31 | nested_dm 32 | 33 | nested_dm$airlines 34 | } 35 | \seealso{ 36 | \code{\link[=dm_wrap_tbl]{dm_wrap_tbl()}}, \code{\link[=dm_unwrap_tbl]{dm_unwrap_tbl()}}, \code{\link[=dm_pack_tbl]{dm_pack_tbl()}} 37 | } 38 | -------------------------------------------------------------------------------- /man/dm_nrow.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/filter-helpers.R 3 | \name{dm_nrow} 4 | \alias{dm_nrow} 5 | \title{Number of rows} 6 | \usage{ 7 | dm_nrow(dm) 8 | } 9 | \arguments{ 10 | \item{dm}{A \code{\link{dm}} object.} 11 | } 12 | \value{ 13 | A named vector with the number of rows for each table. 14 | } 15 | \description{ 16 | Returns a named vector with the number of rows for each table. 17 | } 18 | \examples{ 19 | \dontshow{if (rlang::is_installed("nycflights13")) withAutoprint(\{ # examplesIf} 20 | dm_nycflights13() \%>\% 21 | dm_filter(airports = (faa \%in\% c("EWR", "LGA"))) \%>\% 22 | dm_nrow() 23 | \dontshow{\}) # examplesIf} 24 | } 25 | -------------------------------------------------------------------------------- /man/dm_pack_tbl.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dm_nest_tbl.R 3 | \name{dm_pack_tbl} 4 | \alias{dm_pack_tbl} 5 | \title{dm_pack_tbl()} 6 | \usage{ 7 | dm_pack_tbl(dm, parent_table, into = NULL) 8 | } 9 | \arguments{ 10 | \item{dm}{A dm.} 11 | 12 | \item{parent_table}{A terminal table with one child table.} 13 | 14 | \item{into}{The table to pack \code{parent_tables} into, optional as it can be guessed 15 | from the foreign keys unambiguously but useful to be explicit.} 16 | } 17 | \description{ 18 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 19 | 20 | \code{dm_pack_tbl()} converts a parent table to a packed column in its child 21 | table. 22 | The parent table should not have parent tables itself (i.e. it needs to be a 23 | \emph{terminal parent table}). 24 | } 25 | \examples{ 26 | dm_packed <- 27 | dm_nycflights13() \%>\% 28 | dm_pack_tbl(planes) 29 | 30 | dm_packed 31 | 32 | dm_packed$flights 33 | 34 | dm_packed$flights$planes 35 | } 36 | \seealso{ 37 | \code{\link[=dm_wrap_tbl]{dm_wrap_tbl()}}, \code{\link[=dm_unwrap_tbl]{dm_unwrap_tbl()}}, \code{\link[=dm_nest_tbl]{dm_nest_tbl()}}. 38 | } 39 | -------------------------------------------------------------------------------- /man/dm_pixarfilms.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pixarfilms.R 3 | \name{dm_pixarfilms} 4 | \alias{dm_pixarfilms} 5 | \title{Creates a dm object for the \pkg{pixarfilms} data} 6 | \usage{ 7 | dm_pixarfilms(..., color = TRUE, consistent = FALSE) 8 | } 9 | \arguments{ 10 | \item{...}{These dots are for future extensions and must be empty.} 11 | 12 | \item{color}{Boolean, if \code{TRUE} (default), the resulting \code{dm} object will 13 | have colors assigned to different tables for visualization with 14 | \code{dm_draw()}.} 15 | 16 | \item{consistent}{Boolean, In the original \code{dm} the \code{film} column in 17 | \code{pixar_films} contains missing values so cannot be made a proper primary key. 18 | Set to \code{TRUE} to remove those records.} 19 | } 20 | \value{ 21 | A \code{dm} object consisting of \pkg{pixarfilms} tables, complete with 22 | primary and foreign keys and optionally colored. 23 | } 24 | \description{ 25 | Creates an example \code{\link{dm}} object from the tables in 26 | \pkg{pixarfilms}, along with the references. 27 | } 28 | \examples{ 29 | \dontshow{if (rlang::is_installed(c("pixarfilms", "DiagrammeR"))) withAutoprint(\{ # examplesIf} 30 | dm_pixarfilms() 31 | dm_pixarfilms() \%>\% 32 | dm_draw() 33 | \dontshow{\}) # examplesIf} 34 | } 35 | -------------------------------------------------------------------------------- /man/dm_ptype.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ptype.R 3 | \name{dm_ptype} 4 | \alias{dm_ptype} 5 | \title{Prototype for a dm object} 6 | \usage{ 7 | dm_ptype(dm) 8 | } 9 | \arguments{ 10 | \item{dm}{A \code{dm} object.} 11 | } 12 | \description{ 13 | The prototype contains all tables, all primary and foreign keys, 14 | but no data. 15 | All tables are truncated and converted to zero-row tibbles, 16 | also for remote data models. 17 | Columns retain their type. 18 | This is useful for performing creation and population of a database 19 | in separate steps. 20 | } 21 | \examples{ 22 | \dontshow{if (dm:::dm_has_financial()) withAutoprint(\{ # examplesIf} 23 | dm_financial() \%>\% 24 | dm_ptype() 25 | 26 | dm_financial() \%>\% 27 | dm_ptype() \%>\% 28 | dm_nrow() 29 | \dontshow{\}) # examplesIf} 30 | } 31 | -------------------------------------------------------------------------------- /man/dm_rm_uk.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/unique-keys.R 3 | \name{dm_rm_uk} 4 | \alias{dm_rm_uk} 5 | \title{Remove a unique key} 6 | \usage{ 7 | dm_rm_uk(dm, table = NULL, columns = NULL, ...) 8 | } 9 | \arguments{ 10 | \item{dm}{A \code{dm} object.} 11 | 12 | \item{table}{A table in the \code{dm}. 13 | Pass \code{NULL} to remove all matching keys.} 14 | 15 | \item{columns}{Table columns, unquoted. 16 | To refer to a compound key, use \code{c(col1, col2)}. 17 | Pass \code{NULL} (the default) to remove all matching keys.} 18 | 19 | \item{...}{These dots are for future extensions and must be empty.} 20 | } 21 | \value{ 22 | An updated \code{dm} without the indicated unique key(s). 23 | } 24 | \description{ 25 | \code{dm_rm_uk()} removes one or more unique keys from a table and leaves the \code{\link{dm}} object otherwise unaltered. 26 | An error is thrown if no unique key matches the selection criteria. 27 | If the selection criteria are ambiguous, a message with unambiguous replacement code is shown. 28 | Foreign keys are never removed. 29 | } 30 | \seealso{ 31 | Other primary key functions: 32 | \code{\link{dm_add_pk}()}, 33 | \code{\link{dm_add_uk}()}, 34 | \code{\link{dm_get_all_pks}()}, 35 | \code{\link{dm_get_all_uks}()}, 36 | \code{\link{dm_has_pk}()}, 37 | \code{\link{dm_rm_pk}()}, 38 | \code{\link{enum_pk_candidates}()} 39 | } 40 | \concept{primary key functions} 41 | -------------------------------------------------------------------------------- /man/dm_select_tbl.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/select-tbl.R 3 | \name{dm_select_tbl} 4 | \alias{dm_select_tbl} 5 | \alias{dm_rename_tbl} 6 | \title{Select and rename tables} 7 | \usage{ 8 | dm_select_tbl(dm, ...) 9 | 10 | dm_rename_tbl(dm, ...) 11 | } 12 | \arguments{ 13 | \item{dm}{A \code{\link{dm}} object.} 14 | 15 | \item{...}{One or more table names of the tables of the \code{\link{dm}} object. 16 | \code{tidyselect} is supported, see \code{\link[dplyr:select]{dplyr::select()}} for details on the semantics.} 17 | } 18 | \value{ 19 | The input \code{dm} with tables renamed or removed. 20 | } 21 | \description{ 22 | \code{dm_select_tbl()} keeps the selected tables and their relationships, 23 | optionally renaming them. 24 | 25 | \code{dm_rename_tbl()} renames tables. 26 | } 27 | \examples{ 28 | \dontshow{if (rlang::is_installed("nycflights13")) withAutoprint(\{ # examplesIf} 29 | dm_nycflights13() \%>\% 30 | dm_select_tbl(airports, fl = flights) 31 | \dontshow{\}) # examplesIf} 32 | \dontshow{if (rlang::is_installed("nycflights13")) withAutoprint(\{ # examplesIf} 33 | dm_nycflights13() \%>\% 34 | dm_rename_tbl(ap = airports, fl = flights) 35 | \dontshow{\}) # examplesIf} 36 | } 37 | -------------------------------------------------------------------------------- /man/dm_validate.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/validate.R 3 | \name{dm_validate} 4 | \alias{dm_validate} 5 | \title{Validator} 6 | \usage{ 7 | dm_validate(x) 8 | } 9 | \arguments{ 10 | \item{x}{An object.} 11 | } 12 | \value{ 13 | Returns the \code{dm}, invisibly, after finishing all checks. 14 | } 15 | \description{ 16 | \code{dm_validate()} checks the internal consistency of a \code{dm} object. 17 | } 18 | \details{ 19 | In theory, with the exception of \code{\link[=new_dm]{new_dm()}}, all \code{dm} objects 20 | created or modified by functions in this package should be valid, 21 | and this function should not be needed. 22 | Please file an issue if any dm operation creates an invalid object. 23 | } 24 | \examples{ 25 | dm_validate(dm()) 26 | 27 | bad_dm <- structure(list(bad = "dm"), class = "dm") 28 | try(dm_validate(bad_dm)) 29 | } 30 | -------------------------------------------------------------------------------- /man/figures/cynkra-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/man/figures/cynkra-72.png -------------------------------------------------------------------------------- /man/figures/energie-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/man/figures/energie-72.png -------------------------------------------------------------------------------- /man/figures/lifecycle-archived.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclearchivedarchived -------------------------------------------------------------------------------- /man/figures/lifecycle-defunct.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycledefunctdefunct -------------------------------------------------------------------------------- /man/figures/lifecycle-deprecated.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycledeprecateddeprecated -------------------------------------------------------------------------------- /man/figures/lifecycle-experimental.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycleexperimentalexperimental -------------------------------------------------------------------------------- /man/figures/lifecycle-maturing.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclematuringmaturing -------------------------------------------------------------------------------- /man/figures/lifecycle-questioning.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclequestioningquestioning -------------------------------------------------------------------------------- /man/figures/lifecycle-soft-deprecated.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclesoft-deprecatedsoft-deprecated -------------------------------------------------------------------------------- /man/figures/lifecycle-stable.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclestablestable -------------------------------------------------------------------------------- /man/figures/lifecycle-superseded.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclesupersededsuperseded -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/man/figures/logo.png -------------------------------------------------------------------------------- /man/glimpse.dm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dm.R 3 | \name{glimpse.dm} 4 | \alias{glimpse.dm} 5 | \alias{glimpse.dm_zoomed} 6 | \title{Get a glimpse of your \code{dm} object} 7 | \usage{ 8 | \method{glimpse}{dm}(x, width = NULL, ...) 9 | 10 | \method{glimpse}{dm_zoomed}(x, width = NULL, ...) 11 | } 12 | \arguments{ 13 | \item{x}{A \code{dm} object.} 14 | 15 | \item{width}{Controls the maximum number of columns on a line used in 16 | printing. If \code{NULL}, \code{getOption("width")} will be consulted.} 17 | 18 | \item{...}{Passed to \code{\link[pillar:glimpse]{pillar::glimpse()}}.} 19 | } 20 | \description{ 21 | \code{glimpse()} provides an overview (dimensions, column data types, primary 22 | keys, etc.) of all tables included in the \code{dm} object. It will additionally 23 | print details about outgoing foreign keys for the child table. 24 | 25 | \code{glimpse()} is provided by the pillar package, and re-exported by \pkg{dm}. 26 | See \code{\link[pillar:glimpse]{pillar::glimpse()}} for more details. 27 | } 28 | \examples{ 29 | 30 | dm_nycflights13() \%>\% glimpse() 31 | 32 | dm_nycflights13() \%>\% 33 | dm_zoom_to(flights) \%>\% 34 | glimpse() 35 | 36 | } 37 | -------------------------------------------------------------------------------- /man/json_nest.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/json_nest.R 3 | \name{json_nest} 4 | \alias{json_nest} 5 | \title{JSON nest} 6 | \usage{ 7 | json_nest(.data, ..., .names_sep = NULL) 8 | } 9 | \arguments{ 10 | \item{.data}{A data frame, a data frame extension (e.g. a tibble), or a lazy data frame (e.g. from dbplyr or dtplyr).} 11 | 12 | \item{...}{<\code{\link[tidyr:tidyr_tidy_select]{tidy-select}}> Columns to pack, specified 13 | using name-variable pairs of the form \code{new_col = c(col1, col2, col3)}. 14 | The right hand side can be any valid tidy select expression.} 15 | 16 | \item{.names_sep}{If \code{NULL}, the default, the names will be left as is.} 17 | } 18 | \description{ 19 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 20 | 21 | A wrapper around \code{\link[tidyr:nest]{tidyr::nest()}} which stores the nested data into JSON columns. 22 | } 23 | \examples{ 24 | df <- tibble::tibble(x = c(1, 1, 1, 2, 2, 3), y = 1:6, z = 6:1) 25 | nested <- json_nest(df, data = c(y, z)) 26 | nested 27 | } 28 | \seealso{ 29 | \code{\link[tidyr:nest]{tidyr::nest()}}, \code{\link[=json_nest_join]{json_nest_join()}} 30 | } 31 | -------------------------------------------------------------------------------- /man/json_pack.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/json_pack.R 3 | \name{json_pack} 4 | \alias{json_pack} 5 | \title{JSON pack} 6 | \usage{ 7 | json_pack(.data, ..., .names_sep = NULL) 8 | } 9 | \arguments{ 10 | \item{.data}{A data frame, a data frame extension (e.g. a tibble), or a lazy data frame (e.g. from dbplyr or dtplyr).} 11 | 12 | \item{...}{<\code{\link[tidyr:tidyr_tidy_select]{tidy-select}}> Columns to pack, specified 13 | using name-variable pairs of the form \code{new_col = c(col1, col2, col3)}. 14 | The right hand side can be any valid tidy select expression.} 15 | 16 | \item{.names_sep}{If \code{NULL}, the default, the names will be left as is.} 17 | } 18 | \description{ 19 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 20 | 21 | A wrapper around \code{\link[tidyr:pack]{tidyr::pack()}} which stores the packed data into JSON columns. 22 | } 23 | \examples{ 24 | df <- tibble::tibble(x1 = 1:3, x2 = 4:6, x3 = 7:9, y = 1:3) 25 | packed <- json_pack(df, x = c(x1, x2, x3), y = y) 26 | packed 27 | } 28 | \seealso{ 29 | \code{\link[tidyr:pack]{tidyr::pack()}}, \code{\link[=json_pack_join]{json_pack_join()}} 30 | } 31 | -------------------------------------------------------------------------------- /pkgdown/assets/reference/figures/cynkra-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/pkgdown/assets/reference/figures/cynkra-72.png -------------------------------------------------------------------------------- /pkgdown/assets/reference/figures/energie-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/pkgdown/assets/reference/figures/energie-72.png -------------------------------------------------------------------------------- /pkgdown/extra.css: -------------------------------------------------------------------------------- 1 | .cheatsheet-svg { 2 | width: 50%; 3 | } 4 | 5 | .cheatsheet-div { 6 | display: flex; 7 | } 8 | 9 | .cheatsheet-div { 10 | display: flex; 11 | margin-top: 20px; 12 | } 13 | 14 | .cheatsheet-caption { 15 | margin-left: 10px; 16 | width: 50%; 17 | margin-right: 10px; 18 | } 19 | 20 | .cheatsheet-caption pre { 21 | height: fit-content; 22 | } 23 | 24 | 25 | .cheatsheet-icon { 26 | display: none; 27 | } 28 | -------------------------------------------------------------------------------- /pkgdown/favicon/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/pkgdown/favicon/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/pkgdown/favicon/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/pkgdown/favicon/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/pkgdown/favicon/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/pkgdown/favicon/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/pkgdown/favicon/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/pkgdown/favicon/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/pkgdown/favicon/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/pkgdown/favicon/favicon/favicon.ico -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "local>cynkra/renovate-config" 5 | ], 6 | "automerge": "false" 7 | } 8 | -------------------------------------------------------------------------------- /revdep/.gitignore: -------------------------------------------------------------------------------- 1 | cloud.noindex 2 | -------------------------------------------------------------------------------- /scratch/clean.R: -------------------------------------------------------------------------------- 1 | library(tidyverse) 2 | library(dm) 3 | 4 | library(rlang) 5 | 6 | dm <- dm_nycflights13() 7 | dm %>% dm_draw() 8 | 9 | create_exist <- function(dm, child, parent) { 10 | child <- ensym(child) 11 | parent <- ensym(parent) 12 | parent.exist <- sym(paste0(as.character(parent), ".exist")) 13 | pk_col <- sym(dm_get_pk(dm, !!parent)) 14 | 15 | dm %>% 16 | dm_zoom_to(!!parent) %>% 17 | mutate(!!parent.exist := 1L) %>% 18 | dm_update_zoomed() %>% 19 | dm_zoom_to(!!child) %>% 20 | left_join(!!parent, select = c(!!pk_col, !!parent.exist)) %>% 21 | mutate(!!parent.exist := coalesce(!!parent.exist, 0L)) %>% 22 | dm_update_zoomed() %>% 23 | dm_zoom_to(!!parent) %>% 24 | select(-!!parent.exist) %>% 25 | dm_update_zoomed() 26 | } 27 | 28 | dm %>% 29 | create_exist(flights, airlines) %>% 30 | create_exist(flights, planes) %>% 31 | create_exist(flights, airports) 32 | -------------------------------------------------------------------------------- /scratch/code_generation_examples.R: -------------------------------------------------------------------------------- 1 | library(tidyverse) 2 | devtools::load_all() 3 | 4 | # using an input object provided by user: 5 | inp_obj <- quo(dm_nycflights13()) 6 | cg_block <- new_cg_block(cg_input_object = inp_obj) 7 | 8 | # evaluation of object: 9 | cg_block %>% 10 | cg_eval_block() 11 | 12 | # visualisation of object: 13 | cg_block %>% 14 | cg_eval_block() %>% 15 | dm_draw() 16 | 17 | # Code Output in Shiny App: 18 | cg_block 19 | 20 | # user hits add table mtcars: 21 | cg_block_2 <- 22 | cg_block %>% 23 | cg_add_call(dm_add_tbl(., mtcars)) 24 | 25 | # evaluation of object: 26 | cg_block_2 %>% 27 | cg_eval_block() 28 | 29 | # visualisation of object: 30 | cg_block_2 %>% 31 | cg_eval_block() %>% 32 | dm_draw() 33 | 34 | # Code Output in Shiny App: 35 | cg_block_2 36 | 37 | # user adds a primary key for table mtcars: 38 | cg_block_3 <- 39 | cg_block_2 %>% 40 | cg_add_call(dm_add_pk(., mtcars, c(mpg, wt))) 41 | 42 | # evaluation of object: 43 | cg_block_3 %>% 44 | cg_eval_block() 45 | 46 | # visualisation of object: 47 | cg_block_3 %>% 48 | cg_eval_block() %>% 49 | dm_draw() 50 | 51 | # Code Output in Shiny App: 52 | cg_block_3 53 | 54 | # user hits undo last action: FIXME: probably need a function for this 55 | cg_block_4 <- cg_block_3 56 | cg_block_4$cg_f_list <- cg_block_4$cg_f_list[-length(cg_block_4$cg_f_list)] 57 | 58 | # visualisation of object: 59 | cg_block_4 %>% 60 | cg_eval_block() %>% 61 | dm_draw() 62 | 63 | # Code Output in Shiny App: 64 | cg_block_4 65 | -------------------------------------------------------------------------------- /scratch/code_generation_middleware.R: -------------------------------------------------------------------------------- 1 | library(tidyverse) 2 | library(rlang) 3 | devtools::load_all() 4 | 5 | parent <- tibble(a = c(1L, 1:3), b = -1) 6 | child <- tibble(a = 1:4, c = 3) 7 | 8 | dm <- dm(parent, child) 9 | 10 | # This is done by the Shiny app 11 | ops <- enum_ops(dm) 12 | ops 13 | 14 | enum_ops(dm, op_name = "dm_add_pk") 15 | enum_ops(dm, op_name = "dm_add_pk", table_names = "parent") 16 | 17 | final_ops <- enum_ops(dm, op_name = "dm_add_pk", table_names = "parent", column_names = "a") 18 | final_ops 19 | 20 | cg_block <- new_cg_block(quo(dm)) 21 | 22 | cg_block %>% 23 | cg_add_call(!!final_ops$call) 24 | 25 | cg_block %>% 26 | cg_add_call(!!final_ops$call) %>% 27 | cg_eval_block() 28 | -------------------------------------------------------------------------------- /scratch/demo-deconstruct.R: -------------------------------------------------------------------------------- 1 | # pkgload::load_all() 2 | library(dm) 3 | library(dplyr) 4 | 5 | dm <- dm_nycflights13() 6 | 7 | dm %>% 8 | dm_draw() 9 | 10 | tbls <- 11 | dm %>% 12 | dm_get_tables(keyed = TRUE) 13 | 14 | flights <- tbls$flights 15 | airports <- tbls$airports 16 | 17 | flights 18 | airports 19 | 20 | flights %>% 21 | left_join(airports) 22 | 23 | by_origin <- 24 | flights %>% 25 | group_by(origin) %>% 26 | summarize(n = n()) %>% 27 | ungroup() 28 | 29 | by_origin 30 | 31 | result_dm <- dm(flights, airports, by_origin) 32 | result_dm %>% 33 | dm_draw() 34 | -------------------------------------------------------------------------------- /scratch/demo-gui-0.R: -------------------------------------------------------------------------------- 1 | library(dm) 2 | 3 | dm <- dmSVG:::get_dm("AdventureWorks2014") 4 | 5 | con <- DBI::dbConnect(RPostgres::Postgres()) 6 | 7 | DBI::dbExecute(con, "CREATE SCHEMA av2014") 8 | 9 | copy_dm_to(con, dm, schema = "av2014", temporary = FALSE) 10 | -------------------------------------------------------------------------------- /scratch/demo-gui-1.R: -------------------------------------------------------------------------------- 1 | library(dm) 2 | 3 | con <- DBI::dbConnect(RPostgres::Postgres()) 4 | 5 | dm <- 6 | dm_from_con(con, schema = "av2014") 7 | dm_gui(dm = dm, select_tables = FALSE) 8 | -------------------------------------------------------------------------------- /scratch/demo-gui-2.R: -------------------------------------------------------------------------------- 1 | library(dm) 2 | library(nycflights13) 3 | 4 | dm <- dm(flights, airlines, airports, planes) 5 | dm_gui(dm = dm) 6 | -------------------------------------------------------------------------------- /scratch/demo-gui-3.R: -------------------------------------------------------------------------------- 1 | library(conflicted) 2 | library(dm) 3 | library(tidyverse) 4 | 5 | dm <- dm_nycflights13(cycle = TRUE) 6 | dm 7 | dm_deconstruct(dm) 8 | 9 | airlines <- pull_tbl(dm, "airlines", keyed = TRUE) 10 | airports <- pull_tbl(dm, "airports", keyed = TRUE) 11 | flights <- pull_tbl(dm, "flights", keyed = TRUE) 12 | planes <- pull_tbl(dm, "planes", keyed = TRUE) 13 | weather <- pull_tbl(dm, "weather", keyed = TRUE) 14 | 15 | dm(airlines, airports, flights, planes, weather) 16 | 17 | by_origin <- 18 | flights %>% 19 | group_by(origin) %>% 20 | summarize(n = n(), mean_arr_delay = mean(arr_delay)) %>% 21 | ungroup() 22 | 23 | dm(airlines, airports, flights, planes, weather, by_origin) %>% 24 | dm_draw() 25 | -------------------------------------------------------------------------------- /scratch/enum.R: -------------------------------------------------------------------------------- 1 | pkgload::load_all() 2 | dm_nycflights13() %>% dm_enum_fk_candidates(planes) 3 | -------------------------------------------------------------------------------- /scratch/filter.R: -------------------------------------------------------------------------------- 1 | dm_nyc_filtered <- 2 | dm_nycflights13() %>% 3 | dm_filter(airports, name == "John F Kennedy Intl") 4 | 5 | dm_apply_filters_to_tbl(dm_nyc_filtered, flights) 6 | 7 | dm_nycflights13() %>% 8 | dm_filter(airports, name == "John F Kennedy Intl") %>% 9 | dm_apply_filters() 10 | 11 | # If you want to keep only those rows in the parent tables 12 | # whose primary key values appear as foreign key values in 13 | # `flights`, you can set a `TRUE` filter in `flights`: 14 | dm_nycflights13() %>% 15 | dm_filter(flights, 1 == 1) %>% 16 | dm_applyp_filters() %>% 17 | dm_nrow() 18 | # note that in this example, the only affected table is 19 | # `airports` because the departure airports in `flights` are 20 | # only the three New York airports. 21 | 22 | dm_nycflights13() %>% 23 | dm_filter(flights, month == 3) %>% 24 | dm_apply_filters() 25 | 26 | dm_nycflights13() %>% 27 | dm_filter(planes, engine %in% c("Reciprocating", "4 Cycle")) %>% 28 | compute() 29 | dm_nycflights13() %>% 30 | dm_filter(flights, month == 3) %>% 31 | dm_apply_filters_to_tbl(planes) 32 | -------------------------------------------------------------------------------- /scratch/other_test.R: -------------------------------------------------------------------------------- 1 | d1 <- tibble::tibble(a = 1:5, b = letters[1:5]) 2 | d2 <- tibble::tibble(a = c(1,3:6), b = letters[1:5]) 3 | d3 <- tibble::tibble(c = 1:5) 4 | d4 <- tibble::tibble(c = c(1:5,5)) 5 | d5 <- tibble::tibble(a = 1:5) 6 | d6 <- tibble::tibble(c = 1:4) 7 | 8 | 9 | 10 | check_cardinality_0_n(d1, a, d2, a) 11 | check_cardinality_0_n(d1, a, d3, c) 12 | check_cardinality_1_n(d1, a, d3, c) 13 | check_cardinality_1_1(d1, a, d3, c) 14 | check_cardinality_1_1(d1, a, d4, c) 15 | check_cardinality_1_1(d4, c, d1, a) 16 | check_set_equality(d1, a, d3, c) 17 | check_cardinality_0_1(d1, a, d2, a) 18 | check_cardinality_0_1(d1, a, d4, c) 19 | check_cardinality_0_1(d4, c, d1, a) 20 | check_cardinality_0_n(d4, c, d5, a) 21 | check_cardinality_0_n(d5, a, d4, c) 22 | check_cardinality_1_1(d5, a, d4, c) 23 | check_cardinality_0_1(d5, a, d6, c) 24 | -------------------------------------------------------------------------------- /scratch/test.R: -------------------------------------------------------------------------------- 1 | library(tidyverse) 2 | library(dbplyr) 3 | pkgload::load_all() 4 | 5 | dm <- dm_nycflights13(cycle = FALSE) 6 | 7 | src <- src_sqlite(":memory:", create = TRUE) 8 | 9 | dm_sqlite <- dm_copy_to(src, dm) 10 | 11 | dm1 <- 12 | dm_sqlite %>% 13 | dm_filter(airports, faa == "EWR") 14 | 15 | dm1 %>% tbl_impl("airports") 16 | dm1 %>% tbl_impl("flights") 17 | dm1 %>% tbl_impl("weather") 18 | dm1 %>% tbl_impl("airlines") 19 | dm1 %>% tbl_impl("planes") 20 | 21 | dm1 %>% dm_get_tables() 22 | 23 | dm1 %>% dm_get_tables() %>% map(nrow) 24 | 25 | dm1 %>% tbl_impl("airports") %>% sql_render() 26 | dm1 %>% tbl_impl("flights") %>% sql_render() 27 | dm1 %>% tbl_impl("weather") %>% sql_render() 28 | dm1 %>% tbl_impl("airlines") %>% sql_render() 29 | dm1 %>% tbl_impl("planes") %>% sql_render() 30 | 31 | dm1 %>% tbl_impl("airports") %>% count() %>% explain() 32 | dm1 %>% tbl_impl("flights") %>% count() %>% explain() 33 | dm1 %>% tbl_impl("weather") %>% count() %>% explain() 34 | dm1 %>% tbl_impl("airlines") %>% count() %>% explain() 35 | dm1 %>% tbl_impl("planes") %>% count() %>% explain() 36 | 37 | dm1 %>% tbl_impl("airports") %>% count() 38 | dm1 %>% tbl_impl("flights") %>% count() 39 | dm1 %>% tbl_impl("weather") %>% count() 40 | dm1 %>% tbl_impl("airlines") %>% count() 41 | dm1 %>% tbl_impl("planes") %>% count() 42 | -------------------------------------------------------------------------------- /scratch/vendor-gui-back.R: -------------------------------------------------------------------------------- 1 | input <- fs::dir_ls("R", glob = "R/gui-*.R") 2 | 3 | new_names <- gsub("^gui-", "", fs::path_file(input)) 4 | new_paths <- fs::path("../dmSVG/R", new_names) 5 | fs::file_copy(input, new_paths, overwrite = TRUE) 6 | -------------------------------------------------------------------------------- /scratch/vendor-gui.R: -------------------------------------------------------------------------------- 1 | old <- fs::dir_ls("R", glob = "R/gui-*.R") 2 | fs::file_delete(old) 3 | 4 | input <- setdiff(fs::dir_ls("../dmSVG/R"), "../dmSVG/R/dmSVG-package.R") 5 | 6 | new_names <- paste0("gui-", fs::path_file(input)) 7 | new_paths <- fs::path("R", new_names) 8 | fs::file_copy(input, new_paths) 9 | 10 | if (fs::dir_exists("inst/htmlwidgets")) { 11 | fs::dir_delete("inst/htmlwidgets") 12 | } 13 | 14 | fs::dir_copy("../dmSVG/inst/htmlwidgets", "inst") 15 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | 3 | # Need to use qualified call, this is checked in helper-print.R 4 | testthat::test_check("dm") 5 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/autoincrement.md: -------------------------------------------------------------------------------- 1 | # autoincrement produces valid R code 2 | 3 | Code 4 | dm 5 | Output 6 | -- Metadata -------------------------------------------------------------------- 7 | Tables: `x`, `y` 8 | Columns: 5 9 | Primary keys: 2 10 | Foreign keys: 1 11 | 12 | # autoincrement produces valid SQL queries and R code - RSQLite 13 | 14 | Code 15 | df$sql_table 16 | Output 17 | CREATE TEMPORARY TABLE `x` ( 18 | `x_id` INTEGER, 19 | `x_data` TEXT, 20 | PRIMARY KEY (`x_id`) 21 | ) 22 | CREATE TEMPORARY TABLE `y` ( 23 | `y_id` INTEGER, 24 | `x_id` INTEGER, 25 | `y_data` TEXT, 26 | PRIMARY KEY (`y_id`), 27 | FOREIGN KEY (`x_id`) REFERENCES `x` (`x_id`) 28 | ) 29 | 30 | --- 31 | 32 | Code 33 | dm_paste(dm) 34 | Message 35 | dm::dm( 36 | x, 37 | y, 38 | ) %>% 39 | dm::dm_add_pk(x, x_id, autoincrement = TRUE) %>% 40 | dm::dm_add_pk(y, y_id) %>% 41 | dm::dm_add_fk(y, x_id, x) 42 | 43 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/datamodelr-code/weird.dot: -------------------------------------------------------------------------------- 1 | #data_model 2 | digraph { 3 | graph [rankdir=BT tooltip="Data Model" ] 4 | 5 | node [margin=0 fontcolor = "#444444" ] 6 | 7 | edge [color = "#555555", arrowsize = 1, ] 8 | 9 | pack=true 10 | packmode= "node" 11 | 12 | "a b" [id = "a b", label = < 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 |
a b 15 |
c d
>, shape = "plaintext"] 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/db-interface.md: -------------------------------------------------------------------------------- 1 | # copy_dm_to() rejects overwrite and types arguments 2 | 3 | Code 4 | copy_dm_to(my_test_src(), dm_for_filter(), overwrite = TRUE) 5 | Condition 6 | Error in `copy_dm_to()`: 7 | ! `...` must be empty. 8 | x Problematic argument: 9 | * overwrite = TRUE 10 | 11 | --- 12 | 13 | Code 14 | copy_dm_to(my_test_src(), dm_for_filter(), types = character()) 15 | Condition 16 | Error in `copy_dm_to()`: 17 | ! `...` must be empty. 18 | x Problematic argument: 19 | * types = character() 20 | 21 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/disambiguate.md: -------------------------------------------------------------------------------- 1 | # dm_disambiguate_cols() works as intended 2 | 3 | Code 4 | dm_for_flatten() %>% dm_disambiguate_cols() %>% dm_paste(options = c("select", 5 | "keys")) 6 | Message 7 | Renaming ambiguous columns: %>% 8 | dm_rename(fact, something.fact = something) %>% 9 | dm_rename(dim_1, something.dim_1 = something) %>% 10 | dm_rename(dim_2, something.dim_2 = something) %>% 11 | dm_rename(dim_3, something.dim_3 = something) %>% 12 | dm_rename(dim_4, something.dim_4 = something) 13 | dm::dm( 14 | fact, 15 | dim_1, 16 | dim_2, 17 | dim_3, 18 | dim_4, 19 | ) %>% 20 | dm::dm_select(fact, fact, dim_1_key_1, dim_1_key_2, dim_2_key, dim_3_key, dim_4_key, something.fact) %>% 21 | dm::dm_select(dim_1, dim_1_pk_1, dim_1_pk_2, something.dim_1) %>% 22 | dm::dm_select(dim_2, dim_2_pk, something.dim_2) %>% 23 | dm::dm_select(dim_3, dim_3_pk, something.dim_3) %>% 24 | dm::dm_select(dim_4, dim_4_pk, something.dim_4) %>% 25 | dm::dm_add_pk(dim_1, c(dim_1_pk_1, dim_1_pk_2)) %>% 26 | dm::dm_add_pk(dim_2, dim_2_pk) %>% 27 | dm::dm_add_pk(dim_3, dim_3_pk) %>% 28 | dm::dm_add_pk(dim_4, dim_4_pk) %>% 29 | dm::dm_add_fk(fact, c(dim_1_key_1, dim_1_key_2), dim_1) %>% 30 | dm::dm_add_fk(fact, dim_2_key, dim_2) %>% 31 | dm::dm_add_fk(fact, dim_3_key, dim_3) %>% 32 | dm::dm_add_fk(fact, dim_4_key, dim_4) 33 | 34 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/dm_deconstruct.md: -------------------------------------------------------------------------------- 1 | # snapshot test 2 | 3 | Code 4 | dm <- dm_nycflights13() 5 | dm_deconstruct(dm) 6 | Message 7 | airlines <- pull_tbl(dm, "airlines", keyed = TRUE) 8 | airports <- pull_tbl(dm, "airports", keyed = TRUE) 9 | flights <- pull_tbl(dm, "flights", keyed = TRUE) 10 | planes <- pull_tbl(dm, "planes", keyed = TRUE) 11 | weather <- pull_tbl(dm, "weather", keyed = TRUE) 12 | 13 | # non-syntactic names 14 | 15 | Code 16 | dm <- dm(`if` = tibble(a = 1), `a b` = tibble(b = 1)) 17 | dm_deconstruct(dm) 18 | Message 19 | `if` <- pull_tbl(dm, "if", keyed = TRUE) 20 | `a b` <- pull_tbl(dm, "a b", keyed = TRUE) 21 | 22 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/dm_pixarfilms.md: -------------------------------------------------------------------------------- 1 | # `dm_pixarfilms()` works 2 | 3 | Code 4 | dm_examine_constraints(dm_pixarfilms(consistent = FALSE)) 5 | Message 6 | ! Unsatisfied constraints: 7 | Output 8 | * Table `pixar_films`: primary key `film`: has 1 missing values 9 | 10 | --- 11 | 12 | Code 13 | dm_examine_constraints(dm_pixarfilms(consistent = TRUE)) 14 | Message 15 | i All constraints satisfied. 16 | 17 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/draw-dm/single-empty-table-dm.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | %0 11 | 12 | 13 | 14 | 15 | 16 | 17 | a 18 | 19 | a 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/format.md: -------------------------------------------------------------------------------- 1 | # output 2 | 3 | Code 4 | commas(character()) 5 | Output 6 | 7 | Code 8 | commas(letters[1]) 9 | Output 10 | a 11 | Code 12 | commas(letters[1:2]) 13 | Output 14 | a, b 15 | Code 16 | commas(letters[1:3]) 17 | Output 18 | a, b, c 19 | Code 20 | commas(letters[seq_len(MAX_COMMAS - 1)]) 21 | Output 22 | a, b, c, d, e 23 | Code 24 | commas(letters[seq_len(MAX_COMMAS)]) 25 | Output 26 | a, b, c, d, e, f 27 | Code 28 | commas(letters[seq_len(MAX_COMMAS + 1)]) 29 | Output 30 | a, b, c, d, e, ... (7 total) 31 | Code 32 | commas(letters[1:4], max_commas = 3) 33 | Output 34 | a, b, ... (4 total) 35 | Code 36 | commas(letters, capped = TRUE) 37 | Output 38 | a, b, c, d, e, ... 39 | Code 40 | commas(letters, fun = tick) 41 | Output 42 | `a`, `b`, `c`, `d`, `e`, ... (26 total) 43 | 44 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/graph.md: -------------------------------------------------------------------------------- 1 | # functions working with graphs do the right thing? 2 | 3 | Code 4 | attr(igraph::E(create_graph_from_dm(nyc_comp())), "vnames") 5 | Output 6 | [1] "airlines|flights" "airports|flights" "flights|planes" "flights|weather" 7 | 8 | # empty graph 9 | 10 | Code 11 | create_graph_from_dm(empty_dm()) 12 | Output 13 | IGRAPH UN-- 0 0 -- 14 | + attr: name (v/c) 15 | + edges (vertex names): 16 | Code 17 | create_graph_from_dm(dm(x = tibble(a = 1))) 18 | Output 19 | IGRAPH UN-- 1 0 -- 20 | + attr: name (v/c) 21 | + edges (vertex names): 22 | 23 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/json.md: -------------------------------------------------------------------------------- 1 | # json joins work 2 | 3 | Code 4 | packed <- json_pack_join(df1, df2, by = "key") 5 | packed 6 | Output 7 | # A tibble: 3 x 3 8 | col1 key df2 9 | 10 | 1 1 a 11 | 2 1 a 12 | 3 2 b 13 | Code 14 | packed$df2 15 | Output 16 | [[1]] 17 | [{"col2":3,"col3":"X"}] 18 | 19 | [[2]] 20 | [{"col2":4,"col3":"Y"}] 21 | 22 | [[3]] 23 | [{"col2":3.14159265358979,"col3":"Z"}] 24 | 25 | 26 | --- 27 | 28 | Code 29 | nested <- json_nest_join(df1, df2, by = "key") 30 | nested 31 | Output 32 | # A tibble: 2 x 3 33 | col1 key df2 34 | 35 | 1 1 a 36 | 2 2 b 37 | Code 38 | nested$df2 39 | Output 40 | [[1]] 41 | [{"col2":3,"col3":"X"},{"col2":4,"col3":"Y"}] 42 | 43 | [[2]] 44 | [{"col2":3.14159265358979,"col3":"Z"}] 45 | 46 | 47 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/json_nest.md: -------------------------------------------------------------------------------- 1 | # `json_nest()` and `json_unnest()` work 2 | 3 | Code 4 | df <- tibble::tibble(x = c(1, 1, 1, 2, 2, 3), y = 1:6, z = 6:1) 5 | nested <- json_nest(df, data = c(y, z)) 6 | nested 7 | Output 8 | # A tibble: 3 x 2 9 | x data 10 | 11 | 1 1 "[{\"y\":1,\"z\":6},{\"y\":2,\"z\":5},{\"y\":3,\"z\":4}]" 12 | 2 2 "[{\"y\":4,\"z\":3},{\"y\":5,\"z\":2}]" 13 | 3 3 "[{\"y\":6,\"z\":1}]" 14 | 15 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/json_pack.md: -------------------------------------------------------------------------------- 1 | # `json_pack()` works 2 | 3 | Code 4 | df <- tibble::tibble(x1 = 1:3, x2 = 4:6, x3 = 7:9, y = 1:3) 5 | packed <- json_pack(df, x = c(x1, x2, x3), y = y) 6 | packed 7 | Output 8 | # A tibble: 3 x 2 9 | x y 10 | 11 | 1 "{\"x1\":1,\"x2\":4,\"x3\":7}" "{\"y\":1}" 12 | 2 "{\"x1\":2,\"x2\":5,\"x3\":8}" "{\"y\":2}" 13 | 3 "{\"x1\":3,\"x2\":6,\"x3\":9}" "{\"y\":3}" 14 | 15 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/maria/flatten.md: -------------------------------------------------------------------------------- 1 | # `dm_flatten_to_tbl()` does the right things for 'inner_join()' 2 | 3 | Code 4 | out 5 | Output 6 | fact dim_1_key_1 dim_1_key_2 dim_2_key dim_3_key dim_4_key something.fact 7 | 8 | 1 acorn 14 N c X 7 1 9 | 2 blubber 13 M d W 8 2 10 | 3 cindere~ 12 L e V 9 3 11 | 4 depth 11 K f U 10 4 12 | 5 elysium 10 J g T 11 5 13 | 6 fantasy 9 I h S 12 6 14 | 7 gorgeous 8 H i R 13 7 15 | 8 halo 7 G j Q 14 8 16 | 9 ill-adv~ 6 F k P 15 9 17 | 10 jitter 5 E l O 16 10 18 | # i 4 more variables: something.dim_1 , something.dim_2 , 19 | # something.dim_3 , something.dim_4 20 | 21 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/mssql/flatten.md: -------------------------------------------------------------------------------- 1 | # `dm_flatten_to_tbl()` does the right things for 'inner_join()' 2 | 3 | Code 4 | out 5 | Output 6 | fact dim_1_key_1 dim_1_key_2 dim_2_key dim_3_key dim_4_key something.fact 7 | 8 | 1 acorn 14 N c X 7 1 9 | 2 blubber 13 M d W 8 2 10 | 3 cindere~ 12 L e V 9 3 11 | 4 depth 11 K f U 10 4 12 | 5 elysium 10 J g T 11 5 13 | 6 fantasy 9 I h S 12 6 14 | 7 gorgeous 8 H i R 13 7 15 | 8 halo 7 G j Q 14 8 16 | 9 ill-adv~ 6 F k P 15 9 17 | 10 jitter 5 E l O 16 10 18 | # i 4 more variables: something.dim_1 , something.dim_2 , 19 | # something.dim_3 , something.dim_4 20 | 21 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/mssql/json_pack.md: -------------------------------------------------------------------------------- 1 | # `json_pack()` works remotely 2 | 3 | Code 4 | query <- json_pack(remote, a = starts_with("a")) %>% dbplyr::sql_render() 5 | gsub("test_frame_[_0-9]+", "test_frame_...", query) 6 | Output 7 | SELECT "grp", (SELECT value FROM OPENJSON((SELECT "a_i", "a_j" FOR JSON PATH))) AS "a" FROM (SELECT * 8 | FROM "#test_frame_...") "*tmp*" 9 | Code 10 | json_pack(remote, a = starts_with("a")) 11 | Output 12 | grp a 13 | 14 | 1 1 "{\"a_i\":\"a\",\"a_j\":\"A\"}" 15 | 2 1 "{\"a_i\":\"b\",\"a_j\":\"B\"}" 16 | 3 2 "{\"a_i\":\"c\",\"a_j\":\"C\"}" 17 | 4 2 "{\"a_i\":\"d\",\"a_j\":\"D\"}" 18 | Code 19 | query <- json_pack(remote, a = starts_with("a"), .names_sep = "_") %>% dbplyr::sql_render() 20 | gsub("test_frame_[_0-9]+", "test_frame_...", query) 21 | Output 22 | SELECT "grp", (SELECT value FROM OPENJSON((SELECT "a_i" "i", "a_j" "j" FOR JSON PATH))) AS "a" FROM (SELECT * 23 | FROM "#test_frame_...") "*tmp*" 24 | Code 25 | json_pack(remote, a = starts_with("a"), .names_sep = "_") 26 | Output 27 | grp a 28 | 29 | 1 1 "{\"i\":\"a\",\"j\":\"A\"}" 30 | 2 1 "{\"i\":\"b\",\"j\":\"B\"}" 31 | 3 2 "{\"i\":\"c\",\"j\":\"C\"}" 32 | 4 2 "{\"i\":\"d\",\"j\":\"D\"}" 33 | 34 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/postgres/flatten.md: -------------------------------------------------------------------------------- 1 | # `dm_flatten_to_tbl()` does the right things for 'inner_join()' 2 | 3 | Code 4 | out 5 | Output 6 | fact dim_1_key_1 dim_1_key_2 dim_2_key dim_3_key dim_4_key something.fact 7 | 8 | 1 acorn 14 N c X 7 1 9 | 2 blubber 13 M d W 8 2 10 | 3 cindere~ 12 L e V 9 3 11 | 4 depth 11 K f U 10 4 12 | 5 elysium 10 J g T 11 5 13 | 6 fantasy 9 I h S 12 6 14 | 7 gorgeous 8 H i R 13 7 15 | 8 halo 7 G j Q 14 8 16 | 9 ill-adv~ 6 F k P 15 9 17 | 10 jitter 5 E l O 16 10 18 | # i 4 more variables: something.dim_1 , something.dim_2 , 19 | # something.dim_3 , something.dim_4 20 | 21 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/postgres/json_pack.md: -------------------------------------------------------------------------------- 1 | # `json_pack()` works remotely 2 | 3 | Code 4 | query <- json_pack(remote, a = starts_with("a")) %>% dbplyr::sql_render() 5 | gsub("test_frame_[_0-9]+", "test_frame_...", query) 6 | Output 7 | SELECT "grp", JSON_BUILD_OBJECT('a_i', "a_i", 'a_j', "a_j") AS "a" 8 | FROM "test_frame_..." 9 | Code 10 | json_pack(remote, a = starts_with("a")) 11 | Output 12 | grp a 13 | 14 | 1 1 {"a_i" : "a", "a_j" : "A"} 15 | 2 1 {"a_i" : "b", "a_j" : "B"} 16 | 3 2 {"a_i" : "c", "a_j" : "C"} 17 | 4 2 {"a_i" : "d", "a_j" : "D"} 18 | Code 19 | query <- json_pack(remote, a = starts_with("a"), .names_sep = "_") %>% dbplyr::sql_render() 20 | gsub("test_frame_[_0-9]+", "test_frame_...", query) 21 | Output 22 | SELECT "grp", JSON_BUILD_OBJECT('i', "a_i", 'j', "a_j") AS "a" 23 | FROM "test_frame_..." 24 | Code 25 | json_pack(remote, a = starts_with("a"), .names_sep = "_") 26 | Output 27 | grp a 28 | 29 | 1 1 {"i" : "a", "j" : "A"} 30 | 2 1 {"i" : "b", "j" : "B"} 31 | 3 2 {"i" : "c", "j" : "C"} 32 | 4 2 {"i" : "d", "j" : "D"} 33 | 34 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/select-tbl.md: -------------------------------------------------------------------------------- 1 | # dm_select_tbl() remembers all FKs 2 | 3 | Code 4 | dm_nycflights_small() %>% dm_add_fk(flights, origin, airports) %>% 5 | dm_select_tbl(airports, flights) %>% dm_paste() 6 | Message 7 | dm::dm( 8 | airports, 9 | flights, 10 | ) %>% 11 | dm::dm_add_pk(airports, faa) %>% 12 | dm::dm_add_fk(flights, dest, airports) %>% 13 | dm::dm_add_fk(flights, origin, airports) 14 | 15 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/sqlite/flatten.md: -------------------------------------------------------------------------------- 1 | # `dm_flatten_to_tbl()` does the right things for 'inner_join()' 2 | 3 | Code 4 | out 5 | Output 6 | fact dim_1_key_1 dim_1_key_2 dim_2_key dim_3_key dim_4_key something.fact 7 | 8 | 1 acorn 14 N c X 7 1 9 | 2 blubber 13 M d W 8 2 10 | 3 cindere~ 12 L e V 9 3 11 | 4 depth 11 K f U 10 4 12 | 5 elysium 10 J g T 11 5 13 | 6 fantasy 9 I h S 12 6 14 | 7 gorgeous 8 H i R 13 7 15 | 8 halo 7 G j Q 14 8 16 | 9 ill-adv~ 6 F k P 15 9 17 | 10 jitter 5 E l O 16 10 18 | # i 4 more variables: something.dim_1 , something.dim_2 , 19 | # something.dim_3 , something.dim_4 20 | 21 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/standalone-check_suggested.md: -------------------------------------------------------------------------------- 1 | # `check_suggested()` works 2 | 3 | Code 4 | check_suggested("rlang", "foo") 5 | Output 6 | [1] TRUE 7 | Code 8 | check_suggested("dm", "foo", use = NA) 9 | Output 10 | [1] FALSE 11 | Code 12 | check_suggested("iurtnkjvmomweicopbt", "foo", use = NA) 13 | Output 14 | [1] FALSE 15 | Code 16 | check_suggested("iurtnkjvmomweicopbt", use = NA) 17 | Output 18 | [1] FALSE 19 | Code 20 | check_suggested("dm", "foo", use = FALSE) 21 | Output 22 | [1] FALSE 23 | Code 24 | check_suggested("iurtnkjvmomweicopbt", "foo", use = FALSE) 25 | Output 26 | [1] FALSE 27 | Code 28 | check_suggested("iurtnkjvmomweicopbt", use = FALSE) 29 | Output 30 | [1] FALSE 31 | 32 | # `check_suggested()` works for error messages 33 | 34 | Code 35 | check_suggested("iurtnkjvmomweicopbt", "foo") 36 | Condition 37 | Error: 38 | ! The package "iurtnkjvmomweicopbt" is required to use `foo()`. 39 | 40 | --- 41 | 42 | Code 43 | check_suggested(c("iurtnkjvmomweicopbt (>= 0.5)", "xxx", "cli"), "foo", use = NA) 44 | Message 45 | `foo()` is improved by the "iurtnkjvmomweicopbt (>= 0.5)" and "xxx" packages. Consider installing them. 46 | Output 47 | [1] FALSE 48 | 49 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/testthat-legacy/draw-dm.md: -------------------------------------------------------------------------------- 1 | # `dm_set_colors()` works 2 | 3 | Code 4 | dm_nycflights_small() %>% dm_set_colors(blue = "flights", green = "airports") %>% 5 | dm_get_colors() 6 | Output 7 | default #00FF00FF #0000FFFF default default 8 | "airlines" "airports" "flights" "planes" "weather" 9 | 10 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/testthat-new/draw-dm.md: -------------------------------------------------------------------------------- 1 | # `dm_set_colors()` works 2 | 3 | Code 4 | dm_nycflights_small() %>% dm_set_colors(!!!colset) %>% dm_get_colors() 5 | Output 6 | default #00FF00FF #0000FFFF default default 7 | "airlines" "airports" "flights" "planes" "weather" 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/tidyselect.md: -------------------------------------------------------------------------------- 1 | # output 2 | 3 | Code 4 | dm_for_filter() %>% dm_select_tbl(tf_7) 5 | Condition 6 | Error in `eval_select_indices()`: 7 | ! Can't subset tables that don't exist. 8 | x Table `tf_7` doesn't exist. 9 | Code 10 | dm_for_filter() %>% dm_rename_tbl(tf_0 = tf_7) 11 | Condition 12 | Error in `eval_rename_indices()`: 13 | ! Can't rename tables that don't exist. 14 | x Table `tf_7` doesn't exist. 15 | 16 | -------------------------------------------------------------------------------- /tests/testthat/dm/v1.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/tests/testthat/dm/v1.rds -------------------------------------------------------------------------------- /tests/testthat/dm/v1_zoomed.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/tests/testthat/dm/v1_zoomed.rds -------------------------------------------------------------------------------- /tests/testthat/dm/v2.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/tests/testthat/dm/v2.rds -------------------------------------------------------------------------------- /tests/testthat/dm/v2_zoomed.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/tests/testthat/dm/v2_zoomed.rds -------------------------------------------------------------------------------- /tests/testthat/dm/v3.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/tests/testthat/dm/v3.rds -------------------------------------------------------------------------------- /tests/testthat/dm/v3_zoomed.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/tests/testthat/dm/v3_zoomed.rds -------------------------------------------------------------------------------- /tests/testthat/dm/v4.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/tests/testthat/dm/v4.rds -------------------------------------------------------------------------------- /tests/testthat/dm/v4_zoomed.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/tests/testthat/dm/v4_zoomed.rds -------------------------------------------------------------------------------- /tests/testthat/helper-filter-dm.R: -------------------------------------------------------------------------------- 1 | expect_pred_chain <- function(fc, chain) { 2 | # Check that node is unique 3 | expect_true(identical(fc$node, unique(fc$node))) 4 | 5 | filtered_fc <- 6 | fc %>% 7 | filter(node %in% !!chain) 8 | 9 | # Beware of https://github.com/r-lib/testthat/issues/929 10 | expect_equal(filtered_fc$node, !!chain) 11 | } 12 | 13 | expect_not_pred <- function(fc, node) { 14 | # Check that node is missing 15 | expect_false(any(node %in% fc$node)) 16 | } 17 | -------------------------------------------------------------------------------- /tests/testthat/helper-jsonlite.R: -------------------------------------------------------------------------------- 1 | to_snapshot_json <- function(x) { 2 | # https://github.com/cynkra/dm/pull/1891#issuecomment-1589176764 3 | # print(jsonlite::toJSON(x, pretty = TRUE)) 4 | print(x) 5 | } 6 | -------------------------------------------------------------------------------- /tests/testthat/helper-print.R: -------------------------------------------------------------------------------- 1 | # Only run if the top level call is devtools::test() or testthat::test_check() 2 | if (is_this_a_test()) { 3 | # trim both the print output of `tbl_df` and `tbl_sql` so they match 4 | # FIXME: what if a table has more than 10 rows? 5 | if (rlang::is_installed("dbplyr")) { 6 | tbl_sum.tbl_sql <- function(x, ...) c() 7 | s3_register("tibble::tbl_sum", "tbl_sql", tbl_sum.tbl_sql) 8 | s3_register("pillar::tbl_sum", "tbl_sql", tbl_sum.tbl_sql) 9 | tbl_format_header.tbl_sql <- function(x, ...) invisible() 10 | s3_register("pillar::tbl_format_header", "tbl_sql", tbl_format_header.tbl_sql) 11 | } 12 | # Not sure why this works without s3_register(), and is also required 13 | tbl_sum.tbl_df <- function(x, ...) c() 14 | } 15 | -------------------------------------------------------------------------------- /tests/testthat/helper-testthat.R: -------------------------------------------------------------------------------- 1 | options(testthat.progress.verbose_skips = FALSE) 2 | options(Ncpus = min(parallel::detectCores(), 4)) 3 | options(tidyselect_verbosity = "verbose") 4 | -------------------------------------------------------------------------------- /tests/testthat/helper-zoom.R: -------------------------------------------------------------------------------- 1 | # helper to check if key tracking works 2 | get_all_keys <- function(dm, table_name = NULL) { 3 | fks <- 4 | dm_get_all_fks_impl(dm, table_name) 5 | pks <- 6 | dm_get_all_pks_impl(dm, table_name) 7 | 8 | list( 9 | pks = pks, 10 | fks = fks 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /tests/testthat/setup.R: -------------------------------------------------------------------------------- 1 | # utils::Rprof(paste0("~/", Sys.getpid(), ".Rprof"), line.profiling = TRUE) 2 | # 3 | # withr::defer(utils::Rprof(NULL), teardown_env()) 4 | 5 | local_options( 6 | pillar.min_title_chars = NULL, 7 | pillar.max_title_chars = NULL, 8 | pillar.max_footer_lines = NULL, 9 | pillar.bold = NULL, 10 | .frame = teardown_env() 11 | ) 12 | -------------------------------------------------------------------------------- /tests/testthat/test-autoincrement.R: -------------------------------------------------------------------------------- 1 | x <- tibble::tibble( 2 | x_id = integer(0L), 3 | x_data = character(0L), 4 | ) 5 | y <- tibble::tibble( 6 | y_id = integer(0L), 7 | x_id = integer(0L), 8 | y_data = character(0L), 9 | ) 10 | 11 | dm <- dm(x, y) %>% 12 | dm_add_pk(x, x_id, autoincrement = TRUE) %>% 13 | dm_add_pk(y, y_id, autoincrement = FALSE) %>% 14 | dm_add_fk(y, x_id, x) 15 | 16 | test_that("autoincrement produces valid R code", { 17 | expect_snapshot(dm) 18 | }) 19 | 20 | test_that("autoincrement produces valid SQL queries and R code - RSQLite", { 21 | skip_if_not_installed("RSQLite") 22 | 23 | con <- DBI::dbConnect(RSQLite::SQLite()) 24 | df <- dm:::build_copy_queries(con, dm) 25 | 26 | expect_snapshot(df$sql_table) 27 | expect_snapshot(dm_paste(dm)) 28 | }) 29 | -------------------------------------------------------------------------------- /tests/testthat/test-colors.R: -------------------------------------------------------------------------------- 1 | test_that("color related functions work", { 2 | # is_dark_color() 3 | expect_true(is_dark_color(rgb = c(100, 100, 100, 255))) 4 | expect_false(is_dark_color(rgb = c(142, 164, 143, 255))) 5 | 6 | # is_hex_color() 7 | expect_true(is_hex_color("#92A87F")) 8 | expect_true(is_hex_color("#92A87F4C")) 9 | expect_false(is_hex_color("#92A87F4")) 10 | expect_false(is_hex_color("92A87F")) 11 | 12 | # col_to_hex() 13 | expect_identical( 14 | col_to_hex(c("brown", "#92A87F", "darkgreen", "#92A87F4C")), 15 | c("#A52A2AFF", "#92A87FFF", "#006400FF", "#92A87F4C") 16 | ) 17 | 18 | expect_dm_error( 19 | col_to_hex("darklightpink"), 20 | "cols_not_avail" 21 | ) 22 | 23 | # hex_from_rgb() 24 | expect_identical( 25 | hex_from_rgb(matrix(100, 4, 1)), 26 | "#64646464" 27 | ) 28 | 29 | expect_identical( 30 | hex_from_rgb(matrix(100:107, 4, 2)), 31 | c("#64656667", "#68696A6B") 32 | ) 33 | 34 | expect_identical( 35 | calc_bodycol_rgb(matrix(c(100, 20, 200, 155), 4, 1)), 36 | matrix(c(224, 208, 244, 155), 4, 1) 37 | ) 38 | }) 39 | -------------------------------------------------------------------------------- /tests/testthat/test-disambiguate.R: -------------------------------------------------------------------------------- 1 | test_that("dm_disambiguate_cols() works as intended", { 2 | expect_snapshot({ 3 | dm_for_flatten() %>% 4 | dm_disambiguate_cols() %>% 5 | dm_paste(options = c("select", "keys")) 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /tests/testthat/test-disentangle.R: -------------------------------------------------------------------------------- 1 | test_that("dm_disentangle() works", { 2 | expect_snapshot({ 3 | dm_disentangle(dm_for_filter_w_cycle(), tf_1) %>% 4 | dm_get_all_fks() 5 | dm_disentangle(dm_for_filter_w_cycle(), tf_5) %>% 6 | dm_get_all_fks() 7 | dm_disentangle(entangled_dm(), a, quiet = TRUE) %>% 8 | dm_get_all_fks() 9 | dm_disentangle(entangled_dm(), c) %>% 10 | dm_get_all_fks() 11 | dm_disentangle(entangled_dm_2(), a) %>% 12 | dm_get_all_fks() 13 | dm_disentangle(entangled_dm_2(), d, quiet = TRUE) %>% 14 | dm_get_all_fks() 15 | }) 16 | 17 | expect_snapshot_error(class = dm_error("only_possible_wo_zoom"), { 18 | dm_for_filter_w_cycle() %>% 19 | dm_zoom_to(tf_1) %>% 20 | dm_disentangle(tf_1) 21 | }) 22 | 23 | expect_snapshot_error({ 24 | dm_for_filter_w_cycle() %>% 25 | dm_disentangle() 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /tests/testthat/test-dm_deconstruct.R: -------------------------------------------------------------------------------- 1 | test_that("snapshot test", { 2 | expect_snapshot({ 3 | dm <- dm_nycflights13() 4 | dm_deconstruct(dm) 5 | }) 6 | }) 7 | 8 | test_that("non-syntactic names", { 9 | expect_snapshot({ 10 | dm <- dm(`if` = tibble(a = 1), `a b` = tibble(b = 1)) 11 | dm_deconstruct(dm) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /tests/testthat/test-dm_pixarfilms.R: -------------------------------------------------------------------------------- 1 | test_that("`dm_pixarfilms()` works", { 2 | expect_snapshot( 3 | dm_examine_constraints(dm_pixarfilms(consistent = FALSE)) 4 | ) 5 | expect_snapshot( 6 | dm_examine_constraints(dm_pixarfilms(consistent = TRUE)) 7 | ) 8 | }) 9 | -------------------------------------------------------------------------------- /tests/testthat/test-dm_sql.R: -------------------------------------------------------------------------------- 1 | test_that("snapshot test", { 2 | skip_if_src_not("df") 3 | 4 | expect_snapshot({ 5 | dm_for_filter() %>% 6 | dm_sql(test_src_duckdb()$con) 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /tests/testthat/test-dm_unnest_tbl.R: -------------------------------------------------------------------------------- 1 | test_that("`dm_unnest_tbl()` and `dm_unpack_tbl()` failure modes", { 2 | skip_if_remote_src() 3 | 4 | # trying to unpack or unnest a column that doesn't exist gives informative error 5 | expect_error(dm_unnest_tbl(dm_for_filter(), tf_2, tf_1, dm_for_filter()), "Column `tf_1` doesn't exist") 6 | }) 7 | 8 | test_that("`dm_unpack_tbl()` failure modes", { 9 | skip_if_remote_src() 10 | 11 | # trying to unpack a column that doesn't exist gives informative error 12 | expect_error(dm_unpack_tbl(dm_for_filter(), tf_2, tf_1, dm_for_filter()), "Column `tf_1` doesn't exist") 13 | }) 14 | -------------------------------------------------------------------------------- /tests/testthat/test-duckdb.R: -------------------------------------------------------------------------------- 1 | test_that("dummy", { 2 | expect_snapshot({ 3 | "dummy" 4 | }) 5 | }) 6 | 7 | test_that("dm_sql()", { 8 | # Need skip in every test block, unfortunately 9 | skip_if_src_not("duckdb") 10 | 11 | # https://github.com/tidyverse/dbplyr/pull/1190 12 | skip_if(is(my_test_con(), "MySQLConnection")) 13 | 14 | expect_snapshot({ 15 | dm_for_filter_df() %>% 16 | dm_sql(my_test_con()) 17 | }) 18 | 19 | expect_snapshot({ 20 | dm(x = data.frame(a = strrep("x", 300))) %>% 21 | dm_sql(my_test_con()) 22 | }) 23 | 24 | expect_snapshot({ 25 | dm(x = data.frame(a = strrep("x", 10000))) %>% 26 | dm_sql(my_test_con()) 27 | }) 28 | }) 29 | 30 | test_that("long text columns with copy_dm_to()", { 31 | # Need skip in every test block, unfortunately 32 | skip_if_src_not("duckdb") 33 | 34 | dm <- dm(x = data.frame(a = strrep("x", 300))) 35 | dm_out <- copy_dm_to(my_test_con(), dm) 36 | expect_equal(collect(dm_out$x)$a, dm$x$a) 37 | dm_out_out <- copy_dm_to(my_test_con(), dm_out) 38 | expect_equal(collect(dm_out_out$x)$a, dm$x$a) 39 | 40 | dm <- dm(x = data.frame(a = strrep("x", 10000))) 41 | dm_out <- copy_dm_to(my_test_con(), dm) 42 | expect_equal(collect(dm_out$x)$a, dm$x$a) 43 | dm_out_out <- copy_dm_to(my_test_con(), dm_out) 44 | expect_equal(collect(dm_out_out$x)$a, dm$x$a) 45 | }) 46 | -------------------------------------------------------------------------------- /tests/testthat/test-enumerate_all_paths.R: -------------------------------------------------------------------------------- 1 | test_that("enumerate_all_paths() works", { 2 | expect_snapshot({ 3 | enumerate_all_paths(dm_for_filter_w_cycle(), "tf_1") 4 | enumerate_all_paths(dm_for_filter_w_cycle(), "tf_5") 5 | enumerate_all_paths(entangled_dm(), "a") 6 | enumerate_all_paths(entangled_dm(), "c") 7 | enumerate_all_paths(entangled_dm_2(), "a") 8 | enumerate_all_paths(entangled_dm_2(), "d") 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /tests/testthat/test-examine-cardinalities.R: -------------------------------------------------------------------------------- 1 | test_that("dm_examine_cardinalities() works", { 2 | expect_snapshot({ 3 | dm_examine_cardinalities(dm_for_card()) 4 | dm_examine_cardinalities(dm_for_card()) %>% as_tibble() 5 | dm_for_card() %>% 6 | dm_rm_fk(dc_6, c, dc_1, a) %>% 7 | dm_rm_fk(dc_4, c(b, a), dc_3, c(b, a)) %>% 8 | dm_examine_cardinalities() 9 | dm_examine_cardinalities(dm()) 10 | }) 11 | }) 12 | 13 | test_that("`dm_examine_cardinalities()` API", { 14 | local_options(lifecycle_verbosity = "warning") 15 | 16 | expect_snapshot({ 17 | dm_examine_cardinalities(dm_test_obj(), progress = FALSE) 18 | dm_examine_cardinalities(dm = dm_test_obj()) 19 | }) 20 | }) 21 | 22 | test_that("`dm_examine_cardinalities()` API (2)", { 23 | expect_snapshot(error = TRUE, { 24 | dm_examine_cardinalities(dm_test_obj(), foo = "bar") 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /tests/testthat/test-filter-helpers.R: -------------------------------------------------------------------------------- 1 | test_that("dm_nrow() works?", { 2 | expect_identical( 3 | as.integer(sum(dm_nrow(dm_test_obj()))), 4 | rows_dm_obj 5 | ) 6 | }) 7 | -------------------------------------------------------------------------------- /tests/testthat/test-format.R: -------------------------------------------------------------------------------- 1 | test_that("output", { 2 | expect_snapshot({ 3 | commas(character()) 4 | commas(letters[1]) 5 | commas(letters[1:2]) 6 | commas(letters[1:3]) 7 | commas(letters[seq_len(MAX_COMMAS - 1)]) 8 | commas(letters[seq_len(MAX_COMMAS)]) 9 | commas(letters[seq_len(MAX_COMMAS + 1)]) 10 | commas(letters[1:4], max_commas = 3) 11 | commas(letters, capped = TRUE) 12 | commas(letters, fun = tick) 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /tests/testthat/test-graph.R: -------------------------------------------------------------------------------- 1 | test_that("functions working with graphs do the right thing?", { 2 | join_list_tbl_1 <- tibble( 3 | lhs = c("tf_2", "tf_3", "tf_4", "tf_5", "tf_6"), 4 | rhs = c("tf_1", "tf_2", "tf_3", "tf_4", "tf_5"), 5 | rank = as.numeric(2:6), 6 | has_father = rep(TRUE, 5) 7 | ) 8 | 9 | join_list_tbl_3 <- tibble::tribble( 10 | ~lhs, ~rhs, ~rank, ~has_father, 11 | "tf_2", "tf_3", 2, TRUE, 12 | "tf_4", "tf_3", 3, TRUE, 13 | "tf_1", "tf_2", 4, TRUE, 14 | "tf_5", "tf_4", 5, TRUE, 15 | "tf_6", "tf_5", 6, TRUE 16 | ) 17 | 18 | expect_identical_graph( 19 | igraph::graph_from_data_frame( 20 | tibble( 21 | tables = c("tf_1", "tf_2", "tf_2", "tf_3", "tf_4", "tf_5", "tf_6"), 22 | ref_tables = c("tf_2", "tf_7", "tf_3", "tf_4", "tf_5", "tf_6", "tf_7") 23 | ), 24 | directed = FALSE 25 | ), 26 | create_graph_from_dm(dm_for_filter_w_cycle()) 27 | ) 28 | 29 | expect_snapshot({ 30 | attr(igraph::E(create_graph_from_dm(nyc_comp())), "vnames") 31 | }) 32 | }) 33 | 34 | test_that("empty graph", { 35 | opt <- igraph::igraph_options(print.id = FALSE) 36 | on.exit(igraph::igraph_options(opt)) 37 | 38 | expect_snapshot({ 39 | create_graph_from_dm(empty_dm()) 40 | create_graph_from_dm(dm(x = tibble(a = 1))) 41 | }) 42 | }) 43 | -------------------------------------------------------------------------------- /tests/testthat/test-json.R: -------------------------------------------------------------------------------- 1 | test_that("json joins work", { 2 | df1 <- tibble(col1 = 1:2, key = letters[1:2]) 3 | df2 <- tibble(col2 = c(3:4, pi), col3 = c("X", "Y", "Z"), key = letters[c(1, 1:2)]) 4 | 5 | expect_snapshot({ 6 | packed <- json_pack_join(df1, df2, by = "key") 7 | packed 8 | packed$df2 9 | }) 10 | 11 | expect_snapshot({ 12 | nested <- json_nest_join(df1, df2, by = "key") 13 | nested 14 | nested$df2 15 | }) 16 | 17 | # Make sure precision is not lost in JSON conversion 18 | packed <- json_pack_join(df1, df2, by = "key") 19 | nested <- json_nest_join(df1, df2, by = "key") 20 | expect_equal(jsonlite::fromJSON(packed$df2[[3]])[["col2"]], pi) 21 | expect_equal(jsonlite::fromJSON(nested$df2[[2]])[["col2"]], pi) 22 | }) 23 | -------------------------------------------------------------------------------- /tests/testthat/test-json_pack.R: -------------------------------------------------------------------------------- 1 | test_that("`json_pack()` works", { 2 | expect_snapshot({ 3 | df <- tibble::tibble(x1 = 1:3, x2 = 4:6, x3 = 7:9, y = 1:3) 4 | packed <- json_pack(df, x = c(x1, x2, x3), y = y) 5 | packed 6 | }) 7 | 8 | df_roundtrip <- json_unpack(packed, c(x, y)) 9 | expect_equal(df, df_roundtrip) 10 | }) 11 | 12 | test_that("`json_pack()` works remotely", { 13 | skip_if_src_not("postgres", "mssql") 14 | con <- my_test_src()$con 15 | 16 | local <- tibble(grp = c(1, 1, 2, 2), a_i = letters[1:4], a_j = LETTERS[1:4]) 17 | remote <- test_db_src_frame(!!!local) 18 | 19 | expect_snapshot(variant = my_test_src_name, { 20 | query <- json_pack(remote, a = starts_with("a")) %>% dbplyr::sql_render() 21 | # For stable POSTGRES tests 22 | gsub("test_frame_[_0-9]+", "test_frame_...", query) 23 | json_pack(remote, a = starts_with("a")) 24 | query <- json_pack(remote, a = starts_with("a"), .names_sep = "_") %>% dbplyr::sql_render() 25 | # For stable POSTGRES tests 26 | gsub("test_frame_[_0-9]+", "test_frame_...", query) 27 | json_pack(remote, a = starts_with("a"), .names_sep = "_") 28 | }) 29 | 30 | expect_identical( 31 | local %>% json_pack(a = starts_with("a")) %>% unjson_nested(), 32 | remote %>% json_pack(a = starts_with("a")) %>% collect() %>% unjson_nested() 33 | ) 34 | }) 35 | -------------------------------------------------------------------------------- /tests/testthat/test-maria.R: -------------------------------------------------------------------------------- 1 | test_that("dummy", { 2 | expect_snapshot({ 3 | "dummy" 4 | }) 5 | }) 6 | 7 | test_that("dm_sql()", { 8 | # Need skip in every test block, unfortunately 9 | skip_if_src_not("maria") 10 | 11 | # https://github.com/tidyverse/dbplyr/pull/1190 12 | skip_if(is(my_test_con(), "MySQLConnection")) 13 | 14 | expect_snapshot({ 15 | dm_for_filter_df() %>% 16 | dm_sql(my_test_con()) 17 | }) 18 | 19 | expect_snapshot({ 20 | dm(x = data.frame(a = strrep("x", 300))) %>% 21 | dm_sql(my_test_con()) 22 | }) 23 | 24 | expect_snapshot({ 25 | dm(x = data.frame(a = strrep("x", 10000))) %>% 26 | dm_sql(my_test_con()) 27 | }) 28 | }) 29 | 30 | test_that("long text columns with copy_dm_to()", { 31 | # Need skip in every test block, unfortunately 32 | skip_if_src_not("maria") 33 | 34 | dm <- dm(x = data.frame(a = strrep("x", 300))) 35 | dm_out <- copy_dm_to(my_test_con(), dm) 36 | expect_equal(collect(dm_out$x)$a, dm$x$a) 37 | dm_out_out <- copy_dm_to(my_test_con(), dm_out) 38 | expect_equal(collect(dm_out_out$x)$a, dm$x$a) 39 | 40 | dm <- dm(x = data.frame(a = strrep("x", 10000))) 41 | dm_out <- copy_dm_to(my_test_con(), dm) 42 | expect_equal(collect(dm_out$x)$a, dm$x$a) 43 | dm_out_out <- copy_dm_to(my_test_con(), dm_out) 44 | expect_equal(collect(dm_out_out$x)$a, dm$x$a) 45 | }) 46 | -------------------------------------------------------------------------------- /tests/testthat/test-meta.R: -------------------------------------------------------------------------------- 1 | test_that("dummy", { 2 | # To avoid deletion of file 3 | expect_snapshot({ 4 | TRUE 5 | }) 6 | }) 7 | 8 | test_that("dm_meta() data model", { 9 | skip_if_schema_not_supported() 10 | 11 | expect_snapshot({ 12 | dm_meta(my_test_src()) %>% 13 | dm_paste(options = c("select", "keys", "color")) 14 | }) 15 | }) 16 | 17 | test_that("dm_meta(simple = TRUE) columns", { 18 | # Still stored as snapshot in columns.csv, never cleared 19 | skip("Dependent on database version, find better way to record this info") 20 | 21 | columns <- tryCatch( 22 | my_db_test_src() %>% 23 | dm_meta(simple = TRUE) %>% 24 | .$columns %>% 25 | filter(tolower(table_schema) == "information_schema") %>% 26 | arrange(table_name, ordinal_position) %>% 27 | select(-table_catalog) %>% 28 | collect(), 29 | error = function(e) { 30 | data.frame(error = conditionMessage(e)) 31 | } 32 | ) 33 | 34 | path <- withr::local_tempfile(fileext = ".csv") 35 | write.csv(columns, path, na = "") 36 | 37 | expect_snapshot_file(path, name = "columns.csv", variant = my_test_src_name) 38 | }) 39 | -------------------------------------------------------------------------------- /tests/testthat/test-mssql.R: -------------------------------------------------------------------------------- 1 | test_that("dummy", { 2 | expect_snapshot({ 3 | "dummy" 4 | }) 5 | }) 6 | 7 | test_that("dm_sql()", { 8 | # Need skip in every test block, unfortunately 9 | skip_if_src_not("mssql") 10 | 11 | # https://github.com/tidyverse/dbplyr/pull/1190 12 | skip_if(is(my_test_con(), "MySQLConnection")) 13 | 14 | expect_snapshot({ 15 | dm_for_filter_df() %>% 16 | dm_sql(my_test_con()) 17 | }) 18 | 19 | expect_snapshot({ 20 | dm(x = data.frame(a = strrep("x", 300))) %>% 21 | dm_sql(my_test_con()) 22 | }) 23 | 24 | expect_snapshot({ 25 | dm(x = data.frame(a = strrep("x", 10000))) %>% 26 | dm_sql(my_test_con()) 27 | }) 28 | }) 29 | 30 | test_that("long text columns with copy_dm_to()", { 31 | # Need skip in every test block, unfortunately 32 | skip_if_src_not("mssql") 33 | 34 | dm <- dm(x = data.frame(a = strrep("x", 300))) 35 | dm_out <- copy_dm_to(my_test_con(), dm) 36 | expect_equal(collect(dm_out$x)$a, dm$x$a) 37 | dm_out_out <- copy_dm_to(my_test_con(), dm_out) 38 | expect_equal(collect(dm_out_out$x)$a, dm$x$a) 39 | 40 | dm <- dm(x = data.frame(a = strrep("x", 10000))) 41 | dm_out <- copy_dm_to(my_test_con(), dm) 42 | expect_equal(collect(dm_out$x)$a, dm$x$a) 43 | dm_out_out <- copy_dm_to(my_test_con(), dm_out) 44 | expect_equal(collect(dm_out_out$x)$a, dm$x$a) 45 | }) 46 | -------------------------------------------------------------------------------- /tests/testthat/test-pool-support.R: -------------------------------------------------------------------------------- 1 | test_that("dm_from_con() supports 'Pool'", { 2 | skip_if_not_installed("pool") 3 | skip_if_not_installed("RSQLite") 4 | 5 | # expect no error 6 | conn <- pool::dbPool(RSQLite::SQLite(), dbname = "", timeout = 10) 7 | on.exit(pool::poolClose(conn)) 8 | DBI::dbWriteTable(conn, "mtcars", mtcars) 9 | dm <- dm::dm_from_con(conn, learn_keys = FALSE) 10 | expect_identical(names(dm), "mtcars") 11 | }) 12 | -------------------------------------------------------------------------------- /tests/testthat/test-postgres.R: -------------------------------------------------------------------------------- 1 | test_that("dummy", { 2 | expect_snapshot({ 3 | "dummy" 4 | }) 5 | }) 6 | 7 | test_that("dm_sql()", { 8 | # Need skip in every test block, unfortunately 9 | skip_if_src_not("postgres") 10 | 11 | # https://github.com/tidyverse/dbplyr/pull/1190 12 | skip_if(is(my_test_con(), "MySQLConnection")) 13 | 14 | expect_snapshot({ 15 | dm_for_filter_df() %>% 16 | dm_sql(my_test_con()) 17 | }) 18 | 19 | expect_snapshot({ 20 | dm(x = data.frame(a = strrep("x", 300))) %>% 21 | dm_sql(my_test_con()) 22 | }) 23 | 24 | expect_snapshot({ 25 | dm(x = data.frame(a = strrep("x", 10000))) %>% 26 | dm_sql(my_test_con()) 27 | }) 28 | }) 29 | 30 | test_that("long text columns with copy_dm_to()", { 31 | # Need skip in every test block, unfortunately 32 | skip_if_src_not("postgres") 33 | 34 | dm <- dm(x = data.frame(a = strrep("x", 300))) 35 | dm_out <- copy_dm_to(my_test_con(), dm) 36 | expect_equal(collect(dm_out$x)$a, dm$x$a) 37 | dm_out_out <- copy_dm_to(my_test_con(), dm_out) 38 | expect_equal(collect(dm_out_out$x)$a, dm$x$a) 39 | 40 | dm <- dm(x = data.frame(a = strrep("x", 10000))) 41 | dm_out <- copy_dm_to(my_test_con(), dm) 42 | expect_equal(collect(dm_out$x)$a, dm$x$a) 43 | dm_out_out <- copy_dm_to(my_test_con(), dm_out) 44 | expect_equal(collect(dm_out_out$x)$a, dm$x$a) 45 | }) 46 | -------------------------------------------------------------------------------- /tests/testthat/test-sqlite.R: -------------------------------------------------------------------------------- 1 | test_that("dummy", { 2 | expect_snapshot({ 3 | "dummy" 4 | }) 5 | }) 6 | 7 | test_that("dm_sql()", { 8 | # Need skip in every test block, unfortunately 9 | skip_if_src_not("sqlite") 10 | 11 | # https://github.com/tidyverse/dbplyr/pull/1190 12 | skip_if(is(my_test_con(), "MySQLConnection")) 13 | 14 | expect_snapshot({ 15 | dm_for_filter_df() %>% 16 | dm_sql(my_test_con()) 17 | }) 18 | 19 | expect_snapshot({ 20 | dm(x = data.frame(a = strrep("x", 300))) %>% 21 | dm_sql(my_test_con()) 22 | }) 23 | 24 | expect_snapshot({ 25 | dm(x = data.frame(a = strrep("x", 10000))) %>% 26 | dm_sql(my_test_con()) 27 | }) 28 | }) 29 | 30 | test_that("long text columns with copy_dm_to()", { 31 | # Need skip in every test block, unfortunately 32 | skip_if_src_not("sqlite") 33 | 34 | dm <- dm(x = data.frame(a = strrep("x", 300))) 35 | dm_out <- copy_dm_to(my_test_con(), dm) 36 | expect_equal(collect(dm_out$x)$a, dm$x$a) 37 | dm_out_out <- copy_dm_to(my_test_con(), dm_out) 38 | expect_equal(collect(dm_out_out$x)$a, dm$x$a) 39 | 40 | dm <- dm(x = data.frame(a = strrep("x", 10000))) 41 | dm_out <- copy_dm_to(my_test_con(), dm) 42 | expect_equal(collect(dm_out$x)$a, dm$x$a) 43 | dm_out_out <- copy_dm_to(my_test_con(), dm_out) 44 | expect_equal(collect(dm_out_out$x)$a, dm$x$a) 45 | }) 46 | -------------------------------------------------------------------------------- /tests/testthat/test-standalone-check_suggested.R: -------------------------------------------------------------------------------- 1 | test_that("`check_suggested()` works", { 2 | withr::local_envvar("TESTTHAT" = "") 3 | expect_snapshot({ 4 | check_suggested("rlang", "foo") 5 | check_suggested("dm", "foo", use = NA) 6 | check_suggested("iurtnkjvmomweicopbt", "foo", use = NA) 7 | check_suggested("iurtnkjvmomweicopbt", use = NA) 8 | 9 | check_suggested("dm", "foo", use = FALSE) 10 | check_suggested("iurtnkjvmomweicopbt", "foo", use = FALSE) 11 | check_suggested("iurtnkjvmomweicopbt", use = FALSE) 12 | }) 13 | }) 14 | 15 | test_that("`check_suggested()` works for error messages", { 16 | withr::local_envvar("TESTTHAT" = "") 17 | expect_snapshot(error = TRUE, { 18 | check_suggested("iurtnkjvmomweicopbt", "foo") 19 | }) 20 | rlang::local_interactive(TRUE) 21 | expect_snapshot({ 22 | # A message 23 | check_suggested(c("iurtnkjvmomweicopbt (>= 0.5)", "xxx", "cli"), "foo", use = NA) 24 | }) 25 | }) 26 | 27 | 28 | test_that("`check_suggested()` will skip.", { 29 | # this should be skipped. 30 | check_suggested("iurtnkjvmomweicopbt", "foo") 31 | # Catching an error if it is not skipped. 32 | expect_equal("skipped", "not skipped") 33 | }) 34 | -------------------------------------------------------------------------------- /tests/testthat/test-test-dm.R: -------------------------------------------------------------------------------- 1 | test_that("general check-functions work", { 2 | expect_silent(check_param_class(1, "numeric", "one")) 3 | expect_dm_error(check_param_class("1", "numeric", "one"), "parameter_not_correct_class") 4 | expect_silent(check_param_length(1:3, 3, "count_to_three")) 5 | expect_dm_error(check_param_length(1:4, 3, "count_to_three"), "parameter_not_correct_length") 6 | }) 7 | -------------------------------------------------------------------------------- /tests/testthat/test-testthat-wrappers.R: -------------------------------------------------------------------------------- 1 | testthat::test_that("testthat wrappers return the object", { 2 | expect_equal( 3 | expect_message_obj( 4 | { 5 | message("abc") 6 | "foo" 7 | }, 8 | "a" 9 | ), 10 | "foo" 11 | ) 12 | expect_equal( 13 | expect_warning_obj( 14 | { 15 | warning("abc") 16 | "foo" 17 | }, 18 | "a" 19 | ), 20 | "foo" 21 | ) 22 | expect_equal( 23 | expect_condition_obj( 24 | { 25 | message("abc") 26 | "foo" 27 | }, 28 | "a" 29 | ), 30 | "foo" 31 | ) 32 | }) 33 | -------------------------------------------------------------------------------- /tests/testthat/test-tidyselect.R: -------------------------------------------------------------------------------- 1 | test_that("tidyselecting tables works", { 2 | table_names <- c("table_1", "table_2", "table_3") 3 | quo <- quo(c(table_3_new = table_3, table_1_new = table_1)) 4 | 5 | expect_identical( 6 | eval_select_table_indices(quo, table_names), 7 | c(table_3_new = 3L, table_1_new = 1L) 8 | ) 9 | 10 | expect_identical( 11 | eval_select_table(quo, table_names), 12 | set_names(c("table_3", "table_1"), c("table_3_new", "table_1_new")) 13 | ) 14 | 15 | expect_identical( 16 | eval_rename_table_all(quo, table_names), 17 | set_names(table_names, c("table_1_new", "table_2", "table_3_new")) 18 | ) 19 | }) 20 | 21 | test_that("output", { 22 | skip_if_not_installed("vctrs", "0.4.1") 23 | skip_if(packageVersion("tidyselect") > "1.2.0") 24 | 25 | expect_snapshot(error = TRUE, { 26 | dm_for_filter() %>% 27 | dm_select_tbl(tf_7) 28 | 29 | dm_for_filter() %>% 30 | dm_rename_tbl(tf_0 = tf_7) 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /tests/testthat/test-utils.R: -------------------------------------------------------------------------------- 1 | test_that("utils-methods work", { 2 | expect_equivalent_tbl( 3 | dm_zoomed() %>% arrange(d) %>% head(3) %>% tbl_zoomed(), 4 | head(tf_2() %>% arrange(d), 3) 5 | ) 6 | 7 | # Not implemented for remote sources: 8 | skip_if_remote_src() 9 | expect_equivalent_tbl( 10 | dm_zoomed() %>% tail(2) %>% tbl_zoomed(), 11 | tail(tf_2(), 2) 12 | ) 13 | }) 14 | -------------------------------------------------------------------------------- /tests/testthat/test-waldo.R: -------------------------------------------------------------------------------- 1 | withr::local_seed(20220706) 2 | 3 | test_that("waldo", { 4 | skip_if_not_installed("waldo", "0.3.0") 5 | 6 | dm <- dm_nycflights13() 7 | 8 | expect_snapshot({ 9 | dm %>% 10 | waldo::compare(dm, max_diffs = 10) 11 | }) 12 | expect_snapshot({ 13 | dm %>% 14 | dm_select_tbl(-airlines) %>% 15 | waldo::compare(dm, max_diffs = 10) 16 | }) 17 | expect_snapshot({ 18 | dm %>% 19 | dm_select(airlines, -name) %>% 20 | waldo::compare(dm, max_diffs = 10) 21 | }) 22 | expect_snapshot({ 23 | dm %>% 24 | dm_rm_fk() %>% 25 | waldo::compare(dm, max_diffs = 10) 26 | }) 27 | expect_snapshot({ 28 | dm %>% 29 | dm_rm_pk() %>% 30 | waldo::compare(dm, max_diffs = 10) 31 | }) 32 | expect_snapshot({ 33 | dm %>% 34 | dm_set_colors("yellow" = flights) %>% 35 | waldo::compare(dm, max_diffs = 10) 36 | }) 37 | expect_snapshot({ 38 | dm %>% 39 | dm_zoom_to(flights) %>% 40 | waldo::compare(dm, max_diffs = 10) 41 | }) 42 | }) 43 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | -------------------------------------------------------------------------------- /vignettes/abstracts/erum-2020.md: -------------------------------------------------------------------------------- 1 | Storing all data related to a problem in a single table or data frame ("the dataset") can result in many repetitive values. Separation into multiple tables helps data quality but requires "merge" or "join" operations. {dm} is a new package that fills a gap in the R ecosystem: it makes working with multiple tables just as easy as working with a single table. 2 | 3 | A "data model" consists of tables (both the definition and the data), and primary and foreign keys. The {dm} package combines these concepts with data manipulation powered by the tidyverse: entire data models are handled in a single entity, a "dm" object. 4 | 5 | Three principal use cases for {dm} can be identified: 6 | 7 | 1. When you consume a data model, {dm} helps access and manipulate a dataset consisting of multiple tables (database or local data frames) through a consistent interface. 8 | 9 | 2. When you use a third-party dataset, {dm} helps normalizing the data to remove redundancies as part of the cleaning process. 10 | 11 | 3. To create a relational data model, you can prepare the data using R and familiar tools and seamlessly export to a database. 12 | 13 | The presentation revolves around these use cases and shows a few applications. The {dm} package is available on GitHub and will be submitted to CRAN in early February. 14 | -------------------------------------------------------------------------------- /vignettes/abstracts/user-2019.md: -------------------------------------------------------------------------------- 1 | Complex datasets are often organized as several tables, interlinked through common values in columns. 2 | Working with these datasets requires an understanding of the relationships 3 | between tables. Occasionally, reorganization such as normalization, decomposition, or aggregation may be necessary, in particular if the data comes as a single denormalized table. 4 | Defining a rigorous data model helps, but we found surprisingly few tools in the R ecosystem 5 | that deal with this problem. One example is the datamodelr package on GitHub, which 6 | focuses on describing data models and drawing diagrams. 7 | 8 | The dm package offers tools to prepare, specify and validate a data model (e.g., decomposing 9 | tables, defining and checking keys and cardinality). It focuses on both data and metadata, 10 | and can work with any dplyr-compatible data source, in particular in-memory data frames 11 | and SQL databases are supported. With a validated data model, join operations are well- 12 | defined and can be generated automatically. An interface to datamodelr for drawing the 13 | data model diagram is provided. A Shiny module for browsing and filtering the tables of the 14 | data model or a submodel, respecting the relationships between the tables, makes it easy to 15 | build custom apps for interactive work with data spread across multiple tables. 16 | -------------------------------------------------------------------------------- /vignettes/articles/cheatsheet-figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/articles/cheatsheet-figures/logo.png -------------------------------------------------------------------------------- /vignettes/articles/cheatsheet-figures/shiny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/articles/cheatsheet-figures/shiny.png -------------------------------------------------------------------------------- /vignettes/out/dm_files/figure-gfm/visualize_keys-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/dm_files/figure-gfm/visualize_keys-1.png -------------------------------------------------------------------------------- /vignettes/out/howto-dm-copy_files/figure-gfm/unnamed-chunk-9-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/howto-dm-copy_files/figure-gfm/unnamed-chunk-9-1.png -------------------------------------------------------------------------------- /vignettes/out/howto-dm-db_files/figure-gfm/unnamed-chunk-4-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/howto-dm-db_files/figure-gfm/unnamed-chunk-4-1.png -------------------------------------------------------------------------------- /vignettes/out/howto-dm-db_files/figure-gfm/unnamed-chunk-9-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/howto-dm-db_files/figure-gfm/unnamed-chunk-9-1.png -------------------------------------------------------------------------------- /vignettes/out/howto-dm-df_files/figure-gfm/unnamed-chunk-6-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/howto-dm-df_files/figure-gfm/unnamed-chunk-6-1.png -------------------------------------------------------------------------------- /vignettes/out/howto-dm-df_files/figure-gfm/unnamed-chunk-6-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/howto-dm-df_files/figure-gfm/unnamed-chunk-6-2.png -------------------------------------------------------------------------------- /vignettes/out/howto-dm-df_files/figure-gfm/unnamed-chunk-6-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/howto-dm-df_files/figure-gfm/unnamed-chunk-6-3.png -------------------------------------------------------------------------------- /vignettes/out/howto-dm-df_files/figure-gfm/unnamed-chunk-6-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/howto-dm-df_files/figure-gfm/unnamed-chunk-6-4.png -------------------------------------------------------------------------------- /vignettes/out/howto-dm-rows_files/figure-gfm/unnamed-chunk-1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/howto-dm-rows_files/figure-gfm/unnamed-chunk-1-1.png -------------------------------------------------------------------------------- /vignettes/out/howto-dm-theory_files/figure-gfm/unnamed-chunk-2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/howto-dm-theory_files/figure-gfm/unnamed-chunk-2-1.png -------------------------------------------------------------------------------- /vignettes/out/tech-dm-draw_files/figure-gfm/unnamed-chunk-2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/tech-dm-draw_files/figure-gfm/unnamed-chunk-2-1.png -------------------------------------------------------------------------------- /vignettes/out/tech-dm-draw_files/figure-gfm/unnamed-chunk-5-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/tech-dm-draw_files/figure-gfm/unnamed-chunk-5-1.png -------------------------------------------------------------------------------- /vignettes/out/tech-dm-draw_files/figure-gfm/unnamed-chunk-7-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/tech-dm-draw_files/figure-gfm/unnamed-chunk-7-1.png -------------------------------------------------------------------------------- /vignettes/out/tech-dm-draw_files/figure-gfm/unnamed-chunk-8-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/tech-dm-draw_files/figure-gfm/unnamed-chunk-8-1.png -------------------------------------------------------------------------------- /vignettes/out/tech-dm-filter_files/figure-gfm/unnamed-chunk-4-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/tech-dm-filter_files/figure-gfm/unnamed-chunk-4-1.png -------------------------------------------------------------------------------- /vignettes/out/tech-dm-join_files/figure-gfm/unnamed-chunk-3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/tech-dm-join_files/figure-gfm/unnamed-chunk-3-1.png -------------------------------------------------------------------------------- /vignettes/out/tech-dm-zoom_files/figure-gfm/unnamed-chunk-1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/tech-dm-zoom_files/figure-gfm/unnamed-chunk-1-1.png -------------------------------------------------------------------------------- /vignettes/out/tech-dm-zoom_files/figure-gfm/unnamed-chunk-2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/tech-dm-zoom_files/figure-gfm/unnamed-chunk-2-1.png -------------------------------------------------------------------------------- /vignettes/out/tech-dm-zoom_files/figure-gfm/unnamed-chunk-3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/tech-dm-zoom_files/figure-gfm/unnamed-chunk-3-1.png -------------------------------------------------------------------------------- /vignettes/out/tech-dm-zoom_files/figure-gfm/unnamed-chunk-4-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/tech-dm-zoom_files/figure-gfm/unnamed-chunk-4-1.png -------------------------------------------------------------------------------- /vignettes/out/tech-dm-zoom_files/figure-gfm/unnamed-chunk-5-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/tech-dm-zoom_files/figure-gfm/unnamed-chunk-5-1.png -------------------------------------------------------------------------------- /vignettes/out/tech-dm-zoom_files/figure-gfm/zoom-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cynkra/dm/053de31ee87c8761a5268fdbeb673b376fce11b1/vignettes/out/tech-dm-zoom_files/figure-gfm/zoom-1.png -------------------------------------------------------------------------------- /vignettes/out/wip/dm-shiny-dynafilter.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | FIXME: This vignette is not yet written, but will be available in a 4 | future update. 5 | -------------------------------------------------------------------------------- /vignettes/out/wip/dm-tips-and-tricks.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | FIXME: This vignette is not yet written, but will be available in a 4 | future update. 5 | -------------------------------------------------------------------------------- /vignettes/setup/setup.R: -------------------------------------------------------------------------------- 1 | default_eval <- function() { 2 | # Only build vignettes in pkgdown for now 3 | (Sys.getenv("IN_PKGDOWN") != "") || grepl("^cran-", Sys.getenv("GITHUB_HEAD_REF")) 4 | } 5 | 6 | knitr::opts_chunk$set( 7 | error = (Sys.getenv("IN_PKGDOWN") == "") || !dm:::dm_has_financial(), 8 | # Only build vignettes: 9 | # - on pkgdown 10 | # - if not running in GitHub Actions 11 | # - if running in a branch that starts with CRAN in GitHub Actions 12 | eval = default_eval(), 13 | message = TRUE, 14 | collapse = TRUE, 15 | comment = "#>" 16 | ) 17 | fansi::set_knit_hooks(knitr::knit_hooks, which = c("output", "message")) 18 | options(crayon.enabled = knitr::is_html_output(excludes = "gfm"), width = 75, cli.width = 75) 19 | 20 | knit_print.grViz <- function(x, ...) { 21 | x %>% 22 | DiagrammeRsvg::export_svg() %>% 23 | c("`````{=html}\n", ., "\n`````\n") %>% 24 | knitr::asis_output() 25 | } 26 | 27 | # If input loads dm or tidyverse, we load it here to omit warnings 28 | input <- readLines(knitr::current_input()) 29 | if (rlang::has_length(grep('^library[(]"?dm"?[)]', input))) { 30 | library(dm) 31 | } 32 | if (rlang::has_length(grep('^library[(]"?dplyr"?[)]', input))) { 33 | library(dplyr) 34 | } 35 | 36 | ## Link helper to enable links only on pkgdown 37 | href <- function(title, url) { 38 | if (Sys.getenv("IN_PKGDOWN") == "") { 39 | paste0(title, " (", url, ")") 40 | } else { 41 | paste0("[", title, "](", url, ")") 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /vignettes/wip/dm-shiny-dynafilter.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "shiny with {dynafilter}" 3 | date: "`r Sys.Date()`" 4 | output: rmarkdown::html_vignette 5 | vignette: > 6 | %\VignetteIndexEntry{shiny with {dynafilter}} 7 | %\VignetteEncoding{UTF-8} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | editor_options: 10 | chunk_output_type: console 11 | --- 12 | 13 | ```{r setup, include = FALSE} 14 | knitr::opts_chunk$set( 15 | collapse = TRUE, 16 | comment = "#>" 17 | ) 18 | fansi::set_knit_hooks(knitr::knit_hooks) 19 | options(crayon.enabled = TRUE, width = 75, cli.width = 75) 20 | 21 | knit_print.grViz <- function(x, ...) { 22 | x %>% 23 | DiagrammeRsvg::export_svg() %>% 24 | c("`````{=html}\n", ., "\n`````\n") %>% 25 | knitr::asis_output() 26 | } 27 | ``` 28 | 29 | FIXME: 30 | This vignette is not yet written, but will be available in a future update. 31 | -------------------------------------------------------------------------------- /vignettes/wip/dm-tips-and-tricks.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Tips and tricks" 3 | date: "`r Sys.Date()`" 4 | output: rmarkdown::html_vignette 5 | vignette: > 6 | %\VignetteIndexEntry{Tips and tricks} 7 | %\VignetteEncoding{UTF-8} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | editor_options: 10 | chunk_output_type: console 11 | --- 12 | 13 | ```{r setup, include = FALSE} 14 | knitr::opts_chunk$set( 15 | collapse = TRUE, 16 | comment = "#>" 17 | ) 18 | fansi::set_knit_hooks(knitr::knit_hooks) 19 | options(crayon.enabled = TRUE, width = 75, cli.width = 75) 20 | 21 | knit_print.grViz <- function(x, ...) { 22 | x %>% 23 | DiagrammeRsvg::export_svg() %>% 24 | c("`````{=html}\n", ., "\n`````\n") %>% 25 | knitr::asis_output() 26 | } 27 | ``` 28 | 29 | 30 | FIXME: 31 | This vignette is not yet written, but will be available in a future update. 32 | --------------------------------------------------------------------------------