From c0897d40d01c2f977cc89515957052132bc4fc65 Mon Sep 17 00:00:00 2001 From: May Yong Date: Fri, 10 Apr 2026 15:35:02 +0100 Subject: [PATCH 01/45] Update to ignore opiates --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 8318b43..20d6890 100644 --- a/.gitignore +++ b/.gitignore @@ -153,3 +153,5 @@ docs/temp/* *.yaml.gz *_stories.py + +/examples/opiates/* From a0537422447b3d2716279b68a3b6b90279c31944 Mon Sep 17 00:00:00 2001 From: May Yong Date: Mon, 13 Apr 2026 15:10:18 +0100 Subject: [PATCH 02/45] Template omop orm.yaml, config.yaml and df.py files --- examples/mimic_omop/README.md | 19 + examples/mimic_omop/config.yaml | 122 ++ examples/mimic_omop/df.py | 1733 +++++++++++++++++++++++++ examples/mimic_omop/orm.yaml | 2092 +++++++++++++++++++++++++++++++ 4 files changed, 3966 insertions(+) create mode 100644 examples/mimic_omop/README.md create mode 100644 examples/mimic_omop/config.yaml create mode 100644 examples/mimic_omop/df.py create mode 100644 examples/mimic_omop/orm.yaml diff --git a/examples/mimic_omop/README.md b/examples/mimic_omop/README.md new file mode 100644 index 0000000..f89239d --- /dev/null +++ b/examples/mimic_omop/README.md @@ -0,0 +1,19 @@ +1. Make a YAML file representing the tables in the schema + +`poetry run datafaker make-tables --orm-file ./examples/mimic_omop/orm.yaml` + +2. Create schema from the ORM YAML file + +`poetry run datafaker create-tables --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml` + +3. Create generator table + +`poetry run datafaker create-generators --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml --df-file ./examples/mimic_omop/df.py` + +3. Create data + +`poetry run datafaker create-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml --df-file .\examples\pollution\df.py` + +4. Remove data + +`poetry run datafaker remove-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml` \ No newline at end of file diff --git a/examples/mimic_omop/config.yaml b/examples/mimic_omop/config.yaml new file mode 100644 index 0000000..55fb110 --- /dev/null +++ b/examples/mimic_omop/config.yaml @@ -0,0 +1,122 @@ +tables: + # Unnecessary tables + _measurement_links: + ignore: true + _observation_links: + ignore: true + _person_links: + ignore: true + _procedure_occurrence_links: + ignore: true + _visit_occurrence_links: + ignore: true + + # Vocab tables + concept: + # This one is a vocab, but its too big to handle the usual way + ignore: true + # vocabulary_table: true + concept_ancestor: + # This one is a vocab, but its too big to handle the usual way + ignore: true + # vocabulary_table: true + vocabulary: + vocabulary_table: true + domain: + vocabulary_table: true + concept_class: + vocabulary_table: true + concept_synonym: + # This one is a vocab, but its too big to handle the usual way + ignore: true + # vocabulary_table: true + concept_relationship: + # This one is a vocab, but its too big to handle the usual way + ignore: true + # vocabulary_table: true + drug_strength: + # This one is a vocab, but its too big to handle the usual way + ignore: true + # vocabulary_table: true + relationship: + vocabulary_table: true + source_to_concept_map: + vocabulary_table: true + location: + vocabulary_table: true + care_site: + vocabulary_table: true + provider: + vocabulary_table: true + cdm_source: + vocabulary_table: true + + attribute_definition: + num_rows_per_pass: 0 + + cohort_definition: + num_rows_per_pass: 0 + + condition_era: + num_rows_per_pass: 0 + + cost: + num_rows_per_pass: 0 + + device_exposure: + num_rows_per_pass: 0 + + dose_era: + num_rows_per_pass: 0 + + drug_era: + num_rows_per_pass: 0 + + drug_exposure: + num_rows_per_pass: 0 + + fact_relationship: + num_rows_per_pass: 0 + + measurement: + num_rows_per_pass: 0 + + metadata: + num_rows_per_pass: 0 + + note: + num_rows_per_pass: 0 + + note_nlp: + num_rows_per_pass: 0 + + observation: + num_rows_per_pass: 0 + + observation_period: + num_rows_per_pass: 0 + + payer_plan_period: + num_rows_per_pass: 0 + + procedure_occurrence: + num_rows_per_pass: 0 + + specimen: + num_rows_per_pass: 0 + + visit_detail: + num_rows_per_pass: 0 + + visit_occurrence: + num_rows_per_pass: 0 + + person: + num_rows_per_pass: 0 + + death: + num_rows_per_pass: 0 + + condition_occurrence: + num_rows_per_pass: 0 + diff --git a/examples/mimic_omop/df.py b/examples/mimic_omop/df.py new file mode 100644 index 0000000..d5a1dbd --- /dev/null +++ b/examples/mimic_omop/df.py @@ -0,0 +1,1733 @@ +"""This file was auto-generated by datafaker but can be edited manually.""" +from mimesis import Generic, Numeric, Person +from mimesis.locales import Locale +import sqlalchemy +import sys +from datafaker.base import FileUploader, TableGenerator, ColumnPresence +from datafaker.providers import DistributionProvider + +generic = Generic(locale=Locale.EN_GB) +numeric = Numeric() +person = Person() +dist_gen = DistributionProvider() +column_presence = ColumnPresence() + +sys.path.append("") + +from datafaker.providers import ( + BytesProvider, + ColumnValueProvider, + DistributionProvider, + NullProvider, + SQLGroupByProvider, + TimedeltaProvider, + TimespanProvider, + WeightedBooleanProvider, +) + +generic.add_provider(BytesProvider) +generic.add_provider(ColumnValueProvider) +generic.add_provider(DistributionProvider) +generic.add_provider(NullProvider) +generic.add_provider(SQLGroupByProvider) +generic.add_provider(TimedeltaProvider) +generic.add_provider(TimespanProvider) +generic.add_provider(WeightedBooleanProvider) + + +class CohortGenerator(TableGenerator): + num_rows_per_pass = 1 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "cohort_start_date", + "cohort_end_date", + "cohort_definition_id", + "subject_id", + } + ) + while columns_to_generate: + if "cohort_definition_id" in columns_to_generate: + result["cohort_definition_id"] = generic.numeric.integer_number() + if "cohort_end_date" in columns_to_generate: + result["cohort_end_date"] = generic.datetime.date() + if "cohort_start_date" in columns_to_generate: + result["cohort_start_date"] = generic.datetime.date() + if "subject_id" in columns_to_generate: + result["subject_id"] = generic.numeric.integer_number() + columns_to_generate = set() + return result + + +class Cohort_DefinitionGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "cohort_initiation_date", + "definition_type_concept_id", + "cohort_definition_syntax", + "cohort_definition_id", + "cohort_definition_description", + "subject_concept_id", + "cohort_definition_name", + } + ) + while columns_to_generate: + if "cohort_definition_description" in columns_to_generate: + result["cohort_definition_description"] = generic.text.color() + if "cohort_definition_id" in columns_to_generate: + result["cohort_definition_id"] = generic.numeric.integer_number() + if "cohort_definition_name" in columns_to_generate: + result["cohort_definition_name"] = generic.person.password(length=255) + if "cohort_definition_syntax" in columns_to_generate: + result["cohort_definition_syntax"] = generic.text.color() + if "cohort_initiation_date" in columns_to_generate: + result["cohort_initiation_date"] = generic.datetime.date() + if "definition_type_concept_id" in columns_to_generate: + result["definition_type_concept_id"] = generic.numeric.integer_number() + if "subject_concept_id" in columns_to_generate: + result["subject_concept_id"] = generic.numeric.integer_number() + columns_to_generate = set() + return result + + +class Condition_EraGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "condition_era_id", + "person_id", + "condition_era_start_date", + "condition_era_end_date", + "condition_occurrence_count", + "condition_concept_id", + } + ) + while columns_to_generate: + if "condition_concept_id" in columns_to_generate: + result["condition_concept_id"] = generic.numeric.integer_number() + if "condition_era_end_date" in columns_to_generate: + result["condition_era_end_date"] = generic.datetime.date() + if "condition_era_id" in columns_to_generate: + result["condition_era_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["condition_era"].columns["condition_era_id"], + ) + if "condition_era_start_date" in columns_to_generate: + result["condition_era_start_date"] = generic.datetime.date() + if "condition_occurrence_count" in columns_to_generate: + result["condition_occurrence_count"] = generic.numeric.integer_number() + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + columns_to_generate = set() + return result + + +class Condition_OccurrenceGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "visit_detail_id", + "condition_occurrence_id", + "condition_start_datetime", + "condition_status_concept_id", + "condition_source_value", + "person_id", + "provider_id", + "condition_start_date", + "stop_reason", + "condition_end_date", + "condition_status_source_value", + "condition_end_datetime", + "visit_occurrence_id", + "condition_type_concept_id", + "condition_concept_id", + "condition_source_concept_id", + } + ) + while columns_to_generate: + if "condition_concept_id" in columns_to_generate: + result["condition_concept_id"] = generic.numeric.integer_number() + if "condition_end_date" in columns_to_generate: + result["condition_end_date"] = generic.datetime.date() + if "condition_end_datetime" in columns_to_generate: + result["condition_end_datetime"] = generic.datetime.datetime() + if "condition_occurrence_id" in columns_to_generate: + result[ + "condition_occurrence_id" + ] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["condition_occurrence"].columns[ + "condition_occurrence_id" + ], + ) + if "condition_source_concept_id" in columns_to_generate: + result["condition_source_concept_id"] = generic.numeric.integer_number() + if "condition_source_value" in columns_to_generate: + result["condition_source_value"] = generic.person.password(length=50) + if "condition_start_date" in columns_to_generate: + result["condition_start_date"] = generic.datetime.date() + if "condition_start_datetime" in columns_to_generate: + result["condition_start_datetime"] = generic.datetime.datetime() + if "condition_status_concept_id" in columns_to_generate: + result["condition_status_concept_id"] = generic.person.password( + length=50 + ) + if "condition_status_source_value" in columns_to_generate: + result["condition_status_source_value"] = generic.person.password( + length=50 + ) + if "condition_type_concept_id" in columns_to_generate: + result["condition_type_concept_id"] = generic.numeric.integer_number() + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + if "provider_id" in columns_to_generate: + result["provider_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["provider"], "provider_id" + ) + if "stop_reason" in columns_to_generate: + result["stop_reason"] = generic.person.password(length=20) + if "visit_detail_id" in columns_to_generate: + result["visit_detail_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" + ) + if "visit_occurrence_id" in columns_to_generate: + result[ + "visit_occurrence_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, + metadata.tables["visit_occurrence"], + "visit_occurrence_id", + ) + columns_to_generate = set() + return result + + +class CostGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "paid_patient_deductible", + "drg_concept_id", + "currency_concept_id", + "amount_allowed", + "cost_type_concept_id", + "total_charge", + "total_paid", + "revenue_code_concept_id", + "drg_source_value", + "paid_patient_copay", + "cost_event_id", + "paid_by_patient", + "paid_by_payer", + "cost_id", + "paid_patient_coinsurance", + "total_cost", + "paid_by_primary", + "payer_plan_period_id", + "cost_domain_id", + "revenue_code_source_value", + "paid_dispensing_fee", + "paid_ingredient_cost", + } + ) + while columns_to_generate: + if "amount_allowed" in columns_to_generate: + result["amount_allowed"] = generic.numeric.float_number() + if "cost_domain_id" in columns_to_generate: + result["cost_domain_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["domain"], "domain_id" + ) + if "cost_event_id" in columns_to_generate: + result["cost_event_id"] = generic.numeric.integer_number() + if "cost_id" in columns_to_generate: + result["cost_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["cost"].columns["cost_id"], + ) + if "cost_type_concept_id" in columns_to_generate: + result["cost_type_concept_id"] = generic.numeric.integer_number() + if "currency_concept_id" in columns_to_generate: + result["currency_concept_id"] = generic.numeric.integer_number() + if "drg_concept_id" in columns_to_generate: + result["drg_concept_id"] = generic.numeric.integer_number() + if "drg_source_value" in columns_to_generate: + result["drg_source_value"] = generic.person.password(length=3) + if "paid_by_patient" in columns_to_generate: + result["paid_by_patient"] = generic.numeric.float_number() + if "paid_by_payer" in columns_to_generate: + result["paid_by_payer"] = generic.numeric.float_number() + if "paid_by_primary" in columns_to_generate: + result["paid_by_primary"] = generic.numeric.float_number() + if "paid_dispensing_fee" in columns_to_generate: + result["paid_dispensing_fee"] = generic.numeric.float_number() + if "paid_ingredient_cost" in columns_to_generate: + result["paid_ingredient_cost"] = generic.numeric.float_number() + if "paid_patient_coinsurance" in columns_to_generate: + result["paid_patient_coinsurance"] = generic.numeric.float_number() + if "paid_patient_copay" in columns_to_generate: + result["paid_patient_copay"] = generic.numeric.float_number() + if "paid_patient_deductible" in columns_to_generate: + result["paid_patient_deductible"] = generic.numeric.float_number() + if "payer_plan_period_id" in columns_to_generate: + result["payer_plan_period_id"] = generic.numeric.integer_number() + if "revenue_code_concept_id" in columns_to_generate: + result["revenue_code_concept_id"] = generic.numeric.integer_number() + if "revenue_code_source_value" in columns_to_generate: + result["revenue_code_source_value"] = generic.person.password(length=50) + if "total_charge" in columns_to_generate: + result["total_charge"] = generic.numeric.float_number() + if "total_cost" in columns_to_generate: + result["total_cost"] = generic.numeric.float_number() + if "total_paid" in columns_to_generate: + result["total_paid"] = generic.numeric.float_number() + columns_to_generate = set() + return result + + +class DeathGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "death_datetime", + "cause_concept_id", + "cause_source_concept_id", + "person_id", + "cause_source_value", + "death_type_concept_id", + "death_date", + } + ) + while columns_to_generate: + if "cause_concept_id" in columns_to_generate: + result["cause_concept_id"] = generic.numeric.integer_number() + if "cause_source_concept_id" in columns_to_generate: + result["cause_source_concept_id"] = generic.numeric.integer_number() + if "cause_source_value" in columns_to_generate: + result["cause_source_value"] = generic.person.password(length=50) + if "death_date" in columns_to_generate: + result["death_date"] = generic.datetime.date() + if "death_datetime" in columns_to_generate: + result["death_datetime"] = generic.datetime.datetime() + if "death_type_concept_id" in columns_to_generate: + result["death_type_concept_id"] = generic.numeric.integer_number() + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + columns_to_generate = set() + return result + + +class Device_ExposureGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "device_exposure_start_date", + "visit_detail_id", + "unique_device_id", + "person_id", + "device_source_value", + "provider_id", + "quantity", + "device_concept_id", + "device_exposure_end_datetime", + "device_exposure_end_date", + "device_source_concept_id", + "device_type_concept_id", + "visit_occurrence_id", + "device_exposure_id", + "device_exposure_start_datetime", + } + ) + while columns_to_generate: + if "device_concept_id" in columns_to_generate: + result["device_concept_id"] = generic.numeric.integer_number() + if "device_exposure_end_date" in columns_to_generate: + result["device_exposure_end_date"] = generic.datetime.date() + if "device_exposure_end_datetime" in columns_to_generate: + result["device_exposure_end_datetime"] = generic.datetime.datetime() + if "device_exposure_id" in columns_to_generate: + result["device_exposure_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["device_exposure"].columns[ + "device_exposure_id" + ], + ) + if "device_exposure_start_date" in columns_to_generate: + result["device_exposure_start_date"] = generic.datetime.date() + if "device_exposure_start_datetime" in columns_to_generate: + result["device_exposure_start_datetime"] = generic.datetime.datetime() + if "device_source_concept_id" in columns_to_generate: + result["device_source_concept_id"] = generic.numeric.integer_number() + if "device_source_value" in columns_to_generate: + result["device_source_value"] = generic.person.password(length=50) + if "device_type_concept_id" in columns_to_generate: + result["device_type_concept_id"] = generic.numeric.integer_number() + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + if "provider_id" in columns_to_generate: + result["provider_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["provider"], "provider_id" + ) + if "quantity" in columns_to_generate: + result["quantity"] = generic.numeric.integer_number() + if "unique_device_id" in columns_to_generate: + result["unique_device_id"] = generic.person.password(length=255) + if "visit_detail_id" in columns_to_generate: + result["visit_detail_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" + ) + if "visit_occurrence_id" in columns_to_generate: + result[ + "visit_occurrence_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, + metadata.tables["visit_occurrence"], + "visit_occurrence_id", + ) + columns_to_generate = set() + return result + + +class Dose_EraGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "drug_concept_id", + "unit_concept_id", + "dose_era_start_date", + "person_id", + "dose_era_end_date", + "dose_value", + "dose_era_id", + } + ) + while columns_to_generate: + if "dose_era_end_date" in columns_to_generate: + result["dose_era_end_date"] = generic.datetime.date() + if "dose_era_id" in columns_to_generate: + result["dose_era_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["dose_era"].columns["dose_era_id"], + ) + if "dose_era_start_date" in columns_to_generate: + result["dose_era_start_date"] = generic.datetime.date() + if "dose_value" in columns_to_generate: + result["dose_value"] = generic.numeric.float_number() + if "drug_concept_id" in columns_to_generate: + result["drug_concept_id"] = generic.numeric.integer_number() + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + if "unit_concept_id" in columns_to_generate: + result["unit_concept_id"] = generic.numeric.integer_number() + columns_to_generate = set() + return result + + +class Drug_EraGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "drug_concept_id", + "person_id", + "drug_exposure_count", + "drug_era_id", + "drug_era_end_date", + "gap_days", + "drug_era_start_date", + } + ) + while columns_to_generate: + if "drug_concept_id" in columns_to_generate: + result["drug_concept_id"] = generic.numeric.integer_number() + if "drug_era_end_date" in columns_to_generate: + result["drug_era_end_date"] = generic.datetime.date() + if "drug_era_id" in columns_to_generate: + result["drug_era_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["drug_era"].columns["drug_era_id"], + ) + if "drug_era_start_date" in columns_to_generate: + result["drug_era_start_date"] = generic.datetime.date() + if "drug_exposure_count" in columns_to_generate: + result["drug_exposure_count"] = generic.numeric.integer_number() + if "gap_days" in columns_to_generate: + result["gap_days"] = generic.numeric.integer_number() + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + columns_to_generate = set() + return result + + +class Drug_ExposureGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "sig", + "drug_source_concept_id", + "drug_exposure_end_datetime", + "stop_reason", + "lot_number", + "drug_exposure_end_date", + "route_concept_id", + "days_supply", + "route_source_value", + "dose_unit_source_value", + "drug_source_value", + "provider_id", + "drug_exposure_start_datetime", + "drug_concept_id", + "person_id", + "drug_type_concept_id", + "drug_exposure_id", + "verbatim_end_date", + "drug_exposure_start_date", + "visit_detail_id", + "refills", + "quantity", + "visit_occurrence_id", + } + ) + while columns_to_generate: + if "days_supply" in columns_to_generate: + result["days_supply"] = generic.numeric.integer_number() + if "dose_unit_source_value" in columns_to_generate: + result["dose_unit_source_value"] = generic.person.password(length=50) + if "drug_concept_id" in columns_to_generate: + result["drug_concept_id"] = generic.numeric.integer_number() + if "drug_exposure_end_date" in columns_to_generate: + result["drug_exposure_end_date"] = generic.datetime.date() + if "drug_exposure_end_datetime" in columns_to_generate: + result["drug_exposure_end_datetime"] = generic.datetime.datetime() + if "drug_exposure_id" in columns_to_generate: + result["drug_exposure_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["drug_exposure"].columns["drug_exposure_id"], + ) + if "drug_exposure_start_date" in columns_to_generate: + result["drug_exposure_start_date"] = generic.datetime.date() + if "drug_exposure_start_datetime" in columns_to_generate: + result["drug_exposure_start_datetime"] = generic.datetime.datetime() + if "drug_source_concept_id" in columns_to_generate: + result["drug_source_concept_id"] = generic.numeric.integer_number() + if "drug_source_value" in columns_to_generate: + result["drug_source_value"] = generic.person.password(length=255) + if "drug_type_concept_id" in columns_to_generate: + result["drug_type_concept_id"] = generic.numeric.integer_number() + if "lot_number" in columns_to_generate: + result["lot_number"] = generic.person.password(length=50) + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + if "provider_id" in columns_to_generate: + result["provider_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["provider"], "provider_id" + ) + if "quantity" in columns_to_generate: + result["quantity"] = generic.numeric.float_number() + if "refills" in columns_to_generate: + result["refills"] = generic.numeric.integer_number() + if "route_concept_id" in columns_to_generate: + result["route_concept_id"] = generic.numeric.integer_number() + if "route_source_value" in columns_to_generate: + result["route_source_value"] = generic.person.password(length=50) + if "sig" in columns_to_generate: + result["sig"] = generic.text.color() + if "stop_reason" in columns_to_generate: + result["stop_reason"] = generic.person.password(length=20) + if "verbatim_end_date" in columns_to_generate: + result["verbatim_end_date"] = generic.datetime.date() + if "visit_detail_id" in columns_to_generate: + result["visit_detail_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" + ) + if "visit_occurrence_id" in columns_to_generate: + result[ + "visit_occurrence_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, + metadata.tables["visit_occurrence"], + "visit_occurrence_id", + ) + columns_to_generate = set() + return result + + +class EpisodeGenerator(TableGenerator): + num_rows_per_pass = 1 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "episode_end_datetime", + "episode_end_date", + "episode_source_value", + "episode_id", + "person_id", + "episode_number", + "episode_start_datetime", + "episode_parent_id", + "episode_type_concept_id", + "episode_source_concept_id", + "episode_object_concept_id", + "episode_start_date", + "episode_concept_id", + } + ) + while columns_to_generate: + if "episode_concept_id" in columns_to_generate: + result["episode_concept_id"] = generic.numeric.integer_number() + if "episode_end_date" in columns_to_generate: + result["episode_end_date"] = generic.datetime.date() + if "episode_end_datetime" in columns_to_generate: + result["episode_end_datetime"] = generic.datetime.datetime() + if "episode_id" in columns_to_generate: + result["episode_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["episode"].columns["episode_id"], + ) + if "episode_number" in columns_to_generate: + result["episode_number"] = generic.numeric.integer_number() + if "episode_object_concept_id" in columns_to_generate: + result["episode_object_concept_id"] = generic.numeric.integer_number() + if "episode_parent_id" in columns_to_generate: + result["episode_parent_id"] = generic.numeric.integer_number() + if "episode_source_concept_id" in columns_to_generate: + result["episode_source_concept_id"] = generic.numeric.integer_number() + if "episode_source_value" in columns_to_generate: + result["episode_source_value"] = generic.person.password(length=50) + if "episode_start_date" in columns_to_generate: + result["episode_start_date"] = generic.datetime.date() + if "episode_start_datetime" in columns_to_generate: + result["episode_start_datetime"] = generic.datetime.datetime() + if "episode_type_concept_id" in columns_to_generate: + result["episode_type_concept_id"] = generic.numeric.integer_number() + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + columns_to_generate = set() + return result + + +class Episode_EventGenerator(TableGenerator): + num_rows_per_pass = 1 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + {"event_id", "episode_event_field_concept_id", "episode_id"} + ) + while columns_to_generate: + if "episode_event_field_concept_id" in columns_to_generate: + result[ + "episode_event_field_concept_id" + ] = generic.numeric.integer_number() + if "episode_id" in columns_to_generate: + result["episode_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["episode"], "episode_id" + ) + if "event_id" in columns_to_generate: + result["event_id"] = generic.numeric.integer_number() + columns_to_generate = set() + return result + + +class Fact_RelationshipGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "domain_concept_id_1", + "fact_id_1", + "domain_concept_id_2", + "fact_id_2", + "relationship_concept_id", + } + ) + while columns_to_generate: + if "domain_concept_id_1" in columns_to_generate: + result["domain_concept_id_1"] = generic.numeric.integer_number() + if "domain_concept_id_2" in columns_to_generate: + result["domain_concept_id_2"] = generic.numeric.integer_number() + if "fact_id_1" in columns_to_generate: + result["fact_id_1"] = generic.numeric.integer_number() + if "fact_id_2" in columns_to_generate: + result["fact_id_2"] = generic.numeric.integer_number() + if "relationship_concept_id" in columns_to_generate: + result["relationship_concept_id"] = generic.numeric.integer_number() + columns_to_generate = set() + return result + + +class MeasurementGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "value_as_number", + "measurement_time", + "range_high", + "provider_id", + "value_as_concept_id", + "measurement_type_concept_id", + "measurement_date", + "person_id", + "measurement_id", + "range_low", + "measurement_datetime", + "measurement_source_concept_id", + "visit_detail_id", + "unit_concept_id", + "measurement_concept_id", + "unit_source_value", + "operator_concept_id", + "visit_occurrence_id", + "value_source_value", + "measurement_source_value", + } + ) + while columns_to_generate: + if "measurement_concept_id" in columns_to_generate: + result["measurement_concept_id"] = generic.numeric.integer_number() + if "measurement_date" in columns_to_generate: + result["measurement_date"] = generic.datetime.date() + if "measurement_datetime" in columns_to_generate: + result["measurement_datetime"] = generic.datetime.datetime() + if "measurement_id" in columns_to_generate: + result["measurement_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["measurement"].columns["measurement_id"], + ) + if "measurement_source_concept_id" in columns_to_generate: + result[ + "measurement_source_concept_id" + ] = generic.numeric.integer_number() + if "measurement_source_value" in columns_to_generate: + result["measurement_source_value"] = generic.person.password(length=50) + if "measurement_time" in columns_to_generate: + result["measurement_time"] = generic.person.password(length=10) + if "measurement_type_concept_id" in columns_to_generate: + result["measurement_type_concept_id"] = generic.numeric.integer_number() + if "operator_concept_id" in columns_to_generate: + result["operator_concept_id"] = generic.numeric.integer_number() + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + if "provider_id" in columns_to_generate: + result["provider_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["provider"], "provider_id" + ) + if "range_high" in columns_to_generate: + result["range_high"] = generic.numeric.float_number() + if "range_low" in columns_to_generate: + result["range_low"] = generic.numeric.float_number() + if "unit_concept_id" in columns_to_generate: + result["unit_concept_id"] = generic.numeric.integer_number() + if "unit_source_value" in columns_to_generate: + result["unit_source_value"] = generic.person.password(length=50) + if "value_as_concept_id" in columns_to_generate: + result["value_as_concept_id"] = generic.numeric.integer_number() + if "value_as_number" in columns_to_generate: + result["value_as_number"] = generic.numeric.float_number() + if "value_source_value" in columns_to_generate: + result["value_source_value"] = generic.person.password(length=50) + if "visit_detail_id" in columns_to_generate: + result["visit_detail_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" + ) + if "visit_occurrence_id" in columns_to_generate: + result[ + "visit_occurrence_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, + metadata.tables["visit_occurrence"], + "visit_occurrence_id", + ) + columns_to_generate = set() + return result + + +class MetadataGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "value_as_string", + "metadata_id", + "value_as_number", + "value_as_concept_id", + "name", + "metadata_concept_id", + "metadata_date", + "metadata_type_concept_id", + "metadata_datetime", + } + ) + while columns_to_generate: + if "metadata_concept_id" in columns_to_generate: + result["metadata_concept_id"] = generic.numeric.integer_number() + if "metadata_date" in columns_to_generate: + result["metadata_date"] = generic.datetime.date() + if "metadata_datetime" in columns_to_generate: + result["metadata_datetime"] = generic.datetime.datetime() + if "metadata_id" in columns_to_generate: + result["metadata_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["metadata"].columns["metadata_id"], + ) + if "metadata_type_concept_id" in columns_to_generate: + result["metadata_type_concept_id"] = generic.numeric.integer_number() + if "name" in columns_to_generate: + result["name"] = generic.person.password(length=250) + if "value_as_concept_id" in columns_to_generate: + result["value_as_concept_id"] = generic.numeric.integer_number() + if "value_as_number" in columns_to_generate: + result["value_as_number"] = generic.numeric.float_number() + if "value_as_string" in columns_to_generate: + result["value_as_string"] = generic.person.password(length=250) + columns_to_generate = set() + return result + + +class NoteGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "note_text", + "visit_detail_id", + "encoding_concept_id", + "note_class_concept_id", + "person_id", + "provider_id", + "note_date", + "note_id", + "note_title", + "note_type_concept_id", + "note_event_id", + "visit_occurrence_id", + "note_event_field_concept_id", + "note_datetime", + "note_source_value", + "language_concept_id", + } + ) + while columns_to_generate: + if "encoding_concept_id" in columns_to_generate: + result["encoding_concept_id"] = generic.numeric.integer_number() + if "language_concept_id" in columns_to_generate: + result["language_concept_id"] = generic.numeric.integer_number() + if "note_class_concept_id" in columns_to_generate: + result["note_class_concept_id"] = generic.numeric.integer_number() + if "note_date" in columns_to_generate: + result["note_date"] = generic.datetime.date() + if "note_datetime" in columns_to_generate: + result["note_datetime"] = generic.datetime.datetime() + if "note_event_field_concept_id" in columns_to_generate: + result["note_event_field_concept_id"] = generic.numeric.integer_number() + if "note_event_id" in columns_to_generate: + result["note_event_id"] = generic.numeric.integer_number() + if "note_id" in columns_to_generate: + result["note_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["note"].columns["note_id"], + ) + if "note_source_value" in columns_to_generate: + result["note_source_value"] = generic.person.password(length=50) + if "note_text" in columns_to_generate: + result["note_text"] = generic.text.color() + if "note_title" in columns_to_generate: + result["note_title"] = generic.person.password(length=250) + if "note_type_concept_id" in columns_to_generate: + result["note_type_concept_id"] = generic.numeric.integer_number() + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + if "provider_id" in columns_to_generate: + result["provider_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["provider"], "provider_id" + ) + if "visit_detail_id" in columns_to_generate: + result["visit_detail_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" + ) + if "visit_occurrence_id" in columns_to_generate: + result[ + "visit_occurrence_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, + metadata.tables["visit_occurrence"], + "visit_occurrence_id", + ) + columns_to_generate = set() + return result + + +class Note_NlpGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "offset", + "lexical_variant", + "term_modifiers", + "nlp_datetime", + "nlp_system", + "note_id", + "nlp_date", + "snippet", + "note_nlp_source_concept_id", + "section_concept_id", + "term_temporal", + "term_exists", + "note_nlp_id", + "note_nlp_concept_id", + } + ) + while columns_to_generate: + if "lexical_variant" in columns_to_generate: + result["lexical_variant"] = generic.person.password(length=250) + if "nlp_date" in columns_to_generate: + result["nlp_date"] = generic.datetime.date() + if "nlp_datetime" in columns_to_generate: + result["nlp_datetime"] = generic.datetime.datetime() + if "nlp_system" in columns_to_generate: + result["nlp_system"] = generic.person.password(length=250) + if "note_id" in columns_to_generate: + result["note_id"] = generic.numeric.integer_number() + if "note_nlp_concept_id" in columns_to_generate: + result["note_nlp_concept_id"] = generic.numeric.integer_number() + if "note_nlp_id" in columns_to_generate: + result["note_nlp_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["note_nlp"].columns["note_nlp_id"], + ) + if "note_nlp_source_concept_id" in columns_to_generate: + result["note_nlp_source_concept_id"] = generic.numeric.integer_number() + if "offset" in columns_to_generate: + result["offset"] = generic.person.password(length=50) + if "section_concept_id" in columns_to_generate: + result["section_concept_id"] = generic.numeric.integer_number() + if "snippet" in columns_to_generate: + result["snippet"] = generic.person.password(length=250) + if "term_exists" in columns_to_generate: + result["term_exists"] = generic.person.password(length=1) + if "term_modifiers" in columns_to_generate: + result["term_modifiers"] = generic.person.password(length=2000) + if "term_temporal" in columns_to_generate: + result["term_temporal"] = generic.person.password(length=50) + columns_to_generate = set() + return result + + +class ObservationGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "observation_source_concept_id", + "value_as_string", + "qualifier_source_value", + "unit_concept_id", + "observation_source_value", + "visit_detail_id", + "person_id", + "observation_concept_id", + "provider_id", + "value_as_number", + "observation_type_concept_id", + "qualifier_concept_id", + "unit_source_value", + "value_as_concept_id", + "observation_id", + "visit_occurrence_id", + "observation_datetime", + "observation_date", + } + ) + while columns_to_generate: + if "observation_concept_id" in columns_to_generate: + result["observation_concept_id"] = generic.numeric.integer_number() + if "observation_date" in columns_to_generate: + result["observation_date"] = generic.datetime.date() + if "observation_datetime" in columns_to_generate: + result["observation_datetime"] = generic.datetime.datetime() + if "observation_id" in columns_to_generate: + result["observation_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["observation"].columns["observation_id"], + ) + if "observation_source_concept_id" in columns_to_generate: + result[ + "observation_source_concept_id" + ] = generic.numeric.integer_number() + if "observation_source_value" in columns_to_generate: + result["observation_source_value"] = generic.person.password(length=50) + if "observation_type_concept_id" in columns_to_generate: + result["observation_type_concept_id"] = generic.numeric.integer_number() + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + if "provider_id" in columns_to_generate: + result["provider_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["provider"], "provider_id" + ) + if "qualifier_concept_id" in columns_to_generate: + result["qualifier_concept_id"] = generic.numeric.integer_number() + if "qualifier_source_value" in columns_to_generate: + result["qualifier_source_value"] = generic.person.password(length=50) + if "unit_concept_id" in columns_to_generate: + result["unit_concept_id"] = generic.numeric.integer_number() + if "unit_source_value" in columns_to_generate: + result["unit_source_value"] = generic.person.password(length=50) + if "value_as_concept_id" in columns_to_generate: + result["value_as_concept_id"] = generic.numeric.integer_number() + if "value_as_number" in columns_to_generate: + result["value_as_number"] = generic.numeric.float_number() + if "value_as_string" in columns_to_generate: + result["value_as_string"] = generic.person.password(length=120) + if "visit_detail_id" in columns_to_generate: + result["visit_detail_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" + ) + if "visit_occurrence_id" in columns_to_generate: + result[ + "visit_occurrence_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, + metadata.tables["visit_occurrence"], + "visit_occurrence_id", + ) + columns_to_generate = set() + return result + + +class Observation_PeriodGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "observation_period_id", + "person_id", + "period_type_concept_id", + "observation_period_start_date", + "observation_period_end_date", + } + ) + while columns_to_generate: + if "observation_period_end_date" in columns_to_generate: + result["observation_period_end_date"] = generic.datetime.date() + if "observation_period_id" in columns_to_generate: + result[ + "observation_period_id" + ] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["observation_period"].columns[ + "observation_period_id" + ], + ) + if "observation_period_start_date" in columns_to_generate: + result["observation_period_start_date"] = generic.datetime.date() + if "period_type_concept_id" in columns_to_generate: + result["period_type_concept_id"] = generic.numeric.integer_number() + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + columns_to_generate = set() + return result + + +class Payer_Plan_PeriodGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "plan_source_value", + "plan_concept_id", + "plan_source_concept_id", + "person_id", + "family_source_value", + "sponsor_source_concept_id", + "payer_plan_period_id", + "sponsor_source_value", + "payer_concept_id", + "stop_reason_source_value", + "payer_plan_period_start_date", + "payer_source_value", + "stop_reason_concept_id", + "sponsor_concept_id", + "stop_reason_source_concept_id", + "payer_plan_period_end_date", + "payer_source_concept_id", + } + ) + while columns_to_generate: + if "family_source_value" in columns_to_generate: + result["family_source_value"] = generic.person.password(length=50) + if "payer_concept_id" in columns_to_generate: + result["payer_concept_id"] = generic.numeric.integer_number() + if "payer_plan_period_end_date" in columns_to_generate: + result["payer_plan_period_end_date"] = generic.datetime.date() + if "payer_plan_period_id" in columns_to_generate: + result[ + "payer_plan_period_id" + ] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["payer_plan_period"].columns[ + "payer_plan_period_id" + ], + ) + if "payer_plan_period_start_date" in columns_to_generate: + result["payer_plan_period_start_date"] = generic.datetime.date() + if "payer_source_concept_id" in columns_to_generate: + result["payer_source_concept_id"] = generic.numeric.integer_number() + if "payer_source_value" in columns_to_generate: + result["payer_source_value"] = generic.person.password(length=50) + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + if "plan_concept_id" in columns_to_generate: + result["plan_concept_id"] = generic.numeric.integer_number() + if "plan_source_concept_id" in columns_to_generate: + result["plan_source_concept_id"] = generic.numeric.integer_number() + if "plan_source_value" in columns_to_generate: + result["plan_source_value"] = generic.person.password(length=50) + if "sponsor_concept_id" in columns_to_generate: + result["sponsor_concept_id"] = generic.numeric.integer_number() + if "sponsor_source_concept_id" in columns_to_generate: + result["sponsor_source_concept_id"] = generic.numeric.integer_number() + if "sponsor_source_value" in columns_to_generate: + result["sponsor_source_value"] = generic.person.password(length=50) + if "stop_reason_concept_id" in columns_to_generate: + result["stop_reason_concept_id"] = generic.numeric.integer_number() + if "stop_reason_source_concept_id" in columns_to_generate: + result[ + "stop_reason_source_concept_id" + ] = generic.numeric.integer_number() + if "stop_reason_source_value" in columns_to_generate: + result["stop_reason_source_value"] = generic.person.password(length=50) + columns_to_generate = set() + return result + + +class PersonGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "gender_source_value", + "person_source_value", + "day_of_birth", + "race_source_concept_id", + "birth_datetime", + "ethnicity_concept_id", + "person_id", + "ethnicity_source_value", + "provider_id", + "race_source_value", + "gender_source_concept_id", + "care_site_id", + "month_of_birth", + "location_id", + "ethnicity_source_concept_id", + "race_concept_id", + "gender_concept_id", + "year_of_birth", + } + ) + while columns_to_generate: + if "birth_datetime" in columns_to_generate: + result["birth_datetime"] = generic.datetime.datetime() + if "care_site_id" in columns_to_generate: + result["care_site_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["care_site"], "care_site_id" + ) + if "day_of_birth" in columns_to_generate: + result["day_of_birth"] = generic.numeric.integer_number() + if "ethnicity_concept_id" in columns_to_generate: + result["ethnicity_concept_id"] = generic.numeric.integer_number() + if "ethnicity_source_concept_id" in columns_to_generate: + result["ethnicity_source_concept_id"] = generic.numeric.integer_number() + if "ethnicity_source_value" in columns_to_generate: + result["ethnicity_source_value"] = generic.person.password(length=50) + if "gender_concept_id" in columns_to_generate: + result["gender_concept_id"] = generic.numeric.integer_number() + if "gender_source_concept_id" in columns_to_generate: + result["gender_source_concept_id"] = generic.numeric.integer_number() + if "gender_source_value" in columns_to_generate: + result["gender_source_value"] = generic.person.password(length=50) + if "location_id" in columns_to_generate: + result["location_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["location"], "location_id" + ) + if "month_of_birth" in columns_to_generate: + result["month_of_birth"] = generic.numeric.integer_number() + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["person"].columns["person_id"], + ) + if "person_source_value" in columns_to_generate: + result["person_source_value"] = generic.person.password(length=50) + if "provider_id" in columns_to_generate: + result["provider_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["provider"], "provider_id" + ) + if "race_concept_id" in columns_to_generate: + result["race_concept_id"] = generic.numeric.integer_number() + if "race_source_concept_id" in columns_to_generate: + result["race_source_concept_id"] = generic.numeric.integer_number() + if "race_source_value" in columns_to_generate: + result["race_source_value"] = generic.person.password(length=50) + if "year_of_birth" in columns_to_generate: + result["year_of_birth"] = generic.numeric.integer_number() + columns_to_generate = set() + return result + + +class Procedure_OccurrenceGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "procedure_datetime", + "visit_detail_id", + "procedure_source_value", + "person_id", + "provider_id", + "modifier_concept_id", + "procedure_source_concept_id", + "quantity", + "procedure_concept_id", + "procedure_type_concept_id", + "modifier_source_value", + "visit_occurrence_id", + "procedure_occurrence_id", + "procedure_date", + } + ) + while columns_to_generate: + if "modifier_concept_id" in columns_to_generate: + result["modifier_concept_id"] = generic.numeric.integer_number() + if "modifier_source_value" in columns_to_generate: + result["modifier_source_value"] = generic.person.password(length=50) + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + if "procedure_concept_id" in columns_to_generate: + result["procedure_concept_id"] = generic.numeric.integer_number() + if "procedure_date" in columns_to_generate: + result["procedure_date"] = generic.datetime.date() + if "procedure_datetime" in columns_to_generate: + result["procedure_datetime"] = generic.datetime.datetime() + if "procedure_occurrence_id" in columns_to_generate: + result[ + "procedure_occurrence_id" + ] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["procedure_occurrence"].columns[ + "procedure_occurrence_id" + ], + ) + if "procedure_source_concept_id" in columns_to_generate: + result["procedure_source_concept_id"] = generic.numeric.integer_number() + if "procedure_source_value" in columns_to_generate: + result["procedure_source_value"] = generic.person.password(length=50) + if "procedure_type_concept_id" in columns_to_generate: + result["procedure_type_concept_id"] = generic.numeric.integer_number() + if "provider_id" in columns_to_generate: + result["provider_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["provider"], "provider_id" + ) + if "quantity" in columns_to_generate: + result["quantity"] = generic.numeric.integer_number() + if "visit_detail_id" in columns_to_generate: + result["visit_detail_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" + ) + if "visit_occurrence_id" in columns_to_generate: + result[ + "visit_occurrence_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, + metadata.tables["visit_occurrence"], + "visit_occurrence_id", + ) + columns_to_generate = set() + return result + + +class SpecimenGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "specimen_date", + "specimen_source_value", + "specimen_type_concept_id", + "unit_concept_id", + "specimen_source_id", + "person_id", + "anatomic_site_source_value", + "quantity", + "specimen_concept_id", + "disease_status_concept_id", + "unit_source_value", + "anatomic_site_concept_id", + "specimen_id", + "specimen_datetime", + "disease_status_source_value", + } + ) + while columns_to_generate: + if "anatomic_site_concept_id" in columns_to_generate: + result["anatomic_site_concept_id"] = generic.numeric.integer_number() + if "anatomic_site_source_value" in columns_to_generate: + result["anatomic_site_source_value"] = generic.person.password( + length=50 + ) + if "disease_status_concept_id" in columns_to_generate: + result["disease_status_concept_id"] = generic.numeric.integer_number() + if "disease_status_source_value" in columns_to_generate: + result["disease_status_source_value"] = generic.person.password( + length=50 + ) + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + if "quantity" in columns_to_generate: + result["quantity"] = generic.numeric.float_number() + if "specimen_concept_id" in columns_to_generate: + result["specimen_concept_id"] = generic.numeric.integer_number() + if "specimen_date" in columns_to_generate: + result["specimen_date"] = generic.datetime.date() + if "specimen_datetime" in columns_to_generate: + result["specimen_datetime"] = generic.datetime.datetime() + if "specimen_id" in columns_to_generate: + result["specimen_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["specimen"].columns["specimen_id"], + ) + if "specimen_source_id" in columns_to_generate: + result["specimen_source_id"] = generic.person.password(length=255) + if "specimen_source_value" in columns_to_generate: + result["specimen_source_value"] = generic.person.password(length=50) + if "specimen_type_concept_id" in columns_to_generate: + result["specimen_type_concept_id"] = generic.numeric.integer_number() + if "unit_concept_id" in columns_to_generate: + result["unit_concept_id"] = generic.numeric.integer_number() + if "unit_source_value" in columns_to_generate: + result["unit_source_value"] = generic.person.password(length=50) + columns_to_generate = set() + return result + + +class Visit_DetailGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "visit_detail_type_concept_id", + "visit_detail_start_date", + "visit_detail_start_datetime", + "visit_detail_source_concept_id", + "admitting_source_value", + "provider_id", + "visit_detail_end_date", + "visit_detail_source_value", + "visit_detail_parent_id", + "visit_detail_end_datetime", + "visit_detail_concept_id", + "person_id", + "discharge_to_source_value", + "admitting_source_concept_id", + "visit_detail_id", + "care_site_id", + "preceding_visit_detail_id", + "visit_occurrence_id", + "discharge_to_concept_id", + } + ) + while columns_to_generate: + if "admitting_source_concept_id" in columns_to_generate: + result["admitting_source_concept_id"] = generic.numeric.integer_number() + if "admitting_source_value" in columns_to_generate: + result["admitting_source_value"] = generic.person.password(length=50) + if "care_site_id" in columns_to_generate: + result["care_site_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["care_site"], "care_site_id" + ) + if "discharge_to_concept_id" in columns_to_generate: + result["discharge_to_concept_id"] = generic.numeric.integer_number() + if "discharge_to_source_value" in columns_to_generate: + result["discharge_to_source_value"] = generic.person.password(length=50) + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + if "preceding_visit_detail_id" in columns_to_generate: + result[ + "preceding_visit_detail_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" + ) + if "provider_id" in columns_to_generate: + result["provider_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["provider"], "provider_id" + ) + if "visit_detail_concept_id" in columns_to_generate: + result["visit_detail_concept_id"] = generic.numeric.integer_number() + if "visit_detail_end_date" in columns_to_generate: + result["visit_detail_end_date"] = generic.datetime.date() + if "visit_detail_end_datetime" in columns_to_generate: + result["visit_detail_end_datetime"] = generic.datetime.datetime() + if "visit_detail_id" in columns_to_generate: + result["visit_detail_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["visit_detail"].columns["visit_detail_id"], + ) + if "visit_detail_parent_id" in columns_to_generate: + result["visit_detail_parent_id"] = generic.person.password(length=50) + if "visit_detail_source_concept_id" in columns_to_generate: + result["visit_detail_source_concept_id"] = generic.person.password( + length=50 + ) + if "visit_detail_source_value" in columns_to_generate: + result["visit_detail_source_value"] = generic.person.password( + length=120 + ) + if "visit_detail_start_date" in columns_to_generate: + result["visit_detail_start_date"] = generic.datetime.date() + if "visit_detail_start_datetime" in columns_to_generate: + result["visit_detail_start_datetime"] = generic.datetime.datetime() + if "visit_detail_type_concept_id" in columns_to_generate: + result[ + "visit_detail_type_concept_id" + ] = generic.numeric.integer_number() + if "visit_occurrence_id" in columns_to_generate: + result[ + "visit_occurrence_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, + metadata.tables["visit_occurrence"], + "visit_occurrence_id", + ) + columns_to_generate = set() + return result + + +class Visit_OccurrenceGenerator(TableGenerator): + num_rows_per_pass = 0 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "visit_source_value", + "preceding_visit_occurrence_id", + "visit_type_concept_id", + "person_id", + "admitted_from_concept_id", + "discharged_to_concept_id", + "admitted_from_source_value", + "provider_id", + "visit_end_date", + "visit_end_datetime", + "care_site_id", + "visit_source_concept_id", + "visit_start_datetime", + "visit_occurrence_id", + "discharged_to_source_value", + "visit_start_date", + "visit_concept_id", + } + ) + while columns_to_generate: + if "admitted_from_concept_id" in columns_to_generate: + result["admitted_from_concept_id"] = generic.numeric.integer_number() + if "admitted_from_source_value" in columns_to_generate: + result["admitted_from_source_value"] = generic.person.password( + length=50 + ) + if "care_site_id" in columns_to_generate: + result["care_site_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["care_site"], "care_site_id" + ) + if "discharged_to_concept_id" in columns_to_generate: + result["discharged_to_concept_id"] = generic.numeric.integer_number() + if "discharged_to_source_value" in columns_to_generate: + result["discharged_to_source_value"] = generic.person.password( + length=50 + ) + if "person_id" in columns_to_generate: + result["person_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["person"], "person_id" + ) + if "preceding_visit_occurrence_id" in columns_to_generate: + result[ + "preceding_visit_occurrence_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, + metadata.tables["visit_occurrence"], + "visit_occurrence_id", + ) + if "provider_id" in columns_to_generate: + result["provider_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["provider"], "provider_id" + ) + if "visit_concept_id" in columns_to_generate: + result["visit_concept_id"] = generic.numeric.integer_number() + if "visit_end_date" in columns_to_generate: + result["visit_end_date"] = generic.datetime.date() + if "visit_end_datetime" in columns_to_generate: + result["visit_end_datetime"] = generic.datetime.datetime() + if "visit_occurrence_id" in columns_to_generate: + result["visit_occurrence_id"] = generic.column_value_provider.increment( + db_connection=dst_db_conn, + column=metadata.tables["visit_occurrence"].columns[ + "visit_occurrence_id" + ], + ) + if "visit_source_concept_id" in columns_to_generate: + result["visit_source_concept_id"] = generic.numeric.integer_number() + if "visit_source_value" in columns_to_generate: + result["visit_source_value"] = generic.person.password(length=50) + if "visit_start_date" in columns_to_generate: + result["visit_start_date"] = generic.datetime.date() + if "visit_start_datetime" in columns_to_generate: + result["visit_start_datetime"] = generic.datetime.datetime() + if "visit_type_concept_id" in columns_to_generate: + result["visit_type_concept_id"] = generic.numeric.integer_number() + columns_to_generate = set() + return result + + +table_generator_dict = { + "cohort": CohortGenerator(), + "cohort_definition": Cohort_DefinitionGenerator(), + "condition_era": Condition_EraGenerator(), + "condition_occurrence": Condition_OccurrenceGenerator(), + "cost": CostGenerator(), + "death": DeathGenerator(), + "device_exposure": Device_ExposureGenerator(), + "dose_era": Dose_EraGenerator(), + "drug_era": Drug_EraGenerator(), + "drug_exposure": Drug_ExposureGenerator(), + "episode": EpisodeGenerator(), + "episode_event": Episode_EventGenerator(), + "fact_relationship": Fact_RelationshipGenerator(), + "measurement": MeasurementGenerator(), + "metadata": MetadataGenerator(), + "note": NoteGenerator(), + "note_nlp": Note_NlpGenerator(), + "observation": ObservationGenerator(), + "observation_period": Observation_PeriodGenerator(), + "payer_plan_period": Payer_Plan_PeriodGenerator(), + "person": PersonGenerator(), + "procedure_occurrence": Procedure_OccurrenceGenerator(), + "specimen": SpecimenGenerator(), + "visit_detail": Visit_DetailGenerator(), + "visit_occurrence": Visit_OccurrenceGenerator(), +} + + +story_generator_list = [] diff --git a/examples/mimic_omop/orm.yaml b/examples/mimic_omop/orm.yaml new file mode 100644 index 0000000..a400553 --- /dev/null +++ b/examples/mimic_omop/orm.yaml @@ -0,0 +1,2092 @@ +dsn: postgresql://postgres@localhost:5432/omop5.4 +schema: mimic +tables: + care_site: + columns: + care_site_id: + nullable: false + primary: true + type: BIGINT + care_site_name: + nullable: true + primary: false + type: VARCHAR(255) + care_site_source_value: + nullable: true + primary: false + type: VARCHAR(50) + location_id: + foreign_keys: + - location.location_id + nullable: true + primary: false + type: BIGINT + place_of_service_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + place_of_service_source_value: + nullable: true + primary: false + type: VARCHAR(50) + unique: [] + cdm_source: + columns: + cdm_etl_reference: + nullable: true + primary: false + type: VARCHAR(255) + cdm_holder: + nullable: false + primary: false + type: VARCHAR(255) + cdm_release_date: + nullable: false + primary: false + type: DATE + cdm_source_abbreviation: + nullable: false + primary: false + type: VARCHAR(25) + cdm_source_name: + nullable: false + primary: false + type: VARCHAR(255) + cdm_version: + nullable: true + primary: false + type: VARCHAR(10) + source_description: + nullable: true + primary: false + type: TEXT + source_documentation_reference: + nullable: true + primary: false + type: VARCHAR(255) + source_release_date: + nullable: false + primary: false + type: DATE + vocabulary_version: + nullable: false + primary: false + type: VARCHAR(20) + unique: [] + cohort: + columns: + cohort_definition_id: + nullable: false + primary: false + type: BIGINT + cohort_end_date: + nullable: false + primary: false + type: DATE + cohort_start_date: + nullable: false + primary: false + type: DATE + subject_id: + nullable: false + primary: false + type: BIGINT + unique: [] + cohort_definition: + columns: + cohort_definition_description: + nullable: true + primary: false + type: TEXT + cohort_definition_id: + nullable: false + primary: false + type: BIGINT + cohort_definition_name: + nullable: false + primary: false + type: VARCHAR(255) + cohort_definition_syntax: + nullable: true + primary: false + type: TEXT + cohort_initiation_date: + nullable: true + primary: false + type: DATE + definition_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + subject_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + unique: [] + concept: + columns: + concept_class_id: + foreign_keys: + - concept_class.concept_class_id + nullable: false + primary: false + type: VARCHAR(20) + concept_code: + nullable: false + primary: false + type: VARCHAR(255) + concept_id: + nullable: false + primary: true + type: BIGINT + concept_name: + nullable: false + primary: false + type: VARCHAR(255) + domain_id: + foreign_keys: + - domain.domain_id + nullable: false + primary: false + type: VARCHAR(20) + invalid_reason: + nullable: true + primary: false + type: VARCHAR(1) + standard_concept: + nullable: true + primary: false + type: VARCHAR(1) + valid_end_date: + nullable: false + primary: false + type: DATE + valid_start_date: + nullable: false + primary: false + type: DATE + vocabulary_id: + foreign_keys: + - vocabulary.vocabulary_id + nullable: false + primary: false + type: VARCHAR(50) + unique: [] + concept_ancestor: + columns: + ancestor_concept_id: + nullable: false + primary: false + type: BIGINT + descendant_concept_id: + nullable: false + primary: false + type: BIGINT + max_levels_of_separation: + nullable: false + primary: false + type: BIGINT + min_levels_of_separation: + nullable: false + primary: false + type: BIGINT + unique: [] + concept_class: + columns: + concept_class_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + concept_class_id: + nullable: false + primary: true + type: VARCHAR(20) + concept_class_name: + nullable: false + primary: false + type: VARCHAR(255) + unique: [] + concept_relationship: + columns: + concept_id_1: + nullable: false + primary: false + type: BIGINT + concept_id_2: + nullable: false + primary: false + type: BIGINT + invalid_reason: + nullable: true + primary: false + type: VARCHAR(1) + relationship_id: + foreign_keys: + - relationship.relationship_id + nullable: false + primary: false + type: VARCHAR(20) + valid_end_date: + nullable: false + primary: false + type: DATE + valid_start_date: + nullable: false + primary: false + type: DATE + unique: [] + concept_synonym: + columns: + concept_id: + nullable: false + primary: false + type: BIGINT + concept_synonym_name: + nullable: false + primary: false + type: VARCHAR(1000) + language_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + unique: [] + condition_era: + columns: + condition_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + condition_era_end_date: + nullable: false + primary: false + type: DATE + condition_era_id: + nullable: false + primary: true + type: BIGINT + condition_era_start_date: + nullable: false + primary: false + type: DATE + condition_occurrence_count: + nullable: true + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + unique: [] + condition_occurrence: + columns: + condition_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + condition_end_date: + nullable: true + primary: false + type: DATE + condition_end_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + condition_occurrence_id: + nullable: false + primary: true + type: BIGINT + condition_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + condition_source_value: + nullable: true + primary: false + type: VARCHAR(50) + condition_start_date: + nullable: false + primary: false + type: DATE + condition_start_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + condition_status_concept_id: + nullable: true + primary: false + type: VARCHAR(50) + condition_status_source_value: + nullable: true + primary: false + type: VARCHAR(50) + condition_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + stop_reason: + nullable: true + primary: false + type: VARCHAR(20) + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + cost: + columns: + amount_allowed: + nullable: true + primary: false + type: NUMERIC + cost_domain_id: + foreign_keys: + - domain.domain_id + nullable: false + primary: false + type: VARCHAR(20) + cost_event_id: + nullable: false + primary: false + type: BIGINT + cost_id: + nullable: false + primary: true + type: BIGINT + cost_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + currency_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + drg_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + drg_source_value: + nullable: true + primary: false + type: VARCHAR(3) + paid_by_patient: + nullable: true + primary: false + type: NUMERIC + paid_by_payer: + nullable: true + primary: false + type: NUMERIC + paid_by_primary: + nullable: true + primary: false + type: NUMERIC + paid_dispensing_fee: + nullable: true + primary: false + type: NUMERIC + paid_ingredient_cost: + nullable: true + primary: false + type: NUMERIC + paid_patient_coinsurance: + nullable: true + primary: false + type: NUMERIC + paid_patient_copay: + nullable: true + primary: false + type: NUMERIC + paid_patient_deductible: + nullable: true + primary: false + type: NUMERIC + payer_plan_period_id: + nullable: true + primary: false + type: BIGINT + revenue_code_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + revenue_code_source_value: + nullable: true + primary: false + type: VARCHAR(50) + total_charge: + nullable: true + primary: false + type: NUMERIC + total_cost: + nullable: true + primary: false + type: NUMERIC + total_paid: + nullable: true + primary: false + type: NUMERIC + unique: [] + death: + columns: + cause_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + cause_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + cause_source_value: + nullable: true + primary: false + type: VARCHAR(50) + death_date: + nullable: false + primary: false + type: DATE + death_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + death_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + unique: [] + device_exposure: + columns: + device_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + device_exposure_end_date: + nullable: true + primary: false + type: DATE + device_exposure_end_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + device_exposure_id: + nullable: false + primary: true + type: BIGINT + device_exposure_start_date: + nullable: false + primary: false + type: DATE + device_exposure_start_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + device_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + device_source_value: + nullable: true + primary: false + type: VARCHAR(50) + device_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + quantity: + nullable: true + primary: false + type: BIGINT + unique_device_id: + nullable: true + primary: false + type: VARCHAR(255) + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + domain: + columns: + domain_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + domain_id: + nullable: false + primary: true + type: VARCHAR(20) + domain_name: + nullable: false + primary: false + type: VARCHAR(255) + unique: [] + dose_era: + columns: + dose_era_end_date: + nullable: false + primary: false + type: DATE + dose_era_id: + nullable: false + primary: true + type: BIGINT + dose_era_start_date: + nullable: false + primary: false + type: DATE + dose_value: + nullable: false + primary: false + type: NUMERIC + drug_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + unique: [] + drug_era: + columns: + drug_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + drug_era_end_date: + nullable: false + primary: false + type: DATE + drug_era_id: + nullable: false + primary: true + type: BIGINT + drug_era_start_date: + nullable: false + primary: false + type: DATE + drug_exposure_count: + nullable: true + primary: false + type: BIGINT + gap_days: + nullable: true + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + unique: [] + drug_exposure: + columns: + days_supply: + nullable: true + primary: false + type: BIGINT + dose_unit_source_value: + nullable: true + primary: false + type: VARCHAR(50) + drug_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + drug_exposure_end_date: + nullable: false + primary: false + type: DATE + drug_exposure_end_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + drug_exposure_id: + nullable: false + primary: true + type: BIGINT + drug_exposure_start_date: + nullable: false + primary: false + type: DATE + drug_exposure_start_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + drug_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + drug_source_value: + nullable: true + primary: false + type: VARCHAR(255) + drug_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + lot_number: + nullable: true + primary: false + type: VARCHAR(50) + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + quantity: + nullable: true + primary: false + type: NUMERIC + refills: + nullable: true + primary: false + type: BIGINT + route_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + route_source_value: + nullable: true + primary: false + type: VARCHAR(50) + sig: + nullable: true + primary: false + type: TEXT + stop_reason: + nullable: true + primary: false + type: VARCHAR(20) + verbatim_end_date: + nullable: true + primary: false + type: DATE + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + drug_strength: + columns: + amount_unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + amount_value: + nullable: true + primary: false + type: NUMERIC + box_size: + nullable: true + primary: false + type: BIGINT + denominator_unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + denominator_value: + nullable: true + primary: false + type: NUMERIC + drug_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + ingredient_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + invalid_reason: + nullable: true + primary: false + type: VARCHAR(1) + numerator_unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + numerator_value: + nullable: true + primary: false + type: NUMERIC + valid_end_date: + nullable: false + primary: false + type: DATE + valid_start_date: + nullable: false + primary: false + type: DATE + unique: [] + episode: + columns: + episode_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + episode_end_date: + nullable: true + primary: false + type: DATE + episode_end_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + episode_id: + nullable: false + primary: true + type: BIGINT + episode_number: + nullable: true + primary: false + type: BIGINT + episode_object_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + episode_parent_id: + nullable: true + primary: false + type: BIGINT + episode_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + episode_source_value: + nullable: true + primary: false + type: VARCHAR(50) + episode_start_date: + nullable: false + primary: false + type: DATE + episode_start_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + episode_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + unique: [] + episode_event: + columns: + episode_event_field_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + episode_id: + foreign_keys: + - episode.episode_id + nullable: false + primary: false + type: BIGINT + event_id: + nullable: false + primary: false + type: BIGINT + unique: [] + fact_relationship: + columns: + domain_concept_id_1: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + domain_concept_id_2: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + fact_id_1: + nullable: false + primary: false + type: BIGINT + fact_id_2: + nullable: false + primary: false + type: BIGINT + relationship_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + unique: [] + location: + columns: + address_1: + nullable: true + primary: false + type: VARCHAR(50) + address_2: + nullable: true + primary: false + type: VARCHAR(50) + city: + nullable: true + primary: false + type: VARCHAR(50) + county: + nullable: true + primary: false + type: VARCHAR(20) + location_id: + nullable: false + primary: true + type: BIGINT + location_source_value: + nullable: true + primary: false + type: VARCHAR(50) + state: + nullable: true + primary: false + type: VARCHAR(2) + zip: + nullable: true + primary: false + type: VARCHAR(9) + unique: [] + measurement: + columns: + measurement_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + measurement_date: + nullable: false + primary: false + type: DATE + measurement_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + measurement_id: + nullable: false + primary: true + type: BIGINT + measurement_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + measurement_source_value: + nullable: true + primary: false + type: VARCHAR(50) + measurement_time: + nullable: true + primary: false + type: VARCHAR(10) + measurement_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + operator_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + range_high: + nullable: true + primary: false + type: NUMERIC + range_low: + nullable: true + primary: false + type: NUMERIC + unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + unit_source_value: + nullable: true + primary: false + type: VARCHAR(50) + value_as_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + value_as_number: + nullable: true + primary: false + type: NUMERIC + value_source_value: + nullable: true + primary: false + type: VARCHAR(50) + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + metadata: + columns: + metadata_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + metadata_date: + nullable: true + primary: false + type: DATE + metadata_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + metadata_id: + nullable: false + primary: true + type: BIGINT + metadata_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + name: + nullable: false + primary: false + type: VARCHAR(250) + value_as_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + value_as_number: + nullable: true + primary: false + type: NUMERIC + value_as_string: + nullable: true + primary: false + type: VARCHAR(250) + unique: [] + note: + columns: + encoding_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + language_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + note_class_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + note_date: + nullable: false + primary: false + type: DATE + note_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + note_event_field_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + note_event_id: + nullable: true + primary: false + type: BIGINT + note_id: + nullable: false + primary: true + type: BIGINT + note_source_value: + nullable: true + primary: false + type: VARCHAR(50) + note_text: + nullable: false + primary: false + type: TEXT + note_title: + nullable: true + primary: false + type: VARCHAR(250) + note_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + note_nlp: + columns: + lexical_variant: + nullable: false + primary: false + type: VARCHAR(250) + nlp_date: + nullable: false + primary: false + type: DATE + nlp_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + nlp_system: + nullable: true + primary: false + type: VARCHAR(250) + note_id: + nullable: false + primary: false + type: BIGINT + note_nlp_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + note_nlp_id: + nullable: false + primary: true + type: BIGINT + note_nlp_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + offset: + nullable: true + primary: false + type: VARCHAR(50) + section_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + snippet: + nullable: true + primary: false + type: VARCHAR(250) + term_exists: + nullable: true + primary: false + type: VARCHAR(1) + term_modifiers: + nullable: true + primary: false + type: VARCHAR(2000) + term_temporal: + nullable: true + primary: false + type: VARCHAR(50) + unique: [] + observation: + columns: + observation_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + observation_date: + nullable: false + primary: false + type: DATE + observation_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + observation_id: + nullable: false + primary: true + type: BIGINT + observation_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + observation_source_value: + nullable: true + primary: false + type: VARCHAR(50) + observation_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + qualifier_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + qualifier_source_value: + nullable: true + primary: false + type: VARCHAR(50) + unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + unit_source_value: + nullable: true + primary: false + type: VARCHAR(50) + value_as_concept_id: + nullable: true + primary: false + type: BIGINT + value_as_number: + nullable: true + primary: false + type: NUMERIC + value_as_string: + nullable: true + primary: false + type: VARCHAR(120) + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + observation_period: + columns: + observation_period_end_date: + nullable: false + primary: false + type: DATE + observation_period_id: + nullable: false + primary: true + type: BIGINT + observation_period_start_date: + nullable: false + primary: false + type: DATE + period_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + unique: [] + payer_plan_period: + columns: + family_source_value: + nullable: true + primary: false + type: VARCHAR(50) + payer_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + payer_plan_period_end_date: + nullable: false + primary: false + type: DATE + payer_plan_period_id: + nullable: false + primary: true + type: BIGINT + payer_plan_period_start_date: + nullable: false + primary: false + type: DATE + payer_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + payer_source_value: + nullable: true + primary: false + type: VARCHAR(50) + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + plan_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + plan_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + plan_source_value: + nullable: true + primary: false + type: VARCHAR(50) + sponsor_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + sponsor_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + sponsor_source_value: + nullable: true + primary: false + type: VARCHAR(50) + stop_reason_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + stop_reason_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + stop_reason_source_value: + nullable: true + primary: false + type: VARCHAR(50) + unique: [] + person: + columns: + birth_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + care_site_id: + foreign_keys: + - care_site.care_site_id + nullable: true + primary: false + type: BIGINT + day_of_birth: + nullable: true + primary: false + type: BIGINT + ethnicity_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + ethnicity_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + ethnicity_source_value: + nullable: true + primary: false + type: VARCHAR(50) + gender_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + gender_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + gender_source_value: + nullable: true + primary: false + type: VARCHAR(50) + location_id: + foreign_keys: + - location.location_id + nullable: true + primary: false + type: BIGINT + month_of_birth: + nullable: true + primary: false + type: BIGINT + person_id: + nullable: false + primary: true + type: BIGINT + person_source_value: + nullable: true + primary: false + type: VARCHAR(50) + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + race_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + race_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + race_source_value: + nullable: true + primary: false + type: VARCHAR(50) + year_of_birth: + nullable: false + primary: false + type: BIGINT + unique: [] + procedure_occurrence: + columns: + modifier_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + modifier_source_value: + nullable: true + primary: false + type: VARCHAR(50) + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + procedure_concept_id: + nullable: false + primary: false + type: BIGINT + procedure_date: + nullable: false + primary: false + type: DATE + procedure_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + procedure_occurrence_id: + nullable: false + primary: true + type: BIGINT + procedure_source_concept_id: + nullable: true + primary: false + type: BIGINT + procedure_source_value: + nullable: true + primary: false + type: VARCHAR(50) + procedure_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + quantity: + nullable: true + primary: false + type: BIGINT + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + provider: + columns: + care_site_id: + foreign_keys: + - care_site.care_site_id + nullable: true + primary: false + type: BIGINT + dea: + nullable: true + primary: false + type: VARCHAR(20) + gender_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + gender_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + gender_source_value: + nullable: true + primary: false + type: VARCHAR(50) + npi: + nullable: true + primary: false + type: VARCHAR(20) + provider_id: + nullable: false + primary: true + type: BIGINT + provider_name: + nullable: true + primary: false + type: VARCHAR(255) + provider_source_value: + nullable: true + primary: false + type: VARCHAR(50) + specialty_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + specialty_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + specialty_source_value: + nullable: true + primary: false + type: VARCHAR(50) + year_of_birth: + nullable: true + primary: false + type: BIGINT + unique: [] + relationship: + columns: + defines_ancestry: + nullable: false + primary: false + type: VARCHAR(1) + is_hierarchical: + nullable: false + primary: false + type: VARCHAR(1) + relationship_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + relationship_id: + nullable: false + primary: true + type: VARCHAR(20) + relationship_name: + nullable: false + primary: false + type: VARCHAR(255) + reverse_relationship_id: + nullable: false + primary: false + type: VARCHAR(20) + unique: [] + source_to_concept_map: + columns: + invalid_reason: + nullable: true + primary: false + type: VARCHAR(1) + source_code: + nullable: false + primary: false + type: VARCHAR(50) + source_code_description: + nullable: true + primary: false + type: VARCHAR(255) + source_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + source_vocabulary_id: + nullable: false + primary: false + type: VARCHAR(20) + target_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + target_vocabulary_id: + foreign_keys: + - vocabulary.vocabulary_id + nullable: false + primary: false + type: VARCHAR(20) + valid_end_date: + nullable: false + primary: false + type: DATE + valid_start_date: + nullable: false + primary: false + type: DATE + unique: [] + specimen: + columns: + anatomic_site_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + anatomic_site_source_value: + nullable: true + primary: false + type: VARCHAR(50) + disease_status_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + disease_status_source_value: + nullable: true + primary: false + type: VARCHAR(50) + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + quantity: + nullable: true + primary: false + type: NUMERIC + specimen_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + specimen_date: + nullable: false + primary: false + type: DATE + specimen_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + specimen_id: + nullable: false + primary: true + type: BIGINT + specimen_source_id: + nullable: true + primary: false + type: VARCHAR(255) + specimen_source_value: + nullable: true + primary: false + type: VARCHAR(50) + specimen_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + unit_source_value: + nullable: true + primary: false + type: VARCHAR(50) + unique: [] + visit_detail: + columns: + admitting_source_concept_id: + nullable: true + primary: false + type: BIGINT + admitting_source_value: + nullable: true + primary: false + type: VARCHAR(50) + care_site_id: + foreign_keys: + - care_site.care_site_id + nullable: true + primary: false + type: BIGINT + discharge_to_concept_id: + nullable: true + primary: false + type: BIGINT + discharge_to_source_value: + nullable: true + primary: false + type: VARCHAR(50) + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + preceding_visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + visit_detail_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + visit_detail_end_date: + nullable: false + primary: false + type: DATE + visit_detail_end_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + visit_detail_id: + nullable: false + primary: true + type: BIGINT + visit_detail_parent_id: + nullable: true + primary: false + type: VARCHAR(50) + visit_detail_source_concept_id: + nullable: true + primary: false + type: VARCHAR(50) + visit_detail_source_value: + nullable: true + primary: false + type: VARCHAR(120) + visit_detail_start_date: + nullable: false + primary: false + type: DATE + visit_detail_start_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + visit_detail_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: false + primary: false + type: BIGINT + unique: [] + visit_occurrence: + columns: + admitted_from_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + admitted_from_source_value: + nullable: true + primary: false + type: VARCHAR(50) + care_site_id: + foreign_keys: + - care_site.care_site_id + nullable: true + primary: false + type: BIGINT + discharged_to_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + discharged_to_source_value: + nullable: true + primary: false + type: VARCHAR(50) + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + preceding_visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + visit_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + visit_end_date: + nullable: false + primary: false + type: DATE + visit_end_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + visit_occurrence_id: + nullable: false + primary: true + type: BIGINT + visit_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + visit_source_value: + nullable: true + primary: false + type: VARCHAR(50) + visit_start_date: + nullable: false + primary: false + type: DATE + visit_start_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + visit_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + unique: [] + vocabulary: + columns: + vocabulary_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + vocabulary_id: + nullable: false + primary: true + type: VARCHAR(30) + vocabulary_name: + nullable: false + primary: false + type: VARCHAR(255) + vocabulary_reference: + nullable: true + primary: false + type: VARCHAR(255) + vocabulary_version: + nullable: true + primary: false + type: VARCHAR(255) + unique: [] From 675dd921cd5d7e762400c151ab54e6f9425a648b Mon Sep 17 00:00:00 2001 From: May Yong Date: Mon, 13 Apr 2026 16:05:37 +0100 Subject: [PATCH 03/45] Fix ordered list formatting --- examples/mimic_omop/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/mimic_omop/README.md b/examples/mimic_omop/README.md index f89239d..ac8ce79 100644 --- a/examples/mimic_omop/README.md +++ b/examples/mimic_omop/README.md @@ -2,18 +2,18 @@ `poetry run datafaker make-tables --orm-file ./examples/mimic_omop/orm.yaml` -2. Create schema from the ORM YAML file +1. Create schema from the ORM YAML file `poetry run datafaker create-tables --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml` -3. Create generator table +1. Create generator table `poetry run datafaker create-generators --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml --df-file ./examples/mimic_omop/df.py` -3. Create data +1. Create data `poetry run datafaker create-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml --df-file .\examples\pollution\df.py` -4. Remove data +1. Remove data -`poetry run datafaker remove-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml` \ No newline at end of file +`poetry run datafaker remove-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml` From 54d13b59ebf06f6921540590a3ecdbb04e00b473 Mon Sep 17 00:00:00 2001 From: May Yong Date: Mon, 13 Apr 2026 16:11:26 +0100 Subject: [PATCH 04/45] Fix pre-commit hooks. --- examples/mimic_omop/README.md | 4 +++- examples/mimic_omop/config.yaml | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/mimic_omop/README.md b/examples/mimic_omop/README.md index ac8ce79..b2ab990 100644 --- a/examples/mimic_omop/README.md +++ b/examples/mimic_omop/README.md @@ -1,3 +1,5 @@ +### How to run datafaker process + 1. Make a YAML file representing the tables in the schema `poetry run datafaker make-tables --orm-file ./examples/mimic_omop/orm.yaml` @@ -12,7 +14,7 @@ 1. Create data -`poetry run datafaker create-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml --df-file .\examples\pollution\df.py` +`poetry run datafaker create-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml --df-file .\examples\mimic_omop\df.py` 1. Remove data diff --git a/examples/mimic_omop/config.yaml b/examples/mimic_omop/config.yaml index 55fb110..34c7009 100644 --- a/examples/mimic_omop/config.yaml +++ b/examples/mimic_omop/config.yaml @@ -119,4 +119,3 @@ tables: condition_occurrence: num_rows_per_pass: 0 - From 1c42c49f2b91bb7a8773325482d15fe4a6cece0d Mon Sep 17 00:00:00 2001 From: May Yong Date: Mon, 13 Apr 2026 16:18:32 +0100 Subject: [PATCH 05/45] Fix headers that broke pre-commit hook --- examples/mimic_omop/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mimic_omop/README.md b/examples/mimic_omop/README.md index b2ab990..bd04883 100644 --- a/examples/mimic_omop/README.md +++ b/examples/mimic_omop/README.md @@ -1,4 +1,4 @@ -### How to run datafaker process +# How to run datafaker process on omop schema 1. Make a YAML file representing the tables in the schema From b311776815f1a351f78246c8f4f0e4a4d1415251 Mon Sep 17 00:00:00 2001 From: May Yong Date: Mon, 13 Apr 2026 17:56:54 +0100 Subject: [PATCH 06/45] Organised UI commands --- datafaker/main.py | 565 +++++++++++++++++++++++----------------------- 1 file changed, 282 insertions(+), 283 deletions(-) diff --git a/datafaker/main.py b/datafaker/main.py index e3d5e5f..4ac6d55 100644 --- a/datafaker/main.py +++ b/datafaker/main.py @@ -23,10 +23,9 @@ TableWriter, get_parquet_table_writer, ) -from datafaker.interactive import ( +from datafaker.interactive import ( # update_missingness, update_config_generators, update_config_tables, - update_missingness, ) from datafaker.interactive.base import DbCmd from datafaker.make import ( @@ -140,99 +139,206 @@ def main( conf_logger(verbose) -@app.command() -def create_data( +@app.command(rich_help_panel="Configure") +def make_tables( + orm_file: Path = Option(ORM_FILENAME, help="Path to write the ORM yaml file to"), + force: bool = Option( + False, "--force", "-f", help="Overwrite any existing orm yaml file." + ), + parquet_dir: Optional[Path] = Option( + None, + help=( + "Directory of Parquet files to consider part of the database." + " This can be useful when using DuckDB." + " Make sure you check the output!" + ), + file_okay=False, + dir_okay=True, + ), +) -> None: + """Make a YAML file representing the tables in the schema. + + Example: + $ datafaker make_tables + """ + logger.debug("Creating %s.", orm_file) + + orm_file_path = Path(orm_file) + if not force: + _check_file_non_existence(orm_file_path) + + content = make_tables_file( + get_source_dsn(), + get_source_schema(), + parquet_dir, + ) + orm_file_path.write_text(content, encoding="utf-8") + logger.debug("%s created.", orm_file) + + +@app.command(rich_help_panel="Configure") +def make_vocab( orm_file: Path = Option( ORM_FILENAME, help="The name of the ORM yaml file", dir_okay=False, ), - df_file: str = Option( - DF_FILENAME, - help="The name of the generators file. Must be in the current working directory.", - dir_okay=False, - ), config_file: Optional[Path] = Option( CONFIG_FILENAME, help="The configuration file", + dir_okay=False, ), - num_passes: int = Option(1, help="Number of passes (rows or stories) to make"), + force: bool = Option( + False, + "--force/--no-force", + "-f/+f", + help="Overwrite any existing vocabulary file.", + ), + compress: bool = Option(False, help="Compress file to .gz"), + only: list[str] = Option([], help="Only download this table."), ) -> None: - """Populate the schema in the target directory with synthetic data. - - This CLI command generates synthetic data for - Python table structures, and inserts these rows - into a destination schema. - - Also takes as input object relational model as represented - by file containing Python classes and its attributes. - - Takes as input datafaker output as represented by Python - classes, its attributes and methods for generating values - for those attributes. + """Make files of vocabulary tables. - Final input is the number of rows required. + Each table marked in the configuration file as "vocabulary_table: true" Example: - $ datafaker create-data + $ datafaker make-vocab --config-file config.yml """ - logger.debug("Creating data.") - config = read_config_file(config_file) if config_file is not None else {} - orm_metadata = load_metadata_for_output(orm_file, config) - df_module = import_file(df_file) - try: - row_counts = create_db_data( - sorted_non_vocabulary_tables(orm_metadata, config), - df_module, - num_passes, - orm_metadata, + generator_config = read_config_file(config_file) if config_file is not None else {} + orm_metadata = load_metadata(orm_file, generator_config) + make_vocabulary_tables( + orm_metadata, + generator_config, + overwrite_files=force, + compress=compress, + table_names=set(only) if only else None, + ) + + +@app.command(rich_help_panel="Configure") +def configure_tables( + config_file: Path = Option( + CONFIG_FILENAME, + help="Path to write the configuration file to", + dir_okay=False, + ), + orm_file: Path = Option( + ORM_FILENAME, + help="The name of the ORM yaml file", + dir_okay=False, + ), +) -> None: + """Interactively set tables to ignored, vocabulary or primary private.""" + logger.debug("Configuring tables in %s.", config_file) + config = {} + if config_file.exists(): + config = yaml.load( + config_file.read_text(encoding="UTF-8"), Loader=yaml.SafeLoader ) - logger.debug( - "Data created in %s %s.", - num_passes, - "pass" if num_passes == 1 else "passes", + # we don't pass config here so that no tables are ignored + meta_dict = load_metadata_config(orm_file) + metadata = dict_to_metadata(meta_dict, None) + config_updated = update_config_tables( + get_source_dsn(), + get_source_schema(), + metadata, + config, + Path(meta_dict["parquet-dir"]) if "parquet-dir" in meta_dict else None, + ) + if config_updated is None: + logger.debug("Cancelled") + return + content = yaml.dump(config_updated) + config_file.write_text(content, encoding="utf-8") + logger.debug("Tables configured in %s.", config_file) + + +@app.command(rich_help_panel="Configure") +def configure_generators( + config_file: Path = Option( + CONFIG_FILENAME, + help="Path of the configuration file to alter", + dir_okay=False, + ), + orm_file: Path = Option( + ORM_FILENAME, + help="The name of the ORM yaml file", + dir_okay=False, + ), + spec: Path = Option( + None, + help=( + "CSV file (headerless) with fields table-name," + " column-name, generator-name to set non-interactively" + ), + ), +) -> None: + """Interactively set generators for column data.""" + logger.debug("Configuring generators in %s.", config_file) + config = {} + if config_file.exists(): + config = yaml.load( + config_file.read_text(encoding="UTF-8"), Loader=yaml.SafeLoader ) - for table_name, row_count in row_counts.items(): - logger.debug( - "%s: %s %s created.", - table_name, - row_count, - "row" if row_count == 1 else "rows", - ) + meta_dict = load_metadata_config(orm_file) + metadata = dict_to_metadata(meta_dict, None) + config_updated = update_config_generators( + DbCmd.Settings( + get_source_dsn(), + get_source_schema(), + config, + metadata, + meta_dict.get("parquet-dir", None), + ), + spec_path=spec, + ) + if config_updated is None: + logger.debug("Cancelled") return - except RuntimeError as e: - logger.error(e.args[0]) - raise Exit(1) + content = yaml.dump(config_updated) + config_file.write_text(content, encoding="utf-8") + logger.debug("Generators configured in %s.", config_file) -@app.command() -def create_vocab( +@app.command(rich_help_panel="Extract") +def make_stats( orm_file: Path = Option( ORM_FILENAME, help="The name of the ORM yaml file", dir_okay=False, ), - config_file: Path = Option( + config_file: Optional[Path] = Option( CONFIG_FILENAME, help="The configuration file", dir_okay=False, ), + stats_file: Path = Option(STATS_FILENAME), + force: bool = Option( + False, "--force", "-f", help="Overwrite any existing vocabulary file." + ), ) -> None: - """Import vocabulary data into the target database. + """Compute summary statistics from the source database.""" + logger.debug("Creating %s.", stats_file) + + if not force: + _check_file_non_existence(stats_file) - Example: - $ datafaker create-vocab - """ - logger.debug("Loading vocab.") config = read_config_file(config_file) if config_file is not None else {} meta_dict = load_metadata_config(orm_file, config) - orm_metadata = dict_to_metadata(meta_dict, config) - vocabs_loaded = create_db_vocab(orm_metadata, meta_dict, config) - num_vocabs = len(vocabs_loaded) - logger.debug("%s %s loaded.", num_vocabs, "table" if num_vocabs == 1 else "tables") + + src_stats = asyncio.get_event_loop().run_until_complete( + make_src_stats( + get_source_dsn(), + config, + get_source_schema(), + parquet_dir=meta_dict.get("parquet-dir", None), + ) + ) + stats_file.write_text(yaml.dump(src_stats), encoding="utf-8") + logger.debug("%s created.", stats_file) -@app.command() +@app.command(rich_help_panel="Create Synthetic Database") def create_tables( orm_file: Path = Option( ORM_FILENAME, @@ -260,7 +366,34 @@ def create_tables( logger.debug("Tables created.") -@app.command() +@app.command(rich_help_panel="Create Synthetic Database") +def create_vocab( + orm_file: Path = Option( + ORM_FILENAME, + help="The name of the ORM yaml file", + dir_okay=False, + ), + config_file: Path = Option( + CONFIG_FILENAME, + help="The configuration file", + dir_okay=False, + ), +) -> None: + """Import vocabulary data into the target database. + + Example: + $ datafaker create-vocab + """ + logger.debug("Loading vocab.") + config = read_config_file(config_file) if config_file is not None else {} + meta_dict = load_metadata_config(orm_file, config) + orm_metadata = dict_to_metadata(meta_dict, config) + vocabs_loaded = create_db_vocab(orm_metadata, meta_dict, config) + num_vocabs = len(vocabs_loaded) + logger.debug("%s %s loaded.", num_vocabs, "table" if num_vocabs == 1 else "tables") + + +@app.command(rich_help_panel="Create Synthetic Database") def create_generators( orm_file: Path = Option( ORM_FILENAME, @@ -320,242 +453,69 @@ def create_generators( logger.debug("%s created.", df_file) -@app.command() -def make_vocab( +@app.command(rich_help_panel="Create Synthetic Database") +def create_data( orm_file: Path = Option( ORM_FILENAME, help="The name of the ORM yaml file", dir_okay=False, ), - config_file: Optional[Path] = Option( - CONFIG_FILENAME, - help="The configuration file", - dir_okay=False, - ), - force: bool = Option( - False, - "--force/--no-force", - "-f/+f", - help="Overwrite any existing vocabulary file.", - ), - compress: bool = Option(False, help="Compress file to .gz"), - only: list[str] = Option([], help="Only download this table."), -) -> None: - """Make files of vocabulary tables. - - Each table marked in the configuration file as "vocabulary_table: true" - - Example: - $ datafaker make-vocab --config-file config.yml - """ - generator_config = read_config_file(config_file) if config_file is not None else {} - orm_metadata = load_metadata(orm_file, generator_config) - make_vocabulary_tables( - orm_metadata, - generator_config, - overwrite_files=force, - compress=compress, - table_names=set(only) if only else None, - ) - - -@app.command() -def make_stats( - orm_file: Path = Option( - ORM_FILENAME, - help="The name of the ORM yaml file", + df_file: str = Option( + DF_FILENAME, + help="The name of the generators file. Must be in the current working directory.", dir_okay=False, ), config_file: Optional[Path] = Option( CONFIG_FILENAME, help="The configuration file", - dir_okay=False, - ), - stats_file: Path = Option(STATS_FILENAME), - force: bool = Option( - False, "--force", "-f", help="Overwrite any existing vocabulary file." ), + num_passes: int = Option(1, help="Number of passes (rows or stories) to make"), ) -> None: - """Compute summary statistics from the source database.""" - logger.debug("Creating %s.", stats_file) - - if not force: - _check_file_non_existence(stats_file) + """Populate the schema in the target directory with synthetic data. - config = read_config_file(config_file) if config_file is not None else {} - meta_dict = load_metadata_config(orm_file, config) + This CLI command generates synthetic data for + Python table structures, and inserts these rows + into a destination schema. - src_stats = asyncio.get_event_loop().run_until_complete( - make_src_stats( - get_source_dsn(), - config, - get_source_schema(), - parquet_dir=meta_dict.get("parquet-dir", None), - ) - ) - stats_file.write_text(yaml.dump(src_stats), encoding="utf-8") - logger.debug("%s created.", stats_file) + Also takes as input object relational model as represented + by file containing Python classes and its attributes. + Takes as input datafaker output as represented by Python + classes, its attributes and methods for generating values + for those attributes. -@app.command() -def make_tables( - orm_file: Path = Option(ORM_FILENAME, help="Path to write the ORM yaml file to"), - force: bool = Option( - False, "--force", "-f", help="Overwrite any existing orm yaml file." - ), - parquet_dir: Optional[Path] = Option( - None, - help=( - "Directory of Parquet files to consider part of the database." - " This can be useful when using DuckDB." - " Make sure you check the output!" - ), - file_okay=False, - dir_okay=True, - ), -) -> None: - """Make a YAML file representing the tables in the schema. + Final input is the number of rows required. Example: - $ datafaker make_tables + $ datafaker create-data """ - logger.debug("Creating %s.", orm_file) - - orm_file_path = Path(orm_file) - if not force: - _check_file_non_existence(orm_file_path) - - content = make_tables_file( - get_source_dsn(), - get_source_schema(), - parquet_dir, - ) - orm_file_path.write_text(content, encoding="utf-8") - logger.debug("%s created.", orm_file) - - -@app.command() -def configure_tables( - config_file: Path = Option( - CONFIG_FILENAME, - help="Path to write the configuration file to", - dir_okay=False, - ), - orm_file: Path = Option( - ORM_FILENAME, - help="The name of the ORM yaml file", - dir_okay=False, - ), -) -> None: - """Interactively set tables to ignored, vocabulary or primary private.""" - logger.debug("Configuring tables in %s.", config_file) - config = {} - if config_file.exists(): - config = yaml.load( - config_file.read_text(encoding="UTF-8"), Loader=yaml.SafeLoader - ) - # we don't pass config here so that no tables are ignored - meta_dict = load_metadata_config(orm_file) - metadata = dict_to_metadata(meta_dict, None) - config_updated = update_config_tables( - get_source_dsn(), - get_source_schema(), - metadata, - config, - Path(meta_dict["parquet-dir"]) if "parquet-dir" in meta_dict else None, - ) - if config_updated is None: - logger.debug("Cancelled") - return - content = yaml.dump(config_updated) - config_file.write_text(content, encoding="utf-8") - logger.debug("Tables configured in %s.", config_file) - - -@app.command() -def configure_missing( - config_file: Path = Option( - CONFIG_FILENAME, - help="Path to write the configuration file to", - dir_okay=False, - ), - orm_file: Path = Option( - ORM_FILENAME, - help="The name of the ORM yaml file", - dir_okay=False, - ), -) -> None: - """Interactively set the missingness of the generated data.""" - logger.debug("Configuring missingness in %s.", config_file) - config: dict[str, Any] = {} - if config_file.exists(): - config_any = yaml.load( - config_file.read_text(encoding="UTF-8"), Loader=yaml.SafeLoader + logger.debug("Creating data.") + config = read_config_file(config_file) if config_file is not None else {} + orm_metadata = load_metadata_for_output(orm_file, config) + df_module = import_file(df_file) + try: + row_counts = create_db_data( + sorted_non_vocabulary_tables(orm_metadata, config), + df_module, + num_passes, + orm_metadata, ) - if isinstance(config_any, dict): - config = config_any - meta_dict = load_metadata_config(orm_file, config) - metadata = dict_to_metadata(meta_dict, None) - config_updated = update_missingness( - get_source_dsn(), - get_source_schema(), - metadata, - config, - Path(meta_dict["parquet-dir"]) if "parquet-dir" in meta_dict else None, - ) - if config_updated is None: - logger.debug("Cancelled") - return - content = yaml.dump(config_updated) - config_file.write_text(content, encoding="utf-8") - logger.debug("Generators missingness in %s.", config_file) - - -@app.command() -def configure_generators( - config_file: Path = Option( - CONFIG_FILENAME, - help="Path of the configuration file to alter", - dir_okay=False, - ), - orm_file: Path = Option( - ORM_FILENAME, - help="The name of the ORM yaml file", - dir_okay=False, - ), - spec: Path = Option( - None, - help=( - "CSV file (headerless) with fields table-name," - " column-name, generator-name to set non-interactively" - ), - ), -) -> None: - """Interactively set generators for column data.""" - logger.debug("Configuring generators in %s.", config_file) - config = {} - if config_file.exists(): - config = yaml.load( - config_file.read_text(encoding="UTF-8"), Loader=yaml.SafeLoader + logger.debug( + "Data created in %s %s.", + num_passes, + "pass" if num_passes == 1 else "passes", ) - meta_dict = load_metadata_config(orm_file) - metadata = dict_to_metadata(meta_dict, None) - config_updated = update_config_generators( - DbCmd.Settings( - get_source_dsn(), - get_source_schema(), - config, - metadata, - meta_dict.get("parquet-dir", None), - ), - spec_path=spec, - ) - if config_updated is None: - logger.debug("Cancelled") + for table_name, row_count in row_counts.items(): + logger.debug( + "%s: %s %s created.", + table_name, + row_count, + "row" if row_count == 1 else "rows", + ) return - content = yaml.dump(config_updated) - config_file.write_text(content, encoding="utf-8") - logger.debug("Generators configured in %s.", config_file) + except RuntimeError as e: + logger.error(e.args[0]) + raise Exit(1) def convert_table_names_to_tables( @@ -627,7 +587,7 @@ def _dump_tables_to_directory( logger.warning("Failed to write %s", f) -@app.command() +@app.command(rich_help_panel="Inspect and Export") def dump_data( config_file: Optional[Path] = Option( CONFIG_FILENAME, @@ -689,7 +649,7 @@ def dump_data( _dump_tables_to_directory(writer, directory, mtables) -@app.command() +@app.command(rich_help_panel="Inspect and Export") def validate_config( config_file: Path = Argument(help="The configuration file to validate"), ) -> None: @@ -706,7 +666,7 @@ def validate_config( logger.debug("Config file is valid.") -@app.command() +@app.command(rich_help_panel="Remove") def remove_data( orm_file: Path = Option( ORM_FILENAME, @@ -733,7 +693,7 @@ def remove_data( logger.info("Would truncate non-vocabulary tables if called with --yes.") -@app.command() +@app.command(rich_help_panel="Remove") def remove_vocab( orm_file: Path = Option( ORM_FILENAME, @@ -761,7 +721,7 @@ def remove_vocab( logger.info("Would truncate vocabulary tables if called with --yes.") -@app.command() +@app.command(rich_help_panel="Remove") def remove_tables( orm_file: Path = Option( ORM_FILENAME, @@ -812,7 +772,7 @@ class TableType(str, Enum): GENERATED = "generated" -@app.command() +@app.command(rich_help_panel="Inspect and Export") def list_tables( orm_file: Path = Option( ORM_FILENAME, @@ -845,7 +805,7 @@ def list_tables( print(name) -@app.command() +@app.command(rich_help_panel="Inspect and Export") def version() -> None: """Display version information.""" logger.info( @@ -857,3 +817,42 @@ def version() -> None: if __name__ == "__main__": datafaker() + + +# @app.command(rich_help_panel="Discovery and Configuration") +# def configure_missing( +# config_file: Path = Option( +# CONFIG_FILENAME, +# help="Path to write the configuration file to", +# dir_okay=False, +# ), +# orm_file: Path = Option( +# ORM_FILENAME, +# help="The name of the ORM yaml file", +# dir_okay=False, +# ), +# ) -> None: +# """Interactively set the missingness of the generated data.""" +# logger.debug("Configuring missingness in %s.", config_file) +# config: dict[str, Any] = {} +# if config_file.exists(): +# config_any = yaml.load( +# config_file.read_text(encoding="UTF-8"), Loader=yaml.SafeLoader +# ) +# if isinstance(config_any, dict): +# config = config_any +# meta_dict = load_metadata_config(orm_file, config) +# metadata = dict_to_metadata(meta_dict, None) +# config_updated = update_missingness( +# get_source_dsn(), +# get_source_schema(), +# metadata, +# config, +# Path(meta_dict["parquet-dir"]) if "parquet-dir" in meta_dict else None, +# ) +# if config_updated is None: +# logger.debug("Cancelled") +# return +# content = yaml.dump(config_updated) +# config_file.write_text(content, encoding="utf-8") +# logger.debug("Generators missingness in %s.", config_file) From b2f14ab1d81097c085e53b2f9771f47291d3fa6b Mon Sep 17 00:00:00 2001 From: May Yong Date: Tue, 19 May 2026 13:04:46 +0100 Subject: [PATCH 07/45] Add initial MS-SQL support: driver deps, async DSN rewriting, schema routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses issues #93, #94, and #95. Issue #93 – Driver dependency - Move psycopg2-binary to an optional 'postgres' extra - Add optional pyodbc and aioodbc as a new 'mssql' extra - Remove unconditional top-level `import psycopg2`; replace the `psycopg2.errors.UndefinedObject` check with `_is_undefined_object_error`, which lazily imports psycopg2 when available and falls back to checking the SQLSTATE pgcode (42704) otherwise Issue #94 – Hardcoded async DSN rewriting - Add `make_async_dsn()` helper that parses the DSN dialect with SQLAlchemy's `make_url` and rewrites the driver via `_ASYNC_DRIVER_MAP` (postgresql → asyncpg, mssql → aioodbc); raises ValueError for unknown dialects instead of silently producing a broken DSN - Replace the hardcoded `db_dsn.replace("postgresql://", ...)` in `create_db_engine` with a call to `make_async_dsn` Issue #95 – PostgreSQL search_path schema selection - Replace `SET search_path TO ` (PostgreSQL-only) with `engine.execution_options(schema_translate_map={None: schema_name})`, which is dialect-neutral and works for PostgreSQL, MS-SQL, and DuckDB - The `set_db_settings` connect-event hook is now only wired up for DuckDB's `file_search_path`; update its docstring accordingly - Add `schema_name` parameter to `get_metadata` and pass it to `MetaData.reflect(engine, schema=schema_name)` so reflection targets the right schema without relying on search_path - Update `make_tables_file` and `remove_db_tables` to forward schema_name to `get_metadata` Also adds: - examples/omop-mssql/ with README documenting all eight MS-SQL challenges (challenges 1–3 link to GitHub issues #93–#95) - tests/test_utils_mssql.py with 19 unit tests covering all new helpers and the schema_translate_map behaviour Co-Authored-By: Claude Sonnet 4.6 --- datafaker/make.py | 2 +- datafaker/remove.py | 5 +- datafaker/utils.py | 74 ++++++++-- examples/omop-mssql/README.md | 74 ++++++++++ poetry.lock | 269 +++++++++++++++++++++++++++++++--- pyproject.toml | 6 +- tests/test_utils_mssql.py | 207 ++++++++++++++++++++++++++ 7 files changed, 595 insertions(+), 42 deletions(-) create mode 100644 examples/omop-mssql/README.md create mode 100644 tests/test_utils_mssql.py diff --git a/datafaker/make.py b/datafaker/make.py index a19b146..27e69c5 100644 --- a/datafaker/make.py +++ b/datafaker/make.py @@ -719,7 +719,7 @@ def make_tables_file( """Construct the YAML file representing the schema.""" engine = get_sync_engine(create_db_engine(db_dsn, schema_name=schema_name)) - metadata = get_metadata(engine) + metadata = get_metadata(engine, schema_name=schema_name) meta_dict = metadata_to_dict(metadata, schema_name, engine, parquet_dir) if parquet_dir is not None: diff --git a/datafaker/remove.py b/datafaker/remove.py index 71213e2..3c42c33 100644 --- a/datafaker/remove.py +++ b/datafaker/remove.py @@ -61,12 +61,13 @@ def remove_db_vocab( def remove_db_tables(metadata: Optional[MetaData]) -> None: """Drop the tables in the destination schema.""" + schema_name = get_destination_schema() dst_engine = get_sync_engine( create_db_engine( get_destination_dsn(), - schema_name=get_destination_schema(), + schema_name=schema_name, ) ) if metadata is None: - metadata = get_metadata(dst_engine) + metadata = get_metadata(dst_engine, schema_name=schema_name) metadata.drop_all(dst_engine) diff --git a/datafaker/utils.py b/datafaker/utils.py index a0ab358..b47c2e1 100644 --- a/datafaker/utils.py +++ b/datafaker/utils.py @@ -26,12 +26,12 @@ Union, ) -import psycopg2 import sqlalchemy import yaml from jsonschema.exceptions import ValidationError from jsonschema.validators import validate from sqlalchemy import Connection, Engine, ForeignKey, create_engine, event, select +from sqlalchemy.engine import make_url from sqlalchemy.engine.interfaces import DBAPIConnection from sqlalchemy.exc import ( IntegrityError, @@ -195,6 +195,48 @@ def get_sync_engine(engine: MaybeAsyncEngine) -> Engine: return engine +_ASYNC_DRIVER_MAP: dict[str, str] = { + "postgresql": "postgresql+asyncpg", + "mssql": "mssql+aioodbc", +} + + +def make_async_dsn(db_dsn: str) -> str: + """Return an async-driver DSN for the given sync DSN. + + Replaces the driver component based on the dialect so that both PostgreSQL + and MS-SQL connections can be made async without hardcoding dialect names at + each call site. Raises ``ValueError`` for dialects with no known async driver. + """ + url = make_url(db_dsn) + dialect = url.drivername.split("+")[0] + async_driver = _ASYNC_DRIVER_MAP.get(dialect) + if async_driver is None: + raise ValueError( + f"No async driver is registered for dialect '{dialect}'. " + f"Add an entry to _ASYNC_DRIVER_MAP in datafaker/utils.py." + ) + return str(url.set(drivername=async_driver)) + + +def _is_undefined_object_error(exc: Exception) -> bool: + """Return True if *exc* represents a 'constraint does not exist' error. + + Checks for psycopg2's UndefinedObject when psycopg2 is installed, and falls + back to inspecting the SQLSTATE pgcode attribute so the function works without + psycopg2 (e.g. in an MS-SQL environment). + """ + try: + import psycopg2.errors # type: ignore[import] + + if isinstance(exc, psycopg2.errors.UndefinedObject): + return True + except ImportError: + pass + # SQLSTATE 42704 = undefined_object — present on psycopg2 and pyodbc errors + return getattr(exc, "pgcode", None) == "42704" + + def create_db_engine( db_dsn: str, schema_name: Optional[str] = None, @@ -205,8 +247,7 @@ def create_db_engine( """Create a SQLAlchemy Engine.""" try: if use_asyncio: - async_dsn = db_dsn.replace("postgresql://", "postgresql+asyncpg://") - engine: MaybeAsyncEngine = create_async_engine(async_dsn, **kwargs) + engine: MaybeAsyncEngine = create_async_engine(make_async_dsn(db_dsn), **kwargs) else: engine = create_engine(db_dsn, **kwargs) except NoSuchModuleError as exc: @@ -217,22 +258,25 @@ def create_db_engine( logger.error("DSN %s is malformed: %s", db_dsn, exc) raise Exit(1) from exc - settings = {} - if schema_name is not None: - settings["search_path"] = schema_name + # DuckDB needs file_search_path set at connection level via a SET command. + # schema_name is handled cross-dialect via schema_translate_map below. if parquet_dir is not None: joined = ",".join(_find_parquet_directories(parquet_dir)) # double up single quotes dj = joined.replace("'", "''") # enclose in single quotes - settings["file_search_path"] = f"'{dj}'" - - if settings: + duckdb_settings = {"file_search_path": f"'{dj}'"} event_engine = get_sync_engine(engine) @event.listens_for(event_engine, "connect", insert=True) def connect(dbapi_connection: DBAPIConnection, _: Any) -> None: - set_db_settings(dbapi_connection, settings) + set_db_settings(dbapi_connection, duckdb_settings) + + # Route unqualified table references to the target schema in a + # dialect-neutral way. This replaces the PostgreSQL-only search_path + # approach and works for MS-SQL, PostgreSQL, and DuckDB alike. + if schema_name is not None: + engine = engine.execution_options(schema_translate_map={None: schema_name}) return engine @@ -266,11 +310,11 @@ def create_db_engine_dst( return create_db_engine(db_dsn, schema_name, use_asyncio) -def get_metadata(engine: Engine) -> MetaData: +def get_metadata(engine: Engine, schema_name: Optional[str] = None) -> MetaData: """Get the MetaData object associated with the engine passed.""" md = MetaData() try: - md.reflect(engine) + md.reflect(engine, schema=schema_name) except OperationalError as exc: logger.error("Cannot connect to database: %s", exc) raise Exit(1) from exc @@ -295,8 +339,7 @@ def _names_include_parquet(path: Path, file_names: Iterable[str]) -> bool: def set_db_settings(connection: DBAPIConnection, settings: Mapping[str, str]) -> None: - """Set the SEARCH_PATH for a PostgreSQL connection.""" - # https://docs.sqlalchemy.org/en/20/dialects/postgresql.html#remote-schema-table-introspection-and-postgresql-search-path + """Issue SET commands on a raw DBAPI connection (currently used for DuckDB only).""" existing_autocommit = connection.autocommit connection.autocommit = True @@ -647,8 +690,7 @@ def remove_vocab_foreign_key_constraints( ) except ProgrammingError as e: session.rollback() - # pylint: disable=no-member - if isinstance(e.orig, psycopg2.errors.UndefinedObject): + if _is_undefined_object_error(e.orig): logger.debug("Constraint does not exist") else: raise e diff --git a/examples/omop-mssql/README.md b/examples/omop-mssql/README.md new file mode 100644 index 0000000..6ddebdb --- /dev/null +++ b/examples/omop-mssql/README.md @@ -0,0 +1,74 @@ +# How to run datafaker process on OMOP schema with MS SQL Server + +## About + +This example is for testing datafaker against a Microsoft SQL Server (MS-SQL) database using the OMOP schema. It can be used to verify that datafaker correctly generates and manages synthetic data in an MS-SQL environment. + +## Challenges for MS-SQL support + +Datafaker was built with PostgreSQL as its primary target. The following issues need to be addressed to support MS-SQL (Microsoft SQL Server). + +### 1. Driver dependency ([#93](https://github.com/SAFEHR-data/datafaker/issues/93)) + +`psycopg2` (PostgreSQL driver) is a hard dependency imported directly in [datafaker/utils.py](../../datafaker/utils.py). MS-SQL requires a different driver such as `pyodbc` or `pymssql`, which are not currently listed in `pyproject.toml`. The `asyncpg` async driver is also PostgreSQL-specific; MS-SQL async support would require `aioodbc` or similar. + +### 2. Hardcoded async connection string rewriting ([#94](https://github.com/SAFEHR-data/datafaker/issues/94)) + +In [datafaker/utils.py:208](../../datafaker/utils.py), the async DSN is built by string-replacing `postgresql://` with `postgresql+asyncpg://`. This logic would silently fail (or produce a malformed DSN) for an `mssql://` connection string. + +### 3. PostgreSQL `search_path` for schema selection ([#95](https://github.com/SAFEHR-data/datafaker/issues/95)) + +When a schema name is provided, the code issues `SET search_path TO ` via a connection-level event listener ([datafaker/utils.py:222, 305](../../datafaker/utils.py)). This is PostgreSQL-specific syntax. MS-SQL uses two-part `[schema].[table]` naming and does not support `SET search_path`. SQLAlchemy's `schema` argument on `MetaData` and `Table` objects is the correct cross-dialect approach. + +### 4. PostgreSQL-specific column types in the type parser + +[datafaker/serialize_metadata.py](../../datafaker/serialize_metadata.py) registers parsers for several PostgreSQL-only types that have no direct MS-SQL equivalent: + +| PostgreSQL type | MS-SQL equivalent / issue | +|---|---| +| `postgresql.TSVECTOR` | No native equivalent (full-text indexing works differently) | +| `postgresql.CIDR` | No native network address type | +| `postgresql.BYTEA` | Use `VARBINARY(MAX)` | +| `postgresql.ARRAY` | Not supported; would need denormalisation or JSON | +| `postgresql.ENUM` | Implemented via `CHECK` constraint or lookup table | +| `postgresql.DOMAIN` | Not supported | +| `postgresql.BIT` | MS-SQL `BIT` is boolean (0/1 only); multi-bit columns use `BINARY` | +| `postgresql.REAL` / `TIMESTAMP` / `TIME` with timezone | Need MS-SQL dialect equivalents (`DATETIMEOFFSET` for tz-aware timestamps) | + +### 5. `SERIAL` autoincrement columns + +PostgreSQL uses `SERIAL` for autoincrement columns. The code already strips `SERIAL` for DuckDB in [datafaker/create.py:29](../../datafaker/create.py), but there is no equivalent handler for MS-SQL, which uses `IDENTITY(1,1)`. + +### 6. `postgresql.UUID` type mapping + +[datafaker/make.py:384](../../datafaker/make.py) maps `postgresql.UUID` to a generator. MS-SQL uses `UNIQUEIDENTIFIER` for UUIDs, which SQLAlchemy exposes as `sqlalchemy.dialects.mssql.UNIQUEIDENTIFIER`. + +### 7. PostgreSQL-specific error handling + +[datafaker/utils.py:651](../../datafaker/utils.py) catches `psycopg2.errors.UndefinedObject` to handle missing constraints gracefully. This is a PostgreSQL/psycopg2-specific exception. For MS-SQL the equivalent `pyodbc` error would need to be caught instead, or the check should be made dialect-agnostic. + +### 8. `autocommit` handling in `set_db_settings` + +[datafaker/utils.py:297-309](../../datafaker/utils.py) toggles `connection.autocommit` directly on the DBAPI connection before executing `SET` commands. The availability and behaviour of `autocommit` differs between `psycopg2`, `pyodbc`, and `pymssql`, so this would need testing or an abstraction per driver. + +## Steps + +1. Make a YAML file representing the tables in the schema + +`poetry run datafaker make-tables --orm-file ./examples/omop-mssql/orm.yaml` + +1. Create schema from the ORM YAML file + +`poetry run datafaker create-tables --orm-file ./examples/omop-mssql/orm.yaml --config-file ./examples/omop-mssql/config.yaml` + +1. Create generator table + +`poetry run datafaker create-generators --orm-file ./examples/omop-mssql/orm.yaml --config-file ./examples/omop-mssql/config.yaml --df-file ./examples/omop-mssql/df.py` + +1. Create data + +`poetry run datafaker create-data --orm-file ./examples/omop-mssql/orm.yaml --config-file ./examples/omop-mssql/config.yaml --df-file ./examples/omop-mssql/df.py` + +1. Remove data + +`poetry run datafaker remove-data --orm-file ./examples/omop-mssql/orm.yaml --config-file ./examples/omop-mssql/config.yaml` diff --git a/poetry.lock b/poetry.lock index d26c56c..33f76a9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,20 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.3.1 and should not be changed by hand. + +[[package]] +name = "aioodbc" +version = "0.5.0" +description = "ODBC driver for asyncio." +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"mssql\"" +files = [ + {file = "aioodbc-0.5.0-py3-none-any.whl", hash = "sha256:bcaf16f007855fa4bf0ce6754b1f72c6c5a3d544188849577ddd55c5dc42985e"}, + {file = "aioodbc-0.5.0.tar.gz", hash = "sha256:cbccd89ce595c033a49c9e6b4b55bbace7613a104b8a46e3d4c58c4bc4f25075"}, +] + +[package.dependencies] +pyodbc = ">=5.0.1" [[package]] name = "alabaster" @@ -6,10 +22,12 @@ version = "0.7.16" description = "A light, configurable Sphinx theme" optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, ] +markers = {main = "extra == \"docs\""} [[package]] name = "antlr4-python3-runtime" @@ -17,6 +35,7 @@ version = "4.9.3" description = "ANTLR 4.9.3 runtime for Python 3.7" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"}, ] @@ -27,6 +46,7 @@ version = "1.5.1" description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67"}, {file = "asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c"}, @@ -38,6 +58,7 @@ version = "3.3.11" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.9.0" +groups = ["dev"] files = [ {file = "astroid-3.3.11-py3-none-any.whl", hash = "sha256:54c760ae8322ece1abd213057c4b5bba7c49818853fc901ef09719a60dbf9dec"}, {file = "astroid-3.3.11.tar.gz", hash = "sha256:1e5a5011af2920c7c67a53f65d536d65bfa7116feeaf2354d8b94f29573bb0ce"}, @@ -52,6 +73,8 @@ version = "5.0.1" description = "Timeout context manager for asyncio programs" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "python_version == \"3.10\"" files = [ {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, @@ -63,6 +86,7 @@ version = "0.30.0" description = "An asyncio PostgreSQL driver" optional = false python-versions = ">=3.8.0" +groups = ["main"] files = [ {file = "asyncpg-0.30.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bfb4dd5ae0699bad2b233672c8fc5ccbd9ad24b89afded02341786887e37927e"}, {file = "asyncpg-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc1f62c792752a49f88b7e6f774c26077091b44caceb1983509edc18a2222ec0"}, @@ -120,8 +144,8 @@ async-timeout = {version = ">=4.0.3", markers = "python_version < \"3.11.0\""} [package.extras] docs = ["Sphinx (>=8.1.3,<8.2.0)", "sphinx-rtd-theme (>=1.2.2)"] -gssauth = ["gssapi", "sspilib"] -test = ["distro (>=1.9.0,<1.10.0)", "flake8 (>=6.1,<7.0)", "flake8-pyi (>=24.1.0,<24.2.0)", "gssapi", "k5test", "mypy (>=1.8.0,<1.9.0)", "sspilib", "uvloop (>=0.15.3)"] +gssauth = ["gssapi ; platform_system != \"Windows\"", "sspilib ; platform_system == \"Windows\""] +test = ["distro (>=1.9.0,<1.10.0)", "flake8 (>=6.1,<7.0)", "flake8-pyi (>=24.1.0,<24.2.0)", "gssapi ; platform_system == \"Linux\"", "k5test ; platform_system == \"Linux\"", "mypy (>=1.8.0,<1.9.0)", "sspilib ; platform_system == \"Windows\"", "uvloop (>=0.15.3) ; platform_system != \"Windows\" and python_version < \"3.14.0\""] [[package]] name = "attrs" @@ -129,6 +153,7 @@ version = "25.4.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373"}, {file = "attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11"}, @@ -140,13 +165,15 @@ version = "2.18.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35"}, {file = "babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d"}, ] +markers = {main = "extra == \"docs\""} [package.extras] -dev = ["backports.zoneinfo", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata"] +dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] [[package]] name = "black" @@ -154,6 +181,7 @@ version = "23.12.1" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"}, {file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"}, @@ -190,7 +218,7 @@ typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +d = ["aiohttp (>=3.7.4) ; sys_platform != \"win32\" or implementation_name != \"pypy\"", "aiohttp (>=3.7.4,!=3.9.0) ; sys_platform == \"win32\" and implementation_name == \"pypy\""] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] @@ -200,10 +228,12 @@ version = "2026.1.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c"}, {file = "certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120"}, ] +markers = {main = "extra == \"docs\""} [[package]] name = "cfgv" @@ -211,6 +241,7 @@ version = "3.5.0" description = "Validate configuration and produce human readable error messages." optional = false python-versions = ">=3.10" +groups = ["dev"] files = [ {file = "cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0"}, {file = "cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132"}, @@ -222,6 +253,7 @@ version = "3.4.4" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d"}, {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8"}, @@ -337,6 +369,7 @@ files = [ {file = "charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f"}, {file = "charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a"}, ] +markers = {main = "extra == \"docs\""} [[package]] name = "click" @@ -344,6 +377,7 @@ version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -358,10 +392,12 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev", "extras"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +markers = {main = "extra == \"docs\" and sys_platform == \"win32\" or platform_system == \"Windows\"", dev = "platform_system == \"Windows\" or sys_platform == \"win32\"", extras = "platform_system == \"Windows\""} [[package]] name = "cramjam" @@ -369,6 +405,7 @@ version = "2.11.0" description = "Thin Python bindings to de/compression algorithms in Rust" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "cramjam-2.11.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:d0859c65775e8ebf2cbc084bfd51bd0ffda10266da6f9306451123b89f8e5a63"}, {file = "cramjam-2.11.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:1d77b9b0aca02a3f6eeeff27fcd315ca5972616c0919ee38e522cce257bcd349"}, @@ -514,6 +551,7 @@ version = "0.6.7" description = "Easily serialize dataclasses to and from JSON." optional = false python-versions = "<4.0,>=3.7" +groups = ["dev"] files = [ {file = "dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a"}, {file = "dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0"}, @@ -529,6 +567,7 @@ version = "1.3.1" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +groups = ["main"] files = [ {file = "deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f"}, {file = "deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223"}, @@ -538,7 +577,7 @@ files = [ wrapt = ">=1.10,<3" [package.extras] -dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools", "tox"] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"] [[package]] name = "dill" @@ -546,6 +585,7 @@ version = "0.4.1" description = "serialize all of Python" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d"}, {file = "dill-0.4.1.tar.gz", hash = "sha256:423092df4182177d4d8ba8290c8a5b640c66ab35ec7da59ccfa00f6fa3eea5fa"}, @@ -561,6 +601,7 @@ version = "0.4.0" description = "Distribution utilities" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, @@ -572,10 +613,12 @@ version = "0.18.1" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main", "dev"] files = [ {file = "docutils-0.18.1-py2.py3-none-any.whl", hash = "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c"}, {file = "docutils-0.18.1.tar.gz", hash = "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06"}, ] +markers = {main = "extra == \"docs\""} [[package]] name = "duckdb" @@ -583,6 +626,7 @@ version = "1.4.4" description = "DuckDB in-process database" optional = false python-versions = ">=3.9.0" +groups = ["main", "dev"] files = [ {file = "duckdb-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e870a441cb1c41d556205deb665749f26347ed13b3a247b53714f5d589596977"}, {file = "duckdb-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:49123b579e4a6323e65139210cd72dddc593a72d840211556b60f9703bda8526"}, @@ -636,6 +680,7 @@ version = "0.17.0" description = "SQLAlchemy driver for duckdb" optional = false python-versions = "<4,>=3.9" +groups = ["main"] files = [ {file = "duckdb_engine-0.17.0-py3-none-any.whl", hash = "sha256:3aa72085e536b43faab635f487baf77ddc5750069c16a2f8d9c6c3cb6083e979"}, {file = "duckdb_engine-0.17.0.tar.gz", hash = "sha256:396b23869754e536aa80881a92622b8b488015cf711c5a40032d05d2cf08f3cf"}, @@ -652,6 +697,7 @@ version = "2024.11.0" description = "Python support for Parquet file format" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "fastparquet-2024.11.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:60ccf587410f0979105e17036df61bb60e1c2b81880dc91895cdb4ee65b71e7f"}, {file = "fastparquet-2024.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a5ad5fc14b0567e700bea3cd528a0bd45a6f9371370b49de8889fb3d10a6574a"}, @@ -712,6 +758,7 @@ version = "3.20.3" description = "A platform independent file lock." optional = false python-versions = ">=3.10" +groups = ["dev"] files = [ {file = "filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1"}, {file = "filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1"}, @@ -723,6 +770,7 @@ version = "2026.1.0" description = "File-system specification" optional = false python-versions = ">=3.10" +groups = ["main"] files = [ {file = "fsspec-2026.1.0-py3-none-any.whl", hash = "sha256:cb76aa913c2285a3b49bdd5fc55b1d7c708d7208126b60f2eb8194fe1b4cbdcc"}, {file = "fsspec-2026.1.0.tar.gz", hash = "sha256:e987cb0496a0d81bba3a9d1cee62922fb395e7d4c3b575e57f547953334fe07b"}, @@ -753,7 +801,7 @@ smb = ["smbprotocol"] ssh = ["paramiko"] test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"] test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"] -test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "backports-zstd", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr"] +test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "backports-zstd ; python_version < \"3.14\"", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr"] tqdm = ["tqdm"] [[package]] @@ -762,6 +810,7 @@ version = "0.21" description = "Simple Python interface for Graphviz" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "graphviz-0.21-py3-none-any.whl", hash = "sha256:54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42"}, {file = "graphviz-0.21.tar.gz", hash = "sha256:20743e7183be82aaaa8ad6c93f8893c923bd6658a04c32ee115edb3c8a835f78"}, @@ -778,6 +827,7 @@ version = "3.3.1" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.10" +groups = ["main"] files = [ {file = "greenlet-3.3.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:04bee4775f40ecefcdaa9d115ab44736cd4b9c5fba733575bfe9379419582e13"}, {file = "greenlet-3.3.1-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:50e1457f4fed12a50e427988a07f0f9df53cf0ee8da23fab16e6732c2ec909d4"}, @@ -844,6 +894,7 @@ version = "2.6.16" description = "File identification library for Python" optional = false python-versions = ">=3.10" +groups = ["dev"] files = [ {file = "identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0"}, {file = "identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980"}, @@ -858,10 +909,12 @@ version = "3.11" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, ] +markers = {main = "extra == \"docs\""} [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] @@ -872,10 +925,12 @@ version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main", "dev"] files = [ {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, ] +markers = {main = "extra == \"docs\""} [[package]] name = "isort" @@ -883,6 +938,7 @@ version = "5.13.2" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" +groups = ["dev"] files = [ {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, @@ -897,6 +953,7 @@ version = "3.1.6" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, @@ -914,6 +971,7 @@ version = "1.5.1" description = "Generate static HTML documentation from JSON schemas" optional = false python-versions = "<4.0,>=3.9" +groups = ["dev"] files = [ {file = "json_schema_for_humans-1.5.1-py3-none-any.whl", hash = "sha256:6b5bb65c8ccfb46219352f3da32312c9d904c08790bb96f43f109338c2141478"}, {file = "json_schema_for_humans-1.5.1.tar.gz", hash = "sha256:a43023f6c1b99f8e75126cc824c22992d8f55e941060aa3fddfc7c38de3cb973"}, @@ -935,6 +993,7 @@ version = "4.26.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.10" +groups = ["main"] files = [ {file = "jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce"}, {file = "jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326"}, @@ -942,7 +1001,7 @@ files = [ [package.dependencies] attrs = ">=22.2.0" -jsonschema-specifications = ">=2023.03.6" +jsonschema-specifications = ">=2023.3.6" referencing = ">=0.28.4" rpds-py = ">=0.25.0" @@ -956,6 +1015,7 @@ version = "2025.9.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe"}, {file = "jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d"}, @@ -970,6 +1030,8 @@ version = "0.7.8" description = "Mypyc runtime library" optional = false python-versions = ">=3.9" +groups = ["dev"] +markers = "platform_python_implementation != \"PyPy\"" files = [ {file = "librt-0.7.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b45306a1fc5f53c9330fbee134d8b3227fe5da2ab09813b892790400aa49352d"}, {file = "librt-0.7.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:864c4b7083eeee250ed55135d2127b260d7eb4b5e953a9e5df09c852e327961b"}, @@ -1055,6 +1117,7 @@ version = "4.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false python-versions = ">=3.10" +groups = ["main"] files = [ {file = "markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147"}, {file = "markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3"}, @@ -1078,15 +1141,16 @@ version = "2.5.4" description = "A fast and complete Python implementation of Markdown" optional = false python-versions = "<4,>=3.9" +groups = ["dev"] files = [ {file = "markdown2-2.5.4-py3-none-any.whl", hash = "sha256:3c4b2934e677be7fec0e6f2de4410e116681f4ad50ec8e5ba7557be506d3f439"}, {file = "markdown2-2.5.4.tar.gz", hash = "sha256:a09873f0b3c23dbfae589b0080587df52ad75bb09a5fa6559147554736676889"}, ] [package.extras] -all = ["latex2mathml", "pygments (>=2.7.3)", "wavedrom"] +all = ["latex2mathml ; python_version >= \"3.8.1\"", "pygments (>=2.7.3)", "wavedrom"] code-syntax-highlighting = ["pygments (>=2.7.3)"] -latex = ["latex2mathml"] +latex = ["latex2mathml ; python_version >= \"3.8.1\""] wavedrom = ["wavedrom"] [[package]] @@ -1095,6 +1159,7 @@ version = "3.0.3" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, @@ -1193,6 +1258,7 @@ version = "3.26.2" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "marshmallow-3.26.2-py3-none-any.whl", hash = "sha256:013fa8a3c4c276c24d26d84ce934dc964e2aa794345a0f8c7e5a7191482c8a73"}, {file = "marshmallow-3.26.2.tar.gz", hash = "sha256:bbe2adb5a03e6e3571b573f42527c6fe926e17467833660bebd11593ab8dfd57"}, @@ -1212,6 +1278,7 @@ version = "0.7.0" description = "McCabe checker, plugin for flake8" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, @@ -1223,6 +1290,7 @@ version = "0.1.2" description = "Markdown URL utilities" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, @@ -1234,6 +1302,7 @@ version = "18.0.0" description = "Mimesis: Fake Data Generator." optional = false python-versions = "<4.0,>=3.10" +groups = ["main"] files = [ {file = "mimesis-18.0.0-py3-none-any.whl", hash = "sha256:a51854a5ce63ebf2bd6a98e8841412e04cede38593be7e16d1d712848e6273df"}, {file = "mimesis-18.0.0.tar.gz", hash = "sha256:7d7c76ecd680ae48afe8dc4413ef1ef1ee7ef20e16f9f9cb42892add642fc1b2"}, @@ -1249,6 +1318,7 @@ version = "1.19.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "mypy-1.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f05aa3d375b385734388e844bc01733bd33c644ab48e9684faa54e5389775ec"}, {file = "mypy-1.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:022ea7279374af1a5d78dfcab853fe6a536eebfda4b59deab53cd21f6cd9f00b"}, @@ -1310,6 +1380,7 @@ version = "1.1.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, @@ -1321,6 +1392,7 @@ version = "1.10.0" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] files = [ {file = "nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827"}, {file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"}, @@ -1332,6 +1404,7 @@ version = "2.2.6" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.10" +groups = ["main"] files = [ {file = "numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb"}, {file = "numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90"}, @@ -1396,6 +1469,7 @@ version = "0.12.1" description = "Python bindings for the OpenDP Library" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "opendp-0.12.1-cp39-abi3-macosx_10_13_x86_64.whl", hash = "sha256:72edcd516e606a983ceaf828663655e46ed7d2a712e6335845413672ce10b89a"}, {file = "opendp-0.12.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:6315380316fada9fd051ac0d0e46d323da1c9a509f0a808908a9c980be4f448a"}, @@ -1421,6 +1495,7 @@ version = "26.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"}, {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, @@ -1432,6 +1507,7 @@ version = "2.3.3" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c"}, {file = "pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a"}, @@ -1531,6 +1607,7 @@ version = "2.2" description = "Easy-to-use parser combinators, for parsing in pure Python" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "parsy-2.2-py3-none-any.whl", hash = "sha256:5e981613d9d2d8b68012d1dd0afe928967bea2e4eefdb76c2f545af0dd02a9e7"}, {file = "parsy-2.2.tar.gz", hash = "sha256:e943147644a8cf0d82d1bcb5c5867dd517495254cea3e3eb058b1e421cb7561f"}, @@ -1542,6 +1619,7 @@ version = "1.0.4" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723"}, {file = "pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645"}, @@ -1559,6 +1637,7 @@ version = "1.31.5" description = "PostgreSQL interface library" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "pg8000-1.31.5-py3-none-any.whl", hash = "sha256:0af2c1926b153307639868d2ee5cef6cd3a7d07448e12736989b10e1d491e201"}, {file = "pg8000-1.31.5.tar.gz", hash = "sha256:46ebb03be52b7a77c03c725c79da2ca281d6e8f59577ca66b17c9009618cae78"}, @@ -1574,6 +1653,7 @@ version = "4.5.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.10" +groups = ["main", "dev"] files = [ {file = "platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31"}, {file = "platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda"}, @@ -1590,10 +1670,12 @@ version = "0.9.1" description = "A collection of helpful Python tools!" optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "pockets-0.9.1-py2.py3-none-any.whl", hash = "sha256:68597934193c08a08eb2bf6a1d85593f627c22f9b065cc727a4f03f669d96d86"}, {file = "pockets-0.9.1.tar.gz", hash = "sha256:9320f1a3c6f7a9133fe3b571f283bcf3353cd70249025ae8d618e40e9f7e92b3"}, ] +markers = {main = "extra == \"docs\""} [package.dependencies] six = ">=1.5.2" @@ -1604,6 +1686,7 @@ version = "3.8.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, @@ -1622,6 +1705,7 @@ version = "3.17.0" description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" optional = false python-versions = ">=3.10" +groups = ["main"] files = [ {file = "prettytable-3.17.0-py3-none-any.whl", hash = "sha256:aad69b294ddbe3e1f95ef8886a060ed1666a0b83018bbf56295f6f226c43d287"}, {file = "prettytable-3.17.0.tar.gz", hash = "sha256:59f2590776527f3c9e8cf9fe7b66dd215837cca96a9c39567414cbc632e8ddb0"}, @@ -1637,8 +1721,10 @@ tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"] name = "psycopg2-binary" version = "2.9.11" description = "psycopg2 - Python-PostgreSQL Database Adapter" -optional = false +optional = true python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"postgres\"" files = [ {file = "psycopg2-binary-2.9.11.tar.gz", hash = "sha256:b6aed9e096bf63f9e75edf2581aa9a7e7186d97ab5c177aa6c87797cd591236c"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d6fe6b47d0b42ce1c9f1fa3e35bb365011ca22e39db37074458f27921dca40f2"}, @@ -1715,6 +1801,7 @@ version = "1.10.26" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" +groups = ["main", "dev"] files = [ {file = "pydantic-1.10.26-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f7ae36fa0ecef8d39884120f212e16c06bb096a38f523421278e2f39c1784546"}, {file = "pydantic-1.10.26-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d95a76cf503f0f72ed7812a91de948440b2bf564269975738a4751e4fadeb572"}, @@ -1769,6 +1856,7 @@ version = "6.3.0" description = "Python docstring style checker" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, @@ -1778,7 +1866,7 @@ files = [ snowballstemmer = ">=2.2.0" [package.extras] -toml = ["tomli (>=1.2.3)"] +toml = ["tomli (>=1.2.3) ; python_version < \"3.11\""] [[package]] name = "pygments" @@ -1786,6 +1874,7 @@ version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, @@ -1800,6 +1889,7 @@ version = "3.3.9" description = "python code static checker" optional = false python-versions = ">=3.9.0" +groups = ["dev"] files = [ {file = "pylint-3.3.9-py3-none-any.whl", hash = "sha256:01f9b0462c7730f94786c283f3e52a1fbdf0494bbe0971a78d7277ef46a751e7"}, {file = "pylint-3.3.9.tar.gz", hash = "sha256:d312737d7b25ccf6b01cc4ac629b5dcd14a0fcf3ec392735ac70f137a9d5f83a"}, @@ -1811,7 +1901,7 @@ colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, + {version = ">=0.3.6", markers = "python_version == \"3.11\""}, ] isort = ">=4.2.5,<5.13 || >5.13,<7" mccabe = ">=0.6,<0.8" @@ -1829,6 +1919,7 @@ version = "1.1.2" description = "Pure Python MySQL Driver" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pymysql-1.1.2-py3-none-any.whl", hash = "sha256:e6b1d89711dd51f8f74b1631fe08f039e7d76cf67a42a323d3178f0f25762ed9"}, {file = "pymysql-1.1.2.tar.gz", hash = "sha256:4961d3e165614ae65014e361811a724e2044ad3ea3739de9903ae7c21f539f03"}, @@ -1838,12 +1929,88 @@ files = [ ed25519 = ["PyNaCl (>=1.4.0)"] rsa = ["cryptography"] +[[package]] +name = "pyodbc" +version = "5.3.0" +description = "DB API module for ODBC" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"mssql\"" +files = [ + {file = "pyodbc-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6682cdec78f1302d0c559422c8e00991668e039ed63dece8bf99ef62173376a5"}, + {file = "pyodbc-5.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9cd3f0a9796b3e1170a9fa168c7e7ca81879142f30e20f46663b882db139b7d2"}, + {file = "pyodbc-5.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46185a1a7f409761716c71de7b95e7bbb004390c650d00b0b170193e3d6224bb"}, + {file = "pyodbc-5.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:349a9abae62a968b98f6bbd23d2825151f8d9de50b3a8f5f3271b48958fdb672"}, + {file = "pyodbc-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ac23feb7ddaa729f6b840639e92f83ff0ccaa7072801d944f1332cd5f5b05f47"}, + {file = "pyodbc-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8aa396c6d6af52ccd51b8c8a5bffbb46fd44e52ce07ea4272c1d28e5e5b12722"}, + {file = "pyodbc-5.3.0-cp310-cp310-win32.whl", hash = "sha256:46869b9a6555ff003ed1d8ebad6708423adf2a5c88e1a578b9f029fb1435186e"}, + {file = "pyodbc-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:705903acf6f43c44fc64e764578d9a88649eb21bf7418d78677a9d2e337f56f2"}, + {file = "pyodbc-5.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:c68d9c225a97aedafb7fff1c0e1bfe293093f77da19eaf200d0e988fa2718d16"}, + {file = "pyodbc-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ebc3be93f61ea0553db88589e683ace12bf975baa954af4834ab89f5ee7bf8ae"}, + {file = "pyodbc-5.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9b987a25a384f31e373903005554230f5a6d59af78bce62954386736a902a4b3"}, + {file = "pyodbc-5.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:676031723aac7dcbbd2813bddda0e8abf171b20ec218ab8dfb21d64a193430ea"}, + {file = "pyodbc-5.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5c30c5cd40b751f77bbc73edd32c4498630939bcd4e72ee7e6c9a4b982cc5ca"}, + {file = "pyodbc-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2035c7dfb71677cd5be64d3a3eb0779560279f0a8dc6e33673499498caa88937"}, + {file = "pyodbc-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5cbe4d753723c8a8f65020b7a259183ef5f14307587165ce37e8c7e251951852"}, + {file = "pyodbc-5.3.0-cp311-cp311-win32.whl", hash = "sha256:d255f6b117d05cfc046a5201fdf39535264045352ea536c35777cf66d321fbb8"}, + {file = "pyodbc-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:f1ad0e93612a6201621853fc661209d82ff2a35892b7d590106fe8f97d9f1f2a"}, + {file = "pyodbc-5.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:0df7ff47fab91ea05548095b00e5eb87ed88ddf4648c58c67b4db95ea4913e23"}, + {file = "pyodbc-5.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5ebf6b5d989395efe722b02b010cb9815698a4d681921bf5db1c0e1195ac1bde"}, + {file = "pyodbc-5.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:197bb6ddafe356a916b8ee1b8752009057fce58e216e887e2174b24c7ab99269"}, + {file = "pyodbc-5.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c6ccb5315ec9e081f5cbd66f36acbc820ad172b8fa3736cf7f993cdf69bd8a96"}, + {file = "pyodbc-5.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5dd3d5e469f89a3112cf8b0658c43108a4712fad65e576071e4dd44d2bd763c7"}, + {file = "pyodbc-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b180bc5e49b74fd40a24ef5b0fe143d0c234ac1506febe810d7434bf47cb925b"}, + {file = "pyodbc-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e3c39de3005fff3ae79246f952720d44affc6756b4b85398da4c5ea76bf8f506"}, + {file = "pyodbc-5.3.0-cp312-cp312-win32.whl", hash = "sha256:d32c3259762bef440707098010035bbc83d1c73d81a434018ab8c688158bd3bb"}, + {file = "pyodbc-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe77eb9dcca5fc1300c9121f81040cc9011d28cff383e2c35416e9ec06d4bc95"}, + {file = "pyodbc-5.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:afe7c4ac555a8d10a36234788fc6cfc22a86ce37fc5ba88a1f75b3e6696665dc"}, + {file = "pyodbc-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e9ab0b91de28a5ab838ac4db0253d7cc8ce2452efe4ad92ee6a57b922bf0c24"}, + {file = "pyodbc-5.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6132554ffbd7910524d643f13ce17f4a72f3a6824b0adef4e9a7f66efac96350"}, + {file = "pyodbc-5.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1629af4706e9228d79dabb4863c11cceb22a6dab90700db0ef449074f0150c0d"}, + {file = "pyodbc-5.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ceaed87ba2ea848c11223f66f629ef121f6ebe621f605cde9cfdee4fd9f4b68"}, + {file = "pyodbc-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3cc472c8ae2feea5b4512e23b56e2b093d64f7cbc4b970af51da488429ff7818"}, + {file = "pyodbc-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c79df54bbc25bce9f2d87094e7b39089c28428df5443d1902b0cc5f43fd2da6f"}, + {file = "pyodbc-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c2eb0b08e24fe5c40c7ebe9240c5d3bd2f18cd5617229acee4b0a0484dc226f2"}, + {file = "pyodbc-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:01166162149adf2b8a6dc21a212718f205cabbbdff4047dc0c415af3fd85867e"}, + {file = "pyodbc-5.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:363311bd40320b4a61454bebf7c38b243cd67c762ed0f8a5219de3ec90c96353"}, + {file = "pyodbc-5.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3f1bdb3ce6480a17afaaef4b5242b356d4997a872f39e96f015cabef00613797"}, + {file = "pyodbc-5.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7713c740a10f33df3cb08f49a023b7e1e25de0c7c99650876bbe717bc95ee780"}, + {file = "pyodbc-5.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cf18797a12e70474e1b7f5027deeeccea816372497e3ff2d46b15bec2d18a0cc"}, + {file = "pyodbc-5.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:08b2439500e212625471d32f8fde418075a5ddec556e095e5a4ba56d61df2dc6"}, + {file = "pyodbc-5.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:729c535341bb09c476f219d6f7ab194bcb683c4a0a368010f1cb821a35136f05"}, + {file = "pyodbc-5.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c67e7f2ce649155ea89beb54d3b42d83770488f025cf3b6f39ca82e9c598a02e"}, + {file = "pyodbc-5.3.0-cp314-cp314-win32.whl", hash = "sha256:a48d731432abaee5256ed6a19a3e1528b8881f9cb25cb9cf72d8318146ea991b"}, + {file = "pyodbc-5.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:58635a1cc859d5af3f878c85910e5d7228fe5c406d4571bffcdd281375a54b39"}, + {file = "pyodbc-5.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:754d052030d00c3ac38da09ceb9f3e240e8dd1c11da8906f482d5419c65b9ef5"}, + {file = "pyodbc-5.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f927b440c38ade1668f0da64047ffd20ec34e32d817f9a60d07553301324b364"}, + {file = "pyodbc-5.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:25c4cfb2c08e77bc6e82f666d7acd52f0e52a0401b1876e60f03c73c3b8aedc0"}, + {file = "pyodbc-5.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc834567c2990584b9726cba365834d039380c9dbbcef3030ddeb00c6541b943"}, + {file = "pyodbc-5.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8339d3094858893c1a68ee1af93efc4dff18b8b65de54d99104b99af6306320d"}, + {file = "pyodbc-5.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74528fe148980d0c735c0ebb4a4dc74643ac4574337c43c1006ac4d09593f92d"}, + {file = "pyodbc-5.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d89a7f2e24227150c13be8164774b7e1f9678321a4248f1356a465b9cc17d31e"}, + {file = "pyodbc-5.3.0-cp314-cp314t-win32.whl", hash = "sha256:af4d8c9842fc4a6360c31c35508d6594d5a3b39922f61b282c2b4c9d9da99514"}, + {file = "pyodbc-5.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:bfeb3e34795d53b7d37e66dd54891d4f9c13a3889a8f5fe9640e56a82d770955"}, + {file = "pyodbc-5.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:13656184faa3f2d5c6f19b701b8f247342ed581484f58bf39af7315c054e69db"}, + {file = "pyodbc-5.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0263323fc47082c2bf02562f44149446bbbfe91450d271e44bffec0c3143bfb1"}, + {file = "pyodbc-5.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:452e7911a35ee12a56b111ac5b596d6ed865b83fcde8427127913df53132759e"}, + {file = "pyodbc-5.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b35b9983ad300e5aea82b8d1661fc9d3afe5868de527ee6bd252dd550e61ecd6"}, + {file = "pyodbc-5.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e981db84fee4cebec67f41bd266e1e7926665f1b99c3f8f4ea73cd7f7666e381"}, + {file = "pyodbc-5.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:25b6766e56748eb1fc1d567d863e06cbb7b7c749a41dfed85db0031e696fa39a"}, + {file = "pyodbc-5.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2eb7151ed0a1959cae65b6ac0454f5c8bbcd2d8bafeae66483c09d58b0c7a7fc"}, + {file = "pyodbc-5.3.0-cp39-cp39-win32.whl", hash = "sha256:fc5ac4f2165f7088e74ecec5413b5c304247949f9702c8853b0e43023b4187e8"}, + {file = "pyodbc-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:c25dc9c41f61573bdcf61a3408c34b65e4c0f821b8f861ca7531b1353b389804"}, + {file = "pyodbc-5.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:101313a21d2654df856a60e4a13763e4d9f6c5d3fd974bcf3fc6b4e86d1bbe8e"}, + {file = "pyodbc-5.3.0.tar.gz", hash = "sha256:2fe0e063d8fb66efd0ac6dc39236c4de1a45f17c33eaded0d553d21c199f4d05"}, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main", "dev"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -1858,6 +2025,7 @@ version = "1.2.1" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61"}, {file = "python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6"}, @@ -1872,6 +2040,7 @@ version = "2025.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"}, {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, @@ -1883,6 +2052,7 @@ version = "6.0.3" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, @@ -1965,6 +2135,7 @@ version = "0.37.0" description = "JSON Referencing + Python" optional = false python-versions = ">=3.10" +groups = ["main"] files = [ {file = "referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231"}, {file = "referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8"}, @@ -1981,10 +2152,12 @@ version = "2.32.5" description = "Python HTTP for Humans." optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, ] +markers = {main = "extra == \"docs\""} [package.dependencies] certifi = ">=2017.4.17" @@ -2002,6 +2175,7 @@ version = "1.4.1" description = "reStructuredText linter" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "restructuredtext_lint-1.4.1.tar.gz", hash = "sha256:a9f5a7150b3ddb26b9f5252a2c9007fd95ddaa2914a7141b1d7cc78a43e90cdb"}, ] @@ -2015,6 +2189,7 @@ version = "14.3.2" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.8.0" +groups = ["main"] files = [ {file = "rich-14.3.2-py3-none-any.whl", hash = "sha256:08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69"}, {file = "rich-14.3.2.tar.gz", hash = "sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8"}, @@ -2033,6 +2208,7 @@ version = "0.30.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.10" +groups = ["main"] files = [ {file = "rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288"}, {file = "rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00"}, @@ -2157,6 +2333,7 @@ version = "1.0.3" description = "Checks syntax of reStructuredText and code blocks nested within it" optional = false python-versions = ">=3.7,<4.0" +groups = ["dev"] files = [ {file = "rstcheck_core-1.0.3-py3-none-any.whl", hash = "sha256:d75d7df8f15b58e8aafe322d6fb6ef1ac8d12bb563089b0696948a00ee7f601a"}, {file = "rstcheck_core-1.0.3.tar.gz", hash = "sha256:add19c9a1b97d9087f4b463b49c12cd8a9c03689a255e99089c70a2692f16369"}, @@ -2172,7 +2349,7 @@ types-docutils = ">=0.18,<0.20" docs = ["m2r2 (>=0.3.2)", "sphinx (>=4.0,<6.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-autodoc-typehints (>=1.15)", "sphinx-rtd-dark-mode (>=1.2.4,<2.0.0)", "sphinx-rtd-theme (<1)", "sphinxcontrib-apidoc (>=0.3)", "sphinxcontrib-spelling (>=7.3)"] sphinx = ["sphinx (>=4.0,<6.0)"] testing = ["coverage-conditional-plugin (>=0.5)", "coverage[toml] (>=6.0)", "pytest (>=6.0)", "pytest-cov (>=3.0)", "pytest-mock (>=3.7)", "pytest-randomly (>=3.0)", "pytest-sugar (>=0.9.5)"] -toml = ["tomli (>=2.0,<3.0)"] +toml = ["tomli (>=2.0,<3.0) ; python_version < \"3.11\""] [[package]] name = "scramp" @@ -2180,6 +2357,7 @@ version = "1.4.8" description = "An implementation of the SCRAM protocol." optional = false python-versions = ">=3.10" +groups = ["dev"] files = [ {file = "scramp-1.4.8-py3-none-any.whl", hash = "sha256:87c2f15976845a2872fe5490a06097f0d01813cceb53774ea168c911f2ad025c"}, {file = "scramp-1.4.8.tar.gz", hash = "sha256:bd018fabfe46343cceeb9f1c3e8d23f55770271e777e3accbfaee3ff0a316e71"}, @@ -2194,6 +2372,7 @@ version = "1.5.4" description = "Tool to Detect Surrounding Shell" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, @@ -2205,6 +2384,7 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main", "dev"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -2216,6 +2396,7 @@ version = "1.0.6" description = "Differentially Private SQL Queries" optional = false python-versions = "<3.14,>=3.8" +groups = ["main"] files = [ {file = "smartnoise_sql-1.0.6-py3-none-any.whl", hash = "sha256:95f29f3eef7527d99d9f0ddbc89e4a6ce069c2748c3e729b9efb5288dcba3b1c"}, {file = "smartnoise_sql-1.0.6.tar.gz", hash = "sha256:680d909fefd67453ed4d33d63be4cae0ceecc15987a3ea9c7520eff66d059d8e"}, @@ -2235,10 +2416,12 @@ version = "3.0.1" description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*" +groups = ["main", "dev"] files = [ {file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"}, {file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"}, ] +markers = {main = "extra == \"docs\""} [[package]] name = "sphinx" @@ -2246,10 +2429,12 @@ version = "5.3.0" description = "Python documentation generator" optional = false python-versions = ">=3.6" +groups = ["main", "dev"] files = [ {file = "Sphinx-5.3.0.tar.gz", hash = "sha256:51026de0a9ff9fc13c05d74913ad66047e104f56a129ff73e174eb5c3ee794b5"}, {file = "sphinx-5.3.0-py3-none-any.whl", hash = "sha256:060ca5c9f7ba57a08a1219e547b269fadf125ae25b06b9fa7f66768efb652d6d"}, ] +markers = {main = "extra == \"docs\""} [package.dependencies] alabaster = ">=0.7,<0.8" @@ -2272,7 +2457,7 @@ sphinxcontrib-serializinghtml = ">=1.1.5" [package.extras] docs = ["sphinxcontrib-websupport"] lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-bugbear", "flake8-comprehensions", "flake8-simplify", "isort", "mypy (>=0.981)", "sphinx-lint", "types-requests", "types-typed-ast"] -test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast"] +test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast ; python_version < \"3.8\""] [[package]] name = "sphinx-rtd-theme" @@ -2280,10 +2465,12 @@ version = "1.3.0" description = "Read the Docs theme for Sphinx" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +groups = ["main", "dev"] files = [ {file = "sphinx_rtd_theme-1.3.0-py2.py3-none-any.whl", hash = "sha256:46ddef89cc2416a81ecfbeaceab1881948c014b1b6e4450b815311a89fb977b0"}, {file = "sphinx_rtd_theme-1.3.0.tar.gz", hash = "sha256:590b030c7abb9cf038ec053b95e5380b5c70d61591eb0b552063fbe7c41f0931"}, ] +markers = {main = "extra == \"docs\""} [package.dependencies] docutils = "<0.19" @@ -2299,10 +2486,12 @@ version = "2.0.0" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, ] +markers = {main = "extra == \"docs\""} [package.extras] lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] @@ -2315,10 +2504,12 @@ version = "2.0.0" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, ] +markers = {main = "extra == \"docs\""} [package.extras] lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] @@ -2331,10 +2522,12 @@ version = "2.1.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, ] +markers = {main = "extra == \"docs\""} [package.extras] lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] @@ -2347,10 +2540,12 @@ version = "4.1" description = "Extension to include jQuery on newer Sphinx releases" optional = false python-versions = ">=2.7" +groups = ["main", "dev"] files = [ {file = "sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a"}, {file = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"}, ] +markers = {main = "extra == \"docs\""} [package.dependencies] Sphinx = ">=1.8" @@ -2361,10 +2556,12 @@ version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" optional = false python-versions = ">=3.5" +groups = ["main", "dev"] files = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, ] +markers = {main = "extra == \"docs\""} [package.extras] test = ["flake8", "mypy", "pytest"] @@ -2375,6 +2572,7 @@ version = "2.0.0" description = "Mermaid diagrams in your Sphinx-powered docs" optional = false python-versions = ">=3.10" +groups = ["dev"] files = [ {file = "sphinxcontrib_mermaid-2.0.0-py3-none-any.whl", hash = "sha256:59a73249bbee2c74b1a4db036f8e8899ade65982bdda6712cf22b4f4e9874bb5"}, {file = "sphinxcontrib_mermaid-2.0.0.tar.gz", hash = "sha256:cf4f7d453d001132eaba5d1fdf53d42049f02e913213cf8337427483bfca26f4"}, @@ -2394,10 +2592,12 @@ version = "0.7" description = "Sphinx \"napoleon\" extension." optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "sphinxcontrib-napoleon-0.7.tar.gz", hash = "sha256:407382beed396e9f2d7f3043fad6afda95719204a1e1a231ac865f40abcbfcf8"}, {file = "sphinxcontrib_napoleon-0.7-py2.py3-none-any.whl", hash = "sha256:711e41a3974bdf110a484aec4c1a556799eb0b3f3b897521a018ad7e2db13fef"}, ] +markers = {main = "extra == \"docs\""} [package.dependencies] pockets = ">=0.3" @@ -2409,10 +2609,12 @@ version = "2.0.0" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, ] +markers = {main = "extra == \"docs\""} [package.extras] lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] @@ -2425,10 +2627,12 @@ version = "2.0.0" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, ] +markers = {main = "extra == \"docs\""} [package.extras] lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] @@ -2441,6 +2645,7 @@ version = "2.0.44" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "SQLAlchemy-2.0.44-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:471733aabb2e4848d609141a9e9d56a427c0a038f4abf65dd19d7a21fd563632"}, {file = "SQLAlchemy-2.0.44-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48bf7d383a35e668b984c805470518b635d48b95a3c57cb03f37eaa3551b5f9f"}, @@ -2536,6 +2741,7 @@ version = "0.41.2" description = "Various utility functions for SQLAlchemy." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "SQLAlchemy-Utils-0.41.2.tar.gz", hash = "sha256:bc599c8c3b3319e53ce6c5c3c471120bd325d0071fb6f38a10e924e3d07b9990"}, {file = "SQLAlchemy_Utils-0.41.2-py3-none-any.whl", hash = "sha256:85cf3842da2bf060760f955f8467b87983fb2e30f1764fd0e24a48307dc8ec6e"}, @@ -2553,8 +2759,8 @@ intervals = ["intervals (>=0.7.1)"] password = ["passlib (>=1.6,<2.0)"] pendulum = ["pendulum (>=2.0.5)"] phone = ["phonenumbers (>=5.9.2)"] -test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "backports.zoneinfo", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "pg8000 (>=1.12.4)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] -test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "backports.zoneinfo", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] +test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "backports.zoneinfo ; python_version < \"3.9\"", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "pg8000 (>=1.12.4)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] +test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "backports.zoneinfo ; python_version < \"3.9\"", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] timezone = ["python-dateutil"] url = ["furl (>=0.4.1)"] @@ -2564,6 +2770,7 @@ version = "2.0.3" description = "utilities for testing.* packages" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "testing.common.database-2.0.3-py2.py3-none-any.whl", hash = "sha256:e3ed492bf480a87f271f74c53b262caf5d85c8bc09989a8f534fa2283ec52492"}, {file = "testing.common.database-2.0.3.tar.gz", hash = "sha256:965d80b2985315325dc358c3061b174a712f4d4d5bf6a80b58b11f9a1dd86d73"}, @@ -2578,6 +2785,7 @@ version = "1.3.0" description = "automatically setups a postgresql instance in a temporary directory, and destroys it after testing" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "testing.postgresql-1.3.0-py2.py3-none-any.whl", hash = "sha256:1b41daeb98dfc8cd4a584bb91e8f5f4ab182993870f95257afe5f1ba6151a598"}, {file = "testing.postgresql-1.3.0.tar.gz", hash = "sha256:8e1a69760369a7a8ffe63a66b6d95a5cd82db2fb976e4a8f85ffd24fbfc447d8"}, @@ -2596,6 +2804,8 @@ version = "2.4.0" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] +markers = "python_version == \"3.10\"" files = [ {file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"}, {file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"}, @@ -2652,6 +2862,7 @@ version = "0.14.0" description = "Style preserving TOML library" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680"}, {file = "tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064"}, @@ -2663,6 +2874,7 @@ version = "4.67.3" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" +groups = ["extras"] files = [ {file = "tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf"}, {file = "tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb"}, @@ -2684,6 +2896,7 @@ version = "0.15.4" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "typer-0.15.4-py3-none-any.whl", hash = "sha256:eb0651654dcdea706780c466cf06d8f174405a659ffff8f163cfbfee98c0e173"}, {file = "typer-0.15.4.tar.gz", hash = "sha256:89507b104f9b6a0730354f27c39fae5b63ccd0c95b1ce1f1a6ba0cfd329997c3"}, @@ -2701,6 +2914,7 @@ version = "0.19.1.9" description = "Typing stubs for docutils" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "types-docutils-0.19.1.9.tar.gz", hash = "sha256:1d029567e67c52992fd42aa968778bc10a5e445c8450fc751d672d6f50330a4a"}, {file = "types_docutils-0.19.1.9-py3-none-any.whl", hash = "sha256:556fb7ee19248aa482caa142a830c940b776b0f8c7577a98abe0977574546a1d"}, @@ -2712,6 +2926,7 @@ version = "6.0.12.20250915" description = "Typing stubs for PyYAML" optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "types_pyyaml-6.0.12.20250915-py3-none-any.whl", hash = "sha256:e7d4d9e064e89a3b3cae120b4990cd370874d2bf12fa5f46c97018dd5d3c9ab6"}, {file = "types_pyyaml-6.0.12.20250915.tar.gz", hash = "sha256:0f8b54a528c303f0e6f7165687dd33fafa81c807fcac23f632b63aa624ced1d3"}, @@ -2723,6 +2938,7 @@ version = "4.15.0" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, @@ -2734,6 +2950,7 @@ version = "0.9.0" description = "Runtime inspection utilities for typing module." optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, @@ -2749,6 +2966,7 @@ version = "2025.3" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" +groups = ["main"] files = [ {file = "tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1"}, {file = "tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7"}, @@ -2760,16 +2978,18 @@ version = "2.6.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" +groups = ["main", "dev"] files = [ {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, ] +markers = {main = "extra == \"docs\""} [package.extras] -brotli = ["brotli (>=1.2.0)", "brotlicffi (>=1.2.0.0)"] +brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["backports-zstd (>=1.0.0)"] +zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] [[package]] name = "virtualenv" @@ -2777,6 +2997,7 @@ version = "20.36.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f"}, {file = "virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba"}, @@ -2790,7 +3011,7 @@ typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\"" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] [[package]] name = "wcwidth" @@ -2798,6 +3019,7 @@ version = "0.5.3" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "wcwidth-0.5.3-py3-none-any.whl", hash = "sha256:d584eff31cd4753e1e5ff6c12e1edfdb324c995713f75d26c29807bb84bf649e"}, {file = "wcwidth-0.5.3.tar.gz", hash = "sha256:53123b7af053c74e9fe2e92ac810301f6139e64379031f7124574212fb3b4091"}, @@ -2809,6 +3031,7 @@ version = "2.1.1" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "wrapt-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e927375e43fd5a985b27a8992327c22541b6dede1362fc79df337d26e23604f"}, {file = "wrapt-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c99544b6a7d40ca22195563b6d8bc3986ee8bb82f272f31f0670fe9440c869"}, @@ -2891,8 +3114,10 @@ dev = ["pytest", "setuptools"] [extras] docs = ["sphinx-rtd-theme", "sphinxcontrib-napoleon"] +mssql = ["aioodbc", "pyodbc"] +postgres = ["psycopg2-binary"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = ">=3.10,<3.14" -content-hash = "acfff071bfdc279f1937312612083daf291adb2f83b6f3944ea05434c2ae94f2" +content-hash = "7ef13779158747973d48c5072cbb4b1cbb5ac8613c1cb1d896fcf209387d7ef8" diff --git a/pyproject.toml b/pyproject.toml index 912fc6e..cc8e1ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,9 @@ homepage = "https://github.com/SAFEHR-data/datafaker" [tool.poetry.dependencies] python = ">=3.10,<3.14" pydantic = {extras = ["dotenv"], version = "^1.10.2"} -psycopg2-binary = "^2.9.5" +psycopg2-binary = {version = "^2.9.5", optional = true} +pyodbc = {version = "^5.0.0", optional = true} +aioodbc = {version = "^0.5.0", optional = true} sqlalchemy-utils = "^0.41.2" mimesis = "^18.0.0" typer = "^0.15.4" @@ -60,6 +62,8 @@ tqdm = "^4.65.0" [tool.poetry.extras] docs = ["sphinx-rtd-theme", "sphinxcontrib-napoleon", "sphinxcontrib-mermaid"] +mssql = ["pyodbc", "aioodbc"] +postgres = ["psycopg2-binary"] [build-system] requires = ["poetry-core"] diff --git a/tests/test_utils_mssql.py b/tests/test_utils_mssql.py new file mode 100644 index 0000000..b9caf94 --- /dev/null +++ b/tests/test_utils_mssql.py @@ -0,0 +1,207 @@ +"""Tests for MS-SQL driver support helpers in datafaker.utils.""" +import sys +import unittest +from unittest.mock import MagicMock, call, patch + + +class TestMakeAsyncDsn(unittest.TestCase): + """Tests for make_async_dsn.""" + + def _call(self, dsn: str) -> str: + from datafaker.utils import make_async_dsn + + return make_async_dsn(dsn) + + def test_postgresql_bare_dialect(self) -> None: + """postgresql:// is rewritten to use asyncpg.""" + result = self._call("postgresql://user:pass@host:5432/db") + self.assertTrue( + result.startswith("postgresql+asyncpg://"), + f"Expected asyncpg driver, got: {result}", + ) + + def test_postgresql_with_existing_driver(self) -> None: + """postgresql+psycopg2:// is also rewritten to asyncpg.""" + result = self._call("postgresql+psycopg2://user:pass@host:5432/db") + self.assertTrue(result.startswith("postgresql+asyncpg://")) + + def test_postgresql_preserves_credentials_and_path(self) -> None: + """Host, port and database name are preserved (password is masked in repr).""" + from sqlalchemy.engine import make_url + + result_url = make_url(self._call("postgresql://alice:secret@dbhost:5433/mydb")) + self.assertEqual(result_url.host, "dbhost") + self.assertEqual(result_url.port, 5433) + self.assertEqual(result_url.database, "mydb") + self.assertEqual(result_url.username, "alice") + + def test_mssql_bare_dialect(self) -> None: + """mssql:// is rewritten to use aioodbc.""" + result = self._call("mssql://user:pass@host:1433/db") + self.assertTrue( + result.startswith("mssql+aioodbc://"), + f"Expected aioodbc driver, got: {result}", + ) + + def test_mssql_with_existing_driver(self) -> None: + """mssql+pyodbc:// is rewritten to aioodbc.""" + result = self._call("mssql+pyodbc://user:pass@host:1433/db") + self.assertTrue(result.startswith("mssql+aioodbc://")) + + def test_unknown_dialect_raises(self) -> None: + """An unknown dialect raises ValueError rather than silently producing a bad DSN.""" + with self.assertRaises(ValueError) as ctx: + self._call("oracle://user:pass@host:1521/db") + self.assertIn("oracle", str(ctx.exception)) + + def test_duckdb_raises(self) -> None: + """DuckDB DSNs are not async-capable and should raise.""" + with self.assertRaises(ValueError): + self._call("duckdb:///path/to/file.db") + + +class TestIsUndefinedObjectError(unittest.TestCase): + """Tests for _is_undefined_object_error.""" + + def _call(self, exc: Exception) -> bool: + from datafaker.utils import _is_undefined_object_error + + return _is_undefined_object_error(exc) + + def test_pgcode_42704_returns_true(self) -> None: + """Any exception with pgcode 42704 is treated as UndefinedObject.""" + exc = Exception("undefined object") + exc.pgcode = "42704" # type: ignore[attr-defined] + self.assertTrue(self._call(exc)) + + def test_other_pgcode_returns_false(self) -> None: + """Exceptions with a different pgcode are not matched.""" + exc = Exception("some other error") + exc.pgcode = "23505" # type: ignore[attr-defined] + self.assertFalse(self._call(exc)) + + def test_no_pgcode_returns_false(self) -> None: + """Exceptions without a pgcode attribute are not matched.""" + self.assertFalse(self._call(ValueError("no pgcode here"))) + + def test_psycopg2_undefined_object_returns_true(self) -> None: + """A real psycopg2 UndefinedObject exception is matched (if psycopg2 installed).""" + try: + import psycopg2.errors # type: ignore[import] + except ImportError: + self.skipTest("psycopg2 not installed") + + exc = psycopg2.errors.UndefinedObject("constraint does not exist") + self.assertTrue(self._call(exc)) + + def test_works_without_psycopg2(self) -> None: + """_is_undefined_object_error falls back to pgcode check when psycopg2 is absent.""" + with patch.dict(sys.modules, {"psycopg2": None, "psycopg2.errors": None}): + exc = Exception("constraint does not exist") + exc.pgcode = "42704" # type: ignore[attr-defined] + from datafaker.utils import _is_undefined_object_error + + self.assertTrue(_is_undefined_object_error(exc)) + + def test_import_does_not_require_psycopg2(self) -> None: + """datafaker.utils can be imported even when psycopg2 is unavailable.""" + with patch.dict(sys.modules, {"psycopg2": None, "psycopg2.errors": None}): + import importlib + + import datafaker.utils as utils_mod + + importlib.reload(utils_mod) + + +class TestSchemaTranslateMap(unittest.TestCase): + """Tests for the cross-dialect schema routing in create_db_engine.""" + + def _make_engine(self, dsn: str, schema_name: str | None = None): + from datafaker.utils import create_db_engine, get_sync_engine + + return get_sync_engine(create_db_engine(dsn, schema_name=schema_name)) + + def test_no_schema_no_translate_map(self) -> None: + """Without a schema_name, schema_translate_map is absent from execution options.""" + engine = self._make_engine("duckdb:///:memory:") + opts = engine.get_execution_options() + self.assertNotIn("schema_translate_map", opts) + + def test_schema_sets_translate_map(self) -> None: + """When schema_name is given, schema_translate_map routes None to that schema.""" + engine = self._make_engine("duckdb:///:memory:", schema_name="myschema") + opts = engine.get_execution_options() + self.assertIn("schema_translate_map", opts) + self.assertEqual(opts["schema_translate_map"], {None: "myschema"}) + + def test_search_path_not_issued(self) -> None: + """set_db_settings is never called with a search_path key.""" + from datafaker.utils import create_db_engine, get_sync_engine + + with patch("datafaker.utils.set_db_settings") as mock_set: + engine = get_sync_engine( + create_db_engine("duckdb:///:memory:", schema_name="myschema") + ) + # Force a connection so any connect-event handler would fire + with engine.connect() as conn: + conn.execute(__import__("sqlalchemy").text("SELECT 1")) + + for c in mock_set.call_args_list: + settings_arg = c.args[1] if len(c.args) > 1 else c.kwargs.get("settings", {}) + self.assertNotIn( + "search_path", + settings_arg, + "search_path must not be passed to set_db_settings", + ) + + def test_mssql_dsn_schema_sets_translate_map(self) -> None: + """schema_translate_map is set even for an MS-SQL DSN (engine creation, no connect).""" + from datafaker.utils import create_db_engine, get_sync_engine + + # create_engine with mssql+pyodbc does not connect at construction time, + # so this is safe to run even without an ODBC driver installed. + try: + engine = get_sync_engine( + create_db_engine("mssql+pyodbc://user:pass@host/db", schema_name="dbo") + ) + except Exception: + self.skipTest("mssql+pyodbc driver not available in this environment") + + opts = engine.get_execution_options() + self.assertEqual(opts.get("schema_translate_map"), {None: "dbo"}) + + +class TestGetMetadataSchema(unittest.TestCase): + """Tests for the schema_name parameter on get_metadata.""" + + def test_reflect_called_with_schema(self) -> None: + """get_metadata passes schema_name to MetaData.reflect.""" + from datafaker.utils import get_metadata + + mock_engine = MagicMock() + mock_engine.connect.return_value.__enter__ = MagicMock(return_value=MagicMock()) + mock_engine.connect.return_value.__exit__ = MagicMock(return_value=False) + + with patch("datafaker.utils.MetaData") as MockMetaData: + mock_md = MagicMock() + MockMetaData.return_value = mock_md + mock_md.reflect.return_value = None + + get_metadata(mock_engine, schema_name="myschema") + + mock_md.reflect.assert_called_once_with(mock_engine, schema="myschema") + + def test_reflect_called_without_schema_when_none(self) -> None: + """get_metadata passes schema=None to reflect when no schema_name is given.""" + from datafaker.utils import get_metadata + + mock_engine = MagicMock() + + with patch("datafaker.utils.MetaData") as MockMetaData: + mock_md = MagicMock() + MockMetaData.return_value = mock_md + mock_md.reflect.return_value = None + + get_metadata(mock_engine) + + mock_md.reflect.assert_called_once_with(mock_engine, schema=None) From 76fec75987748b3caa8ca4b1fcc0b6675368b75b Mon Sep 17 00:00:00 2001 From: May Yong Date: Tue, 19 May 2026 13:20:04 +0100 Subject: [PATCH 08/45] Extend type parser for MS-SQL column types (issue #96) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add sqlalchemy.dialects.mssql import to serialize_metadata.py - Map PostgreSQL-only type strings to cross-dialect equivalents: TSVECTOR → sqltypes.Text (no MS-SQL equivalent) BYTEA → sqltypes.LargeBinary (renders as VARBINARY(MAX) on MS-SQL) CIDR → sqltypes.String(43) (stored as plain string) REAL → sqltypes.REAL (generic, replaces postgresql.REAL) - Add _mssql_varbinary_parser to handle VARBINARY, VARBINARY(n), VARBINARY(max), and VARBINARY(MAX) - Register parsers for MS-SQL-native types: UNIQUEIDENTIFIER, DATETIMEOFFSET(n), DATETIME2(n), BINARY(n), MONEY, SMALLMONEY, IMAGE, TINYINT, SMALLDATETIME, NTEXT, SQL_VARIANT, ROWVERSION - Place DATETIME2/DATETIMEOFFSET before DATETIME in parsy.alt() to avoid prefix-collision: ordered-choice parsers must try longer names first - Rename time_type parameter pg_type → tz_type (no behavioural change) - Add mssql.UNIQUEIDENTIFIER → UUID generator mapping in make.py - Add tests/test_serialize_metadata_mssql.py: 50 tests covering all new MS-SQL types, PostgreSQL degradation mappings, and regression coverage for all pre-existing type strings - Update examples/omop-mssql/README.md challenge 4 with issue link #96 Co-Authored-By: Claude Sonnet 4.6 --- datafaker/make.py | 5 +- datafaker/serialize_metadata.py | 55 ++++-- examples/omop-mssql/README.md | 2 +- tests/test_serialize_metadata_mssql.py | 227 +++++++++++++++++++++++++ 4 files changed, 277 insertions(+), 12 deletions(-) create mode 100644 tests/test_serialize_metadata_mssql.py diff --git a/datafaker/make.py b/datafaker/make.py index 27e69c5..3207f8b 100644 --- a/datafaker/make.py +++ b/datafaker/make.py @@ -17,7 +17,7 @@ from jinja2 import Environment, FileSystemLoader, Template from mimesis.providers.base import BaseProvider from sqlalchemy import CursorResult, Engine, MetaData, UniqueConstraint, text -from sqlalchemy.dialects import postgresql +from sqlalchemy.dialects import mssql, postgresql from sqlalchemy.engine import Connection from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine from sqlalchemy.schema import Column, Table @@ -384,6 +384,9 @@ def get_result_mappings( postgresql.UUID: GeneratorInfo( generator="generic.cryptographic.uuid", ), + mssql.UNIQUEIDENTIFIER: GeneratorInfo( + generator="generic.cryptographic.uuid", + ), sqltypes.String: GeneratorInfo( generator=_string_generator, choice=True, diff --git a/datafaker/serialize_metadata.py b/datafaker/serialize_metadata.py index 62bc01c..70d9e83 100644 --- a/datafaker/serialize_metadata.py +++ b/datafaker/serialize_metadata.py @@ -5,7 +5,7 @@ import parsy from sqlalchemy import Column, Dialect, Engine, ForeignKey, MetaData, Table -from sqlalchemy.dialects import oracle, postgresql +from sqlalchemy.dialects import mssql, oracle, postgresql from sqlalchemy.sql import schema, sqltypes from datafaker.utils import get_property, make_foreign_key_name, split_column_full_name @@ -79,7 +79,7 @@ def st_parser() -> typing.Generator[ParserType, None, typing.Any]: return st_parser -def time_type(type_: type, pg_type: type) -> ParserType: +def time_type(type_: type, tz_type: type) -> ParserType: """ Make a parser for a SQL date/time type. @@ -87,10 +87,10 @@ def time_type(type_: type, pg_type: type) -> ParserType: or TYPE_NAME(32) WITH TIME ZONE :param type_: The SQLAlchemy type we would like to parse. - :param pg_type: The PostgreSQL type we would like to parse if precision - or timezone is provided. + :param tz_type: The type to instantiate when precision or timezone is + provided (e.g. ``postgresql.types.TIMESTAMP``). :return: ``type_`` if neither precision nor timezone are provided in the - parsed text, ``pg_type(precision, timezone)`` otherwise. + parsed text, ``tz_type(precision, timezone)`` otherwise. """ @parsy.generate(type_.__name__) @@ -108,11 +108,26 @@ def pgt_parser() -> typing.Generator[ParserType, None, typing.Any]: if precision is None and not timezone: # normal sql type return type_ - return pg_type(precision=precision, timezone=timezone) + return tz_type(precision=precision, timezone=timezone) return pgt_parser +@parsy.generate("VARBINARY") +def _mssql_varbinary_parser() -> typing.Generator[ParserType, None, typing.Any]: + """Parse VARBINARY, VARBINARY(n), or VARBINARY(max/MAX).""" + yield parsy.string("VARBINARY") + length: int | None = yield ( + parsy.string("(") + >> ( + (parsy.string("max") | parsy.string("MAX")).result(None) + | integer() + ) + << parsy.string(")") + ).optional() + return mssql.VARBINARY(length=length) + + SIMPLE_TYPE_PARSER = parsy.alt( parsy.string("DOUBLE PRECISION").result( sqltypes.DOUBLE_PRECISION @@ -122,6 +137,11 @@ def pgt_parser() -> typing.Generator[ParserType, None, typing.Any]: simple(sqltypes.INTEGER), simple(sqltypes.SMALLINT), simple(sqltypes.BIGINT), + # DATETIME2 and DATETIMEOFFSET must come before DATETIME — parsy.alt() is + # ordered and does not backtrack once a parser has consumed input, so the + # longer names must be tried first. + numeric_type(mssql.DATETIMEOFFSET), + numeric_type(mssql.DATETIME2), simple(sqltypes.DATETIME), simple(sqltypes.DATE), simple(sqltypes.CLOB), @@ -129,13 +149,28 @@ def pgt_parser() -> typing.Generator[ParserType, None, typing.Any]: simple(sqltypes.UUID), simple(sqltypes.BLOB), simple(sqltypes.BOOLEAN), - simple(postgresql.TSVECTOR), - simple(postgresql.BYTEA), - simple(postgresql.CIDR), + # PostgreSQL-specific types — mapped to cross-dialect equivalents so that + # an orm.yaml produced from a PostgreSQL source can be used with MS-SQL. + # PostgreSQL recreates these correctly; MSSQL gets a functional fallback. + parsy.string("TSVECTOR").result(sqltypes.Text), # no MS-SQL equivalent; degrade to Text + parsy.string("BYTEA").result(sqltypes.LargeBinary), # MS-SQL: VARBINARY(MAX) + parsy.string("CIDR").result(sqltypes.String(43)), # no MS-SQL equivalent; store as VARCHAR(43) numeric_type(sqltypes.NUMERIC), numeric_type(sqltypes.DECIMAL), numeric_type(postgresql.BIT), - numeric_type(postgresql.REAL), + numeric_type(sqltypes.REAL), # was postgresql.REAL; sqltypes.REAL is cross-dialect + # MS-SQL-specific types + simple(mssql.UNIQUEIDENTIFIER), + _mssql_varbinary_parser, + numeric_type(mssql.BINARY), + simple(mssql.MONEY), + simple(mssql.SMALLMONEY), + simple(mssql.IMAGE), + simple(mssql.TINYINT), + simple(mssql.SMALLDATETIME), + simple(mssql.NTEXT), + simple(mssql.SQL_VARIANT), + simple(mssql.ROWVERSION), string_type(sqltypes.CHAR), string_type(sqltypes.NCHAR), string_type(sqltypes.VARCHAR), diff --git a/examples/omop-mssql/README.md b/examples/omop-mssql/README.md index 6ddebdb..9be354a 100644 --- a/examples/omop-mssql/README.md +++ b/examples/omop-mssql/README.md @@ -20,7 +20,7 @@ In [datafaker/utils.py:208](../../datafaker/utils.py), the async DSN is built by When a schema name is provided, the code issues `SET search_path TO ` via a connection-level event listener ([datafaker/utils.py:222, 305](../../datafaker/utils.py)). This is PostgreSQL-specific syntax. MS-SQL uses two-part `[schema].[table]` naming and does not support `SET search_path`. SQLAlchemy's `schema` argument on `MetaData` and `Table` objects is the correct cross-dialect approach. -### 4. PostgreSQL-specific column types in the type parser +### 4. PostgreSQL-specific column types in the type parser ([#96](https://github.com/SAFEHR-data/datafaker/issues/96)) [datafaker/serialize_metadata.py](../../datafaker/serialize_metadata.py) registers parsers for several PostgreSQL-only types that have no direct MS-SQL equivalent: diff --git a/tests/test_serialize_metadata_mssql.py b/tests/test_serialize_metadata_mssql.py new file mode 100644 index 0000000..d15b17d --- /dev/null +++ b/tests/test_serialize_metadata_mssql.py @@ -0,0 +1,227 @@ +"""Tests for MS-SQL type support in datafaker.serialize_metadata.""" +import unittest + +from sqlalchemy.dialects import mssql, postgresql +from sqlalchemy.sql import sqltypes + +from datafaker.serialize_metadata import type_parser + + +def parse(type_str: str): + """Shorthand: parse a type string and return the resulting SQLAlchemy type.""" + return type_parser.parse(type_str) + + +class TestMSSQLTypeParser(unittest.TestCase): + """New MS-SQL-specific type strings are parsed correctly.""" + + def test_uniqueidentifier(self) -> None: + result = parse("UNIQUEIDENTIFIER") + self.assertIs(result, mssql.UNIQUEIDENTIFIER) + + def test_datetimeoffset_bare(self) -> None: + result = parse("DATETIMEOFFSET") + self.assertIsInstance(result, mssql.DATETIMEOFFSET) + + def test_datetimeoffset_with_precision(self) -> None: + result = parse("DATETIMEOFFSET(7)") + self.assertIsInstance(result, mssql.DATETIMEOFFSET) + self.assertEqual(result.precision, 7) + + def test_datetime2_bare(self) -> None: + result = parse("DATETIME2") + self.assertIsInstance(result, mssql.DATETIME2) + + def test_datetime2_with_precision(self) -> None: + result = parse("DATETIME2(3)") + self.assertIsInstance(result, mssql.DATETIME2) + self.assertEqual(result.precision, 3) + + def test_varbinary_bare(self) -> None: + result = parse("VARBINARY") + self.assertIsInstance(result, mssql.VARBINARY) + + def test_varbinary_with_length(self) -> None: + result = parse("VARBINARY(8000)") + self.assertIsInstance(result, mssql.VARBINARY) + self.assertEqual(result.length, 8000) + + def test_varbinary_max_lowercase(self) -> None: + result = parse("VARBINARY(max)") + self.assertIsInstance(result, mssql.VARBINARY) + self.assertIsNone(result.length) + + def test_varbinary_max_uppercase(self) -> None: + result = parse("VARBINARY(MAX)") + self.assertIsInstance(result, mssql.VARBINARY) + self.assertIsNone(result.length) + + def test_binary_bare(self) -> None: + result = parse("BINARY") + self.assertIsInstance(result, mssql.BINARY) + + def test_binary_with_length(self) -> None: + result = parse("BINARY(16)") + self.assertIsInstance(result, mssql.BINARY) + self.assertEqual(result.length, 16) + + def test_money(self) -> None: + self.assertIs(parse("MONEY"), mssql.MONEY) + + def test_smallmoney(self) -> None: + self.assertIs(parse("SMALLMONEY"), mssql.SMALLMONEY) + + def test_image(self) -> None: + self.assertIs(parse("IMAGE"), mssql.IMAGE) + + def test_tinyint(self) -> None: + self.assertIs(parse("TINYINT"), mssql.TINYINT) + + def test_smalldatetime(self) -> None: + self.assertIs(parse("SMALLDATETIME"), mssql.SMALLDATETIME) + + def test_ntext(self) -> None: + self.assertIs(parse("NTEXT"), mssql.NTEXT) + + def test_sql_variant(self) -> None: + self.assertIs(parse("SQL_VARIANT"), mssql.SQL_VARIANT) + + def test_rowversion(self) -> None: + self.assertIs(parse("ROWVERSION"), mssql.ROWVERSION) + + +class TestPostgreSQLTypeDegradation(unittest.TestCase): + """PostgreSQL-specific type strings degrade to cross-dialect equivalents.""" + + def test_tsvector_maps_to_text(self) -> None: + result = parse("TSVECTOR") + self.assertIs(result, sqltypes.Text) + + def test_bytea_maps_to_largebinary(self) -> None: + result = parse("BYTEA") + self.assertIs(result, sqltypes.LargeBinary) + + def test_cidr_maps_to_string_43(self) -> None: + result = parse("CIDR") + self.assertIsInstance(result, sqltypes.String) + self.assertEqual(result.length, 43) + + +class TestExistingPostgreSQLTypesRoundTrip(unittest.TestCase): + """Pre-existing PostgreSQL type strings still parse correctly (regression tests).""" + + def test_integer(self) -> None: + self.assertIs(parse("INTEGER"), sqltypes.INTEGER) + + def test_bigint(self) -> None: + self.assertIs(parse("BIGINT"), sqltypes.BIGINT) + + def test_smallint(self) -> None: + self.assertIs(parse("SMALLINT"), sqltypes.SMALLINT) + + def test_boolean(self) -> None: + self.assertIs(parse("BOOLEAN"), sqltypes.BOOLEAN) + + def test_float(self) -> None: + self.assertIs(parse("FLOAT"), sqltypes.FLOAT) + + def test_double_precision(self) -> None: + self.assertIs(parse("DOUBLE PRECISION"), sqltypes.DOUBLE_PRECISION) + + def test_numeric_bare(self) -> None: + result = parse("NUMERIC") + self.assertIsInstance(result, sqltypes.NUMERIC) + + def test_numeric_with_args(self) -> None: + result = parse("NUMERIC(10, 2)") + self.assertIsInstance(result, sqltypes.NUMERIC) + self.assertEqual(result.precision, 10) + self.assertEqual(result.scale, 2) + + def test_varchar(self) -> None: + result = parse("VARCHAR(255)") + self.assertIsInstance(result, sqltypes.VARCHAR) + self.assertEqual(result.length, 255) + + def test_nvarchar(self) -> None: + result = parse("NVARCHAR(100)") + self.assertIsInstance(result, sqltypes.NVARCHAR) + self.assertEqual(result.length, 100) + + def test_text(self) -> None: + result = parse("TEXT") + self.assertIsInstance(result, sqltypes.TEXT) + + def test_uuid(self) -> None: + self.assertIs(parse("UUID"), sqltypes.UUID) + + def test_date(self) -> None: + self.assertIs(parse("DATE"), sqltypes.DATE) + + def test_datetime(self) -> None: + self.assertIs(parse("DATETIME"), sqltypes.DATETIME) + + def test_timestamp_bare(self) -> None: + self.assertIs(parse("TIMESTAMP"), sqltypes.TIMESTAMP) + + def test_timestamp_with_timezone(self) -> None: + result = parse("TIMESTAMP WITH TIME ZONE") + self.assertIsInstance(result, postgresql.types.TIMESTAMP) + self.assertTrue(result.timezone) + + def test_timestamp_with_precision_and_timezone(self) -> None: + result = parse("TIMESTAMP(6) WITH TIME ZONE") + self.assertIsInstance(result, postgresql.types.TIMESTAMP) + self.assertEqual(result.precision, 6) + self.assertTrue(result.timezone) + + def test_timestamp_without_timezone(self) -> None: + # WITHOUT TIME ZONE means timezone=False; the parser returns the plain + # sqltypes.TIMESTAMP class (not a pg-specific instance) in this case. + result = parse("TIMESTAMP WITHOUT TIME ZONE") + self.assertIs(result, sqltypes.TIMESTAMP) + + def test_time_bare(self) -> None: + self.assertIs(parse("TIME"), sqltypes.TIME) + + def test_time_with_timezone(self) -> None: + result = parse("TIME WITH TIME ZONE") + self.assertIsInstance(result, postgresql.types.TIME) + self.assertTrue(result.timezone) + + def test_bit_bare(self) -> None: + result = parse("BIT") + self.assertIsInstance(result, postgresql.BIT) + + def test_bit_with_length(self) -> None: + result = parse("BIT(8)") + self.assertIsInstance(result, postgresql.BIT) + self.assertEqual(result.length, 8) + + def test_real_bare(self) -> None: + result = parse("REAL") + self.assertIsInstance(result, sqltypes.REAL) + + def test_blob(self) -> None: + self.assertIs(parse("BLOB"), sqltypes.BLOB) + + def test_clob(self) -> None: + self.assertIs(parse("CLOB"), sqltypes.CLOB) + + +class TestArrayType(unittest.TestCase): + """Array types (PostgreSQL-specific) still parse correctly.""" + + def test_integer_array(self) -> None: + result = parse("INTEGER[]") + self.assertIsInstance(result, postgresql.ARRAY) + self.assertEqual(result.dimensions, 1) + + def test_text_array(self) -> None: + result = parse("TEXT[]") + self.assertIsInstance(result, postgresql.ARRAY) + + def test_multidimensional_array(self) -> None: + result = parse("INTEGER[][]") + self.assertIsInstance(result, postgresql.ARRAY) + self.assertEqual(result.dimensions, 2) From da4a69b782461e2463bf65b4c148bcfc91ca881b Mon Sep 17 00:00:00 2001 From: May Yong Date: Tue, 19 May 2026 13:31:08 +0100 Subject: [PATCH 09/45] Strip SERIAL/IDENTITY for MS-SQL target databases (issue #97) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add SERIAL, BIGSERIAL and SMALLSERIAL to the type parser so orm.yaml files using PostgreSQL pseudo-types can be loaded when targeting MS-SQL. Add a @compiles(CreateColumn, "mssql") hook that strips the IDENTITY modifier from DDL — MS-SQL rejects explicit INSERTs into IDENTITY columns without SET IDENTITY_INSERT ON, which datafaker never issues. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/create.py | 15 ++++++ datafaker/serialize_metadata.py | 8 +++ tests/test_create_mssql.py | 74 ++++++++++++++++++++++++++ tests/test_serialize_metadata_mssql.py | 9 ++++ 4 files changed, 106 insertions(+) create mode 100644 tests/test_create_mssql.py diff --git a/datafaker/create.py b/datafaker/create.py index b3aef3f..e83a2d5 100644 --- a/datafaker/create.py +++ b/datafaker/create.py @@ -1,5 +1,6 @@ """Functions and classes to create and populate the target database.""" import pathlib +import re from collections import Counter from types import ModuleType from typing import Any, Generator, Iterable, Iterator, Mapping, Sequence, Tuple @@ -42,6 +43,20 @@ def remove_serial(element: CreateColumn, compiler: Any, **kw: Any) -> str: return text.replace(" SERIAL ", " INTEGER ") +@compiles(CreateColumn, "mssql") +def remove_mssql_identity(element: CreateColumn, compiler: Any, **kw: Any) -> str: + """ + Strip IDENTITY from MS-SQL column DDL. + + datafaker inserts explicit values for every column. MS-SQL rejects explicit + inserts into IDENTITY columns unless SET IDENTITY_INSERT is enabled first, + so we simply omit the IDENTITY modifier — the column stays an INTEGER. + """ + text: str = compiler.visit_create_column(element, **kw) + # Handles both bare IDENTITY and parametrised IDENTITY(m,n) + return re.sub(r" IDENTITY(\(\d+,\s*\d+\))?", "", text) + + @compiles(CreateTable, "duckdb") def remove_on_delete_cascade(element: CreateTable, compiler: Any, **kw: Any) -> str: """ diff --git a/datafaker/serialize_metadata.py b/datafaker/serialize_metadata.py index 70d9e83..a89a087 100644 --- a/datafaker/serialize_metadata.py +++ b/datafaker/serialize_metadata.py @@ -155,6 +155,14 @@ def _mssql_varbinary_parser() -> typing.Generator[ParserType, None, typing.Any]: parsy.string("TSVECTOR").result(sqltypes.Text), # no MS-SQL equivalent; degrade to Text parsy.string("BYTEA").result(sqltypes.LargeBinary), # MS-SQL: VARBINARY(MAX) parsy.string("CIDR").result(sqltypes.String(43)), # no MS-SQL equivalent; store as VARCHAR(43) + # PostgreSQL SERIAL pseudo-types — map to plain integers. datafaker does + # not rely on server-side autoincrement; the @compiles hook in create.py + # strips IDENTITY from MS-SQL DDL so explicit INSERTs work without + # SET IDENTITY_INSERT. BIGSERIAL/SMALLSERIAL listed before SERIAL so + # the common "SERIAL" prefix is tried last (defensive ordering). + parsy.string("BIGSERIAL").result(sqltypes.BIGINT), + parsy.string("SMALLSERIAL").result(sqltypes.SMALLINT), + parsy.string("SERIAL").result(sqltypes.INTEGER), numeric_type(sqltypes.NUMERIC), numeric_type(sqltypes.DECIMAL), numeric_type(postgresql.BIT), diff --git a/tests/test_create_mssql.py b/tests/test_create_mssql.py new file mode 100644 index 0000000..c579884 --- /dev/null +++ b/tests/test_create_mssql.py @@ -0,0 +1,74 @@ +"""Tests for MS-SQL DDL compilation in datafaker.create.""" +import unittest + +from sqlalchemy import Column, Integer, MetaData, String, Table +from sqlalchemy.dialects import mssql +from sqlalchemy.schema import CreateTable + +# Importing create registers the @compiles hooks globally. +import datafaker.create # noqa: F401 + + +def _compile_create_table(table: Table) -> str: + """Compile a CreateTable statement against the MS-SQL dialect.""" + return str(CreateTable(table).compile(dialect=mssql.dialect())) + + +class TestMSSQLRemoveIdentity(unittest.TestCase): + """@compiles(CreateColumn, 'mssql') strips IDENTITY from autoincrement columns.""" + + def _make_table(self) -> Table: + meta = MetaData() + return Table( + "test_table", + meta, + Column("id", Integer(), primary_key=True, autoincrement=True), + Column("value", Integer(), nullable=True), + ) + + def test_identity_absent_from_ddl(self) -> None: + """IDENTITY must be absent so explicit INSERTs succeed without SET IDENTITY_INSERT.""" + ddl = _compile_create_table(self._make_table()) + self.assertNotIn("IDENTITY", ddl) + + def test_integer_type_preserved(self) -> None: + """The INTEGER type is preserved after stripping IDENTITY.""" + ddl = _compile_create_table(self._make_table()) + self.assertIn("INTEGER", ddl) + + def test_primary_key_constraint_preserved(self) -> None: + """PRIMARY KEY constraint is not affected by the hook.""" + ddl = _compile_create_table(self._make_table()) + self.assertIn("PRIMARY KEY", ddl) + + def test_non_autoincrement_column_unchanged(self) -> None: + """Non-autoincrement columns are not altered.""" + ddl = _compile_create_table(self._make_table()) + self.assertIn("value", ddl.lower()) + + def test_multiple_autoincrement_columns_all_stripped(self) -> None: + """IDENTITY is stripped from every column that would receive it.""" + meta = MetaData() + table = Table( + "multi", + meta, + Column("id", Integer(), primary_key=True, autoincrement=True), + Column("seq", Integer(), autoincrement=True), + ) + ddl = _compile_create_table(table) + self.assertNotIn("IDENTITY", ddl) + + def test_duckdb_serial_hook_still_works(self) -> None: + """Adding the mssql hook does not break the existing DuckDB SERIAL hook (regression).""" + from sqlalchemy.dialects import registry + from sqlalchemy import create_engine + from sqlalchemy.schema import CreateColumn + + # Compile a CreateColumn for the duckdb dialect indirectly by checking + # that remove_serial is still registered. + from sqlalchemy.ext.compiler import compiles + + # If the duckdb hook were broken, datafaker.create.remove_serial would + # not be registered. Verify it still exists and is callable. + self.assertTrue(callable(datafaker.create.remove_serial)) + self.assertTrue(callable(datafaker.create.remove_mssql_identity)) diff --git a/tests/test_serialize_metadata_mssql.py b/tests/test_serialize_metadata_mssql.py index d15b17d..ab48e3e 100644 --- a/tests/test_serialize_metadata_mssql.py +++ b/tests/test_serialize_metadata_mssql.py @@ -106,6 +106,15 @@ def test_cidr_maps_to_string_43(self) -> None: self.assertIsInstance(result, sqltypes.String) self.assertEqual(result.length, 43) + def test_serial_maps_to_integer(self) -> None: + self.assertIs(parse("SERIAL"), sqltypes.INTEGER) + + def test_bigserial_maps_to_bigint(self) -> None: + self.assertIs(parse("BIGSERIAL"), sqltypes.BIGINT) + + def test_smallserial_maps_to_smallint(self) -> None: + self.assertIs(parse("SMALLSERIAL"), sqltypes.SMALLINT) + class TestExistingPostgreSQLTypesRoundTrip(unittest.TestCase): """Pre-existing PostgreSQL type strings still parse correctly (regression tests).""" From fabb0cc6f5064f2cea70f87fb4b9c7be935474fd Mon Sep 17 00:00:00 2001 From: May Yong Date: Tue, 19 May 2026 13:31:25 +0100 Subject: [PATCH 10/45] Add commit link to challenge 5 in MS-SQL README Co-Authored-By: Claude Sonnet 4.6 --- examples/omop-mssql/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/omop-mssql/README.md b/examples/omop-mssql/README.md index 9be354a..428dda5 100644 --- a/examples/omop-mssql/README.md +++ b/examples/omop-mssql/README.md @@ -20,7 +20,7 @@ In [datafaker/utils.py:208](../../datafaker/utils.py), the async DSN is built by When a schema name is provided, the code issues `SET search_path TO ` via a connection-level event listener ([datafaker/utils.py:222, 305](../../datafaker/utils.py)). This is PostgreSQL-specific syntax. MS-SQL uses two-part `[schema].[table]` naming and does not support `SET search_path`. SQLAlchemy's `schema` argument on `MetaData` and `Table` objects is the correct cross-dialect approach. -### 4. PostgreSQL-specific column types in the type parser ([#96](https://github.com/SAFEHR-data/datafaker/issues/96)) +### 4. PostgreSQL-specific column types in the type parser ([#96](https://github.com/SAFEHR-data/datafaker/issues/96), commit [76fec75](https://github.com/SAFEHR-data/datafaker/commit/76fec75)) [datafaker/serialize_metadata.py](../../datafaker/serialize_metadata.py) registers parsers for several PostgreSQL-only types that have no direct MS-SQL equivalent: @@ -35,7 +35,7 @@ When a schema name is provided, the code issues `SET search_path TO ` vi | `postgresql.BIT` | MS-SQL `BIT` is boolean (0/1 only); multi-bit columns use `BINARY` | | `postgresql.REAL` / `TIMESTAMP` / `TIME` with timezone | Need MS-SQL dialect equivalents (`DATETIMEOFFSET` for tz-aware timestamps) | -### 5. `SERIAL` autoincrement columns +### 5. `SERIAL` autoincrement columns ([#97](https://github.com/SAFEHR-data/datafaker/issues/97), commit [da4a69b](https://github.com/SAFEHR-data/datafaker/commit/da4a69b)) PostgreSQL uses `SERIAL` for autoincrement columns. The code already strips `SERIAL` for DuckDB in [datafaker/create.py:29](../../datafaker/create.py), but there is no equivalent handler for MS-SQL, which uses `IDENTITY(1,1)`. From dfb698f72e4b9c889eebfee740d6fab4f6a21571 Mon Sep 17 00:00:00 2001 From: May Yong Date: Tue, 19 May 2026 13:34:25 +0100 Subject: [PATCH 11/45] Add issue #98 link for challenge 6 (UUID type mapping) to MS-SQL README Co-Authored-By: Claude Sonnet 4.6 --- examples/omop-mssql/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/omop-mssql/README.md b/examples/omop-mssql/README.md index 428dda5..65e2e48 100644 --- a/examples/omop-mssql/README.md +++ b/examples/omop-mssql/README.md @@ -39,7 +39,7 @@ When a schema name is provided, the code issues `SET search_path TO ` vi PostgreSQL uses `SERIAL` for autoincrement columns. The code already strips `SERIAL` for DuckDB in [datafaker/create.py:29](../../datafaker/create.py), but there is no equivalent handler for MS-SQL, which uses `IDENTITY(1,1)`. -### 6. `postgresql.UUID` type mapping +### 6. `postgresql.UUID` type mapping ([#98](https://github.com/SAFEHR-data/datafaker/issues/98), commit [76fec75](https://github.com/SAFEHR-data/datafaker/commit/76fec75)) [datafaker/make.py:384](../../datafaker/make.py) maps `postgresql.UUID` to a generator. MS-SQL uses `UNIQUEIDENTIFIER` for UUIDs, which SQLAlchemy exposes as `sqlalchemy.dialects.mssql.UNIQUEIDENTIFIER`. From 39709d88ae9f09a2dd004b608318902313ca140a Mon Sep 17 00:00:00 2001 From: May Yong Date: Tue, 19 May 2026 13:45:43 +0100 Subject: [PATCH 12/45] Add tests for challenge 7 dialect-agnostic error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three new tests for _is_undefined_object_error: - pyodbc-style error (SQLSTATE in args[0], no pgcode) → False, documenting that the current pgcode-based fallback does not cover MS-SQL/pyodbc errors - pgcode=None → False - SQLAlchemy ProgrammingError wrapper → only e.orig matches, not the wrapper itself, confirming the call-site convention in remove_vocab_foreign_key_constraints Co-Authored-By: Claude Sonnet 4.6 --- tests/test_utils_mssql.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/test_utils_mssql.py b/tests/test_utils_mssql.py index b9caf94..3879361 100644 --- a/tests/test_utils_mssql.py +++ b/tests/test_utils_mssql.py @@ -112,6 +112,41 @@ def test_import_does_not_require_psycopg2(self) -> None: importlib.reload(utils_mod) + def test_pyodbc_style_error_without_pgcode_returns_false(self) -> None: + """A pyodbc-style error has SQLSTATE in args[0] but no pgcode attribute. + + pyodbc does not set pgcode, so the current implementation cannot + distinguish a 'constraint does not exist' pyodbc error from any other + exception without pgcode. This test documents that known limitation. + """ + exc = Exception("constraint does not exist") + # pyodbc puts SQLSTATE in args[0]; MS-SQL error 3728 maps to SQLSTATE 42000 + exc.args = ("42000", "[42000] [SQL Server] ... is not a constraint. (3728)") + self.assertFalse(self._call(exc)) + + def test_pgcode_none_returns_false(self) -> None: + """pgcode=None is not treated as a match.""" + exc = Exception("undefined object") + exc.pgcode = None # type: ignore[attr-defined] + self.assertFalse(self._call(exc)) + + def test_sqlalchemy_wrapper_not_matched_only_orig_is(self) -> None: + """The helper expects the unwrapped DBAPI error (e.orig), not the SQLAlchemy wrapper. + + The call site in utils.py passes e.orig, not e, so the SQLAlchemy + ProgrammingError itself should not match even when e.orig would. + """ + from sqlalchemy.exc import ProgrammingError + + orig = Exception("underlying DBAPI error") + orig.pgcode = "42704" # type: ignore[attr-defined] + sa_exc = ProgrammingError("statement", {}, orig) + + # The SQLAlchemy exception itself has no pgcode. + self.assertFalse(self._call(sa_exc)) + # Passing e.orig directly does match. + self.assertTrue(self._call(sa_exc.orig)) + class TestSchemaTranslateMap(unittest.TestCase): """Tests for the cross-dialect schema routing in create_db_engine.""" From 0925a93ba0b7cb3cf423f5d2290f3e6c6ff6ee3f Mon Sep 17 00:00:00 2001 From: May Yong Date: Tue, 19 May 2026 13:47:07 +0100 Subject: [PATCH 13/45] Add commit links for challenge 7 to MS-SQL README Co-Authored-By: Claude Sonnet 4.6 --- examples/omop-mssql/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/omop-mssql/README.md b/examples/omop-mssql/README.md index 65e2e48..b5fb1cf 100644 --- a/examples/omop-mssql/README.md +++ b/examples/omop-mssql/README.md @@ -43,7 +43,7 @@ PostgreSQL uses `SERIAL` for autoincrement columns. The code already strips `SER [datafaker/make.py:384](../../datafaker/make.py) maps `postgresql.UUID` to a generator. MS-SQL uses `UNIQUEIDENTIFIER` for UUIDs, which SQLAlchemy exposes as `sqlalchemy.dialects.mssql.UNIQUEIDENTIFIER`. -### 7. PostgreSQL-specific error handling +### 7. PostgreSQL-specific error handling (commits [b2f14ab](https://github.com/SAFEHR-data/datafaker/commit/b2f14ab), [39709d8](https://github.com/SAFEHR-data/datafaker/commit/39709d8)) [datafaker/utils.py:651](../../datafaker/utils.py) catches `psycopg2.errors.UndefinedObject` to handle missing constraints gracefully. This is a PostgreSQL/psycopg2-specific exception. For MS-SQL the equivalent `pyodbc` error would need to be caught instead, or the check should be made dialect-agnostic. From 7183d0599f764e7da1641ea82af73bfefa3f1cfe Mon Sep 17 00:00:00 2001 From: May Yong Date: Tue, 19 May 2026 14:00:43 +0100 Subject: [PATCH 14/45] Document challenge 8 as deferred in README and issue #99 set_db_settings is DuckDB-only; fixing the autocommit toggle in isolation would leave the SET syntax still broken for MS-SQL. Both should be addressed together if the function is ever extended. Co-Authored-By: Claude Sonnet 4.6 --- examples/omop-mssql/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/omop-mssql/README.md b/examples/omop-mssql/README.md index b5fb1cf..10be761 100644 --- a/examples/omop-mssql/README.md +++ b/examples/omop-mssql/README.md @@ -47,10 +47,12 @@ PostgreSQL uses `SERIAL` for autoincrement columns. The code already strips `SER [datafaker/utils.py:651](../../datafaker/utils.py) catches `psycopg2.errors.UndefinedObject` to handle missing constraints gracefully. This is a PostgreSQL/psycopg2-specific exception. For MS-SQL the equivalent `pyodbc` error would need to be caught instead, or the check should be made dialect-agnostic. -### 8. `autocommit` handling in `set_db_settings` +### 8. `autocommit` handling in `set_db_settings` ([#99](https://github.com/SAFEHR-data/datafaker/issues/99)) [datafaker/utils.py:297-309](../../datafaker/utils.py) toggles `connection.autocommit` directly on the DBAPI connection before executing `SET` commands. The availability and behaviour of `autocommit` differs between `psycopg2`, `pyodbc`, and `pymssql`, so this would need testing or an abstraction per driver. +**Deferred.** `set_db_settings` is only ever called for DuckDB connections (`parquet_dir` source feature); MS-SQL connections never reach it. Fixing the `autocommit` toggle in isolation would also leave the `SET {k} TO {v}` SQL syntax broken for MS-SQL (which requires `SET {k} {v}`). Both issues should be addressed together if `set_db_settings` is ever extended to MS-SQL. + ## Steps 1. Make a YAML file representing the tables in the schema From d872fd9aa159cb1efdf5448650e0a8dd94c921df Mon Sep 17 00:00:00 2001 From: May Yong Date: Tue, 19 May 2026 14:32:49 +0100 Subject: [PATCH 15/45] Document macOS ODBC driver setup and add .env.example for MS-SQL - Add Setup section to README covering poetry install --extras mssql, homebrew ODBC driver installation, odbcinst.ini registration, and .env configuration with the correct driver 18 DSN format - Add .env.example with placeholder DSN for safe version control (.env itself is gitignored) Co-Authored-By: Claude Sonnet 4.6 --- examples/omop-mssql/.env.example | 4 +++ examples/omop-mssql/README.md | 53 ++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 examples/omop-mssql/.env.example diff --git a/examples/omop-mssql/.env.example b/examples/omop-mssql/.env.example new file mode 100644 index 0000000..3690019 --- /dev/null +++ b/examples/omop-mssql/.env.example @@ -0,0 +1,4 @@ +SRC_DSN=mssql+pyodbc://:@:1433/?driver=ODBC+Driver+18+for+SQL+Server +SRC_SCHEMA= +DST_DSN=mssql+pyodbc://:@:1433/?driver=ODBC+Driver+18+for+SQL+Server +DST_SCHEMA= diff --git a/examples/omop-mssql/README.md b/examples/omop-mssql/README.md index 10be761..c5c83c2 100644 --- a/examples/omop-mssql/README.md +++ b/examples/omop-mssql/README.md @@ -53,6 +53,59 @@ PostgreSQL uses `SERIAL` for autoincrement columns. The code already strips `SER **Deferred.** `set_db_settings` is only ever called for DuckDB connections (`parquet_dir` source feature); MS-SQL connections never reach it. Fixing the `autocommit` toggle in isolation would also leave the `SET {k} TO {v}` SQL syntax broken for MS-SQL (which requires `SET {k} {v}`). Both issues should be addressed together if `set_db_settings` is ever extended to MS-SQL. + +## Setup + +### 1. Install the MS-SQL Python extras + +`pyodbc` and `aioodbc` are optional dependencies. Install them with: + +```bash +poetry install --extras mssql +``` + +### 2. Install and register the ODBC driver (macOS) + +If you do not already have the Microsoft ODBC driver installed: + +```bash +brew tap microsoft/mssql-release +brew install unixodbc msodbcsql18 mssql-tools18 +``` + +Then verify the driver is registered: + +```bash +odbcinst -q -d +``` + +If the output is empty, register it manually: + +```bash +cat >> /opt/homebrew/etc/odbcinst.ini <<'EOF' +[ODBC Driver 18 for SQL Server] +Description=Microsoft ODBC Driver 18 for SQL Server +Driver=/opt/homebrew/lib/libmsodbcsql.18.dylib +UsageCount=1 +EOF +``` + +### 3. Configure the connection + +Copy the example environment file and fill in your connection details: + +```bash +cp examples/omop-mssql/.env.example examples/omop-mssql/.env +``` + +Edit `.env` with your server hostname, credentials, database name and schema names. The DSN format is: + +``` +mssql+pyodbc://:@:1433/?driver=ODBC+Driver+18+for+SQL+Server +``` + +Run datafaker commands from the `examples/omop-mssql/` directory so that the `.env` file is picked up automatically. + ## Steps 1. Make a YAML file representing the tables in the schema From db2e48b1ff4e6087686f361376072a3f82a37639 Mon Sep 17 00:00:00 2001 From: May Yong Date: Wed, 20 May 2026 16:22:15 +0100 Subject: [PATCH 16/45] Fix Steps paths in MS-SQL README to run from example directory All commands now use relative paths (./orm.yaml etc.) and a cd note makes clear they must be run from examples/omop-mssql/ so the .env file is picked up correctly. Co-Authored-By: Claude Sonnet 4.6 --- examples/omop-mssql/README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/examples/omop-mssql/README.md b/examples/omop-mssql/README.md index c5c83c2..62085f6 100644 --- a/examples/omop-mssql/README.md +++ b/examples/omop-mssql/README.md @@ -108,22 +108,28 @@ Run datafaker commands from the `examples/omop-mssql/` directory so that the `.e ## Steps +Run all commands from the `examples/omop-mssql/` directory so that the `.env` file is picked up automatically. + +```bash +cd examples/omop-mssql +``` + 1. Make a YAML file representing the tables in the schema -`poetry run datafaker make-tables --orm-file ./examples/omop-mssql/orm.yaml` +`poetry run datafaker make-tables --orm-file ./orm.yaml` 1. Create schema from the ORM YAML file -`poetry run datafaker create-tables --orm-file ./examples/omop-mssql/orm.yaml --config-file ./examples/omop-mssql/config.yaml` +`poetry run datafaker create-tables --orm-file ./orm.yaml --config-file ./config.yaml` 1. Create generator table -`poetry run datafaker create-generators --orm-file ./examples/omop-mssql/orm.yaml --config-file ./examples/omop-mssql/config.yaml --df-file ./examples/omop-mssql/df.py` +`poetry run datafaker create-generators --orm-file ./orm.yaml --config-file ./config.yaml --df-file ./df.py` 1. Create data -`poetry run datafaker create-data --orm-file ./examples/omop-mssql/orm.yaml --config-file ./examples/omop-mssql/config.yaml --df-file ./examples/omop-mssql/df.py` +`poetry run datafaker create-data --orm-file ./orm.yaml --config-file ./config.yaml --df-file ./df.py` 1. Remove data -`poetry run datafaker remove-data --orm-file ./examples/omop-mssql/orm.yaml --config-file ./examples/omop-mssql/config.yaml` +`poetry run datafaker remove-data --orm-file ./orm.yaml --config-file ./config.yaml` From fc97b2c9beeca36fca67428152dc6be97260a5f6 Mon Sep 17 00:00:00 2001 From: May Yong Date: Wed, 20 May 2026 16:28:28 +0100 Subject: [PATCH 17/45] Add TrustServerCertificate=yes to MS-SQL DSN examples ODBC Driver 18 defaults to Encrypt=yes with certificate validation. SQL Server's self-signed certificate fails that check, causing a login timeout. TrustServerCertificate=yes bypasses validation for local/dev containers where a proper cert is not in place. Co-Authored-By: Claude Sonnet 4.6 --- examples/omop-mssql/.env.example | 4 ++-- examples/omop-mssql/README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/omop-mssql/.env.example b/examples/omop-mssql/.env.example index 3690019..b16f171 100644 --- a/examples/omop-mssql/.env.example +++ b/examples/omop-mssql/.env.example @@ -1,4 +1,4 @@ -SRC_DSN=mssql+pyodbc://:@:1433/?driver=ODBC+Driver+18+for+SQL+Server +SRC_DSN=mssql+pyodbc://:@:1433/?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes SRC_SCHEMA= -DST_DSN=mssql+pyodbc://:@:1433/?driver=ODBC+Driver+18+for+SQL+Server +DST_DSN=mssql+pyodbc://:@:1433/?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes DST_SCHEMA= diff --git a/examples/omop-mssql/README.md b/examples/omop-mssql/README.md index 62085f6..3a3795d 100644 --- a/examples/omop-mssql/README.md +++ b/examples/omop-mssql/README.md @@ -101,7 +101,7 @@ cp examples/omop-mssql/.env.example examples/omop-mssql/.env Edit `.env` with your server hostname, credentials, database name and schema names. The DSN format is: ``` -mssql+pyodbc://:@:1433/?driver=ODBC+Driver+18+for+SQL+Server +mssql+pyodbc://:@:1433/?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes ``` Run datafaker commands from the `examples/omop-mssql/` directory so that the `.env` file is picked up automatically. From 81a65eb953e7885aeaa1498f1c81a18bbdb71e3d Mon Sep 17 00:00:00 2001 From: May Yong Date: Wed, 20 May 2026 17:53:01 +0100 Subject: [PATCH 18/45] Fix schema-qualified FK resolution and MS-SQL multiple cascade paths (closes #101) Strip leading schema qualifier from FK targets before constructing ForeignKey objects so that 3-part orm.yaml references such as mimic100.concept.concept_id resolve correctly against a MetaData whose tables carry no schema prefix. Add @compiles(CreateTable, "mssql") hook to remove ON DELETE CASCADE from MS-SQL DDL, preventing error 1785 when multiple FK columns on one table all point at the same vocabulary table (common in OMOP-style schemas). Both fixes have tests. Also adds pytest to dev dependencies and the omop-mssql example config.yaml. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/create.py | 15 ++++++ datafaker/serialize_metadata.py | 35 ++++++++++-- examples/omop-mssql/.env.example | 4 +- examples/omop-mssql/README.md | 2 + examples/omop-mssql/config.yaml | 9 ++++ poetry.lock | 73 +++++++++++++++++++++++++- pyproject.toml | 1 + tests/test_create_mssql.py | 34 +++++++++++- tests/test_serialize_metadata_mssql.py | 69 +++++++++++++++++++++++- 9 files changed, 232 insertions(+), 10 deletions(-) create mode 100644 examples/omop-mssql/config.yaml diff --git a/datafaker/create.py b/datafaker/create.py index e83a2d5..bdad04c 100644 --- a/datafaker/create.py +++ b/datafaker/create.py @@ -57,6 +57,21 @@ def remove_mssql_identity(element: CreateColumn, compiler: Any, **kw: Any) -> st return re.sub(r" IDENTITY(\(\d+,\s*\d+\))?", "", text) +@compiles(CreateTable, "mssql") +def remove_mssql_on_delete_cascade(element: CreateTable, compiler: Any, **kw: Any) -> str: + """ + Strip ON DELETE CASCADE from MS-SQL table DDL. + + MS-SQL rejects multiple cascading FK paths to the same table (error 1785). + OMOP-style schemas commonly have many FK columns on one table all pointing at + the same vocabulary table, which triggers this limit. Dropping CASCADE is + safe for datafaker because referential integrity is enforced by insert order, + not by the database engine. + """ + text: str = compiler.visit_create_table(element, **kw) + return text.replace(" ON DELETE CASCADE", "") + + @compiles(CreateTable, "duckdb") def remove_on_delete_cascade(element: CreateTable, compiler: Any, **kw: Any) -> str: """ diff --git a/datafaker/serialize_metadata.py b/datafaker/serialize_metadata.py index a89a087..647b1ea 100644 --- a/datafaker/serialize_metadata.py +++ b/datafaker/serialize_metadata.py @@ -61,7 +61,9 @@ def string_type(type_: type) -> ParserType: Make a parser for a SQL string type. Parses TYPE_NAME, TYPE_NAME(32), TYPE_NAME COLLATE "fr" - or TYPE_NAME(32) COLLATE "fr" + or TYPE_NAME(32) COLLATE "fr" (PostgreSQL style, quoted collation name) + or TYPE_NAME(32) COLLATE SQL_Latin1_General_CP1_CI_AS + (MS-SQL style, unquoted collation name) """ @parsy.generate(type_.__name__) @@ -71,8 +73,11 @@ def st_parser() -> typing.Generator[ParserType, None, typing.Any]: length: int | None = yield ( parsy.string("(") >> integer() << parsy.string(")") ).optional() - collation: str | None = yield ( - parsy.string(' COLLATE "') >> parsy.regex(r'[^"]*') << parsy.string('"') + collation: str | None = yield parsy.alt( + # PostgreSQL: COLLATE "name" (quoted) + parsy.string(' COLLATE "') >> parsy.regex(r'[^"]*') << parsy.string('"'), + # MS-SQL: COLLATE name (unquoted identifier) + parsy.string(" COLLATE ") >> parsy.regex(r'\S+'), ).optional() return type_(length=length, collation=collation) @@ -231,6 +236,19 @@ def column_to_dict(column: Column, dialect: Dialect) -> dict[str, typing.Any]: return result +def _unqualify_fk_target(fk: str) -> str: + """ + Drop the schema qualifier from a 3-part FK target. + + Converts ``schema.table.column`` → ``table.column`` so that SQLAlchemy + can resolve the reference against a MetaData whose tables were registered + without a schema prefix. 2-part ``table.column`` targets are returned + unchanged. + """ + parts = fk.split(".") + return ".".join(parts[-2:]) if len(parts) == 3 else fk + + def dict_to_column( table_name: str, col_name: str, @@ -261,7 +279,7 @@ def dict_to_column( if "foreign_keys" in rep: args = [ ForeignKey( - fk, + _unqualify_fk_target(fk), name=make_foreign_key_name(table_name, col_name), ondelete="CASCADE", ) @@ -358,7 +376,14 @@ def should_ignore_fk(tables_dict: dict[str, TableT], fk: str) -> bool: :param fk: The name of the foreign key. """ (table, _column) = split_column_full_name(fk) - td = get_property(tables_dict, table, dict, {}) + # FK targets may be schema-qualified (e.g. "mimic100.concept"). + # Try the fully-qualified name first so users can be explicit in config + # (e.g. "mimic100.concept: ignore: true"); fall back to the bare table + # name for configs that don't include a schema prefix. + td = get_property(tables_dict, table, dict, None) + if td is None: + bare = table.split(".")[-1] + td = get_property(tables_dict, bare, dict, {}) return get_property(td, "ignore", bool, False) diff --git a/examples/omop-mssql/.env.example b/examples/omop-mssql/.env.example index b16f171..83453da 100644 --- a/examples/omop-mssql/.env.example +++ b/examples/omop-mssql/.env.example @@ -1,4 +1,4 @@ -SRC_DSN=mssql+pyodbc://:@:1433/?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes +SRC_DSN=mssql+pyodbc://:@127.0.0.1:1433/?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes SRC_SCHEMA= -DST_DSN=mssql+pyodbc://:@:1433/?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes +DST_DSN=mssql+pyodbc://:@127.0.0.1:1433/?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes DST_SCHEMA= diff --git a/examples/omop-mssql/README.md b/examples/omop-mssql/README.md index 3a3795d..b2a6936 100644 --- a/examples/omop-mssql/README.md +++ b/examples/omop-mssql/README.md @@ -102,6 +102,8 @@ Edit `.env` with your server hostname, credentials, database name and schema nam ``` mssql+pyodbc://:@:1433/?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes + +> **Note for Docker on macOS:** use `127.0.0.1` rather than `localhost`. macOS resolves `localhost` to `::1` (IPv6) but Docker Desktop's port forwarding only reliably maps the IPv4 address. ``` Run datafaker commands from the `examples/omop-mssql/` directory so that the `.env` file is picked up automatically. diff --git a/examples/omop-mssql/config.yaml b/examples/omop-mssql/config.yaml new file mode 100644 index 0000000..6da446a --- /dev/null +++ b/examples/omop-mssql/config.yaml @@ -0,0 +1,9 @@ +tables: + # Vocab tables + concept: + # This one is a vocab, but its too big to handle the usual way + # ignore: true + vocabulary_table: true + + person: + num_rows_per_pass: 0 diff --git a/poetry.lock b/poetry.lock index 33f76a9..d3ffddf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -691,6 +691,25 @@ duckdb = ">=0.5.0" packaging = ">=21" sqlalchemy = ">=1.3.22" +[[package]] +name = "exceptiongroup" +version = "1.3.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version == \"3.10\"" +files = [ + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "fastparquet" version = "2024.11.0" @@ -932,6 +951,18 @@ files = [ ] markers = {main = "extra == \"docs\""} +[[package]] +name = "iniconfig" +version = "2.3.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, +] + [[package]] name = "isort" version = "5.13.2" @@ -1664,6 +1695,22 @@ docs = ["furo (>=2025.9.25)", "proselint (>=0.14)", "sphinx (>=8.2.3)", "sphinx- test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.4.2)", "pytest-cov (>=7)", "pytest-mock (>=3.15.1)"] type = ["mypy (>=1.18.2)"] +[[package]] +name = "pluggy" +version = "1.6.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["coverage", "pytest", "pytest-benchmark"] + [[package]] name = "pockets" version = "0.9.1" @@ -2004,6 +2051,30 @@ files = [ {file = "pyodbc-5.3.0.tar.gz", hash = "sha256:2fe0e063d8fb66efd0ac6dc39236c4de1a45f17c33eaded0d553d21c199f4d05"}, ] +[[package]] +name = "pytest" +version = "9.0.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9"}, + {file = "pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c"}, +] + +[package.dependencies] +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1.0.1" +packaging = ">=22" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -3120,4 +3191,4 @@ postgres = ["psycopg2-binary"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<3.14" -content-hash = "7ef13779158747973d48c5072cbb4b1cbb5ac8613c1cb1d896fcf209387d7ef8" +content-hash = "f52aba3f825a3e94b4ebb204242225e9604d271df495f80b046439b6e8f32983" diff --git a/pyproject.toml b/pyproject.toml index cc8e1ab..b84a7fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,7 @@ duckdb = "^1.4.3" sphinx-rtd-theme = "^1.2.0" sphinxcontrib-napoleon = "^0.7" sphinxcontrib-mermaid = "^2.0.0" +pytest = "^9.0.3" [tool.poetry.group.extras.dependencies] tqdm = "^4.65.0" diff --git a/tests/test_create_mssql.py b/tests/test_create_mssql.py index c579884..9e087fd 100644 --- a/tests/test_create_mssql.py +++ b/tests/test_create_mssql.py @@ -1,7 +1,7 @@ """Tests for MS-SQL DDL compilation in datafaker.create.""" import unittest -from sqlalchemy import Column, Integer, MetaData, String, Table +from sqlalchemy import Column, ForeignKey, Integer, MetaData, String, Table from sqlalchemy.dialects import mssql from sqlalchemy.schema import CreateTable @@ -72,3 +72,35 @@ def test_duckdb_serial_hook_still_works(self) -> None: # not be registered. Verify it still exists and is callable. self.assertTrue(callable(datafaker.create.remove_serial)) self.assertTrue(callable(datafaker.create.remove_mssql_identity)) + + +class TestMSSQLRemoveOnDeleteCascade(unittest.TestCase): + """@compiles(CreateTable, 'mssql') strips ON DELETE CASCADE to avoid error 1785.""" + + def _make_multi_fk_table(self) -> Table: + meta = MetaData() + concept = Table( + "concept", + meta, + Column("concept_id", Integer(), primary_key=True), + ) + return Table( + "person", + meta, + Column("person_id", Integer(), primary_key=True), + Column("gender_concept_id", Integer(), ForeignKey("concept.concept_id", ondelete="CASCADE")), + Column("race_concept_id", Integer(), ForeignKey("concept.concept_id", ondelete="CASCADE")), + ) + + def test_cascade_absent_from_mssql_ddl(self) -> None: + ddl = _compile_create_table(self._make_multi_fk_table()) + self.assertNotIn("ON DELETE CASCADE", ddl) + + def test_foreign_key_constraint_preserved(self) -> None: + ddl = _compile_create_table(self._make_multi_fk_table()) + self.assertIn("FOREIGN KEY", ddl) + + def test_duckdb_cascade_hook_still_works(self) -> None: + """Adding the mssql CASCADE hook does not break the DuckDB CASCADE hook.""" + self.assertTrue(callable(datafaker.create.remove_on_delete_cascade)) + self.assertTrue(callable(datafaker.create.remove_mssql_on_delete_cascade)) diff --git a/tests/test_serialize_metadata_mssql.py b/tests/test_serialize_metadata_mssql.py index ab48e3e..224cc44 100644 --- a/tests/test_serialize_metadata_mssql.py +++ b/tests/test_serialize_metadata_mssql.py @@ -4,7 +4,7 @@ from sqlalchemy.dialects import mssql, postgresql from sqlalchemy.sql import sqltypes -from datafaker.serialize_metadata import type_parser +from datafaker.serialize_metadata import _unqualify_fk_target, dict_to_metadata, type_parser def parse(type_str: str): @@ -152,6 +152,28 @@ def test_varchar(self) -> None: self.assertIsInstance(result, sqltypes.VARCHAR) self.assertEqual(result.length, 255) + def test_varchar_with_mssql_collation(self) -> None: + result = parse("VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS") + self.assertIsInstance(result, sqltypes.VARCHAR) + self.assertEqual(result.length, 50) + self.assertEqual(result.collation, "SQL_Latin1_General_CP1_CI_AS") + + def test_nvarchar_with_mssql_collation(self) -> None: + result = parse("NVARCHAR(100) COLLATE Latin1_General_CI_AS") + self.assertIsInstance(result, sqltypes.NVARCHAR) + self.assertEqual(result.length, 100) + self.assertEqual(result.collation, "Latin1_General_CI_AS") + + def test_char_with_mssql_collation(self) -> None: + result = parse("CHAR(10) COLLATE SQL_Latin1_General_CP1_CI_AS") + self.assertIsInstance(result, sqltypes.CHAR) + self.assertEqual(result.collation, "SQL_Latin1_General_CP1_CI_AS") + + def test_varchar_with_quoted_collation_still_works(self) -> None: + result = parse('VARCHAR(255) COLLATE "fr"') + self.assertIsInstance(result, sqltypes.VARCHAR) + self.assertEqual(result.collation, "fr") + def test_nvarchar(self) -> None: result = parse("NVARCHAR(100)") self.assertIsInstance(result, sqltypes.NVARCHAR) @@ -234,3 +256,48 @@ def test_multidimensional_array(self) -> None: result = parse("INTEGER[][]") self.assertIsInstance(result, postgresql.ARRAY) self.assertEqual(result.dimensions, 2) + + +class TestUnqualifyFkTarget(unittest.TestCase): + """Schema prefix is stripped from 3-part FK targets.""" + + def test_three_part_target_drops_schema(self) -> None: + self.assertEqual(_unqualify_fk_target("mimic100.concept.concept_id"), "concept.concept_id") + + def test_two_part_target_unchanged(self) -> None: + self.assertEqual(_unqualify_fk_target("concept.concept_id"), "concept.concept_id") + + def test_single_part_unchanged(self) -> None: + self.assertEqual(_unqualify_fk_target("concept_id"), "concept_id") + + +class TestSchemaQualifiedFKResolution(unittest.TestCase): + """Schema-qualified FK targets resolve correctly when building MetaData.""" + + def test_schema_qualified_fk_resolves_in_metadata(self) -> None: + orm_dict = { + "tables": { + "concept": { + "columns": { + "concept_id": {"type": "BIGINT", "primary": True, "nullable": False}, + } + }, + "person": { + "columns": { + "person_id": {"type": "BIGINT", "primary": True, "nullable": False}, + "gender_concept_id": { + "type": "BIGINT", + "primary": False, + "nullable": False, + "foreign_keys": ["myschema.concept.concept_id"], + }, + } + }, + } + } + meta = dict_to_metadata(orm_dict) + person = meta.tables["person"] + fks = list(person.c.gender_concept_id.foreign_keys) + self.assertEqual(len(fks), 1) + # FK target should resolve to the concept table without raising NoReferencedTableError + self.assertEqual(fks[0].column.table.name, "concept") From 84a209fe1f4ea0c42d0ab7359c5ccd683caa1ecf Mon Sep 17 00:00:00 2001 From: May Yong Date: Thu, 21 May 2026 15:53:59 +0100 Subject: [PATCH 19/45] Let database generate integer primary keys on MS-SQL (closes #104) Remove the remove_mssql_identity DDL hook that stripped IDENTITY from CREATE TABLE, and stop supplying explicit PK values in generated df.py files. SQLAlchemy now omits single-column integer PKs from INSERT statements and SQL Server generates them via IDENTITY(1,1). Also fix column_value() to use NEWID() instead of random() on MS-SQL, which has no random() function. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/create.py | 16 +---- datafaker/main.py | 3 +- datafaker/make.py | 50 ++++++++++----- datafaker/providers.py | 8 ++- examples/omop-mssql/df.py | 126 +++++++++++++++++++++++++++++++++++++ tests/test_create_mssql.py | 44 ++++--------- tests/test_make.py | 61 +++++++++++++++++- tests/test_providers.py | 29 +++++++++ 8 files changed, 270 insertions(+), 67 deletions(-) create mode 100644 examples/omop-mssql/df.py diff --git a/datafaker/create.py b/datafaker/create.py index bdad04c..24f887c 100644 --- a/datafaker/create.py +++ b/datafaker/create.py @@ -1,6 +1,5 @@ """Functions and classes to create and populate the target database.""" import pathlib -import re from collections import Counter from types import ModuleType from typing import Any, Generator, Iterable, Iterator, Mapping, Sequence, Tuple @@ -43,19 +42,6 @@ def remove_serial(element: CreateColumn, compiler: Any, **kw: Any) -> str: return text.replace(" SERIAL ", " INTEGER ") -@compiles(CreateColumn, "mssql") -def remove_mssql_identity(element: CreateColumn, compiler: Any, **kw: Any) -> str: - """ - Strip IDENTITY from MS-SQL column DDL. - - datafaker inserts explicit values for every column. MS-SQL rejects explicit - inserts into IDENTITY columns unless SET IDENTITY_INSERT is enabled first, - so we simply omit the IDENTITY modifier — the column stays an INTEGER. - """ - text: str = compiler.visit_create_column(element, **kw) - # Handles both bare IDENTITY and parametrised IDENTITY(m,n) - return re.sub(r" IDENTITY(\(\d+,\s*\d+\))?", "", text) - @compiles(CreateTable, "mssql") def remove_mssql_on_delete_cascade(element: CreateTable, compiler: Any, **kw: Any) -> str: @@ -207,6 +193,7 @@ def create_db_data_into( row_counts: Counter[str] = Counter() with dst_engine.connect() as dst_conn: + for _ in range(num_passes): row_counts += populate( dst_conn, @@ -363,6 +350,7 @@ def populate( with dst_conn.begin(): for _ in range(table_generator.num_rows_per_pass): stmt = insert(table).values(table_generator(dst_conn, metadata)) + logger.debug("Executing statement: %s", stmt) dst_conn.execute(stmt) row_counts[table.name] = row_counts.get(table.name, 0) + 1 dst_conn.commit() diff --git a/datafaker/main.py b/datafaker/main.py index 4ac6d55..582b38e 100644 --- a/datafaker/main.py +++ b/datafaker/main.py @@ -42,6 +42,7 @@ get_source_dsn, get_source_schema, ) +from datafaker.serialize_metadata import dict_to_metadata from datafaker.utils import ( CONFIG_SCHEMA_PATH, conf_logger, @@ -54,8 +55,6 @@ sorted_non_vocabulary_tables, ) -from .serialize_metadata import dict_to_metadata - # pylint: disable=too-many-arguments ORM_FILENAME: Final[str] = "orm.yaml" diff --git a/datafaker/make.py b/datafaker/make.py index 3207f8b..1c272bb 100644 --- a/datafaker/make.py +++ b/datafaker/make.py @@ -16,7 +16,7 @@ from black import FileMode, format_str from jinja2 import Environment, FileSystemLoader, Template from mimesis.providers.base import BaseProvider -from sqlalchemy import CursorResult, Engine, MetaData, UniqueConstraint, text +from sqlalchemy import CursorResult, Engine, Integer, MetaData, UniqueConstraint, text from sqlalchemy.dialects import mssql, postgresql from sqlalchemy.engine import Connection from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine @@ -200,10 +200,28 @@ def _get_row_generator( return row_gen_info, columns_covered -def _get_default_generator(column: Column) -> RowGeneratorInfo: - """Get default generator information, for the given column.""" - # If it's a primary key column, we presume that primary keys are populated - # automatically. +def _is_db_generated_pk(column: Column) -> bool: + """Return True if this column's value should be generated by the database. + + Single-column integer PKs with no FK are left to the DB (IDENTITY / SERIAL). + Composite PKs and PK-FK columns must still be generated explicitly. + """ + return ( + column.primary_key + and not column.foreign_keys + and len(column.table.primary_key.columns) == 1 + and isinstance(column.type, Integer) + ) + + +def _get_default_generator(column: Column) -> RowGeneratorInfo | None: + """Get default generator information, for the given column. + + Returns None for single-column integer PKs; the database generates those. + """ + # Single-column integer PKs are generated by the DB (IDENTITY / SERIAL). + if _is_db_generated_pk(column): + return None # If it's a foreign key column, pull random values from the column it # references. @@ -294,15 +312,7 @@ def _integer_generator(column: Column) -> tuple[str, dict[str, str]]: :return: A pair consisting of the name of a generator and its arguments. """ - if not column.primary_key: - return ("generic.numeric.integer_number", {}) - return ( - "generic.column_value_provider.increment", - { - "db_connection": "dst_db_conn", - "column": f'metadata.tables["{column.table.name}"].columns["{column.name}"]', - }, - ) + return ("generic.numeric.integer_number", {}) _YEAR_SUMMARY_QUERY = ( @@ -508,10 +518,14 @@ def _get_generator_for_table( nonnull_columns = { str(col.name) for col in table.columns - if not table.columns[col.name].nullable + if not table.columns[col.name].nullable and not _is_db_generated_pk(col) } else: - nonnull_columns = {str(col.name) for col in table.columns} + nonnull_columns = { + str(col.name) + for col in table.columns + if not _is_db_generated_pk(col) + } table_data: TableGeneratorInfo = TableGeneratorInfo( table_name=table.name, class_name=table.name.title().replace(".", "") + "Generator", @@ -526,7 +540,9 @@ def _get_generator_for_table( for column in table.columns: if column.name not in columns_covered: - table_data.row_gens.append(_get_default_generator(column)) + gen = _get_default_generator(column) + if gen is not None: + table_data.row_gens.append(gen) return table_data diff --git a/datafaker/providers.py b/datafaker/providers.py index 775a9f6..262743c 100644 --- a/datafaker/providers.py +++ b/datafaker/providers.py @@ -28,7 +28,13 @@ def column_value( db_connection: Connection, orm_class: Any, column_name: str ) -> Any: """Return a random value from the column specified.""" - query = select(orm_class).order_by(functions.random()).limit(1) + # MS-SQL has no random() function; NEWID() produces a per-row random GUID. + # RAND() is not usable here because it returns the same value for every row. + if db_connection.dialect.name == "mssql": + random_fn = func.newid() + else: + random_fn = functions.random() + query = select(orm_class).order_by(random_fn).limit(1) random_row = db_connection.execute(query).first() if random_row: diff --git a/examples/omop-mssql/df.py b/examples/omop-mssql/df.py new file mode 100644 index 0000000..0b2ffff --- /dev/null +++ b/examples/omop-mssql/df.py @@ -0,0 +1,126 @@ +"""This file was auto-generated by datafaker but can be edited manually.""" +from mimesis import Generic, Numeric, Person +from mimesis.locales import Locale +import sqlalchemy +import sys +from datafaker.base import FileUploader, TableGenerator, ColumnPresence +from datafaker.providers import DistributionProvider + +generic = Generic(locale=Locale.EN_GB) +numeric = Numeric() +person = Person() +dist_gen = DistributionProvider() +column_presence = ColumnPresence() + +sys.path.append("") + +from datafaker.providers import ( + BytesProvider, + ColumnValueProvider, + DistributionProvider, + NullProvider, + SQLGroupByProvider, + TimedeltaProvider, + TimespanProvider, + WeightedBooleanProvider, +) + +generic.add_provider(BytesProvider) +generic.add_provider(ColumnValueProvider) +generic.add_provider(DistributionProvider) +generic.add_provider(NullProvider) +generic.add_provider(SQLGroupByProvider) +generic.add_provider(TimedeltaProvider) +generic.add_provider(TimespanProvider) +generic.add_provider(WeightedBooleanProvider) + + +class PersonGenerator(TableGenerator): + num_rows_per_pass = 10 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "birth_datetime", + "ethnicity_source_value", + "ethnicity_source_concept_id", + "ethnicity_concept_id", + "person_source_value", + "race_concept_id", + "month_of_birth", + "race_source_value", + "gender_source_value", + "day_of_birth", + "gender_concept_id", + "race_source_concept_id", + "gender_source_concept_id", + "year_of_birth", + } + ) + while columns_to_generate: + if "birth_datetime" in columns_to_generate: + result["birth_datetime"] = generic.datetime.datetime() + if "day_of_birth" in columns_to_generate: + result["day_of_birth"] = generic.numeric.integer_number() + if "ethnicity_concept_id" in columns_to_generate: + result[ + "ethnicity_concept_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) + if "ethnicity_source_concept_id" in columns_to_generate: + result[ + "ethnicity_source_concept_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) + if "ethnicity_source_value" in columns_to_generate: + result["ethnicity_source_value"] = generic.person.password(length=50) + if "gender_concept_id" in columns_to_generate: + result[ + "gender_concept_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) + if "gender_source_concept_id" in columns_to_generate: + result[ + "gender_source_concept_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) + if "gender_source_value" in columns_to_generate: + result["gender_source_value"] = generic.person.password(length=50) + if "month_of_birth" in columns_to_generate: + result["month_of_birth"] = generic.numeric.integer_number() + if "person_source_value" in columns_to_generate: + result["person_source_value"] = generic.person.password(length=50) + if "race_concept_id" in columns_to_generate: + result["race_concept_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) + if "race_source_concept_id" in columns_to_generate: + result[ + "race_source_concept_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) + if "race_source_value" in columns_to_generate: + result["race_source_value"] = generic.person.password(length=50) + if "year_of_birth" in columns_to_generate: + result["year_of_birth"] = generic.numeric.integer_number() + columns_to_generate = set() + return result + + +table_generator_dict = { + "person": PersonGenerator(), +} + + +story_generator_list = [] diff --git a/tests/test_create_mssql.py b/tests/test_create_mssql.py index 9e087fd..8201970 100644 --- a/tests/test_create_mssql.py +++ b/tests/test_create_mssql.py @@ -14,8 +14,13 @@ def _compile_create_table(table: Table) -> str: return str(CreateTable(table).compile(dialect=mssql.dialect())) -class TestMSSQLRemoveIdentity(unittest.TestCase): - """@compiles(CreateColumn, 'mssql') strips IDENTITY from autoincrement columns.""" +class TestMSSQLIdentityPresent(unittest.TestCase): + """MS-SQL tables should have IDENTITY on autoincrement columns. + + The remove_mssql_identity hook was removed (issue #104): datafaker now lets + the database generate single-column integer PKs rather than supplying + explicit values and fighting with SET IDENTITY_INSERT. + """ def _make_table(self) -> Table: meta = MetaData() @@ -26,18 +31,18 @@ def _make_table(self) -> Table: Column("value", Integer(), nullable=True), ) - def test_identity_absent_from_ddl(self) -> None: - """IDENTITY must be absent so explicit INSERTs succeed without SET IDENTITY_INSERT.""" + def test_identity_present_in_ddl(self) -> None: + """IDENTITY must be present so the DB generates PK values automatically.""" ddl = _compile_create_table(self._make_table()) - self.assertNotIn("IDENTITY", ddl) + self.assertIn("IDENTITY", ddl) def test_integer_type_preserved(self) -> None: - """The INTEGER type is preserved after stripping IDENTITY.""" + """The INTEGER type is preserved.""" ddl = _compile_create_table(self._make_table()) self.assertIn("INTEGER", ddl) def test_primary_key_constraint_preserved(self) -> None: - """PRIMARY KEY constraint is not affected by the hook.""" + """PRIMARY KEY constraint is not affected.""" ddl = _compile_create_table(self._make_table()) self.assertIn("PRIMARY KEY", ddl) @@ -46,32 +51,9 @@ def test_non_autoincrement_column_unchanged(self) -> None: ddl = _compile_create_table(self._make_table()) self.assertIn("value", ddl.lower()) - def test_multiple_autoincrement_columns_all_stripped(self) -> None: - """IDENTITY is stripped from every column that would receive it.""" - meta = MetaData() - table = Table( - "multi", - meta, - Column("id", Integer(), primary_key=True, autoincrement=True), - Column("seq", Integer(), autoincrement=True), - ) - ddl = _compile_create_table(table) - self.assertNotIn("IDENTITY", ddl) - def test_duckdb_serial_hook_still_works(self) -> None: - """Adding the mssql hook does not break the existing DuckDB SERIAL hook (regression).""" - from sqlalchemy.dialects import registry - from sqlalchemy import create_engine - from sqlalchemy.schema import CreateColumn - - # Compile a CreateColumn for the duckdb dialect indirectly by checking - # that remove_serial is still registered. - from sqlalchemy.ext.compiler import compiles - - # If the duckdb hook were broken, datafaker.create.remove_serial would - # not be registered. Verify it still exists and is callable. + """The DuckDB SERIAL hook is not affected by this change.""" self.assertTrue(callable(datafaker.create.remove_serial)) - self.assertTrue(callable(datafaker.create.remove_mssql_identity)) class TestMSSQLRemoveOnDeleteCascade(unittest.TestCase): diff --git a/tests/test_make.py b/tests/test_make.py index 601aae4..132e891 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -2,20 +2,77 @@ import asyncio import os import tempfile +import unittest from pathlib import Path from typing import Any from unittest.mock import MagicMock, patch import pandas as pd import yaml -from sqlalchemy import BigInteger, Column, String, select +from sqlalchemy import BigInteger, Column, ForeignKey, Integer, MetaData, String, Table, select from sqlalchemy.dialects.mysql.types import INTEGER from sqlalchemy.dialects.postgresql import UUID -from datafaker.make import _get_provider_for_column, make_src_stats +from datafaker.make import _get_default_generator, _get_provider_for_column, make_src_stats from tests.utils import DatafakerTestCase, GeneratesDBTestCase, RequiresDBTestCase +class TestGetDefaultGenerator(unittest.TestCase): + """Unit tests for _get_default_generator.""" + + def _make_table(self, *columns: Column) -> Table: + meta = MetaData() + return Table("t", meta, *columns) + + def test_simple_integer_pk_returns_none(self) -> None: + """Single-column INTEGER PK with no FK → DB generates it, skip in df.py.""" + table = self._make_table( + Column("id", Integer(), primary_key=True), + Column("val", String()), + ) + self.assertIsNone(_get_default_generator(table.c.id)) + + def test_simple_biginteger_pk_returns_none(self) -> None: + """BigInteger (BIGINT) single-column PK is also DB-generated.""" + table = self._make_table( + Column("id", BigInteger(), primary_key=True), + Column("val", String()), + ) + self.assertIsNone(_get_default_generator(table.c.id)) + + def test_composite_pk_not_skipped(self) -> None: + """Columns in a composite PK are not DB-generated and must have a generator.""" + table = self._make_table( + Column("a", Integer(), primary_key=True), + Column("b", Integer(), primary_key=True), + ) + self.assertIsNotNone(_get_default_generator(table.c.a)) + self.assertIsNotNone(_get_default_generator(table.c.b)) + + def test_fk_pk_not_skipped(self) -> None: + """A column that is both PK and FK gets a FK generator, not skipped.""" + meta = MetaData() + parent = Table("parent", meta, Column("id", Integer(), primary_key=True)) + child = Table( + "child", + meta, + Column("parent_id", Integer(), ForeignKey("parent.id"), primary_key=True), + ) + result = _get_default_generator(child.c.parent_id) + self.assertIsNotNone(result) + self.assertIn("column_value", result.function_call.function_name) + + def test_non_pk_integer_returns_generator(self) -> None: + """Plain INTEGER column (not a PK) gets a numeric generator.""" + table = self._make_table( + Column("id", Integer(), primary_key=True), + Column("count", Integer()), + ) + result = _get_default_generator(table.c.count) + self.assertIsNotNone(result) + self.assertIn("integer_number", result.function_call.function_name) + + class TestMakeGenerators(GeneratesDBTestCase): """Test the make_table_generators function.""" diff --git a/tests/test_providers.py b/tests/test_providers.py index eab3b1a..4f5a8eb 100644 --- a/tests/test_providers.py +++ b/tests/test_providers.py @@ -1,6 +1,7 @@ """Tests for the providers module.""" import datetime as dt from typing import Any +from unittest.mock import MagicMock, patch from sqlalchemy import Column, Integer, MetaData, Text, insert from sqlalchemy.ext.declarative import declarative_base @@ -67,6 +68,34 @@ def test_column_value_missing(self) -> None: self.assertIsNone(generated_value) +class ColumnValueRandomFunctionTestCase(DatafakerTestCase): + """column_value uses the correct random function for each dialect.""" + + def _make_connection(self, dialect_name: str) -> MagicMock: + conn = MagicMock() + conn.dialect.name = dialect_name + conn.execute.return_value.first.return_value = None + return conn + + def _get_order_by_sql(self, dialect_name: str) -> str: + conn = self._make_connection(dialect_name) + providers.ColumnValueProvider.column_value(conn, Person, "sex") + query = conn.execute.call_args[0][0] + from sqlalchemy.dialects import mssql, postgresql + dialect = mssql.dialect() if dialect_name == "mssql" else postgresql.dialect() + return str(query.compile(dialect=dialect)) + + def test_mssql_uses_newid(self) -> None: + sql = self._get_order_by_sql("mssql") + self.assertIn("newid()", sql.lower()) + self.assertNotIn("random()", sql.lower()) + + def test_postgresql_uses_random(self) -> None: + sql = self._get_order_by_sql("postgresql") + self.assertIn("random()", sql.lower()) + self.assertNotIn("newid()", sql.lower()) + + class TimedeltaProvider(DatafakerTestCase): """Tests for TimedeltaProvider""" From 40fc121a5fbd6666e6afb753bd4a21352dde46db Mon Sep 17 00:00:00 2001 From: May Yong Date: Thu, 21 May 2026 15:57:17 +0100 Subject: [PATCH 20/45] Rename mimic_omop example to omop-mssql Consolidate the OMOP example under examples/omop-mssql. The mimic_omop orm.yaml becomes orm_full.yaml; a trimmed orm.yaml and a copy_vocabulary.sql helper script are added alongside it. Co-Authored-By: Claude Sonnet 4.6 --- examples/mimic_omop/README.md | 21 - examples/mimic_omop/config.yaml | 121 -- examples/mimic_omop/df.py | 1733 ----------------- examples/omop-mssql/README.md | 2 + examples/omop-mssql/config.yaml | 4 +- examples/omop-mssql/orm.yaml | 122 ++ .../orm.yaml => omop-mssql/orm_full.yaml} | 640 ++---- examples/omop-mssql/sql/copy_vocabulary.sql | 24 + 8 files changed, 358 insertions(+), 2309 deletions(-) delete mode 100644 examples/mimic_omop/README.md delete mode 100644 examples/mimic_omop/config.yaml delete mode 100644 examples/mimic_omop/df.py create mode 100644 examples/omop-mssql/orm.yaml rename examples/{mimic_omop/orm.yaml => omop-mssql/orm_full.yaml} (76%) create mode 100644 examples/omop-mssql/sql/copy_vocabulary.sql diff --git a/examples/mimic_omop/README.md b/examples/mimic_omop/README.md deleted file mode 100644 index bd04883..0000000 --- a/examples/mimic_omop/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# How to run datafaker process on omop schema - -1. Make a YAML file representing the tables in the schema - -`poetry run datafaker make-tables --orm-file ./examples/mimic_omop/orm.yaml` - -1. Create schema from the ORM YAML file - -`poetry run datafaker create-tables --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml` - -1. Create generator table - -`poetry run datafaker create-generators --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml --df-file ./examples/mimic_omop/df.py` - -1. Create data - -`poetry run datafaker create-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml --df-file .\examples\mimic_omop\df.py` - -1. Remove data - -`poetry run datafaker remove-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml` diff --git a/examples/mimic_omop/config.yaml b/examples/mimic_omop/config.yaml deleted file mode 100644 index 34c7009..0000000 --- a/examples/mimic_omop/config.yaml +++ /dev/null @@ -1,121 +0,0 @@ -tables: - # Unnecessary tables - _measurement_links: - ignore: true - _observation_links: - ignore: true - _person_links: - ignore: true - _procedure_occurrence_links: - ignore: true - _visit_occurrence_links: - ignore: true - - # Vocab tables - concept: - # This one is a vocab, but its too big to handle the usual way - ignore: true - # vocabulary_table: true - concept_ancestor: - # This one is a vocab, but its too big to handle the usual way - ignore: true - # vocabulary_table: true - vocabulary: - vocabulary_table: true - domain: - vocabulary_table: true - concept_class: - vocabulary_table: true - concept_synonym: - # This one is a vocab, but its too big to handle the usual way - ignore: true - # vocabulary_table: true - concept_relationship: - # This one is a vocab, but its too big to handle the usual way - ignore: true - # vocabulary_table: true - drug_strength: - # This one is a vocab, but its too big to handle the usual way - ignore: true - # vocabulary_table: true - relationship: - vocabulary_table: true - source_to_concept_map: - vocabulary_table: true - location: - vocabulary_table: true - care_site: - vocabulary_table: true - provider: - vocabulary_table: true - cdm_source: - vocabulary_table: true - - attribute_definition: - num_rows_per_pass: 0 - - cohort_definition: - num_rows_per_pass: 0 - - condition_era: - num_rows_per_pass: 0 - - cost: - num_rows_per_pass: 0 - - device_exposure: - num_rows_per_pass: 0 - - dose_era: - num_rows_per_pass: 0 - - drug_era: - num_rows_per_pass: 0 - - drug_exposure: - num_rows_per_pass: 0 - - fact_relationship: - num_rows_per_pass: 0 - - measurement: - num_rows_per_pass: 0 - - metadata: - num_rows_per_pass: 0 - - note: - num_rows_per_pass: 0 - - note_nlp: - num_rows_per_pass: 0 - - observation: - num_rows_per_pass: 0 - - observation_period: - num_rows_per_pass: 0 - - payer_plan_period: - num_rows_per_pass: 0 - - procedure_occurrence: - num_rows_per_pass: 0 - - specimen: - num_rows_per_pass: 0 - - visit_detail: - num_rows_per_pass: 0 - - visit_occurrence: - num_rows_per_pass: 0 - - person: - num_rows_per_pass: 0 - - death: - num_rows_per_pass: 0 - - condition_occurrence: - num_rows_per_pass: 0 diff --git a/examples/mimic_omop/df.py b/examples/mimic_omop/df.py deleted file mode 100644 index d5a1dbd..0000000 --- a/examples/mimic_omop/df.py +++ /dev/null @@ -1,1733 +0,0 @@ -"""This file was auto-generated by datafaker but can be edited manually.""" -from mimesis import Generic, Numeric, Person -from mimesis.locales import Locale -import sqlalchemy -import sys -from datafaker.base import FileUploader, TableGenerator, ColumnPresence -from datafaker.providers import DistributionProvider - -generic = Generic(locale=Locale.EN_GB) -numeric = Numeric() -person = Person() -dist_gen = DistributionProvider() -column_presence = ColumnPresence() - -sys.path.append("") - -from datafaker.providers import ( - BytesProvider, - ColumnValueProvider, - DistributionProvider, - NullProvider, - SQLGroupByProvider, - TimedeltaProvider, - TimespanProvider, - WeightedBooleanProvider, -) - -generic.add_provider(BytesProvider) -generic.add_provider(ColumnValueProvider) -generic.add_provider(DistributionProvider) -generic.add_provider(NullProvider) -generic.add_provider(SQLGroupByProvider) -generic.add_provider(TimedeltaProvider) -generic.add_provider(TimespanProvider) -generic.add_provider(WeightedBooleanProvider) - - -class CohortGenerator(TableGenerator): - num_rows_per_pass = 1 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "cohort_start_date", - "cohort_end_date", - "cohort_definition_id", - "subject_id", - } - ) - while columns_to_generate: - if "cohort_definition_id" in columns_to_generate: - result["cohort_definition_id"] = generic.numeric.integer_number() - if "cohort_end_date" in columns_to_generate: - result["cohort_end_date"] = generic.datetime.date() - if "cohort_start_date" in columns_to_generate: - result["cohort_start_date"] = generic.datetime.date() - if "subject_id" in columns_to_generate: - result["subject_id"] = generic.numeric.integer_number() - columns_to_generate = set() - return result - - -class Cohort_DefinitionGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "cohort_initiation_date", - "definition_type_concept_id", - "cohort_definition_syntax", - "cohort_definition_id", - "cohort_definition_description", - "subject_concept_id", - "cohort_definition_name", - } - ) - while columns_to_generate: - if "cohort_definition_description" in columns_to_generate: - result["cohort_definition_description"] = generic.text.color() - if "cohort_definition_id" in columns_to_generate: - result["cohort_definition_id"] = generic.numeric.integer_number() - if "cohort_definition_name" in columns_to_generate: - result["cohort_definition_name"] = generic.person.password(length=255) - if "cohort_definition_syntax" in columns_to_generate: - result["cohort_definition_syntax"] = generic.text.color() - if "cohort_initiation_date" in columns_to_generate: - result["cohort_initiation_date"] = generic.datetime.date() - if "definition_type_concept_id" in columns_to_generate: - result["definition_type_concept_id"] = generic.numeric.integer_number() - if "subject_concept_id" in columns_to_generate: - result["subject_concept_id"] = generic.numeric.integer_number() - columns_to_generate = set() - return result - - -class Condition_EraGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "condition_era_id", - "person_id", - "condition_era_start_date", - "condition_era_end_date", - "condition_occurrence_count", - "condition_concept_id", - } - ) - while columns_to_generate: - if "condition_concept_id" in columns_to_generate: - result["condition_concept_id"] = generic.numeric.integer_number() - if "condition_era_end_date" in columns_to_generate: - result["condition_era_end_date"] = generic.datetime.date() - if "condition_era_id" in columns_to_generate: - result["condition_era_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["condition_era"].columns["condition_era_id"], - ) - if "condition_era_start_date" in columns_to_generate: - result["condition_era_start_date"] = generic.datetime.date() - if "condition_occurrence_count" in columns_to_generate: - result["condition_occurrence_count"] = generic.numeric.integer_number() - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - columns_to_generate = set() - return result - - -class Condition_OccurrenceGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "visit_detail_id", - "condition_occurrence_id", - "condition_start_datetime", - "condition_status_concept_id", - "condition_source_value", - "person_id", - "provider_id", - "condition_start_date", - "stop_reason", - "condition_end_date", - "condition_status_source_value", - "condition_end_datetime", - "visit_occurrence_id", - "condition_type_concept_id", - "condition_concept_id", - "condition_source_concept_id", - } - ) - while columns_to_generate: - if "condition_concept_id" in columns_to_generate: - result["condition_concept_id"] = generic.numeric.integer_number() - if "condition_end_date" in columns_to_generate: - result["condition_end_date"] = generic.datetime.date() - if "condition_end_datetime" in columns_to_generate: - result["condition_end_datetime"] = generic.datetime.datetime() - if "condition_occurrence_id" in columns_to_generate: - result[ - "condition_occurrence_id" - ] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["condition_occurrence"].columns[ - "condition_occurrence_id" - ], - ) - if "condition_source_concept_id" in columns_to_generate: - result["condition_source_concept_id"] = generic.numeric.integer_number() - if "condition_source_value" in columns_to_generate: - result["condition_source_value"] = generic.person.password(length=50) - if "condition_start_date" in columns_to_generate: - result["condition_start_date"] = generic.datetime.date() - if "condition_start_datetime" in columns_to_generate: - result["condition_start_datetime"] = generic.datetime.datetime() - if "condition_status_concept_id" in columns_to_generate: - result["condition_status_concept_id"] = generic.person.password( - length=50 - ) - if "condition_status_source_value" in columns_to_generate: - result["condition_status_source_value"] = generic.person.password( - length=50 - ) - if "condition_type_concept_id" in columns_to_generate: - result["condition_type_concept_id"] = generic.numeric.integer_number() - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - if "provider_id" in columns_to_generate: - result["provider_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["provider"], "provider_id" - ) - if "stop_reason" in columns_to_generate: - result["stop_reason"] = generic.person.password(length=20) - if "visit_detail_id" in columns_to_generate: - result["visit_detail_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" - ) - if "visit_occurrence_id" in columns_to_generate: - result[ - "visit_occurrence_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, - metadata.tables["visit_occurrence"], - "visit_occurrence_id", - ) - columns_to_generate = set() - return result - - -class CostGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "paid_patient_deductible", - "drg_concept_id", - "currency_concept_id", - "amount_allowed", - "cost_type_concept_id", - "total_charge", - "total_paid", - "revenue_code_concept_id", - "drg_source_value", - "paid_patient_copay", - "cost_event_id", - "paid_by_patient", - "paid_by_payer", - "cost_id", - "paid_patient_coinsurance", - "total_cost", - "paid_by_primary", - "payer_plan_period_id", - "cost_domain_id", - "revenue_code_source_value", - "paid_dispensing_fee", - "paid_ingredient_cost", - } - ) - while columns_to_generate: - if "amount_allowed" in columns_to_generate: - result["amount_allowed"] = generic.numeric.float_number() - if "cost_domain_id" in columns_to_generate: - result["cost_domain_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["domain"], "domain_id" - ) - if "cost_event_id" in columns_to_generate: - result["cost_event_id"] = generic.numeric.integer_number() - if "cost_id" in columns_to_generate: - result["cost_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["cost"].columns["cost_id"], - ) - if "cost_type_concept_id" in columns_to_generate: - result["cost_type_concept_id"] = generic.numeric.integer_number() - if "currency_concept_id" in columns_to_generate: - result["currency_concept_id"] = generic.numeric.integer_number() - if "drg_concept_id" in columns_to_generate: - result["drg_concept_id"] = generic.numeric.integer_number() - if "drg_source_value" in columns_to_generate: - result["drg_source_value"] = generic.person.password(length=3) - if "paid_by_patient" in columns_to_generate: - result["paid_by_patient"] = generic.numeric.float_number() - if "paid_by_payer" in columns_to_generate: - result["paid_by_payer"] = generic.numeric.float_number() - if "paid_by_primary" in columns_to_generate: - result["paid_by_primary"] = generic.numeric.float_number() - if "paid_dispensing_fee" in columns_to_generate: - result["paid_dispensing_fee"] = generic.numeric.float_number() - if "paid_ingredient_cost" in columns_to_generate: - result["paid_ingredient_cost"] = generic.numeric.float_number() - if "paid_patient_coinsurance" in columns_to_generate: - result["paid_patient_coinsurance"] = generic.numeric.float_number() - if "paid_patient_copay" in columns_to_generate: - result["paid_patient_copay"] = generic.numeric.float_number() - if "paid_patient_deductible" in columns_to_generate: - result["paid_patient_deductible"] = generic.numeric.float_number() - if "payer_plan_period_id" in columns_to_generate: - result["payer_plan_period_id"] = generic.numeric.integer_number() - if "revenue_code_concept_id" in columns_to_generate: - result["revenue_code_concept_id"] = generic.numeric.integer_number() - if "revenue_code_source_value" in columns_to_generate: - result["revenue_code_source_value"] = generic.person.password(length=50) - if "total_charge" in columns_to_generate: - result["total_charge"] = generic.numeric.float_number() - if "total_cost" in columns_to_generate: - result["total_cost"] = generic.numeric.float_number() - if "total_paid" in columns_to_generate: - result["total_paid"] = generic.numeric.float_number() - columns_to_generate = set() - return result - - -class DeathGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "death_datetime", - "cause_concept_id", - "cause_source_concept_id", - "person_id", - "cause_source_value", - "death_type_concept_id", - "death_date", - } - ) - while columns_to_generate: - if "cause_concept_id" in columns_to_generate: - result["cause_concept_id"] = generic.numeric.integer_number() - if "cause_source_concept_id" in columns_to_generate: - result["cause_source_concept_id"] = generic.numeric.integer_number() - if "cause_source_value" in columns_to_generate: - result["cause_source_value"] = generic.person.password(length=50) - if "death_date" in columns_to_generate: - result["death_date"] = generic.datetime.date() - if "death_datetime" in columns_to_generate: - result["death_datetime"] = generic.datetime.datetime() - if "death_type_concept_id" in columns_to_generate: - result["death_type_concept_id"] = generic.numeric.integer_number() - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - columns_to_generate = set() - return result - - -class Device_ExposureGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "device_exposure_start_date", - "visit_detail_id", - "unique_device_id", - "person_id", - "device_source_value", - "provider_id", - "quantity", - "device_concept_id", - "device_exposure_end_datetime", - "device_exposure_end_date", - "device_source_concept_id", - "device_type_concept_id", - "visit_occurrence_id", - "device_exposure_id", - "device_exposure_start_datetime", - } - ) - while columns_to_generate: - if "device_concept_id" in columns_to_generate: - result["device_concept_id"] = generic.numeric.integer_number() - if "device_exposure_end_date" in columns_to_generate: - result["device_exposure_end_date"] = generic.datetime.date() - if "device_exposure_end_datetime" in columns_to_generate: - result["device_exposure_end_datetime"] = generic.datetime.datetime() - if "device_exposure_id" in columns_to_generate: - result["device_exposure_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["device_exposure"].columns[ - "device_exposure_id" - ], - ) - if "device_exposure_start_date" in columns_to_generate: - result["device_exposure_start_date"] = generic.datetime.date() - if "device_exposure_start_datetime" in columns_to_generate: - result["device_exposure_start_datetime"] = generic.datetime.datetime() - if "device_source_concept_id" in columns_to_generate: - result["device_source_concept_id"] = generic.numeric.integer_number() - if "device_source_value" in columns_to_generate: - result["device_source_value"] = generic.person.password(length=50) - if "device_type_concept_id" in columns_to_generate: - result["device_type_concept_id"] = generic.numeric.integer_number() - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - if "provider_id" in columns_to_generate: - result["provider_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["provider"], "provider_id" - ) - if "quantity" in columns_to_generate: - result["quantity"] = generic.numeric.integer_number() - if "unique_device_id" in columns_to_generate: - result["unique_device_id"] = generic.person.password(length=255) - if "visit_detail_id" in columns_to_generate: - result["visit_detail_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" - ) - if "visit_occurrence_id" in columns_to_generate: - result[ - "visit_occurrence_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, - metadata.tables["visit_occurrence"], - "visit_occurrence_id", - ) - columns_to_generate = set() - return result - - -class Dose_EraGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "drug_concept_id", - "unit_concept_id", - "dose_era_start_date", - "person_id", - "dose_era_end_date", - "dose_value", - "dose_era_id", - } - ) - while columns_to_generate: - if "dose_era_end_date" in columns_to_generate: - result["dose_era_end_date"] = generic.datetime.date() - if "dose_era_id" in columns_to_generate: - result["dose_era_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["dose_era"].columns["dose_era_id"], - ) - if "dose_era_start_date" in columns_to_generate: - result["dose_era_start_date"] = generic.datetime.date() - if "dose_value" in columns_to_generate: - result["dose_value"] = generic.numeric.float_number() - if "drug_concept_id" in columns_to_generate: - result["drug_concept_id"] = generic.numeric.integer_number() - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - if "unit_concept_id" in columns_to_generate: - result["unit_concept_id"] = generic.numeric.integer_number() - columns_to_generate = set() - return result - - -class Drug_EraGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "drug_concept_id", - "person_id", - "drug_exposure_count", - "drug_era_id", - "drug_era_end_date", - "gap_days", - "drug_era_start_date", - } - ) - while columns_to_generate: - if "drug_concept_id" in columns_to_generate: - result["drug_concept_id"] = generic.numeric.integer_number() - if "drug_era_end_date" in columns_to_generate: - result["drug_era_end_date"] = generic.datetime.date() - if "drug_era_id" in columns_to_generate: - result["drug_era_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["drug_era"].columns["drug_era_id"], - ) - if "drug_era_start_date" in columns_to_generate: - result["drug_era_start_date"] = generic.datetime.date() - if "drug_exposure_count" in columns_to_generate: - result["drug_exposure_count"] = generic.numeric.integer_number() - if "gap_days" in columns_to_generate: - result["gap_days"] = generic.numeric.integer_number() - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - columns_to_generate = set() - return result - - -class Drug_ExposureGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "sig", - "drug_source_concept_id", - "drug_exposure_end_datetime", - "stop_reason", - "lot_number", - "drug_exposure_end_date", - "route_concept_id", - "days_supply", - "route_source_value", - "dose_unit_source_value", - "drug_source_value", - "provider_id", - "drug_exposure_start_datetime", - "drug_concept_id", - "person_id", - "drug_type_concept_id", - "drug_exposure_id", - "verbatim_end_date", - "drug_exposure_start_date", - "visit_detail_id", - "refills", - "quantity", - "visit_occurrence_id", - } - ) - while columns_to_generate: - if "days_supply" in columns_to_generate: - result["days_supply"] = generic.numeric.integer_number() - if "dose_unit_source_value" in columns_to_generate: - result["dose_unit_source_value"] = generic.person.password(length=50) - if "drug_concept_id" in columns_to_generate: - result["drug_concept_id"] = generic.numeric.integer_number() - if "drug_exposure_end_date" in columns_to_generate: - result["drug_exposure_end_date"] = generic.datetime.date() - if "drug_exposure_end_datetime" in columns_to_generate: - result["drug_exposure_end_datetime"] = generic.datetime.datetime() - if "drug_exposure_id" in columns_to_generate: - result["drug_exposure_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["drug_exposure"].columns["drug_exposure_id"], - ) - if "drug_exposure_start_date" in columns_to_generate: - result["drug_exposure_start_date"] = generic.datetime.date() - if "drug_exposure_start_datetime" in columns_to_generate: - result["drug_exposure_start_datetime"] = generic.datetime.datetime() - if "drug_source_concept_id" in columns_to_generate: - result["drug_source_concept_id"] = generic.numeric.integer_number() - if "drug_source_value" in columns_to_generate: - result["drug_source_value"] = generic.person.password(length=255) - if "drug_type_concept_id" in columns_to_generate: - result["drug_type_concept_id"] = generic.numeric.integer_number() - if "lot_number" in columns_to_generate: - result["lot_number"] = generic.person.password(length=50) - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - if "provider_id" in columns_to_generate: - result["provider_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["provider"], "provider_id" - ) - if "quantity" in columns_to_generate: - result["quantity"] = generic.numeric.float_number() - if "refills" in columns_to_generate: - result["refills"] = generic.numeric.integer_number() - if "route_concept_id" in columns_to_generate: - result["route_concept_id"] = generic.numeric.integer_number() - if "route_source_value" in columns_to_generate: - result["route_source_value"] = generic.person.password(length=50) - if "sig" in columns_to_generate: - result["sig"] = generic.text.color() - if "stop_reason" in columns_to_generate: - result["stop_reason"] = generic.person.password(length=20) - if "verbatim_end_date" in columns_to_generate: - result["verbatim_end_date"] = generic.datetime.date() - if "visit_detail_id" in columns_to_generate: - result["visit_detail_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" - ) - if "visit_occurrence_id" in columns_to_generate: - result[ - "visit_occurrence_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, - metadata.tables["visit_occurrence"], - "visit_occurrence_id", - ) - columns_to_generate = set() - return result - - -class EpisodeGenerator(TableGenerator): - num_rows_per_pass = 1 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "episode_end_datetime", - "episode_end_date", - "episode_source_value", - "episode_id", - "person_id", - "episode_number", - "episode_start_datetime", - "episode_parent_id", - "episode_type_concept_id", - "episode_source_concept_id", - "episode_object_concept_id", - "episode_start_date", - "episode_concept_id", - } - ) - while columns_to_generate: - if "episode_concept_id" in columns_to_generate: - result["episode_concept_id"] = generic.numeric.integer_number() - if "episode_end_date" in columns_to_generate: - result["episode_end_date"] = generic.datetime.date() - if "episode_end_datetime" in columns_to_generate: - result["episode_end_datetime"] = generic.datetime.datetime() - if "episode_id" in columns_to_generate: - result["episode_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["episode"].columns["episode_id"], - ) - if "episode_number" in columns_to_generate: - result["episode_number"] = generic.numeric.integer_number() - if "episode_object_concept_id" in columns_to_generate: - result["episode_object_concept_id"] = generic.numeric.integer_number() - if "episode_parent_id" in columns_to_generate: - result["episode_parent_id"] = generic.numeric.integer_number() - if "episode_source_concept_id" in columns_to_generate: - result["episode_source_concept_id"] = generic.numeric.integer_number() - if "episode_source_value" in columns_to_generate: - result["episode_source_value"] = generic.person.password(length=50) - if "episode_start_date" in columns_to_generate: - result["episode_start_date"] = generic.datetime.date() - if "episode_start_datetime" in columns_to_generate: - result["episode_start_datetime"] = generic.datetime.datetime() - if "episode_type_concept_id" in columns_to_generate: - result["episode_type_concept_id"] = generic.numeric.integer_number() - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - columns_to_generate = set() - return result - - -class Episode_EventGenerator(TableGenerator): - num_rows_per_pass = 1 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - {"event_id", "episode_event_field_concept_id", "episode_id"} - ) - while columns_to_generate: - if "episode_event_field_concept_id" in columns_to_generate: - result[ - "episode_event_field_concept_id" - ] = generic.numeric.integer_number() - if "episode_id" in columns_to_generate: - result["episode_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["episode"], "episode_id" - ) - if "event_id" in columns_to_generate: - result["event_id"] = generic.numeric.integer_number() - columns_to_generate = set() - return result - - -class Fact_RelationshipGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "domain_concept_id_1", - "fact_id_1", - "domain_concept_id_2", - "fact_id_2", - "relationship_concept_id", - } - ) - while columns_to_generate: - if "domain_concept_id_1" in columns_to_generate: - result["domain_concept_id_1"] = generic.numeric.integer_number() - if "domain_concept_id_2" in columns_to_generate: - result["domain_concept_id_2"] = generic.numeric.integer_number() - if "fact_id_1" in columns_to_generate: - result["fact_id_1"] = generic.numeric.integer_number() - if "fact_id_2" in columns_to_generate: - result["fact_id_2"] = generic.numeric.integer_number() - if "relationship_concept_id" in columns_to_generate: - result["relationship_concept_id"] = generic.numeric.integer_number() - columns_to_generate = set() - return result - - -class MeasurementGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "value_as_number", - "measurement_time", - "range_high", - "provider_id", - "value_as_concept_id", - "measurement_type_concept_id", - "measurement_date", - "person_id", - "measurement_id", - "range_low", - "measurement_datetime", - "measurement_source_concept_id", - "visit_detail_id", - "unit_concept_id", - "measurement_concept_id", - "unit_source_value", - "operator_concept_id", - "visit_occurrence_id", - "value_source_value", - "measurement_source_value", - } - ) - while columns_to_generate: - if "measurement_concept_id" in columns_to_generate: - result["measurement_concept_id"] = generic.numeric.integer_number() - if "measurement_date" in columns_to_generate: - result["measurement_date"] = generic.datetime.date() - if "measurement_datetime" in columns_to_generate: - result["measurement_datetime"] = generic.datetime.datetime() - if "measurement_id" in columns_to_generate: - result["measurement_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["measurement"].columns["measurement_id"], - ) - if "measurement_source_concept_id" in columns_to_generate: - result[ - "measurement_source_concept_id" - ] = generic.numeric.integer_number() - if "measurement_source_value" in columns_to_generate: - result["measurement_source_value"] = generic.person.password(length=50) - if "measurement_time" in columns_to_generate: - result["measurement_time"] = generic.person.password(length=10) - if "measurement_type_concept_id" in columns_to_generate: - result["measurement_type_concept_id"] = generic.numeric.integer_number() - if "operator_concept_id" in columns_to_generate: - result["operator_concept_id"] = generic.numeric.integer_number() - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - if "provider_id" in columns_to_generate: - result["provider_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["provider"], "provider_id" - ) - if "range_high" in columns_to_generate: - result["range_high"] = generic.numeric.float_number() - if "range_low" in columns_to_generate: - result["range_low"] = generic.numeric.float_number() - if "unit_concept_id" in columns_to_generate: - result["unit_concept_id"] = generic.numeric.integer_number() - if "unit_source_value" in columns_to_generate: - result["unit_source_value"] = generic.person.password(length=50) - if "value_as_concept_id" in columns_to_generate: - result["value_as_concept_id"] = generic.numeric.integer_number() - if "value_as_number" in columns_to_generate: - result["value_as_number"] = generic.numeric.float_number() - if "value_source_value" in columns_to_generate: - result["value_source_value"] = generic.person.password(length=50) - if "visit_detail_id" in columns_to_generate: - result["visit_detail_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" - ) - if "visit_occurrence_id" in columns_to_generate: - result[ - "visit_occurrence_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, - metadata.tables["visit_occurrence"], - "visit_occurrence_id", - ) - columns_to_generate = set() - return result - - -class MetadataGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "value_as_string", - "metadata_id", - "value_as_number", - "value_as_concept_id", - "name", - "metadata_concept_id", - "metadata_date", - "metadata_type_concept_id", - "metadata_datetime", - } - ) - while columns_to_generate: - if "metadata_concept_id" in columns_to_generate: - result["metadata_concept_id"] = generic.numeric.integer_number() - if "metadata_date" in columns_to_generate: - result["metadata_date"] = generic.datetime.date() - if "metadata_datetime" in columns_to_generate: - result["metadata_datetime"] = generic.datetime.datetime() - if "metadata_id" in columns_to_generate: - result["metadata_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["metadata"].columns["metadata_id"], - ) - if "metadata_type_concept_id" in columns_to_generate: - result["metadata_type_concept_id"] = generic.numeric.integer_number() - if "name" in columns_to_generate: - result["name"] = generic.person.password(length=250) - if "value_as_concept_id" in columns_to_generate: - result["value_as_concept_id"] = generic.numeric.integer_number() - if "value_as_number" in columns_to_generate: - result["value_as_number"] = generic.numeric.float_number() - if "value_as_string" in columns_to_generate: - result["value_as_string"] = generic.person.password(length=250) - columns_to_generate = set() - return result - - -class NoteGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "note_text", - "visit_detail_id", - "encoding_concept_id", - "note_class_concept_id", - "person_id", - "provider_id", - "note_date", - "note_id", - "note_title", - "note_type_concept_id", - "note_event_id", - "visit_occurrence_id", - "note_event_field_concept_id", - "note_datetime", - "note_source_value", - "language_concept_id", - } - ) - while columns_to_generate: - if "encoding_concept_id" in columns_to_generate: - result["encoding_concept_id"] = generic.numeric.integer_number() - if "language_concept_id" in columns_to_generate: - result["language_concept_id"] = generic.numeric.integer_number() - if "note_class_concept_id" in columns_to_generate: - result["note_class_concept_id"] = generic.numeric.integer_number() - if "note_date" in columns_to_generate: - result["note_date"] = generic.datetime.date() - if "note_datetime" in columns_to_generate: - result["note_datetime"] = generic.datetime.datetime() - if "note_event_field_concept_id" in columns_to_generate: - result["note_event_field_concept_id"] = generic.numeric.integer_number() - if "note_event_id" in columns_to_generate: - result["note_event_id"] = generic.numeric.integer_number() - if "note_id" in columns_to_generate: - result["note_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["note"].columns["note_id"], - ) - if "note_source_value" in columns_to_generate: - result["note_source_value"] = generic.person.password(length=50) - if "note_text" in columns_to_generate: - result["note_text"] = generic.text.color() - if "note_title" in columns_to_generate: - result["note_title"] = generic.person.password(length=250) - if "note_type_concept_id" in columns_to_generate: - result["note_type_concept_id"] = generic.numeric.integer_number() - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - if "provider_id" in columns_to_generate: - result["provider_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["provider"], "provider_id" - ) - if "visit_detail_id" in columns_to_generate: - result["visit_detail_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" - ) - if "visit_occurrence_id" in columns_to_generate: - result[ - "visit_occurrence_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, - metadata.tables["visit_occurrence"], - "visit_occurrence_id", - ) - columns_to_generate = set() - return result - - -class Note_NlpGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "offset", - "lexical_variant", - "term_modifiers", - "nlp_datetime", - "nlp_system", - "note_id", - "nlp_date", - "snippet", - "note_nlp_source_concept_id", - "section_concept_id", - "term_temporal", - "term_exists", - "note_nlp_id", - "note_nlp_concept_id", - } - ) - while columns_to_generate: - if "lexical_variant" in columns_to_generate: - result["lexical_variant"] = generic.person.password(length=250) - if "nlp_date" in columns_to_generate: - result["nlp_date"] = generic.datetime.date() - if "nlp_datetime" in columns_to_generate: - result["nlp_datetime"] = generic.datetime.datetime() - if "nlp_system" in columns_to_generate: - result["nlp_system"] = generic.person.password(length=250) - if "note_id" in columns_to_generate: - result["note_id"] = generic.numeric.integer_number() - if "note_nlp_concept_id" in columns_to_generate: - result["note_nlp_concept_id"] = generic.numeric.integer_number() - if "note_nlp_id" in columns_to_generate: - result["note_nlp_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["note_nlp"].columns["note_nlp_id"], - ) - if "note_nlp_source_concept_id" in columns_to_generate: - result["note_nlp_source_concept_id"] = generic.numeric.integer_number() - if "offset" in columns_to_generate: - result["offset"] = generic.person.password(length=50) - if "section_concept_id" in columns_to_generate: - result["section_concept_id"] = generic.numeric.integer_number() - if "snippet" in columns_to_generate: - result["snippet"] = generic.person.password(length=250) - if "term_exists" in columns_to_generate: - result["term_exists"] = generic.person.password(length=1) - if "term_modifiers" in columns_to_generate: - result["term_modifiers"] = generic.person.password(length=2000) - if "term_temporal" in columns_to_generate: - result["term_temporal"] = generic.person.password(length=50) - columns_to_generate = set() - return result - - -class ObservationGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "observation_source_concept_id", - "value_as_string", - "qualifier_source_value", - "unit_concept_id", - "observation_source_value", - "visit_detail_id", - "person_id", - "observation_concept_id", - "provider_id", - "value_as_number", - "observation_type_concept_id", - "qualifier_concept_id", - "unit_source_value", - "value_as_concept_id", - "observation_id", - "visit_occurrence_id", - "observation_datetime", - "observation_date", - } - ) - while columns_to_generate: - if "observation_concept_id" in columns_to_generate: - result["observation_concept_id"] = generic.numeric.integer_number() - if "observation_date" in columns_to_generate: - result["observation_date"] = generic.datetime.date() - if "observation_datetime" in columns_to_generate: - result["observation_datetime"] = generic.datetime.datetime() - if "observation_id" in columns_to_generate: - result["observation_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["observation"].columns["observation_id"], - ) - if "observation_source_concept_id" in columns_to_generate: - result[ - "observation_source_concept_id" - ] = generic.numeric.integer_number() - if "observation_source_value" in columns_to_generate: - result["observation_source_value"] = generic.person.password(length=50) - if "observation_type_concept_id" in columns_to_generate: - result["observation_type_concept_id"] = generic.numeric.integer_number() - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - if "provider_id" in columns_to_generate: - result["provider_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["provider"], "provider_id" - ) - if "qualifier_concept_id" in columns_to_generate: - result["qualifier_concept_id"] = generic.numeric.integer_number() - if "qualifier_source_value" in columns_to_generate: - result["qualifier_source_value"] = generic.person.password(length=50) - if "unit_concept_id" in columns_to_generate: - result["unit_concept_id"] = generic.numeric.integer_number() - if "unit_source_value" in columns_to_generate: - result["unit_source_value"] = generic.person.password(length=50) - if "value_as_concept_id" in columns_to_generate: - result["value_as_concept_id"] = generic.numeric.integer_number() - if "value_as_number" in columns_to_generate: - result["value_as_number"] = generic.numeric.float_number() - if "value_as_string" in columns_to_generate: - result["value_as_string"] = generic.person.password(length=120) - if "visit_detail_id" in columns_to_generate: - result["visit_detail_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" - ) - if "visit_occurrence_id" in columns_to_generate: - result[ - "visit_occurrence_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, - metadata.tables["visit_occurrence"], - "visit_occurrence_id", - ) - columns_to_generate = set() - return result - - -class Observation_PeriodGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "observation_period_id", - "person_id", - "period_type_concept_id", - "observation_period_start_date", - "observation_period_end_date", - } - ) - while columns_to_generate: - if "observation_period_end_date" in columns_to_generate: - result["observation_period_end_date"] = generic.datetime.date() - if "observation_period_id" in columns_to_generate: - result[ - "observation_period_id" - ] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["observation_period"].columns[ - "observation_period_id" - ], - ) - if "observation_period_start_date" in columns_to_generate: - result["observation_period_start_date"] = generic.datetime.date() - if "period_type_concept_id" in columns_to_generate: - result["period_type_concept_id"] = generic.numeric.integer_number() - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - columns_to_generate = set() - return result - - -class Payer_Plan_PeriodGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "plan_source_value", - "plan_concept_id", - "plan_source_concept_id", - "person_id", - "family_source_value", - "sponsor_source_concept_id", - "payer_plan_period_id", - "sponsor_source_value", - "payer_concept_id", - "stop_reason_source_value", - "payer_plan_period_start_date", - "payer_source_value", - "stop_reason_concept_id", - "sponsor_concept_id", - "stop_reason_source_concept_id", - "payer_plan_period_end_date", - "payer_source_concept_id", - } - ) - while columns_to_generate: - if "family_source_value" in columns_to_generate: - result["family_source_value"] = generic.person.password(length=50) - if "payer_concept_id" in columns_to_generate: - result["payer_concept_id"] = generic.numeric.integer_number() - if "payer_plan_period_end_date" in columns_to_generate: - result["payer_plan_period_end_date"] = generic.datetime.date() - if "payer_plan_period_id" in columns_to_generate: - result[ - "payer_plan_period_id" - ] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["payer_plan_period"].columns[ - "payer_plan_period_id" - ], - ) - if "payer_plan_period_start_date" in columns_to_generate: - result["payer_plan_period_start_date"] = generic.datetime.date() - if "payer_source_concept_id" in columns_to_generate: - result["payer_source_concept_id"] = generic.numeric.integer_number() - if "payer_source_value" in columns_to_generate: - result["payer_source_value"] = generic.person.password(length=50) - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - if "plan_concept_id" in columns_to_generate: - result["plan_concept_id"] = generic.numeric.integer_number() - if "plan_source_concept_id" in columns_to_generate: - result["plan_source_concept_id"] = generic.numeric.integer_number() - if "plan_source_value" in columns_to_generate: - result["plan_source_value"] = generic.person.password(length=50) - if "sponsor_concept_id" in columns_to_generate: - result["sponsor_concept_id"] = generic.numeric.integer_number() - if "sponsor_source_concept_id" in columns_to_generate: - result["sponsor_source_concept_id"] = generic.numeric.integer_number() - if "sponsor_source_value" in columns_to_generate: - result["sponsor_source_value"] = generic.person.password(length=50) - if "stop_reason_concept_id" in columns_to_generate: - result["stop_reason_concept_id"] = generic.numeric.integer_number() - if "stop_reason_source_concept_id" in columns_to_generate: - result[ - "stop_reason_source_concept_id" - ] = generic.numeric.integer_number() - if "stop_reason_source_value" in columns_to_generate: - result["stop_reason_source_value"] = generic.person.password(length=50) - columns_to_generate = set() - return result - - -class PersonGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "gender_source_value", - "person_source_value", - "day_of_birth", - "race_source_concept_id", - "birth_datetime", - "ethnicity_concept_id", - "person_id", - "ethnicity_source_value", - "provider_id", - "race_source_value", - "gender_source_concept_id", - "care_site_id", - "month_of_birth", - "location_id", - "ethnicity_source_concept_id", - "race_concept_id", - "gender_concept_id", - "year_of_birth", - } - ) - while columns_to_generate: - if "birth_datetime" in columns_to_generate: - result["birth_datetime"] = generic.datetime.datetime() - if "care_site_id" in columns_to_generate: - result["care_site_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["care_site"], "care_site_id" - ) - if "day_of_birth" in columns_to_generate: - result["day_of_birth"] = generic.numeric.integer_number() - if "ethnicity_concept_id" in columns_to_generate: - result["ethnicity_concept_id"] = generic.numeric.integer_number() - if "ethnicity_source_concept_id" in columns_to_generate: - result["ethnicity_source_concept_id"] = generic.numeric.integer_number() - if "ethnicity_source_value" in columns_to_generate: - result["ethnicity_source_value"] = generic.person.password(length=50) - if "gender_concept_id" in columns_to_generate: - result["gender_concept_id"] = generic.numeric.integer_number() - if "gender_source_concept_id" in columns_to_generate: - result["gender_source_concept_id"] = generic.numeric.integer_number() - if "gender_source_value" in columns_to_generate: - result["gender_source_value"] = generic.person.password(length=50) - if "location_id" in columns_to_generate: - result["location_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["location"], "location_id" - ) - if "month_of_birth" in columns_to_generate: - result["month_of_birth"] = generic.numeric.integer_number() - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["person"].columns["person_id"], - ) - if "person_source_value" in columns_to_generate: - result["person_source_value"] = generic.person.password(length=50) - if "provider_id" in columns_to_generate: - result["provider_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["provider"], "provider_id" - ) - if "race_concept_id" in columns_to_generate: - result["race_concept_id"] = generic.numeric.integer_number() - if "race_source_concept_id" in columns_to_generate: - result["race_source_concept_id"] = generic.numeric.integer_number() - if "race_source_value" in columns_to_generate: - result["race_source_value"] = generic.person.password(length=50) - if "year_of_birth" in columns_to_generate: - result["year_of_birth"] = generic.numeric.integer_number() - columns_to_generate = set() - return result - - -class Procedure_OccurrenceGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "procedure_datetime", - "visit_detail_id", - "procedure_source_value", - "person_id", - "provider_id", - "modifier_concept_id", - "procedure_source_concept_id", - "quantity", - "procedure_concept_id", - "procedure_type_concept_id", - "modifier_source_value", - "visit_occurrence_id", - "procedure_occurrence_id", - "procedure_date", - } - ) - while columns_to_generate: - if "modifier_concept_id" in columns_to_generate: - result["modifier_concept_id"] = generic.numeric.integer_number() - if "modifier_source_value" in columns_to_generate: - result["modifier_source_value"] = generic.person.password(length=50) - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - if "procedure_concept_id" in columns_to_generate: - result["procedure_concept_id"] = generic.numeric.integer_number() - if "procedure_date" in columns_to_generate: - result["procedure_date"] = generic.datetime.date() - if "procedure_datetime" in columns_to_generate: - result["procedure_datetime"] = generic.datetime.datetime() - if "procedure_occurrence_id" in columns_to_generate: - result[ - "procedure_occurrence_id" - ] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["procedure_occurrence"].columns[ - "procedure_occurrence_id" - ], - ) - if "procedure_source_concept_id" in columns_to_generate: - result["procedure_source_concept_id"] = generic.numeric.integer_number() - if "procedure_source_value" in columns_to_generate: - result["procedure_source_value"] = generic.person.password(length=50) - if "procedure_type_concept_id" in columns_to_generate: - result["procedure_type_concept_id"] = generic.numeric.integer_number() - if "provider_id" in columns_to_generate: - result["provider_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["provider"], "provider_id" - ) - if "quantity" in columns_to_generate: - result["quantity"] = generic.numeric.integer_number() - if "visit_detail_id" in columns_to_generate: - result["visit_detail_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" - ) - if "visit_occurrence_id" in columns_to_generate: - result[ - "visit_occurrence_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, - metadata.tables["visit_occurrence"], - "visit_occurrence_id", - ) - columns_to_generate = set() - return result - - -class SpecimenGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "specimen_date", - "specimen_source_value", - "specimen_type_concept_id", - "unit_concept_id", - "specimen_source_id", - "person_id", - "anatomic_site_source_value", - "quantity", - "specimen_concept_id", - "disease_status_concept_id", - "unit_source_value", - "anatomic_site_concept_id", - "specimen_id", - "specimen_datetime", - "disease_status_source_value", - } - ) - while columns_to_generate: - if "anatomic_site_concept_id" in columns_to_generate: - result["anatomic_site_concept_id"] = generic.numeric.integer_number() - if "anatomic_site_source_value" in columns_to_generate: - result["anatomic_site_source_value"] = generic.person.password( - length=50 - ) - if "disease_status_concept_id" in columns_to_generate: - result["disease_status_concept_id"] = generic.numeric.integer_number() - if "disease_status_source_value" in columns_to_generate: - result["disease_status_source_value"] = generic.person.password( - length=50 - ) - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - if "quantity" in columns_to_generate: - result["quantity"] = generic.numeric.float_number() - if "specimen_concept_id" in columns_to_generate: - result["specimen_concept_id"] = generic.numeric.integer_number() - if "specimen_date" in columns_to_generate: - result["specimen_date"] = generic.datetime.date() - if "specimen_datetime" in columns_to_generate: - result["specimen_datetime"] = generic.datetime.datetime() - if "specimen_id" in columns_to_generate: - result["specimen_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["specimen"].columns["specimen_id"], - ) - if "specimen_source_id" in columns_to_generate: - result["specimen_source_id"] = generic.person.password(length=255) - if "specimen_source_value" in columns_to_generate: - result["specimen_source_value"] = generic.person.password(length=50) - if "specimen_type_concept_id" in columns_to_generate: - result["specimen_type_concept_id"] = generic.numeric.integer_number() - if "unit_concept_id" in columns_to_generate: - result["unit_concept_id"] = generic.numeric.integer_number() - if "unit_source_value" in columns_to_generate: - result["unit_source_value"] = generic.person.password(length=50) - columns_to_generate = set() - return result - - -class Visit_DetailGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "visit_detail_type_concept_id", - "visit_detail_start_date", - "visit_detail_start_datetime", - "visit_detail_source_concept_id", - "admitting_source_value", - "provider_id", - "visit_detail_end_date", - "visit_detail_source_value", - "visit_detail_parent_id", - "visit_detail_end_datetime", - "visit_detail_concept_id", - "person_id", - "discharge_to_source_value", - "admitting_source_concept_id", - "visit_detail_id", - "care_site_id", - "preceding_visit_detail_id", - "visit_occurrence_id", - "discharge_to_concept_id", - } - ) - while columns_to_generate: - if "admitting_source_concept_id" in columns_to_generate: - result["admitting_source_concept_id"] = generic.numeric.integer_number() - if "admitting_source_value" in columns_to_generate: - result["admitting_source_value"] = generic.person.password(length=50) - if "care_site_id" in columns_to_generate: - result["care_site_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["care_site"], "care_site_id" - ) - if "discharge_to_concept_id" in columns_to_generate: - result["discharge_to_concept_id"] = generic.numeric.integer_number() - if "discharge_to_source_value" in columns_to_generate: - result["discharge_to_source_value"] = generic.person.password(length=50) - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - if "preceding_visit_detail_id" in columns_to_generate: - result[ - "preceding_visit_detail_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["visit_detail"], "visit_detail_id" - ) - if "provider_id" in columns_to_generate: - result["provider_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["provider"], "provider_id" - ) - if "visit_detail_concept_id" in columns_to_generate: - result["visit_detail_concept_id"] = generic.numeric.integer_number() - if "visit_detail_end_date" in columns_to_generate: - result["visit_detail_end_date"] = generic.datetime.date() - if "visit_detail_end_datetime" in columns_to_generate: - result["visit_detail_end_datetime"] = generic.datetime.datetime() - if "visit_detail_id" in columns_to_generate: - result["visit_detail_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["visit_detail"].columns["visit_detail_id"], - ) - if "visit_detail_parent_id" in columns_to_generate: - result["visit_detail_parent_id"] = generic.person.password(length=50) - if "visit_detail_source_concept_id" in columns_to_generate: - result["visit_detail_source_concept_id"] = generic.person.password( - length=50 - ) - if "visit_detail_source_value" in columns_to_generate: - result["visit_detail_source_value"] = generic.person.password( - length=120 - ) - if "visit_detail_start_date" in columns_to_generate: - result["visit_detail_start_date"] = generic.datetime.date() - if "visit_detail_start_datetime" in columns_to_generate: - result["visit_detail_start_datetime"] = generic.datetime.datetime() - if "visit_detail_type_concept_id" in columns_to_generate: - result[ - "visit_detail_type_concept_id" - ] = generic.numeric.integer_number() - if "visit_occurrence_id" in columns_to_generate: - result[ - "visit_occurrence_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, - metadata.tables["visit_occurrence"], - "visit_occurrence_id", - ) - columns_to_generate = set() - return result - - -class Visit_OccurrenceGenerator(TableGenerator): - num_rows_per_pass = 0 - - def __init__(self): - self.initialized = False - - def __call__(self, dst_db_conn, metadata): - if not self.initialized: - self.initialized = True - result = {} - columns_to_generate = set( - { - "visit_source_value", - "preceding_visit_occurrence_id", - "visit_type_concept_id", - "person_id", - "admitted_from_concept_id", - "discharged_to_concept_id", - "admitted_from_source_value", - "provider_id", - "visit_end_date", - "visit_end_datetime", - "care_site_id", - "visit_source_concept_id", - "visit_start_datetime", - "visit_occurrence_id", - "discharged_to_source_value", - "visit_start_date", - "visit_concept_id", - } - ) - while columns_to_generate: - if "admitted_from_concept_id" in columns_to_generate: - result["admitted_from_concept_id"] = generic.numeric.integer_number() - if "admitted_from_source_value" in columns_to_generate: - result["admitted_from_source_value"] = generic.person.password( - length=50 - ) - if "care_site_id" in columns_to_generate: - result["care_site_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["care_site"], "care_site_id" - ) - if "discharged_to_concept_id" in columns_to_generate: - result["discharged_to_concept_id"] = generic.numeric.integer_number() - if "discharged_to_source_value" in columns_to_generate: - result["discharged_to_source_value"] = generic.person.password( - length=50 - ) - if "person_id" in columns_to_generate: - result["person_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["person"], "person_id" - ) - if "preceding_visit_occurrence_id" in columns_to_generate: - result[ - "preceding_visit_occurrence_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, - metadata.tables["visit_occurrence"], - "visit_occurrence_id", - ) - if "provider_id" in columns_to_generate: - result["provider_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["provider"], "provider_id" - ) - if "visit_concept_id" in columns_to_generate: - result["visit_concept_id"] = generic.numeric.integer_number() - if "visit_end_date" in columns_to_generate: - result["visit_end_date"] = generic.datetime.date() - if "visit_end_datetime" in columns_to_generate: - result["visit_end_datetime"] = generic.datetime.datetime() - if "visit_occurrence_id" in columns_to_generate: - result["visit_occurrence_id"] = generic.column_value_provider.increment( - db_connection=dst_db_conn, - column=metadata.tables["visit_occurrence"].columns[ - "visit_occurrence_id" - ], - ) - if "visit_source_concept_id" in columns_to_generate: - result["visit_source_concept_id"] = generic.numeric.integer_number() - if "visit_source_value" in columns_to_generate: - result["visit_source_value"] = generic.person.password(length=50) - if "visit_start_date" in columns_to_generate: - result["visit_start_date"] = generic.datetime.date() - if "visit_start_datetime" in columns_to_generate: - result["visit_start_datetime"] = generic.datetime.datetime() - if "visit_type_concept_id" in columns_to_generate: - result["visit_type_concept_id"] = generic.numeric.integer_number() - columns_to_generate = set() - return result - - -table_generator_dict = { - "cohort": CohortGenerator(), - "cohort_definition": Cohort_DefinitionGenerator(), - "condition_era": Condition_EraGenerator(), - "condition_occurrence": Condition_OccurrenceGenerator(), - "cost": CostGenerator(), - "death": DeathGenerator(), - "device_exposure": Device_ExposureGenerator(), - "dose_era": Dose_EraGenerator(), - "drug_era": Drug_EraGenerator(), - "drug_exposure": Drug_ExposureGenerator(), - "episode": EpisodeGenerator(), - "episode_event": Episode_EventGenerator(), - "fact_relationship": Fact_RelationshipGenerator(), - "measurement": MeasurementGenerator(), - "metadata": MetadataGenerator(), - "note": NoteGenerator(), - "note_nlp": Note_NlpGenerator(), - "observation": ObservationGenerator(), - "observation_period": Observation_PeriodGenerator(), - "payer_plan_period": Payer_Plan_PeriodGenerator(), - "person": PersonGenerator(), - "procedure_occurrence": Procedure_OccurrenceGenerator(), - "specimen": SpecimenGenerator(), - "visit_detail": Visit_DetailGenerator(), - "visit_occurrence": Visit_OccurrenceGenerator(), -} - - -story_generator_list = [] diff --git a/examples/omop-mssql/README.md b/examples/omop-mssql/README.md index b2a6936..98074d0 100644 --- a/examples/omop-mssql/README.md +++ b/examples/omop-mssql/README.md @@ -124,6 +124,8 @@ cd examples/omop-mssql `poetry run datafaker create-tables --orm-file ./orm.yaml --config-file ./config.yaml` +1. Run `copy_vocabulary.sql` to copy vocabulary table rows. (I did it in DBeaver) + 1. Create generator table `poetry run datafaker create-generators --orm-file ./orm.yaml --config-file ./config.yaml --df-file ./df.py` diff --git a/examples/omop-mssql/config.yaml b/examples/omop-mssql/config.yaml index 6da446a..c390d6f 100644 --- a/examples/omop-mssql/config.yaml +++ b/examples/omop-mssql/config.yaml @@ -2,8 +2,8 @@ tables: # Vocab tables concept: # This one is a vocab, but its too big to handle the usual way - # ignore: true + ignore: false vocabulary_table: true person: - num_rows_per_pass: 0 + num_rows_per_pass: 10 diff --git a/examples/omop-mssql/orm.yaml b/examples/omop-mssql/orm.yaml new file mode 100644 index 0000000..da7c81d --- /dev/null +++ b/examples/omop-mssql/orm.yaml @@ -0,0 +1,122 @@ +dsn: mssql+pyodbc://sa:***@127.0.0.1:1433/master?TrustServerCertificate=yes&driver=ODBC+Driver+18+for+SQL+Server +schema: mimic100 +tables: + concept: + columns: + concept_class_id: + nullable: false + primary: false + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS + concept_code: + nullable: false + primary: false + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS + concept_id: + nullable: false + primary: true + type: BIGINT + concept_name: + nullable: false + primary: false + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS + domain_id: + nullable: false + primary: false + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS + invalid_reason: + nullable: true + primary: false + type: VARCHAR(1) COLLATE SQL_Latin1_General_CP1_CI_AS + standard_concept: + nullable: true + primary: false + type: VARCHAR(1) COLLATE SQL_Latin1_General_CP1_CI_AS + valid_end_date: + nullable: false + primary: false + type: DATE + valid_start_date: + nullable: false + primary: false + type: DATE + vocabulary_id: + nullable: false + primary: false + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS + unique: [] + person: + columns: + birth_datetime: + nullable: true + primary: false + type: DATETIME2 + day_of_birth: + nullable: true + primary: false + type: BIGINT + ethnicity_concept_id: + foreign_keys: + - mimic100.concept.concept_id + nullable: false + primary: false + type: BIGINT + ethnicity_source_concept_id: + foreign_keys: + - mimic100.concept.concept_id + nullable: true + primary: false + type: BIGINT + ethnicity_source_value: + nullable: true + primary: false + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS + gender_concept_id: + foreign_keys: + - mimic100.concept.concept_id + nullable: false + primary: false + type: BIGINT + gender_source_concept_id: + foreign_keys: + - mimic100.concept.concept_id + nullable: true + primary: false + type: BIGINT + gender_source_value: + nullable: true + primary: false + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS + month_of_birth: + nullable: true + primary: false + type: BIGINT + person_id: + nullable: false + primary: true + type: BIGINT + person_source_value: + nullable: true + primary: false + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS + race_concept_id: + foreign_keys: + - mimic100.concept.concept_id + nullable: false + primary: false + type: BIGINT + race_source_concept_id: + foreign_keys: + - mimic100.concept.concept_id + nullable: true + primary: false + type: BIGINT + race_source_value: + nullable: true + primary: false + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS + year_of_birth: + nullable: false + primary: false + type: BIGINT + unique: [] + \ No newline at end of file diff --git a/examples/mimic_omop/orm.yaml b/examples/omop-mssql/orm_full.yaml similarity index 76% rename from examples/mimic_omop/orm.yaml rename to examples/omop-mssql/orm_full.yaml index a400553..d4ccf16 100644 --- a/examples/mimic_omop/orm.yaml +++ b/examples/omop-mssql/orm_full.yaml @@ -1,5 +1,5 @@ -dsn: postgresql://postgres@localhost:5432/omop5.4 -schema: mimic +dsn: mssql+pyodbc://sa:***@127.0.0.1:1433/master?TrustServerCertificate=yes&driver=ODBC+Driver+18+for+SQL+Server +schema: mimic100 tables: care_site: columns: @@ -10,38 +10,34 @@ tables: care_site_name: nullable: true primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS care_site_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS location_id: - foreign_keys: - - location.location_id nullable: true primary: false type: BIGINT place_of_service_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT place_of_service_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS unique: [] cdm_source: columns: cdm_etl_reference: nullable: true primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS cdm_holder: nullable: false primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS cdm_release_date: nullable: false primary: false @@ -49,23 +45,23 @@ tables: cdm_source_abbreviation: nullable: false primary: false - type: VARCHAR(25) + type: VARCHAR(25) COLLATE SQL_Latin1_General_CP1_CI_AS cdm_source_name: nullable: false primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS cdm_version: nullable: true primary: false - type: VARCHAR(10) + type: VARCHAR(10) COLLATE SQL_Latin1_General_CP1_CI_AS source_description: nullable: true primary: false - type: TEXT + type: VARCHAR(max) COLLATE SQL_Latin1_General_CP1_CI_AS source_documentation_reference: nullable: true primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS source_release_date: nullable: false primary: false @@ -73,7 +69,7 @@ tables: vocabulary_version: nullable: false primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS unique: [] cohort: columns: @@ -99,7 +95,7 @@ tables: cohort_definition_description: nullable: true primary: false - type: TEXT + type: VARCHAR(max) COLLATE SQL_Latin1_General_CP1_CI_AS cohort_definition_id: nullable: false primary: false @@ -107,24 +103,20 @@ tables: cohort_definition_name: nullable: false primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS cohort_definition_syntax: nullable: true primary: false - type: TEXT + type: VARCHAR(max) COLLATE SQL_Latin1_General_CP1_CI_AS cohort_initiation_date: nullable: true primary: false type: DATE definition_type_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT subject_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -132,15 +124,13 @@ tables: concept: columns: concept_class_id: - foreign_keys: - - concept_class.concept_class_id nullable: false primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS concept_code: nullable: false primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS concept_id: nullable: false primary: true @@ -148,21 +138,19 @@ tables: concept_name: nullable: false primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS domain_id: - foreign_keys: - - domain.domain_id nullable: false primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS invalid_reason: nullable: true primary: false - type: VARCHAR(1) + type: VARCHAR(1) COLLATE SQL_Latin1_General_CP1_CI_AS standard_concept: nullable: true primary: false - type: VARCHAR(1) + type: VARCHAR(1) COLLATE SQL_Latin1_General_CP1_CI_AS valid_end_date: nullable: false primary: false @@ -172,11 +160,9 @@ tables: primary: false type: DATE vocabulary_id: - foreign_keys: - - vocabulary.vocabulary_id nullable: false primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS unique: [] concept_ancestor: columns: @@ -200,19 +186,17 @@ tables: concept_class: columns: concept_class_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT concept_class_id: nullable: false primary: true - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS concept_class_name: nullable: false primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS unique: [] concept_relationship: columns: @@ -227,13 +211,11 @@ tables: invalid_reason: nullable: true primary: false - type: VARCHAR(1) + type: VARCHAR(1) COLLATE SQL_Latin1_General_CP1_CI_AS relationship_id: - foreign_keys: - - relationship.relationship_id nullable: false primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS valid_end_date: nullable: false primary: false @@ -252,10 +234,8 @@ tables: concept_synonym_name: nullable: false primary: false - type: VARCHAR(1000) + type: VARCHAR(1000) COLLATE SQL_Latin1_General_CP1_CI_AS language_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -263,8 +243,6 @@ tables: condition_era: columns: condition_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -285,8 +263,6 @@ tables: primary: false type: BIGINT person_id: - foreign_keys: - - person.person_id nullable: false primary: false type: BIGINT @@ -295,7 +271,7 @@ tables: columns: condition_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: false primary: false type: BIGINT @@ -306,21 +282,21 @@ tables: condition_end_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 condition_occurrence_id: nullable: false primary: true type: BIGINT condition_source_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: true primary: false type: BIGINT condition_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS condition_start_date: nullable: false primary: false @@ -328,46 +304,46 @@ tables: condition_start_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 condition_status_concept_id: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS condition_status_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS condition_type_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: false primary: false type: BIGINT person_id: foreign_keys: - - person.person_id + - mimic100.person.person_id nullable: false primary: false type: BIGINT provider_id: foreign_keys: - - provider.provider_id + - mimic100.provider.provider_id nullable: true primary: false type: BIGINT stop_reason: nullable: true primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS visit_detail_id: foreign_keys: - - visit_detail.visit_detail_id + - mimic100.visit_detail.visit_detail_id nullable: true primary: false type: BIGINT visit_occurrence_id: foreign_keys: - - visit_occurrence.visit_occurrence_id + - mimic100.visit_occurrence.visit_occurrence_id nullable: true primary: false type: BIGINT @@ -377,13 +353,11 @@ tables: amount_allowed: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) cost_domain_id: - foreign_keys: - - domain.domain_id nullable: false primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS cost_event_id: nullable: false primary: false @@ -393,104 +367,92 @@ tables: primary: true type: BIGINT cost_type_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT currency_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT drg_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT drg_source_value: nullable: true primary: false - type: VARCHAR(3) + type: VARCHAR(3) COLLATE SQL_Latin1_General_CP1_CI_AS paid_by_patient: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) paid_by_payer: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) paid_by_primary: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) paid_dispensing_fee: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) paid_ingredient_cost: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) paid_patient_coinsurance: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) paid_patient_copay: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) paid_patient_deductible: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) payer_plan_period_id: nullable: true primary: false type: BIGINT revenue_code_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT revenue_code_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS total_charge: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) total_cost: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) total_paid: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) unique: [] death: columns: cause_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT cause_source_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT cause_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS death_date: nullable: false primary: false @@ -498,16 +460,12 @@ tables: death_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 death_type_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT person_id: - foreign_keys: - - person.person_id nullable: false primary: false type: BIGINT @@ -515,8 +473,6 @@ tables: device_exposure: columns: device_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -527,7 +483,7 @@ tables: device_exposure_end_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 device_exposure_id: nullable: false primary: true @@ -539,32 +495,24 @@ tables: device_exposure_start_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 device_source_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT device_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS device_type_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT person_id: - foreign_keys: - - person.person_id nullable: false primary: false type: BIGINT provider_id: - foreign_keys: - - provider.provider_id nullable: true primary: false type: BIGINT @@ -575,16 +523,12 @@ tables: unique_device_id: nullable: true primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS visit_detail_id: - foreign_keys: - - visit_detail.visit_detail_id nullable: true primary: false type: BIGINT visit_occurrence_id: - foreign_keys: - - visit_occurrence.visit_occurrence_id nullable: true primary: false type: BIGINT @@ -592,19 +536,17 @@ tables: domain: columns: domain_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT domain_id: nullable: false primary: true - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS domain_name: nullable: false primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS unique: [] dose_era: columns: @@ -623,22 +565,16 @@ tables: dose_value: nullable: false primary: false - type: NUMERIC + type: NUMERIC(18, 0) drug_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT person_id: - foreign_keys: - - person.person_id nullable: false primary: false type: BIGINT unit_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -646,8 +582,6 @@ tables: drug_era: columns: drug_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -672,8 +606,6 @@ tables: primary: false type: BIGINT person_id: - foreign_keys: - - person.person_id nullable: false primary: false type: BIGINT @@ -687,10 +619,10 @@ tables: dose_unit_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS drug_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: false primary: false type: BIGINT @@ -701,7 +633,7 @@ tables: drug_exposure_end_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 drug_exposure_id: nullable: false primary: true @@ -713,78 +645,78 @@ tables: drug_exposure_start_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 drug_source_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: true primary: false type: BIGINT drug_source_value: nullable: true primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS drug_type_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: false primary: false type: BIGINT lot_number: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS person_id: foreign_keys: - - person.person_id + - mimic100.person.person_id nullable: false primary: false type: BIGINT provider_id: foreign_keys: - - provider.provider_id + - mimic100.provider.provider_id nullable: true primary: false type: BIGINT quantity: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) refills: nullable: true primary: false type: BIGINT route_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: true primary: false type: BIGINT route_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS sig: nullable: true primary: false - type: TEXT + type: VARCHAR(max) COLLATE SQL_Latin1_General_CP1_CI_AS stop_reason: nullable: true primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS verbatim_end_date: nullable: true primary: false type: DATE visit_detail_id: foreign_keys: - - visit_detail.visit_detail_id + - mimic100.visit_detail.visit_detail_id nullable: true primary: false type: BIGINT visit_occurrence_id: foreign_keys: - - visit_occurrence.visit_occurrence_id + - mimic100.visit_occurrence.visit_occurrence_id nullable: true primary: false type: BIGINT @@ -792,55 +724,45 @@ tables: drug_strength: columns: amount_unit_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT amount_value: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) box_size: nullable: true primary: false type: BIGINT denominator_unit_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT denominator_value: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) drug_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT ingredient_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT invalid_reason: nullable: true primary: false - type: VARCHAR(1) + type: VARCHAR(1) COLLATE SQL_Latin1_General_CP1_CI_AS numerator_unit_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT numerator_value: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) valid_end_date: nullable: false primary: false @@ -853,8 +775,6 @@ tables: episode: columns: episode_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -865,7 +785,7 @@ tables: episode_end_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 episode_id: nullable: false primary: true @@ -875,8 +795,6 @@ tables: primary: false type: BIGINT episode_object_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -885,15 +803,13 @@ tables: primary: false type: BIGINT episode_source_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT episode_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS episode_start_date: nullable: false primary: false @@ -901,16 +817,12 @@ tables: episode_start_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 episode_type_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT person_id: - foreign_keys: - - person.person_id nullable: false primary: false type: BIGINT @@ -918,14 +830,10 @@ tables: episode_event: columns: episode_event_field_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT episode_id: - foreign_keys: - - episode.episode_id nullable: false primary: false type: BIGINT @@ -937,14 +845,10 @@ tables: fact_relationship: columns: domain_concept_id_1: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT domain_concept_id_2: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -957,8 +861,6 @@ tables: primary: false type: BIGINT relationship_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -968,19 +870,19 @@ tables: address_1: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS address_2: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS city: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS county: nullable: true primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS location_id: nullable: false primary: true @@ -988,21 +890,19 @@ tables: location_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS state: nullable: true primary: false - type: VARCHAR(2) + type: VARCHAR(2) COLLATE SQL_Latin1_General_CP1_CI_AS zip: nullable: true primary: false - type: VARCHAR(9) + type: VARCHAR(9) COLLATE SQL_Latin1_General_CP1_CI_AS unique: [] measurement: columns: measurement_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -1013,90 +913,72 @@ tables: measurement_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 measurement_id: nullable: false primary: true type: BIGINT measurement_source_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT measurement_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS measurement_time: nullable: true primary: false - type: VARCHAR(10) + type: VARCHAR(10) COLLATE SQL_Latin1_General_CP1_CI_AS measurement_type_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT operator_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT person_id: - foreign_keys: - - person.person_id nullable: false primary: false type: BIGINT provider_id: - foreign_keys: - - provider.provider_id nullable: true primary: false type: BIGINT range_high: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) range_low: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) unit_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT unit_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS value_as_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT value_as_number: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) value_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS visit_detail_id: - foreign_keys: - - visit_detail.visit_detail_id nullable: true primary: false type: BIGINT visit_occurrence_id: - foreign_keys: - - visit_occurrence.visit_occurrence_id nullable: true primary: false type: BIGINT @@ -1104,8 +986,6 @@ tables: metadata: columns: metadata_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -1116,53 +996,43 @@ tables: metadata_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 metadata_id: nullable: false primary: true type: BIGINT metadata_type_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT name: nullable: false primary: false - type: VARCHAR(250) + type: VARCHAR(250) COLLATE SQL_Latin1_General_CP1_CI_AS value_as_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT value_as_number: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) value_as_string: nullable: true primary: false - type: VARCHAR(250) + type: VARCHAR(250) COLLATE SQL_Latin1_General_CP1_CI_AS unique: [] note: columns: encoding_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT language_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT note_class_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -1173,10 +1043,8 @@ tables: note_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 note_event_field_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT @@ -1191,42 +1059,32 @@ tables: note_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS note_text: nullable: false primary: false - type: TEXT + type: VARCHAR(max) COLLATE SQL_Latin1_General_CP1_CI_AS note_title: nullable: true primary: false - type: VARCHAR(250) + type: VARCHAR(250) COLLATE SQL_Latin1_General_CP1_CI_AS note_type_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT person_id: - foreign_keys: - - person.person_id nullable: false primary: false type: BIGINT provider_id: - foreign_keys: - - provider.provider_id nullable: true primary: false type: BIGINT visit_detail_id: - foreign_keys: - - visit_detail.visit_detail_id nullable: true primary: false type: BIGINT visit_occurrence_id: - foreign_keys: - - visit_occurrence.visit_occurrence_id nullable: true primary: false type: BIGINT @@ -1236,7 +1094,7 @@ tables: lexical_variant: nullable: false primary: false - type: VARCHAR(250) + type: VARCHAR(250) COLLATE SQL_Latin1_General_CP1_CI_AS nlp_date: nullable: false primary: false @@ -1244,18 +1102,16 @@ tables: nlp_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 nlp_system: nullable: true primary: false - type: VARCHAR(250) + type: VARCHAR(250) COLLATE SQL_Latin1_General_CP1_CI_AS note_id: nullable: false primary: false type: BIGINT note_nlp_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT @@ -1264,43 +1120,37 @@ tables: primary: true type: BIGINT note_nlp_source_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT offset: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS section_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT snippet: nullable: true primary: false - type: VARCHAR(250) + type: VARCHAR(250) COLLATE SQL_Latin1_General_CP1_CI_AS term_exists: nullable: true primary: false - type: VARCHAR(1) + type: VARCHAR(1) COLLATE SQL_Latin1_General_CP1_CI_AS term_modifiers: nullable: true primary: false - type: VARCHAR(2000) + type: VARCHAR(2000) COLLATE SQL_Latin1_General_CP1_CI_AS term_temporal: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS unique: [] observation: columns: observation_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -1311,59 +1161,47 @@ tables: observation_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 observation_id: nullable: false primary: true type: BIGINT observation_source_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT observation_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS observation_type_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT person_id: - foreign_keys: - - person.person_id nullable: false primary: false type: BIGINT provider_id: - foreign_keys: - - provider.provider_id nullable: true primary: false type: BIGINT qualifier_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT qualifier_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS unit_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT unit_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS value_as_concept_id: nullable: true primary: false @@ -1371,20 +1209,16 @@ tables: value_as_number: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) value_as_string: nullable: true primary: false - type: VARCHAR(120) + type: VARCHAR(120) COLLATE SQL_Latin1_General_CP1_CI_AS visit_detail_id: - foreign_keys: - - visit_detail.visit_detail_id nullable: true primary: false type: BIGINT visit_occurrence_id: - foreign_keys: - - visit_occurrence.visit_occurrence_id nullable: true primary: false type: BIGINT @@ -1405,13 +1239,13 @@ tables: type: DATE period_type_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: false primary: false type: BIGINT person_id: foreign_keys: - - person.person_id + - mimic100.person.person_id nullable: false primary: false type: BIGINT @@ -1421,10 +1255,8 @@ tables: family_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS payer_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT @@ -1441,79 +1273,63 @@ tables: primary: false type: DATE payer_source_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT payer_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS person_id: - foreign_keys: - - person.person_id nullable: false primary: false type: BIGINT plan_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT plan_source_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT plan_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS sponsor_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT sponsor_source_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT sponsor_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS stop_reason_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT stop_reason_source_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT stop_reason_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS unique: [] person: columns: birth_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 care_site_id: foreign_keys: - - care_site.care_site_id + - mimic100.care_site.care_site_id nullable: true primary: false type: BIGINT @@ -1523,39 +1339,39 @@ tables: type: BIGINT ethnicity_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: false primary: false type: BIGINT ethnicity_source_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: true primary: false type: BIGINT ethnicity_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS gender_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: false primary: false type: BIGINT gender_source_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: true primary: false type: BIGINT gender_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS location_id: foreign_keys: - - location.location_id + - mimic100.location.location_id nullable: true primary: false type: BIGINT @@ -1570,29 +1386,29 @@ tables: person_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS provider_id: foreign_keys: - - provider.provider_id + - mimic100.provider.provider_id nullable: true primary: false type: BIGINT race_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: false primary: false type: BIGINT race_source_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: true primary: false type: BIGINT race_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS year_of_birth: nullable: false primary: false @@ -1601,18 +1417,16 @@ tables: procedure_occurrence: columns: modifier_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT modifier_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS person_id: foreign_keys: - - person.person_id + - mimic100.person.person_id nullable: false primary: false type: BIGINT @@ -1627,7 +1441,7 @@ tables: procedure_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 procedure_occurrence_id: nullable: false primary: true @@ -1639,16 +1453,12 @@ tables: procedure_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS procedure_type_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT provider_id: - foreign_keys: - - provider.provider_id nullable: true primary: false type: BIGINT @@ -1657,14 +1467,10 @@ tables: primary: false type: BIGINT visit_detail_id: - foreign_keys: - - visit_detail.visit_detail_id nullable: true primary: false type: BIGINT visit_occurrence_id: - foreign_keys: - - visit_occurrence.visit_occurrence_id nullable: true primary: false type: BIGINT @@ -1672,35 +1478,29 @@ tables: provider: columns: care_site_id: - foreign_keys: - - care_site.care_site_id nullable: true primary: false type: BIGINT dea: nullable: true primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS gender_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT gender_source_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT gender_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS npi: nullable: true primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS provider_id: nullable: false primary: true @@ -1708,27 +1508,23 @@ tables: provider_name: nullable: true primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS provider_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS specialty_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT specialty_source_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT specialty_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS year_of_birth: nullable: true primary: false @@ -1739,66 +1535,58 @@ tables: defines_ancestry: nullable: false primary: false - type: VARCHAR(1) + type: VARCHAR(1) COLLATE SQL_Latin1_General_CP1_CI_AS is_hierarchical: nullable: false primary: false - type: VARCHAR(1) + type: VARCHAR(1) COLLATE SQL_Latin1_General_CP1_CI_AS relationship_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT relationship_id: nullable: false primary: true - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS relationship_name: nullable: false primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS reverse_relationship_id: nullable: false primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS unique: [] source_to_concept_map: columns: invalid_reason: nullable: true primary: false - type: VARCHAR(1) + type: VARCHAR(1) COLLATE SQL_Latin1_General_CP1_CI_AS source_code: nullable: false primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS source_code_description: nullable: true primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS source_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT source_vocabulary_id: nullable: false primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS target_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT target_vocabulary_id: - foreign_keys: - - vocabulary.vocabulary_id nullable: false primary: false - type: VARCHAR(20) + type: VARCHAR(20) COLLATE SQL_Latin1_General_CP1_CI_AS valid_end_date: nullable: false primary: false @@ -1811,38 +1599,30 @@ tables: specimen: columns: anatomic_site_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT anatomic_site_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS disease_status_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT disease_status_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS person_id: - foreign_keys: - - person.person_id nullable: false primary: false type: BIGINT quantity: nullable: true primary: false - type: NUMERIC + type: NUMERIC(18, 0) specimen_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT @@ -1853,7 +1633,7 @@ tables: specimen_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 specimen_id: nullable: false primary: true @@ -1861,27 +1641,23 @@ tables: specimen_source_id: nullable: true primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS specimen_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS specimen_type_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT unit_concept_id: - foreign_keys: - - concept.concept_id nullable: true primary: false type: BIGINT unit_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS unique: [] visit_detail: columns: @@ -1892,42 +1668,44 @@ tables: admitting_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS care_site_id: foreign_keys: - - care_site.care_site_id + - mimic100.care_site.care_site_id nullable: true primary: false type: BIGINT discharge_to_concept_id: + foreign_keys: + - mimic100.concept.concept_id nullable: true primary: false type: BIGINT discharge_to_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS person_id: foreign_keys: - - person.person_id + - mimic100.person.person_id nullable: false primary: false type: BIGINT preceding_visit_detail_id: foreign_keys: - - visit_detail.visit_detail_id + - mimic100.visit_detail.visit_detail_id nullable: true primary: false type: BIGINT provider_id: foreign_keys: - - provider.provider_id + - mimic100.provider.provider_id nullable: true primary: false type: BIGINT visit_detail_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: false primary: false type: BIGINT @@ -1938,7 +1716,7 @@ tables: visit_detail_end_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 visit_detail_id: nullable: false primary: true @@ -1946,15 +1724,15 @@ tables: visit_detail_parent_id: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS visit_detail_source_concept_id: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS visit_detail_source_value: nullable: true primary: false - type: VARCHAR(120) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS visit_detail_start_date: nullable: false primary: false @@ -1962,16 +1740,16 @@ tables: visit_detail_start_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 visit_detail_type_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: false primary: false type: BIGINT visit_occurrence_id: foreign_keys: - - visit_occurrence.visit_occurrence_id + - mimic100.visit_occurrence.visit_occurrence_id nullable: false primary: false type: BIGINT @@ -1980,51 +1758,51 @@ tables: columns: admitted_from_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: true primary: false type: BIGINT admitted_from_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS care_site_id: foreign_keys: - - care_site.care_site_id + - mimic100.care_site.care_site_id nullable: true primary: false type: BIGINT discharged_to_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: true primary: false type: BIGINT discharged_to_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS person_id: foreign_keys: - - person.person_id + - mimic100.person.person_id nullable: false primary: false type: BIGINT preceding_visit_occurrence_id: foreign_keys: - - visit_occurrence.visit_occurrence_id + - mimic100.visit_occurrence.visit_occurrence_id nullable: true primary: false type: BIGINT provider_id: foreign_keys: - - provider.provider_id + - mimic100.provider.provider_id nullable: true primary: false type: BIGINT visit_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: false primary: false type: BIGINT @@ -2035,21 +1813,21 @@ tables: visit_end_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 visit_occurrence_id: nullable: false primary: true type: BIGINT visit_source_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: true primary: false type: BIGINT visit_source_value: nullable: true primary: false - type: VARCHAR(50) + type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS visit_start_date: nullable: false primary: false @@ -2057,10 +1835,10 @@ tables: visit_start_datetime: nullable: true primary: false - type: TIMESTAMP WITHOUT TIME ZONE + type: DATETIME2 visit_type_concept_id: foreign_keys: - - concept.concept_id + - mimic100.concept.concept_id nullable: false primary: false type: BIGINT @@ -2068,25 +1846,23 @@ tables: vocabulary: columns: vocabulary_concept_id: - foreign_keys: - - concept.concept_id nullable: false primary: false type: BIGINT vocabulary_id: nullable: false primary: true - type: VARCHAR(30) + type: VARCHAR(30) COLLATE SQL_Latin1_General_CP1_CI_AS vocabulary_name: nullable: false primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS vocabulary_reference: nullable: true primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS vocabulary_version: nullable: true primary: false - type: VARCHAR(255) + type: VARCHAR(255) COLLATE SQL_Latin1_General_CP1_CI_AS unique: [] diff --git a/examples/omop-mssql/sql/copy_vocabulary.sql b/examples/omop-mssql/sql/copy_vocabulary.sql new file mode 100644 index 0000000..7d531da --- /dev/null +++ b/examples/omop-mssql/sql/copy_vocabulary.sql @@ -0,0 +1,24 @@ +INSERT INTO mimic100_synthetic.concept ( + concept_class_id, + concept_code, + concept_id, + concept_name, + domain_id, + invalid_reason, + standard_concept, + valid_end_date, + valid_start_date, + vocabulary_id +) +SELECT + concept_class_id, + concept_code, + concept_id, + concept_name, + domain_id, + invalid_reason, + standard_concept, + valid_end_date, + valid_start_date, + vocabulary_id +FROM mimic100.concept; \ No newline at end of file From 1857e7666a1ee24eefcfb4da96ed50b6f65cae66 Mon Sep 17 00:00:00 2001 From: May Yong Date: Thu, 21 May 2026 15:57:30 +0100 Subject: [PATCH 21/45] Add omop-postgresql example and missing test fixture Co-Authored-By: Claude Sonnet 4.6 --- examples/omop-postgresql/README.md | 21 + examples/omop-postgresql/config.yaml | 10 + examples/omop-postgresql/config_template.yaml | 131 ++ examples/omop-postgresql/df.py | 126 + examples/omop-postgresql/orm.yaml | 127 + examples/omop-postgresql/orm_full.yaml | 2092 +++++++++++++++++ tests/examples/does-not-exist.yaml | 3 + 7 files changed, 2510 insertions(+) create mode 100644 examples/omop-postgresql/README.md create mode 100644 examples/omop-postgresql/config.yaml create mode 100644 examples/omop-postgresql/config_template.yaml create mode 100644 examples/omop-postgresql/df.py create mode 100644 examples/omop-postgresql/orm.yaml create mode 100644 examples/omop-postgresql/orm_full.yaml create mode 100644 tests/examples/does-not-exist.yaml diff --git a/examples/omop-postgresql/README.md b/examples/omop-postgresql/README.md new file mode 100644 index 0000000..bd04883 --- /dev/null +++ b/examples/omop-postgresql/README.md @@ -0,0 +1,21 @@ +# How to run datafaker process on omop schema + +1. Make a YAML file representing the tables in the schema + +`poetry run datafaker make-tables --orm-file ./examples/mimic_omop/orm.yaml` + +1. Create schema from the ORM YAML file + +`poetry run datafaker create-tables --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml` + +1. Create generator table + +`poetry run datafaker create-generators --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml --df-file ./examples/mimic_omop/df.py` + +1. Create data + +`poetry run datafaker create-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml --df-file .\examples\mimic_omop\df.py` + +1. Remove data + +`poetry run datafaker remove-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml` diff --git a/examples/omop-postgresql/config.yaml b/examples/omop-postgresql/config.yaml new file mode 100644 index 0000000..ce0204a --- /dev/null +++ b/examples/omop-postgresql/config.yaml @@ -0,0 +1,10 @@ +tables: + # Vocab tables + concept: + # This one is a vocab, but its too big to handle the usual way + ignore: false + vocabulary_table: true + + person: + num_rows_per_pass: 1 + diff --git a/examples/omop-postgresql/config_template.yaml b/examples/omop-postgresql/config_template.yaml new file mode 100644 index 0000000..fe7b265 --- /dev/null +++ b/examples/omop-postgresql/config_template.yaml @@ -0,0 +1,131 @@ +tables: + # Unnecessary tables + _measurement_links: + ignore: true + _observation_links: + ignore: true + _person_links: + ignore: true + _procedure_occurrence_links: + ignore: true + _visit_occurrence_links: + ignore: true + + # Vocab tables + concept: + # This one is a vocab, but its too big to handle the usual way + ignore: false + vocabulary_table: true + concept_ancestor: + # This one is a vocab, but its too big to handle the usual way + ignore: true + vocabulary_table: true + vocabulary: + vocabulary_table: true + domain: + vocabulary_table: true + concept_class: + vocabulary_table: true + concept_synonym: + # This one is a vocab, but its too big to handle the usual way + ignore: true + # vocabulary_table: true + concept_relationship: + # This one is a vocab, but its too big to handle the usual way + ignore: true + # vocabulary_table: true + drug_strength: + # This one is a vocab, but its too big to handle the usual way + ignore: true + # vocabulary_table: true + relationship: + vocabulary_table: true + source_to_concept_map: + vocabulary_table: true + location: + vocabulary_table: true + care_site: + vocabulary_table: true + provider: + vocabulary_table: true + cdm_source: + vocabulary_table: true + + # attribute_definition: + # num_rows_per_pass: 0 + + # cohort_definition: + # num_rows_per_pass: 0 + + # condition_era: + # num_rows_per_pass: 0 + + # cost: + # num_rows_per_pass: 0 + + # device_exposure: + # num_rows_per_pass: 0 + + # dose_era: + # num_rows_per_pass: 0 + + # drug_era: + # num_rows_per_pass: 0 + + # drug_exposure: + # num_rows_per_pass: 0 + + # fact_relationship: + # num_rows_per_pass: 0 + + # measurement: + # num_rows_per_pass: 0 + + # metadata: + # num_rows_per_pass: 0 + + # note: + # num_rows_per_pass: 0 + + # note_nlp: + # num_rows_per_pass: 0 + + # observation: + # num_rows_per_pass: 0 + + # observation_period: + # num_rows_per_pass: 0 + + # payer_plan_period: + # num_rows_per_pass: 0 + + # procedure_occurrence: + # num_rows_per_pass: 0 + # row_generators: + # - name: generic.null_provider.null + # columns_assigned: person_id + # - name: generic.column_value_provider.column_value + # columns_assigned: procedure_concept_id + # args: + # - dst_db_conn + # - metadata.tables["concept"] + # - '"concept_id"' + + + # specimen: + # num_rows_per_pass: 0 + + # visit_detail: + # num_rows_per_pass: 0 + + # visit_occurrence: + # num_rows_per_pass: 0 + + person: + num_rows_per_pass: 0 + + # death: + # num_rows_per_pass: 0 + + # condition_occurrence: + # num_rows_per_pass: 0 diff --git a/examples/omop-postgresql/df.py b/examples/omop-postgresql/df.py new file mode 100644 index 0000000..7557bab --- /dev/null +++ b/examples/omop-postgresql/df.py @@ -0,0 +1,126 @@ +"""This file was auto-generated by datafaker but can be edited manually.""" +from mimesis import Generic, Numeric, Person +from mimesis.locales import Locale +import sqlalchemy +import sys +from datafaker.base import FileUploader, TableGenerator, ColumnPresence +from datafaker.providers import DistributionProvider + +generic = Generic(locale=Locale.EN_GB) +numeric = Numeric() +person = Person() +dist_gen = DistributionProvider() +column_presence = ColumnPresence() + +sys.path.append("") + +from datafaker.providers import ( + BytesProvider, + ColumnValueProvider, + DistributionProvider, + NullProvider, + SQLGroupByProvider, + TimedeltaProvider, + TimespanProvider, + WeightedBooleanProvider, +) + +generic.add_provider(BytesProvider) +generic.add_provider(ColumnValueProvider) +generic.add_provider(DistributionProvider) +generic.add_provider(NullProvider) +generic.add_provider(SQLGroupByProvider) +generic.add_provider(TimedeltaProvider) +generic.add_provider(TimespanProvider) +generic.add_provider(WeightedBooleanProvider) + + +class PersonGenerator(TableGenerator): + num_rows_per_pass = 1 + + def __init__(self): + self.initialized = False + + def __call__(self, dst_db_conn, metadata): + if not self.initialized: + self.initialized = True + result = {} + columns_to_generate = set( + { + "ethnicity_source_value", + "race_concept_id", + "ethnicity_concept_id", + "day_of_birth", + "birth_datetime", + "ethnicity_source_concept_id", + "race_source_concept_id", + "year_of_birth", + "gender_source_concept_id", + "person_source_value", + "month_of_birth", + "race_source_value", + "gender_source_value", + "gender_concept_id", + } + ) + while columns_to_generate: + if "birth_datetime" in columns_to_generate: + result["birth_datetime"] = generic.datetime.datetime() + if "day_of_birth" in columns_to_generate: + result["day_of_birth"] = generic.numeric.integer_number() + if "ethnicity_concept_id" in columns_to_generate: + result[ + "ethnicity_concept_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) + if "ethnicity_source_concept_id" in columns_to_generate: + result[ + "ethnicity_source_concept_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) + if "ethnicity_source_value" in columns_to_generate: + result["ethnicity_source_value"] = generic.person.password(length=50) + if "gender_concept_id" in columns_to_generate: + result[ + "gender_concept_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) + if "gender_source_concept_id" in columns_to_generate: + result[ + "gender_source_concept_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) + if "gender_source_value" in columns_to_generate: + result["gender_source_value"] = generic.person.password(length=50) + if "month_of_birth" in columns_to_generate: + result["month_of_birth"] = generic.numeric.integer_number() + if "person_source_value" in columns_to_generate: + result["person_source_value"] = generic.person.password(length=50) + if "race_concept_id" in columns_to_generate: + result["race_concept_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) + if "race_source_concept_id" in columns_to_generate: + result[ + "race_source_concept_id" + ] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) + if "race_source_value" in columns_to_generate: + result["race_source_value"] = generic.person.password(length=50) + if "year_of_birth" in columns_to_generate: + result["year_of_birth"] = generic.numeric.integer_number() + columns_to_generate = set() + return result + + +table_generator_dict = { + "person": PersonGenerator(), +} + + +story_generator_list = [] diff --git a/examples/omop-postgresql/orm.yaml b/examples/omop-postgresql/orm.yaml new file mode 100644 index 0000000..59dc201 --- /dev/null +++ b/examples/omop-postgresql/orm.yaml @@ -0,0 +1,127 @@ +dsn: postgresql://postgres@localhost:5432/omop5.4 +schema: mimic +tables: + concept: + columns: + concept_class_id: + foreign_keys: + - concept_class.concept_class_id + nullable: false + primary: false + type: VARCHAR(20) + concept_code: + nullable: false + primary: false + type: VARCHAR(255) + concept_id: + nullable: false + primary: true + type: BIGINT + concept_name: + nullable: false + primary: false + type: VARCHAR(255) + domain_id: + foreign_keys: + - domain.domain_id + nullable: false + primary: false + type: VARCHAR(20) + invalid_reason: + nullable: true + primary: false + type: VARCHAR(1) + standard_concept: + nullable: true + primary: false + type: VARCHAR(1) + valid_end_date: + nullable: false + primary: false + type: DATE + valid_start_date: + nullable: false + primary: false + type: DATE + vocabulary_id: + foreign_keys: + - vocabulary.vocabulary_id + nullable: false + primary: false + type: VARCHAR(50) + unique: [] + person: + columns: + birth_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + day_of_birth: + nullable: true + primary: false + type: BIGINT + ethnicity_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + ethnicity_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + ethnicity_source_value: + nullable: true + primary: false + type: VARCHAR(50) + gender_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + gender_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + gender_source_value: + nullable: true + primary: false + type: VARCHAR(50) + month_of_birth: + nullable: true + primary: false + type: BIGINT + person_id: + nullable: false + primary: true + type: BIGINT + person_source_value: + nullable: true + primary: false + type: VARCHAR(50) + race_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + race_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + race_source_value: + nullable: true + primary: false + type: VARCHAR(50) + year_of_birth: + nullable: false + primary: false + type: BIGINT + unique: [] diff --git a/examples/omop-postgresql/orm_full.yaml b/examples/omop-postgresql/orm_full.yaml new file mode 100644 index 0000000..a400553 --- /dev/null +++ b/examples/omop-postgresql/orm_full.yaml @@ -0,0 +1,2092 @@ +dsn: postgresql://postgres@localhost:5432/omop5.4 +schema: mimic +tables: + care_site: + columns: + care_site_id: + nullable: false + primary: true + type: BIGINT + care_site_name: + nullable: true + primary: false + type: VARCHAR(255) + care_site_source_value: + nullable: true + primary: false + type: VARCHAR(50) + location_id: + foreign_keys: + - location.location_id + nullable: true + primary: false + type: BIGINT + place_of_service_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + place_of_service_source_value: + nullable: true + primary: false + type: VARCHAR(50) + unique: [] + cdm_source: + columns: + cdm_etl_reference: + nullable: true + primary: false + type: VARCHAR(255) + cdm_holder: + nullable: false + primary: false + type: VARCHAR(255) + cdm_release_date: + nullable: false + primary: false + type: DATE + cdm_source_abbreviation: + nullable: false + primary: false + type: VARCHAR(25) + cdm_source_name: + nullable: false + primary: false + type: VARCHAR(255) + cdm_version: + nullable: true + primary: false + type: VARCHAR(10) + source_description: + nullable: true + primary: false + type: TEXT + source_documentation_reference: + nullable: true + primary: false + type: VARCHAR(255) + source_release_date: + nullable: false + primary: false + type: DATE + vocabulary_version: + nullable: false + primary: false + type: VARCHAR(20) + unique: [] + cohort: + columns: + cohort_definition_id: + nullable: false + primary: false + type: BIGINT + cohort_end_date: + nullable: false + primary: false + type: DATE + cohort_start_date: + nullable: false + primary: false + type: DATE + subject_id: + nullable: false + primary: false + type: BIGINT + unique: [] + cohort_definition: + columns: + cohort_definition_description: + nullable: true + primary: false + type: TEXT + cohort_definition_id: + nullable: false + primary: false + type: BIGINT + cohort_definition_name: + nullable: false + primary: false + type: VARCHAR(255) + cohort_definition_syntax: + nullable: true + primary: false + type: TEXT + cohort_initiation_date: + nullable: true + primary: false + type: DATE + definition_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + subject_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + unique: [] + concept: + columns: + concept_class_id: + foreign_keys: + - concept_class.concept_class_id + nullable: false + primary: false + type: VARCHAR(20) + concept_code: + nullable: false + primary: false + type: VARCHAR(255) + concept_id: + nullable: false + primary: true + type: BIGINT + concept_name: + nullable: false + primary: false + type: VARCHAR(255) + domain_id: + foreign_keys: + - domain.domain_id + nullable: false + primary: false + type: VARCHAR(20) + invalid_reason: + nullable: true + primary: false + type: VARCHAR(1) + standard_concept: + nullable: true + primary: false + type: VARCHAR(1) + valid_end_date: + nullable: false + primary: false + type: DATE + valid_start_date: + nullable: false + primary: false + type: DATE + vocabulary_id: + foreign_keys: + - vocabulary.vocabulary_id + nullable: false + primary: false + type: VARCHAR(50) + unique: [] + concept_ancestor: + columns: + ancestor_concept_id: + nullable: false + primary: false + type: BIGINT + descendant_concept_id: + nullable: false + primary: false + type: BIGINT + max_levels_of_separation: + nullable: false + primary: false + type: BIGINT + min_levels_of_separation: + nullable: false + primary: false + type: BIGINT + unique: [] + concept_class: + columns: + concept_class_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + concept_class_id: + nullable: false + primary: true + type: VARCHAR(20) + concept_class_name: + nullable: false + primary: false + type: VARCHAR(255) + unique: [] + concept_relationship: + columns: + concept_id_1: + nullable: false + primary: false + type: BIGINT + concept_id_2: + nullable: false + primary: false + type: BIGINT + invalid_reason: + nullable: true + primary: false + type: VARCHAR(1) + relationship_id: + foreign_keys: + - relationship.relationship_id + nullable: false + primary: false + type: VARCHAR(20) + valid_end_date: + nullable: false + primary: false + type: DATE + valid_start_date: + nullable: false + primary: false + type: DATE + unique: [] + concept_synonym: + columns: + concept_id: + nullable: false + primary: false + type: BIGINT + concept_synonym_name: + nullable: false + primary: false + type: VARCHAR(1000) + language_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + unique: [] + condition_era: + columns: + condition_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + condition_era_end_date: + nullable: false + primary: false + type: DATE + condition_era_id: + nullable: false + primary: true + type: BIGINT + condition_era_start_date: + nullable: false + primary: false + type: DATE + condition_occurrence_count: + nullable: true + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + unique: [] + condition_occurrence: + columns: + condition_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + condition_end_date: + nullable: true + primary: false + type: DATE + condition_end_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + condition_occurrence_id: + nullable: false + primary: true + type: BIGINT + condition_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + condition_source_value: + nullable: true + primary: false + type: VARCHAR(50) + condition_start_date: + nullable: false + primary: false + type: DATE + condition_start_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + condition_status_concept_id: + nullable: true + primary: false + type: VARCHAR(50) + condition_status_source_value: + nullable: true + primary: false + type: VARCHAR(50) + condition_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + stop_reason: + nullable: true + primary: false + type: VARCHAR(20) + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + cost: + columns: + amount_allowed: + nullable: true + primary: false + type: NUMERIC + cost_domain_id: + foreign_keys: + - domain.domain_id + nullable: false + primary: false + type: VARCHAR(20) + cost_event_id: + nullable: false + primary: false + type: BIGINT + cost_id: + nullable: false + primary: true + type: BIGINT + cost_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + currency_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + drg_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + drg_source_value: + nullable: true + primary: false + type: VARCHAR(3) + paid_by_patient: + nullable: true + primary: false + type: NUMERIC + paid_by_payer: + nullable: true + primary: false + type: NUMERIC + paid_by_primary: + nullable: true + primary: false + type: NUMERIC + paid_dispensing_fee: + nullable: true + primary: false + type: NUMERIC + paid_ingredient_cost: + nullable: true + primary: false + type: NUMERIC + paid_patient_coinsurance: + nullable: true + primary: false + type: NUMERIC + paid_patient_copay: + nullable: true + primary: false + type: NUMERIC + paid_patient_deductible: + nullable: true + primary: false + type: NUMERIC + payer_plan_period_id: + nullable: true + primary: false + type: BIGINT + revenue_code_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + revenue_code_source_value: + nullable: true + primary: false + type: VARCHAR(50) + total_charge: + nullable: true + primary: false + type: NUMERIC + total_cost: + nullable: true + primary: false + type: NUMERIC + total_paid: + nullable: true + primary: false + type: NUMERIC + unique: [] + death: + columns: + cause_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + cause_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + cause_source_value: + nullable: true + primary: false + type: VARCHAR(50) + death_date: + nullable: false + primary: false + type: DATE + death_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + death_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + unique: [] + device_exposure: + columns: + device_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + device_exposure_end_date: + nullable: true + primary: false + type: DATE + device_exposure_end_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + device_exposure_id: + nullable: false + primary: true + type: BIGINT + device_exposure_start_date: + nullable: false + primary: false + type: DATE + device_exposure_start_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + device_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + device_source_value: + nullable: true + primary: false + type: VARCHAR(50) + device_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + quantity: + nullable: true + primary: false + type: BIGINT + unique_device_id: + nullable: true + primary: false + type: VARCHAR(255) + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + domain: + columns: + domain_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + domain_id: + nullable: false + primary: true + type: VARCHAR(20) + domain_name: + nullable: false + primary: false + type: VARCHAR(255) + unique: [] + dose_era: + columns: + dose_era_end_date: + nullable: false + primary: false + type: DATE + dose_era_id: + nullable: false + primary: true + type: BIGINT + dose_era_start_date: + nullable: false + primary: false + type: DATE + dose_value: + nullable: false + primary: false + type: NUMERIC + drug_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + unique: [] + drug_era: + columns: + drug_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + drug_era_end_date: + nullable: false + primary: false + type: DATE + drug_era_id: + nullable: false + primary: true + type: BIGINT + drug_era_start_date: + nullable: false + primary: false + type: DATE + drug_exposure_count: + nullable: true + primary: false + type: BIGINT + gap_days: + nullable: true + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + unique: [] + drug_exposure: + columns: + days_supply: + nullable: true + primary: false + type: BIGINT + dose_unit_source_value: + nullable: true + primary: false + type: VARCHAR(50) + drug_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + drug_exposure_end_date: + nullable: false + primary: false + type: DATE + drug_exposure_end_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + drug_exposure_id: + nullable: false + primary: true + type: BIGINT + drug_exposure_start_date: + nullable: false + primary: false + type: DATE + drug_exposure_start_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + drug_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + drug_source_value: + nullable: true + primary: false + type: VARCHAR(255) + drug_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + lot_number: + nullable: true + primary: false + type: VARCHAR(50) + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + quantity: + nullable: true + primary: false + type: NUMERIC + refills: + nullable: true + primary: false + type: BIGINT + route_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + route_source_value: + nullable: true + primary: false + type: VARCHAR(50) + sig: + nullable: true + primary: false + type: TEXT + stop_reason: + nullable: true + primary: false + type: VARCHAR(20) + verbatim_end_date: + nullable: true + primary: false + type: DATE + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + drug_strength: + columns: + amount_unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + amount_value: + nullable: true + primary: false + type: NUMERIC + box_size: + nullable: true + primary: false + type: BIGINT + denominator_unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + denominator_value: + nullable: true + primary: false + type: NUMERIC + drug_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + ingredient_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + invalid_reason: + nullable: true + primary: false + type: VARCHAR(1) + numerator_unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + numerator_value: + nullable: true + primary: false + type: NUMERIC + valid_end_date: + nullable: false + primary: false + type: DATE + valid_start_date: + nullable: false + primary: false + type: DATE + unique: [] + episode: + columns: + episode_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + episode_end_date: + nullable: true + primary: false + type: DATE + episode_end_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + episode_id: + nullable: false + primary: true + type: BIGINT + episode_number: + nullable: true + primary: false + type: BIGINT + episode_object_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + episode_parent_id: + nullable: true + primary: false + type: BIGINT + episode_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + episode_source_value: + nullable: true + primary: false + type: VARCHAR(50) + episode_start_date: + nullable: false + primary: false + type: DATE + episode_start_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + episode_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + unique: [] + episode_event: + columns: + episode_event_field_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + episode_id: + foreign_keys: + - episode.episode_id + nullable: false + primary: false + type: BIGINT + event_id: + nullable: false + primary: false + type: BIGINT + unique: [] + fact_relationship: + columns: + domain_concept_id_1: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + domain_concept_id_2: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + fact_id_1: + nullable: false + primary: false + type: BIGINT + fact_id_2: + nullable: false + primary: false + type: BIGINT + relationship_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + unique: [] + location: + columns: + address_1: + nullable: true + primary: false + type: VARCHAR(50) + address_2: + nullable: true + primary: false + type: VARCHAR(50) + city: + nullable: true + primary: false + type: VARCHAR(50) + county: + nullable: true + primary: false + type: VARCHAR(20) + location_id: + nullable: false + primary: true + type: BIGINT + location_source_value: + nullable: true + primary: false + type: VARCHAR(50) + state: + nullable: true + primary: false + type: VARCHAR(2) + zip: + nullable: true + primary: false + type: VARCHAR(9) + unique: [] + measurement: + columns: + measurement_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + measurement_date: + nullable: false + primary: false + type: DATE + measurement_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + measurement_id: + nullable: false + primary: true + type: BIGINT + measurement_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + measurement_source_value: + nullable: true + primary: false + type: VARCHAR(50) + measurement_time: + nullable: true + primary: false + type: VARCHAR(10) + measurement_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + operator_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + range_high: + nullable: true + primary: false + type: NUMERIC + range_low: + nullable: true + primary: false + type: NUMERIC + unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + unit_source_value: + nullable: true + primary: false + type: VARCHAR(50) + value_as_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + value_as_number: + nullable: true + primary: false + type: NUMERIC + value_source_value: + nullable: true + primary: false + type: VARCHAR(50) + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + metadata: + columns: + metadata_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + metadata_date: + nullable: true + primary: false + type: DATE + metadata_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + metadata_id: + nullable: false + primary: true + type: BIGINT + metadata_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + name: + nullable: false + primary: false + type: VARCHAR(250) + value_as_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + value_as_number: + nullable: true + primary: false + type: NUMERIC + value_as_string: + nullable: true + primary: false + type: VARCHAR(250) + unique: [] + note: + columns: + encoding_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + language_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + note_class_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + note_date: + nullable: false + primary: false + type: DATE + note_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + note_event_field_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + note_event_id: + nullable: true + primary: false + type: BIGINT + note_id: + nullable: false + primary: true + type: BIGINT + note_source_value: + nullable: true + primary: false + type: VARCHAR(50) + note_text: + nullable: false + primary: false + type: TEXT + note_title: + nullable: true + primary: false + type: VARCHAR(250) + note_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + note_nlp: + columns: + lexical_variant: + nullable: false + primary: false + type: VARCHAR(250) + nlp_date: + nullable: false + primary: false + type: DATE + nlp_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + nlp_system: + nullable: true + primary: false + type: VARCHAR(250) + note_id: + nullable: false + primary: false + type: BIGINT + note_nlp_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + note_nlp_id: + nullable: false + primary: true + type: BIGINT + note_nlp_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + offset: + nullable: true + primary: false + type: VARCHAR(50) + section_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + snippet: + nullable: true + primary: false + type: VARCHAR(250) + term_exists: + nullable: true + primary: false + type: VARCHAR(1) + term_modifiers: + nullable: true + primary: false + type: VARCHAR(2000) + term_temporal: + nullable: true + primary: false + type: VARCHAR(50) + unique: [] + observation: + columns: + observation_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + observation_date: + nullable: false + primary: false + type: DATE + observation_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + observation_id: + nullable: false + primary: true + type: BIGINT + observation_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + observation_source_value: + nullable: true + primary: false + type: VARCHAR(50) + observation_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + qualifier_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + qualifier_source_value: + nullable: true + primary: false + type: VARCHAR(50) + unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + unit_source_value: + nullable: true + primary: false + type: VARCHAR(50) + value_as_concept_id: + nullable: true + primary: false + type: BIGINT + value_as_number: + nullable: true + primary: false + type: NUMERIC + value_as_string: + nullable: true + primary: false + type: VARCHAR(120) + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + observation_period: + columns: + observation_period_end_date: + nullable: false + primary: false + type: DATE + observation_period_id: + nullable: false + primary: true + type: BIGINT + observation_period_start_date: + nullable: false + primary: false + type: DATE + period_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + unique: [] + payer_plan_period: + columns: + family_source_value: + nullable: true + primary: false + type: VARCHAR(50) + payer_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + payer_plan_period_end_date: + nullable: false + primary: false + type: DATE + payer_plan_period_id: + nullable: false + primary: true + type: BIGINT + payer_plan_period_start_date: + nullable: false + primary: false + type: DATE + payer_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + payer_source_value: + nullable: true + primary: false + type: VARCHAR(50) + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + plan_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + plan_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + plan_source_value: + nullable: true + primary: false + type: VARCHAR(50) + sponsor_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + sponsor_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + sponsor_source_value: + nullable: true + primary: false + type: VARCHAR(50) + stop_reason_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + stop_reason_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + stop_reason_source_value: + nullable: true + primary: false + type: VARCHAR(50) + unique: [] + person: + columns: + birth_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + care_site_id: + foreign_keys: + - care_site.care_site_id + nullable: true + primary: false + type: BIGINT + day_of_birth: + nullable: true + primary: false + type: BIGINT + ethnicity_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + ethnicity_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + ethnicity_source_value: + nullable: true + primary: false + type: VARCHAR(50) + gender_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + gender_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + gender_source_value: + nullable: true + primary: false + type: VARCHAR(50) + location_id: + foreign_keys: + - location.location_id + nullable: true + primary: false + type: BIGINT + month_of_birth: + nullable: true + primary: false + type: BIGINT + person_id: + nullable: false + primary: true + type: BIGINT + person_source_value: + nullable: true + primary: false + type: VARCHAR(50) + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + race_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + race_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + race_source_value: + nullable: true + primary: false + type: VARCHAR(50) + year_of_birth: + nullable: false + primary: false + type: BIGINT + unique: [] + procedure_occurrence: + columns: + modifier_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + modifier_source_value: + nullable: true + primary: false + type: VARCHAR(50) + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + procedure_concept_id: + nullable: false + primary: false + type: BIGINT + procedure_date: + nullable: false + primary: false + type: DATE + procedure_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + procedure_occurrence_id: + nullable: false + primary: true + type: BIGINT + procedure_source_concept_id: + nullable: true + primary: false + type: BIGINT + procedure_source_value: + nullable: true + primary: false + type: VARCHAR(50) + procedure_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + quantity: + nullable: true + primary: false + type: BIGINT + visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + unique: [] + provider: + columns: + care_site_id: + foreign_keys: + - care_site.care_site_id + nullable: true + primary: false + type: BIGINT + dea: + nullable: true + primary: false + type: VARCHAR(20) + gender_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + gender_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + gender_source_value: + nullable: true + primary: false + type: VARCHAR(50) + npi: + nullable: true + primary: false + type: VARCHAR(20) + provider_id: + nullable: false + primary: true + type: BIGINT + provider_name: + nullable: true + primary: false + type: VARCHAR(255) + provider_source_value: + nullable: true + primary: false + type: VARCHAR(50) + specialty_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + specialty_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + specialty_source_value: + nullable: true + primary: false + type: VARCHAR(50) + year_of_birth: + nullable: true + primary: false + type: BIGINT + unique: [] + relationship: + columns: + defines_ancestry: + nullable: false + primary: false + type: VARCHAR(1) + is_hierarchical: + nullable: false + primary: false + type: VARCHAR(1) + relationship_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + relationship_id: + nullable: false + primary: true + type: VARCHAR(20) + relationship_name: + nullable: false + primary: false + type: VARCHAR(255) + reverse_relationship_id: + nullable: false + primary: false + type: VARCHAR(20) + unique: [] + source_to_concept_map: + columns: + invalid_reason: + nullable: true + primary: false + type: VARCHAR(1) + source_code: + nullable: false + primary: false + type: VARCHAR(50) + source_code_description: + nullable: true + primary: false + type: VARCHAR(255) + source_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + source_vocabulary_id: + nullable: false + primary: false + type: VARCHAR(20) + target_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + target_vocabulary_id: + foreign_keys: + - vocabulary.vocabulary_id + nullable: false + primary: false + type: VARCHAR(20) + valid_end_date: + nullable: false + primary: false + type: DATE + valid_start_date: + nullable: false + primary: false + type: DATE + unique: [] + specimen: + columns: + anatomic_site_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + anatomic_site_source_value: + nullable: true + primary: false + type: VARCHAR(50) + disease_status_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + disease_status_source_value: + nullable: true + primary: false + type: VARCHAR(50) + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + quantity: + nullable: true + primary: false + type: NUMERIC + specimen_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + specimen_date: + nullable: false + primary: false + type: DATE + specimen_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + specimen_id: + nullable: false + primary: true + type: BIGINT + specimen_source_id: + nullable: true + primary: false + type: VARCHAR(255) + specimen_source_value: + nullable: true + primary: false + type: VARCHAR(50) + specimen_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + unit_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + unit_source_value: + nullable: true + primary: false + type: VARCHAR(50) + unique: [] + visit_detail: + columns: + admitting_source_concept_id: + nullable: true + primary: false + type: BIGINT + admitting_source_value: + nullable: true + primary: false + type: VARCHAR(50) + care_site_id: + foreign_keys: + - care_site.care_site_id + nullable: true + primary: false + type: BIGINT + discharge_to_concept_id: + nullable: true + primary: false + type: BIGINT + discharge_to_source_value: + nullable: true + primary: false + type: VARCHAR(50) + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + preceding_visit_detail_id: + foreign_keys: + - visit_detail.visit_detail_id + nullable: true + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + visit_detail_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + visit_detail_end_date: + nullable: false + primary: false + type: DATE + visit_detail_end_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + visit_detail_id: + nullable: false + primary: true + type: BIGINT + visit_detail_parent_id: + nullable: true + primary: false + type: VARCHAR(50) + visit_detail_source_concept_id: + nullable: true + primary: false + type: VARCHAR(50) + visit_detail_source_value: + nullable: true + primary: false + type: VARCHAR(120) + visit_detail_start_date: + nullable: false + primary: false + type: DATE + visit_detail_start_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + visit_detail_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: false + primary: false + type: BIGINT + unique: [] + visit_occurrence: + columns: + admitted_from_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + admitted_from_source_value: + nullable: true + primary: false + type: VARCHAR(50) + care_site_id: + foreign_keys: + - care_site.care_site_id + nullable: true + primary: false + type: BIGINT + discharged_to_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + discharged_to_source_value: + nullable: true + primary: false + type: VARCHAR(50) + person_id: + foreign_keys: + - person.person_id + nullable: false + primary: false + type: BIGINT + preceding_visit_occurrence_id: + foreign_keys: + - visit_occurrence.visit_occurrence_id + nullable: true + primary: false + type: BIGINT + provider_id: + foreign_keys: + - provider.provider_id + nullable: true + primary: false + type: BIGINT + visit_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + visit_end_date: + nullable: false + primary: false + type: DATE + visit_end_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + visit_occurrence_id: + nullable: false + primary: true + type: BIGINT + visit_source_concept_id: + foreign_keys: + - concept.concept_id + nullable: true + primary: false + type: BIGINT + visit_source_value: + nullable: true + primary: false + type: VARCHAR(50) + visit_start_date: + nullable: false + primary: false + type: DATE + visit_start_datetime: + nullable: true + primary: false + type: TIMESTAMP WITHOUT TIME ZONE + visit_type_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + unique: [] + vocabulary: + columns: + vocabulary_concept_id: + foreign_keys: + - concept.concept_id + nullable: false + primary: false + type: BIGINT + vocabulary_id: + nullable: false + primary: true + type: VARCHAR(30) + vocabulary_name: + nullable: false + primary: false + type: VARCHAR(255) + vocabulary_reference: + nullable: true + primary: false + type: VARCHAR(255) + vocabulary_version: + nullable: true + primary: false + type: VARCHAR(255) + unique: [] diff --git a/tests/examples/does-not-exist.yaml b/tests/examples/does-not-exist.yaml new file mode 100644 index 0000000..d891803 --- /dev/null +++ b/tests/examples/does-not-exist.yaml @@ -0,0 +1,3 @@ +dsn: postgresql://postgres@localhost:5432/omop5.4 +schema: myschema +tables: {} From 363725876d2d16a469197c25c03d7210d49b95ff Mon Sep 17 00:00:00 2001 From: May Yong Date: Thu, 21 May 2026 16:43:39 +0100 Subject: [PATCH 22/45] Fix dialect-specific SQL in generator commands (closes #105) Replace PostgreSQL-only raw SQL in configure-generators with SQLAlchemy expression API so the same code works on all supported dialects: - generators/mimesis.py: use sqlalchemy.extract() + cast() instead of EXTRACT(YEAR FROM ...) string; compiled SQL strings stored on MimesisDateTimeGenerator now use DATEPART(year,...) on MS-SQL and EXTRACT(YEAR FROM ...) on PostgreSQL/DuckDB. - generators/base.py: use func.stdev on MS-SQL and func.stddev elsewhere instead of the hard-coded STDDEV() string that MS-SQL does not recognise. - make.py: remove dead _YEAR_SUMMARY_QUERY constant and GeneratorInfo.summary_query field (stored but never read anywhere in the codebase). - tests/test_generators_dialect.py: new tests asserting that the compiled SQL contains the correct function name per dialect. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/generators/base.py | 17 ++--- datafaker/generators/mimesis.py | 21 +++--- datafaker/make.py | 13 +--- tests/test_generators_dialect.py | 116 +++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 29 deletions(-) create mode 100644 tests/test_generators_dialect.py diff --git a/datafaker/generators/base.py b/datafaker/generators/base.py index 0ded64c..1019e7f 100644 --- a/datafaker/generators/base.py +++ b/datafaker/generators/base.py @@ -8,7 +8,7 @@ import mimesis import mimesis.locales import sqlalchemy -from sqlalchemy import Column, Engine, text +from sqlalchemy import Column, Engine, func, literal_column, select, table, text from sqlalchemy.types import Integer, Numeric, String, TypeEngine from typing_extensions import Self @@ -319,14 +319,15 @@ def make_buckets( infinity). Each bucket will be set to the count of the number of values in the column within that bucket. """ + col = literal_column(column_name) + stddev_fn = func.stdev if engine.dialect.name == "mssql" else func.stddev + stmt = select( + func.avg(col).label("mean"), + stddev_fn(col).label("stddev"), + func.count(col).label("count"), + ).select_from(table(table_name)) with engine.connect() as connection: - result = connection.execute( - text( - f"SELECT AVG({column_name}) AS mean," - f" STDDEV({column_name}) AS stddev," - f" COUNT({column_name}) AS count FROM {table_name}" - ) - ).first() + result = connection.execute(stmt).first() if result is None or result.stddev is None or getattr(result, "count") < 2: return None try: diff --git a/datafaker/generators/mimesis.py b/datafaker/generators/mimesis.py index 78894ea..77b1582 100644 --- a/datafaker/generators/mimesis.py +++ b/datafaker/generators/mimesis.py @@ -4,7 +4,7 @@ import mimesis import mimesis.locales -from sqlalchemy import Column, Engine, text +from sqlalchemy import Column, Engine, cast, extract, func, literal_column, select from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.types import Date, DateTime, Integer, Numeric, String, Time @@ -186,17 +186,20 @@ def make_singleton( cls, column: Column, engine: Engine, function_name: str ) -> Sequence[Generator]: """Make the appropriate generation configuration for this column.""" - extract_year = f"CAST(EXTRACT(YEAR FROM {column.name}) AS INT)" - max_year = f"MAX({extract_year})" - min_year = f"MIN({extract_year})" + col_expr = literal_column(column.name) + year_expr = cast(extract("year", col_expr), Integer()) + min_expr = func.min(year_expr) + max_expr = func.max(year_expr) + stmt = select(min_expr.label("start"), max_expr.label("end")).select_from( + column.table + ) with engine.connect() as connection: - result = connection.execute( - text( - f"SELECT {min_year} AS start, {max_year} AS end FROM {column.table.name}" - ) - ).first() + result = connection.execute(stmt).first() if result is None or result.start is None or result.end is None: return [] + dialect = engine.dialect + min_year = str(min_expr.compile(dialect=dialect, compile_kwargs={"literal_binds": True})) + max_year = str(max_expr.compile(dialect=dialect, compile_kwargs={"literal_binds": True})) return [ MimesisDateTimeGenerator( column, diff --git a/datafaker/make.py b/datafaker/make.py index 1c272bb..403981d 100644 --- a/datafaker/make.py +++ b/datafaker/make.py @@ -315,22 +315,13 @@ def _integer_generator(column: Column) -> tuple[str, dict[str, str]]: return ("generic.numeric.integer_number", {}) -_YEAR_SUMMARY_QUERY = ( - "SELECT MIN(y) AS start, MAX(y) AS end FROM " - "(SELECT EXTRACT(YEAR FROM {column}) AS y FROM {table}) AS years" -) - - @dataclass class GeneratorInfo: """Description of a generator.""" # Name or function to generate random objects of this type (not using summary data) generator: str | Callable[[Column], tuple[str, dict[str, str]]] - # SQL query that gets the data to supply as arguments to the generator - # ({column} and {table} will be interpolated) - summary_query: str | None = None - # Dictionary of the names returned from the summary_query to arg types. + # Dictionary of arg types for any summary query. # An arg type is a callable turning the returned value into a Python type to # pass as an argument to the generator. arg_types: dict[str, Callable] = field(default_factory=dict) @@ -367,12 +358,10 @@ def get_result_mappings( ), sqltypes.Date: GeneratorInfo( generator="generic.datetime.date", - summary_query=_YEAR_SUMMARY_QUERY, arg_types={"start": int, "end": int}, ), sqltypes.DateTime: GeneratorInfo( generator="generic.datetime.datetime", - summary_query=_YEAR_SUMMARY_QUERY, arg_types={"start": int, "end": int}, ), sqltypes.Integer: GeneratorInfo( # must be before Numeric diff --git a/tests/test_generators_dialect.py b/tests/test_generators_dialect.py new file mode 100644 index 0000000..b9a6a71 --- /dev/null +++ b/tests/test_generators_dialect.py @@ -0,0 +1,116 @@ +"""Tests for dialect-correct SQL in generator classes.""" +import unittest +from unittest.mock import MagicMock + +from sqlalchemy import Column, Integer, MetaData, Table +from sqlalchemy.dialects import mssql, postgresql +from sqlalchemy.types import DateTime + + +class TestMimesisDateTimeDialect(unittest.TestCase): + """MimesisDateTimeGenerator.make_singleton compiles year expressions per dialect.""" + + def _make_column(self) -> Column: + meta = MetaData() + t = Table("person", meta, Column("birth_datetime", DateTime())) + return t.c.birth_datetime + + def _make_engine(self, dialect) -> MagicMock: + engine = MagicMock() + engine.dialect = dialect() + result = MagicMock() + result.start = 1950 + result.end = 2000 + conn = MagicMock() + conn.__enter__ = MagicMock(return_value=conn) + conn.__exit__ = MagicMock(return_value=False) + conn.execute.return_value.first.return_value = result + engine.connect.return_value = conn + return engine + + def test_postgresql_uses_extract(self) -> None: + """PostgreSQL year clause uses EXTRACT.""" + from datafaker.generators.mimesis import MimesisDateTimeGenerator + + column = self._make_column() + engine = self._make_engine(postgresql.dialect) + gens = MimesisDateTimeGenerator.make_singleton(column, engine, "datetime.datetime") + self.assertEqual(len(gens), 1) + clauses = gens[0].select_aggregate_clauses() + min_clause = clauses["birth_datetime__start"]["clause"] + max_clause = clauses["birth_datetime__end"]["clause"] + self.assertIn("EXTRACT", min_clause.upper()) + self.assertIn("EXTRACT", max_clause.upper()) + self.assertNotIn("DATEPART", min_clause.upper()) + + def test_mssql_uses_datepart(self) -> None: + """MS-SQL year clause uses DATEPART.""" + from datafaker.generators.mimesis import MimesisDateTimeGenerator + + column = self._make_column() + engine = self._make_engine(mssql.dialect) + gens = MimesisDateTimeGenerator.make_singleton(column, engine, "datetime.datetime") + self.assertEqual(len(gens), 1) + clauses = gens[0].select_aggregate_clauses() + min_clause = clauses["birth_datetime__start"]["clause"] + max_clause = clauses["birth_datetime__end"]["clause"] + self.assertIn("DATEPART", min_clause.upper()) + self.assertIn("DATEPART", max_clause.upper()) + self.assertNotIn("EXTRACT", min_clause.upper()) + + +class TestBucketsStddevDialect(unittest.TestCase): + """Buckets.make_buckets uses STDEV on MS-SQL and STDDEV on other dialects.""" + + def _make_engine_with_dialect_name(self, dialect_name: str) -> MagicMock: + engine = MagicMock() + engine.dialect.name = dialect_name + result = MagicMock() + result.stddev = 5.0 + result.mean = 42.0 + # count attribute via getattr + result.configure_mock(**{"count": 100}) + conn = MagicMock() + conn.__enter__ = MagicMock(return_value=conn) + conn.__exit__ = MagicMock(return_value=False) + conn.execute.return_value.first.return_value = result + engine.connect.return_value = conn + return engine + + def _get_executed_sql(self, dialect_name: str) -> str: + from datafaker.generators.base import Buckets + + engine = self._make_engine_with_dialect_name(dialect_name) + # make_buckets will call engine.connect().execute(stmt) + # We patch it to capture the compiled SQL + executed_stmts = [] + orig_execute = engine.connect.return_value.execute + + def capture_execute(stmt, *args, **kwargs): + executed_stmts.append(stmt) + return orig_execute(stmt, *args, **kwargs) + + engine.connect.return_value.execute = capture_execute + # Prevent the Buckets constructor from running (it uses a separate query) + with unittest.mock.patch.object(Buckets, "__init__", return_value=None): + Buckets.make_buckets(engine, "person", "age") + + self.assertEqual(len(executed_stmts), 1) + compiled = str(executed_stmts[0].compile( + dialect=mssql.dialect() if dialect_name == "mssql" else postgresql.dialect(), + compile_kwargs={"literal_binds": True}, + )) + return compiled.upper() + + def test_postgresql_uses_stddev(self) -> None: + """PostgreSQL query uses STDDEV function.""" + import unittest.mock + sql = self._get_executed_sql("postgresql") + self.assertIn("STDDEV(", sql) # function call form + + def test_mssql_uses_stdev(self) -> None: + """MS-SQL query uses STDEV function (no trailing D).""" + import unittest.mock + sql = self._get_executed_sql("mssql") + self.assertIn("STDEV(", sql) + self.assertNotIn("STDDEV(", sql) # function call form only, not the alias From ad98acf9f1069fa0926dbca73c235388be4f7754 Mon Sep 17 00:00:00 2001 From: May Yong Date: Thu, 21 May 2026 16:45:25 +0100 Subject: [PATCH 23/45] Update omop-postgresql README to use relative paths Co-Authored-By: Claude Sonnet 4.6 --- examples/omop-postgresql/README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/omop-postgresql/README.md b/examples/omop-postgresql/README.md index bd04883..8467583 100644 --- a/examples/omop-postgresql/README.md +++ b/examples/omop-postgresql/README.md @@ -2,20 +2,23 @@ 1. Make a YAML file representing the tables in the schema -`poetry run datafaker make-tables --orm-file ./examples/mimic_omop/orm.yaml` +`poetry run datafaker make-tables --orm-file ./orm.yaml --config-file ./config.yaml` + +1. Interactively set generators for column data. +`poetry run datafaker configure-generators --orm-file ./orm.yaml --config-file ./config.yaml` 1. Create schema from the ORM YAML file -`poetry run datafaker create-tables --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml` +`poetry run datafaker create-tables --orm-file ./orm.yaml --config-file ./config.yaml` 1. Create generator table -`poetry run datafaker create-generators --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml --df-file ./examples/mimic_omop/df.py` +`poetry run datafaker create-generators --orm-file ./orm.yaml --config-file ./config.yaml --df-file ./df.py` 1. Create data -`poetry run datafaker create-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml --df-file .\examples\mimic_omop\df.py` +`poetry run datafaker create-data --orm-file ./orm.yaml --config-file ./config.yaml --df-file ./df.py` 1. Remove data -`poetry run datafaker remove-data --orm-file ./examples/mimic_omop/orm.yaml --config-file ./examples/mimic_omop/config.yaml` +`poetry run datafaker remove-data --orm-file ./orm.yaml --config-file ./config.yaml` From 7c0add6a0dffb3d8fc89270298c8759c962f2997 Mon Sep 17 00:00:00 2001 From: May Yong Date: Thu, 21 May 2026 17:28:53 +0100 Subject: [PATCH 24/45] Fix RANDOM()/LIMIT dialect incompatibility in ChoiceGeneratorFactory (closes #106) Replace raw RANDOM()/LIMIT SQL in choice.py with SQLAlchemy expression API: - New _choice_stmt() helper builds SELECT expressions using func.random()/ func.newid() and .limit()/.subquery(); SQLAlchemy compiles these to RANDOM()/LIMIT on PostgreSQL/DuckDB and NEWID()/TOP on MS-SQL automatically. - ChoiceGenerator.__init__() gains an optional dialect= parameter; the stored _query string (written to src-stats.yaml for later make-stats execution) is now compiled against the source engine's dialect at configure-generators time. - ChoiceGeneratorFactory.get_generators() builds both live queries as SQLAlchemy select() expressions and passes engine.dialect to all ChoiceGenerator constructors. - The suppress-only subquery no longer contains ORDER BY without TOP, which MS-SQL rejects in derived table expressions. - tests/test_generators_dialect.py: 7 new tests covering stored query SQL for all four sample/suppress combinations and both dialect-correct live queries. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/generators/choice.py | 208 +++++++++++++++++-------------- tests/test_generators_dialect.py | 136 +++++++++++++++++++- 2 files changed, 252 insertions(+), 92 deletions(-) diff --git a/datafaker/generators/choice.py b/datafaker/generators/choice.py index 6f15303..5e886ba 100644 --- a/datafaker/generators/choice.py +++ b/datafaker/generators/choice.py @@ -6,7 +6,7 @@ from abc import abstractmethod from typing import Any, Sequence, Union -from sqlalchemy import Column, CursorResult, Engine, text +from sqlalchemy import Column, CursorResult, Engine, desc, func, literal_column, select, table from datafaker.generators.base import ( Generator, @@ -44,6 +44,55 @@ def zipf_distribution(total: int, bins: int) -> typing.Generator[int, None, None yield x +def _choice_stmt( + column_name: str, + table_name: str, + store_counts: bool, + sample_count: int | None, + suppress_count: int, + random_fn: Any, +) -> Any: + """Build a SQLAlchemy SELECT for gathering choice value distributions. + + Compiles to dialect-correct SQL: LIMIT/random() on PostgreSQL/DuckDB, + TOP/newid() on MS-SQL. MS-SQL also forbids ORDER BY inside a subquery + without TOP; this function never emits such a clause. + """ + col = literal_column(f'"{column_name}"') + tbl = table(table_name) + if sample_count is not None: + sample_sub = ( + select(col.label("value")) + .where(col.isnot(None)) + .select_from(tbl) + .order_by(random_fn) + .limit(sample_count) + .subquery("_inner") + ) + counted_sub = ( + select(sample_sub.c.value, func.count(sample_sub.c.value).label("count")) + .group_by(sample_sub.c.value) + .subquery("_counted") + ) + else: + counted_sub = ( + select(col.label("value"), func.count(col).label("count")) + .where(col.isnot(None)) + .select_from(tbl) + .group_by(col) + .subquery("_counted") + ) + out_cols = [counted_sub.c.value] + if store_counts: + out_cols.append(counted_sub.c["count"]) + stmt = select(*out_cols).select_from(counted_sub) + if suppress_count > 0: + stmt = stmt.where(counted_sub.c["count"] > suppress_count) + else: + stmt = stmt.order_by(desc(counted_sub.c["count"])) + return stmt + + class ChoiceGenerator(Generator): """Base generator for all generators producing choices of items.""" @@ -58,6 +107,7 @@ def __init__( counts: list[int], sample_count: int | None = None, suppress_count: int = 0, + dialect: Any = None, ) -> None: """Initialise a ChoiceGenerator.""" super().__init__() @@ -67,33 +117,28 @@ def __init__( estimated_counts = self.get_estimated_counts(counts) self._fit = fit_from_buckets(counts, estimated_counts) - extra_results = "" - extra_expo = "" - extra_comment = "" - if self.STORE_COUNTS: - extra_results = f", COUNT({column_name}) AS count" - extra_expo = ", count" - extra_comment = " and their counts" + extra_comment = " and their counts" if self.STORE_COUNTS else "" + random_fn = ( + func.newid() + if (dialect is not None and dialect.name == "mssql") + else func.random() + ) + stmt = _choice_stmt( + column_name, table_name, self.STORE_COUNTS, sample_count, suppress_count, random_fn + ) + compile_opts: dict[str, Any] = {"compile_kwargs": {"literal_binds": True}} + if dialect is not None: + compile_opts["dialect"] = dialect + self._query = str(stmt.compile(**compile_opts)) + if suppress_count == 0: if sample_count is None: - self._query = ( - f"SELECT {column_name} AS value{extra_results} FROM {table_name}" - f" WHERE {column_name} IS NOT NULL GROUP BY value" - f" ORDER BY COUNT({column_name}) DESC" - ) self._comment = ( f"All the values{extra_comment} that appear in column {column_name}" f" of table {table_name}" ) self._annotation = None else: - self._query = ( - f"SELECT {column_name} AS value{extra_results} FROM" - f" (SELECT {column_name} FROM {table_name}" - f" WHERE {column_name} IS NOT NULL" - f" ORDER BY RANDOM() LIMIT {sample_count})" - f" AS _inner GROUP BY value ORDER BY COUNT({column_name}) DESC" - ) self._comment = ( f"The values{extra_comment} that appear in column {column_name}" f" of a random sample of {sample_count} rows of table {table_name}" @@ -101,26 +146,12 @@ def __init__( self._annotation = "sampled" else: if sample_count is None: - self._query = ( - f"SELECT value{extra_expo} FROM" - f" (SELECT {column_name} AS value, COUNT({column_name}) AS count" - f" FROM {table_name} WHERE {column_name} IS NOT NULL" - f" GROUP BY value ORDER BY count DESC) AS _inner" - f" WHERE {suppress_count} < count" - ) self._comment = ( f"All the values{extra_comment} that appear in column {column_name}" f" of table {table_name} more than {suppress_count} times" ) self._annotation = "suppressed" else: - self._query = ( - f"SELECT value{extra_expo} FROM (SELECT value, COUNT(value) AS count FROM" - f" (SELECT {column_name} AS value FROM {table_name}" - f" WHERE {column_name} IS NOT NULL ORDER BY RANDOM() LIMIT {sample_count})" - f" AS _inner GROUP BY value ORDER BY count DESC)" - f" AS _inner WHERE {suppress_count} < count" - ) self._comment = ( f"The values{extra_comment} that appear more than {suppress_count} times" f" in column {column_name}, out of a random sample of {sample_count} rows" @@ -302,112 +333,107 @@ def get_generators( column = columns[0] column_name = column.name table_name = column.table.name + dialect = engine.dialect + random_fn = func.newid() if dialect.name == "mssql" else func.random() + col = literal_column(f'"{column_name}"') + tbl = table(table_name) generators = [] with engine.connect() as connection: - results = connection.execute( - text( - f'SELECT "{column_name}" AS v, COUNT("{column_name}")' - f' AS f FROM "{table_name}" GROUP BY v' - f" ORDER BY f DESC LIMIT {MAXIMUM_CHOICES + 1}" - ) + stmt_count = ( + select(col.label("v"), func.count(col).label("f")) + .select_from(tbl) + .group_by(col) + .order_by(desc(func.count(col))) + .limit(MAXIMUM_CHOICES + 1) ) + results = connection.execute(stmt_count) if results is not None and results.rowcount <= MAXIMUM_CHOICES: vg = ValueGatherer(results, self.SUPPRESS_COUNT) if vg.counts: generators += [ ZipfChoiceGenerator( - table_name, column_name, vg.values, vg.counts + table_name, column_name, vg.values, vg.counts, + dialect=dialect, ), UniformChoiceGenerator( - table_name, column_name, vg.values, vg.counts + table_name, column_name, vg.values, vg.counts, + dialect=dialect, ), WeightedChoiceGenerator( - table_name, column_name, vg.cvs, vg.counts + table_name, column_name, vg.cvs, vg.counts, + dialect=dialect, ), ] if vg.counts_not_suppressed: generators += [ ZipfChoiceGenerator( - table_name, - column_name, - vg.values_not_suppressed, - vg.counts_not_suppressed, - suppress_count=self.SUPPRESS_COUNT, + table_name, column_name, + vg.values_not_suppressed, vg.counts_not_suppressed, + suppress_count=self.SUPPRESS_COUNT, dialect=dialect, ), UniformChoiceGenerator( - table_name, - column_name, - vg.values_not_suppressed, - vg.counts_not_suppressed, - suppress_count=self.SUPPRESS_COUNT, + table_name, column_name, + vg.values_not_suppressed, vg.counts_not_suppressed, + suppress_count=self.SUPPRESS_COUNT, dialect=dialect, ), WeightedChoiceGenerator( - table_name=table_name, - column_name=column_name, + table_name=table_name, column_name=column_name, values=vg.cvs_not_suppressed, counts=vg.counts_not_suppressed, - suppress_count=self.SUPPRESS_COUNT, + suppress_count=self.SUPPRESS_COUNT, dialect=dialect, ), ] - sampled_results = connection.execute( - text( - f"SELECT v, COUNT(v) AS f FROM" - f' (SELECT "{column_name}" as v FROM "{table_name}"' - f" ORDER BY RANDOM() LIMIT {self.SAMPLE_COUNT})" - f" AS _inner GROUP BY v ORDER BY f DESC" - ) + inner = ( + select(col.label("v")) + .select_from(tbl) + .order_by(random_fn) + .limit(self.SAMPLE_COUNT) + .subquery("_inner") + ) + stmt_sample = ( + select(inner.c.v, func.count(inner.c.v).label("f")) + .select_from(inner) + .group_by(inner.c.v) + .order_by(desc(func.count(inner.c.v))) ) + sampled_results = connection.execute(stmt_sample) if sampled_results is not None: vg = ValueGatherer(sampled_results, self.SUPPRESS_COUNT) if vg.counts: generators += [ ZipfChoiceGenerator( - table_name, - column_name, - vg.values, - vg.counts, - sample_count=self.SAMPLE_COUNT, + table_name, column_name, vg.values, vg.counts, + sample_count=self.SAMPLE_COUNT, dialect=dialect, ), UniformChoiceGenerator( - table_name, - column_name, - vg.values, - vg.counts, - sample_count=self.SAMPLE_COUNT, + table_name, column_name, vg.values, vg.counts, + sample_count=self.SAMPLE_COUNT, dialect=dialect, ), WeightedChoiceGenerator( - table_name, - column_name, - vg.cvs, - vg.counts, - sample_count=self.SAMPLE_COUNT, + table_name, column_name, vg.cvs, vg.counts, + sample_count=self.SAMPLE_COUNT, dialect=dialect, ), ] if vg.counts_not_suppressed: generators += [ ZipfChoiceGenerator( - table_name, - column_name, - vg.values_not_suppressed, - vg.counts_not_suppressed, + table_name, column_name, + vg.values_not_suppressed, vg.counts_not_suppressed, sample_count=self.SAMPLE_COUNT, - suppress_count=self.SUPPRESS_COUNT, + suppress_count=self.SUPPRESS_COUNT, dialect=dialect, ), UniformChoiceGenerator( - table_name, - column_name, - vg.values_not_suppressed, - vg.counts_not_suppressed, + table_name, column_name, + vg.values_not_suppressed, vg.counts_not_suppressed, sample_count=self.SAMPLE_COUNT, - suppress_count=self.SUPPRESS_COUNT, + suppress_count=self.SUPPRESS_COUNT, dialect=dialect, ), WeightedChoiceGenerator( - table_name=table_name, - column_name=column_name, + table_name=table_name, column_name=column_name, values=vg.cvs_not_suppressed, counts=vg.counts_not_suppressed, sample_count=self.SAMPLE_COUNT, - suppress_count=self.SUPPRESS_COUNT, + suppress_count=self.SUPPRESS_COUNT, dialect=dialect, ), ] return generators diff --git a/tests/test_generators_dialect.py b/tests/test_generators_dialect.py index b9a6a71..ff037a0 100644 --- a/tests/test_generators_dialect.py +++ b/tests/test_generators_dialect.py @@ -1,5 +1,6 @@ """Tests for dialect-correct SQL in generator classes.""" import unittest +import unittest.mock from unittest.mock import MagicMock from sqlalchemy import Column, Integer, MetaData, Table @@ -110,7 +111,140 @@ def test_postgresql_uses_stddev(self) -> None: def test_mssql_uses_stdev(self) -> None: """MS-SQL query uses STDEV function (no trailing D).""" - import unittest.mock sql = self._get_executed_sql("mssql") self.assertIn("STDEV(", sql) self.assertNotIn("STDDEV(", sql) # function call form only, not the alias + + +class TestChoiceGeneratorStoredQuery(unittest.TestCase): + """ChoiceGenerator._query is compiled to dialect-correct SQL at construction time.""" + + def _make_gen(self, dialect, sample_count=None, suppress_count=0): + from datafaker.generators.choice import ZipfChoiceGenerator + return ZipfChoiceGenerator( + table_name="patient", + column_name="gender", + values=["M", "F"], + counts=[70, 30], + sample_count=sample_count, + suppress_count=suppress_count, + dialect=dialect, + ) + + def test_postgresql_sample_uses_random_and_limit(self) -> None: + """PostgreSQL stored query uses random() and LIMIT for sampled path.""" + gen = self._make_gen(postgresql.dialect(), sample_count=500) + sql = gen._query.upper() + self.assertIn("RANDOM()", sql) + self.assertIn("LIMIT", sql) + self.assertNotIn("NEWID()", sql) + self.assertNotIn(" TOP ", sql) + + def test_mssql_sample_uses_newid_and_top(self) -> None: + """MS-SQL stored query uses newid() and TOP for sampled path.""" + gen = self._make_gen(mssql.dialect(), sample_count=500) + sql = gen._query.upper() + self.assertIn("NEWID()", sql) + self.assertIn(" TOP ", sql) + self.assertNotIn("RANDOM()", sql) + self.assertNotIn("LIMIT", sql) + + def test_mssql_suppress_has_no_order_by(self) -> None: + """MS-SQL suppress-only path emits no ORDER BY (was rejected without TOP).""" + gen = self._make_gen(mssql.dialect(), suppress_count=7) + sql = gen._query.upper() + self.assertNotIn("ORDER BY", sql) + + def test_mssql_sample_and_suppress_uses_newid_and_top(self) -> None: + """MS-SQL sample+suppress path uses newid()/TOP and no LIMIT/RANDOM.""" + gen = self._make_gen(mssql.dialect(), sample_count=500, suppress_count=7) + sql = gen._query.upper() + self.assertIn("NEWID()", sql) + self.assertIn(" TOP ", sql) + self.assertNotIn("RANDOM()", sql) + self.assertNotIn("LIMIT", sql) + + def test_no_sample_no_suppress_has_no_random_or_limit(self) -> None: + """No-sample path never includes RANDOM/LIMIT regardless of dialect.""" + for dialect in (postgresql.dialect(), mssql.dialect()): + with self.subTest(dialect=dialect.name): + gen = self._make_gen(dialect) + sql = gen._query.upper() + self.assertNotIn("RANDOM()", sql) + self.assertNotIn("NEWID()", sql) + self.assertNotIn("LIMIT", sql) + self.assertNotIn(" TOP ", sql) + + +class TestChoiceGeneratorFactoryLiveQueries(unittest.TestCase): + """ChoiceGeneratorFactory.get_generators executes dialect-correct live SQL.""" + + def _captured_sqls(self, dialect) -> list[str]: + """Run get_generators with a mocked engine and return compiled SQL strings.""" + from datafaker.generators.choice import ChoiceGeneratorFactory + + engine = MagicMock() + engine.dialect = dialect + + # First execute (distinct count): return one row so rowcount appears <= MAXIMUM_CHOICES + row_count = MagicMock() + row_count.v = "M" + row_count.f = 70 + result_count = MagicMock() + result_count.rowcount = 1 + result_count.__iter__ = MagicMock(return_value=iter([row_count])) + + # Second execute (random sample): return one row + row_sample = MagicMock() + row_sample.v = "M" + row_sample.f = 70 + result_sample = MagicMock() + result_sample.__iter__ = MagicMock(return_value=iter([row_sample])) + + conn = MagicMock() + conn.__enter__ = MagicMock(return_value=conn) + conn.__exit__ = MagicMock(return_value=False) + conn.execute.side_effect = [result_count, result_sample] + engine.connect.return_value = conn + + executed = [] + results_queue = [result_count, result_sample] + + def capture(stmt, *args, **kwargs): + executed.append(stmt) + return results_queue[len(executed) - 1] + + conn.execute.side_effect = capture + + meta = MetaData() + tbl = Table("patient", meta, Column("gender", Integer())) + ChoiceGeneratorFactory().get_generators([tbl.c.gender], engine) + + return [ + str(s.compile(dialect=dialect, compile_kwargs={"literal_binds": True})).upper() + for s in executed + ] + + def test_mssql_live_queries_use_top_and_newid(self) -> None: + """MS-SQL live queries use TOP (not LIMIT) and newid() (not random()).""" + sqls = self._captured_sqls(mssql.dialect()) + # Distinct-count query: TOP, no LIMIT + self.assertIn(" TOP ", sqls[0]) + self.assertNotIn("LIMIT", sqls[0]) + # Random-sample query: TOP + newid() + self.assertIn(" TOP ", sqls[1]) + self.assertIn("NEWID()", sqls[1]) + self.assertNotIn("LIMIT", sqls[1]) + self.assertNotIn("RANDOM()", sqls[1]) + + def test_postgresql_live_queries_use_limit_and_random(self) -> None: + """PostgreSQL live queries use LIMIT and random().""" + sqls = self._captured_sqls(postgresql.dialect()) + # Distinct-count query: LIMIT, no TOP + self.assertIn("LIMIT", sqls[0]) + self.assertNotIn(" TOP ", sqls[0]) + # Random-sample query: LIMIT + random() + self.assertIn("LIMIT", sqls[1]) + self.assertIn("RANDOM()", sqls[1]) + self.assertNotIn(" TOP ", sqls[1]) + self.assertNotIn("NEWID()", sqls[1]) From 2bcea2b4a050f608cac4fe71f210a947f33090e1 Mon Sep 17 00:00:00 2001 From: May Yong Date: Thu, 21 May 2026 17:40:32 +0100 Subject: [PATCH 25/45] Fix schema-qualified table missing from live queries in ChoiceGeneratorFactory ChoiceGeneratorFactory.get_generators() was using table(table_name) to build the FROM clause, which creates a lightweight TableClause with no schema information. On MS-SQL databases with a non-default schema (e.g. dbo.person vs myschema.person) this produced 'Invalid object name' errors. Fix: use column.table directly as the select_from() target. This is the actual SQLAlchemy Table object reflected from the source DB, which carries schema metadata and compiles to a fully-qualified name (e.g. [myschema].[person] on MS-SQL, myschema.person on PostgreSQL). Add test_schema_qualified_table_appears_in_from to verify the schema name appears in the compiled SQL for both MS-SQL and PostgreSQL dialects. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/generators/choice.py | 6 +++--- tests/test_generators_dialect.py | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/datafaker/generators/choice.py b/datafaker/generators/choice.py index 5e886ba..e1c08c9 100644 --- a/datafaker/generators/choice.py +++ b/datafaker/generators/choice.py @@ -336,12 +336,12 @@ def get_generators( dialect = engine.dialect random_fn = func.newid() if dialect.name == "mssql" else func.random() col = literal_column(f'"{column_name}"') - tbl = table(table_name) + src_table = column.table # preserves schema for schema-qualified databases generators = [] with engine.connect() as connection: stmt_count = ( select(col.label("v"), func.count(col).label("f")) - .select_from(tbl) + .select_from(src_table) .group_by(col) .order_by(desc(func.count(col))) .limit(MAXIMUM_CHOICES + 1) @@ -385,7 +385,7 @@ def get_generators( ] inner = ( select(col.label("v")) - .select_from(tbl) + .select_from(src_table) .order_by(random_fn) .limit(self.SAMPLE_COUNT) .subquery("_inner") diff --git a/tests/test_generators_dialect.py b/tests/test_generators_dialect.py index ff037a0..863dd78 100644 --- a/tests/test_generators_dialect.py +++ b/tests/test_generators_dialect.py @@ -179,14 +179,13 @@ def test_no_sample_no_suppress_has_no_random_or_limit(self) -> None: class TestChoiceGeneratorFactoryLiveQueries(unittest.TestCase): """ChoiceGeneratorFactory.get_generators executes dialect-correct live SQL.""" - def _captured_sqls(self, dialect) -> list[str]: + def _captured_sqls(self, dialect, schema=None) -> list[str]: """Run get_generators with a mocked engine and return compiled SQL strings.""" from datafaker.generators.choice import ChoiceGeneratorFactory engine = MagicMock() engine.dialect = dialect - # First execute (distinct count): return one row so rowcount appears <= MAXIMUM_CHOICES row_count = MagicMock() row_count.v = "M" row_count.f = 70 @@ -194,7 +193,6 @@ def _captured_sqls(self, dialect) -> list[str]: result_count.rowcount = 1 result_count.__iter__ = MagicMock(return_value=iter([row_count])) - # Second execute (random sample): return one row row_sample = MagicMock() row_sample.v = "M" row_sample.f = 70 @@ -204,7 +202,6 @@ def _captured_sqls(self, dialect) -> list[str]: conn = MagicMock() conn.__enter__ = MagicMock(return_value=conn) conn.__exit__ = MagicMock(return_value=False) - conn.execute.side_effect = [result_count, result_sample] engine.connect.return_value = conn executed = [] @@ -217,7 +214,7 @@ def capture(stmt, *args, **kwargs): conn.execute.side_effect = capture meta = MetaData() - tbl = Table("patient", meta, Column("gender", Integer())) + tbl = Table("patient", meta, Column("gender", Integer()), schema=schema) ChoiceGeneratorFactory().get_generators([tbl.c.gender], engine) return [ @@ -228,10 +225,8 @@ def capture(stmt, *args, **kwargs): def test_mssql_live_queries_use_top_and_newid(self) -> None: """MS-SQL live queries use TOP (not LIMIT) and newid() (not random()).""" sqls = self._captured_sqls(mssql.dialect()) - # Distinct-count query: TOP, no LIMIT self.assertIn(" TOP ", sqls[0]) self.assertNotIn("LIMIT", sqls[0]) - # Random-sample query: TOP + newid() self.assertIn(" TOP ", sqls[1]) self.assertIn("NEWID()", sqls[1]) self.assertNotIn("LIMIT", sqls[1]) @@ -240,11 +235,17 @@ def test_mssql_live_queries_use_top_and_newid(self) -> None: def test_postgresql_live_queries_use_limit_and_random(self) -> None: """PostgreSQL live queries use LIMIT and random().""" sqls = self._captured_sqls(postgresql.dialect()) - # Distinct-count query: LIMIT, no TOP self.assertIn("LIMIT", sqls[0]) self.assertNotIn(" TOP ", sqls[0]) - # Random-sample query: LIMIT + random() self.assertIn("LIMIT", sqls[1]) self.assertIn("RANDOM()", sqls[1]) self.assertNotIn(" TOP ", sqls[1]) self.assertNotIn("NEWID()", sqls[1]) + + def test_schema_qualified_table_appears_in_from(self) -> None: + """Schema-qualified table name is included in the FROM clause on both dialects.""" + for dialect in (mssql.dialect(), postgresql.dialect()): + with self.subTest(dialect=dialect.name): + sqls = self._captured_sqls(dialect, schema="myschema") + for sql in sqls: + self.assertIn("MYSCHEMA", sql) From 41b96f676be7677e33f180d80d58bb19fdc95e92 Mon Sep 17 00:00:00 2001 From: May Yong Date: Thu, 21 May 2026 18:04:26 +0100 Subject: [PATCH 26/45] Fix schema-missing FROM clause in Buckets queries Buckets.make_buckets() and Buckets.__init__() used table(table_name) (a schema-less TableClause) and raw text() SQL, so queries against schema-qualified databases produced unqualified table names and were rejected with "Invalid object name" on MS-SQL. Both methods now accept an optional src_table parameter (a SQLAlchemy Table object with schema metadata). When provided, select_from() uses it directly, preserving the schema qualifier in the FROM clause. Callers in continuous.py and mimesis.py pass column.table. Buckets.__init__() is also converted from raw text() to a SQLAlchemy expression using func.floor() and group_by(floor_expr), which avoids the GROUP BY alias pattern that MS-SQL rejects. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/generators/base.py | 31 +++++++++------ datafaker/generators/continuous.py | 2 +- datafaker/generators/mimesis.py | 1 + tests/test_generators_dialect.py | 60 ++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 13 deletions(-) diff --git a/datafaker/generators/base.py b/datafaker/generators/base.py index 1019e7f..c5cc570 100644 --- a/datafaker/generators/base.py +++ b/datafaker/generators/base.py @@ -8,7 +8,7 @@ import mimesis import mimesis.locales import sqlalchemy -from sqlalchemy import Column, Engine, func, literal_column, select, table, text +from sqlalchemy import Column, Engine, func, literal_column, select, table from sqlalchemy.types import Integer, Numeric, String, TypeEngine from typing_extensions import Self @@ -279,16 +279,21 @@ def __init__( mean: float, stddev: float, count: int, + src_table: Any = None, ): """Initialise a Buckets object.""" + src = src_table if src_table is not None else table(table_name) + col = literal_column(column_name) + offset = mean - 2 * stddev + width = stddev / 2 + floor_expr = func.floor((col - offset) / width) + stmt = ( + select(func.count(col).label("f"), floor_expr.label("b")) + .select_from(src) + .group_by(floor_expr) + ) with engine.connect() as connection: - raw_buckets = connection.execute( - text( - f"SELECT COUNT({column_name}) AS f," - f" FLOOR(({column_name} - {mean - 2 * stddev})/{stddev / 2}) AS b" - f" FROM {table_name} GROUP BY b" - ) - ) + raw_buckets = connection.execute(stmt) self.buckets: Sequence[int] = [0] * 10 for rb in raw_buckets: try: @@ -303,12 +308,12 @@ def __init__( # catches errors if SQLAlchemy returns something that # isn't a number for some other unknown reason. pass - self.mean = mean - self.stddev = stddev + self.mean = mean + self.stddev = stddev @classmethod def make_buckets( - cls, engine: Engine, table_name: str, column_name: str + cls, engine: Engine, table_name: str, column_name: str, src_table: Any = None ) -> Self | None: """ Construct a Buckets object. @@ -319,13 +324,14 @@ def make_buckets( infinity). Each bucket will be set to the count of the number of values in the column within that bucket. """ + src = src_table if src_table is not None else table(table_name) col = literal_column(column_name) stddev_fn = func.stdev if engine.dialect.name == "mssql" else func.stddev stmt = select( func.avg(col).label("mean"), stddev_fn(col).label("stddev"), func.count(col).label("count"), - ).select_from(table(table_name)) + ).select_from(src) with engine.connect() as connection: result = connection.execute(stmt).first() if result is None or result.stddev is None or getattr(result, "count") < 2: @@ -338,6 +344,7 @@ def make_buckets( result.mean, result.stddev, getattr(result, "count"), + src_table=src_table, ) except sqlalchemy.exc.DatabaseError as exc: logger.debug("Failed to instantiate Buckets object: %s", exc) diff --git a/datafaker/generators/continuous.py b/datafaker/generators/continuous.py index 3d9b9c8..009b1bb 100644 --- a/datafaker/generators/continuous.py +++ b/datafaker/generators/continuous.py @@ -160,7 +160,7 @@ def get_generators( return [] column_name = column.name table_name = column.table.name - buckets = Buckets.make_buckets(engine, table_name, column_name) + buckets = Buckets.make_buckets(engine, table_name, column_name, src_table=column.table) if buckets is None: return [] return self._get_generators_from_buckets( diff --git a/datafaker/generators/mimesis.py b/datafaker/generators/mimesis.py index 77b1582..28b19a0 100644 --- a/datafaker/generators/mimesis.py +++ b/datafaker/generators/mimesis.py @@ -321,6 +321,7 @@ def get_generators( engine, column.table.name, f"LENGTH({column.name})", + src_table=column.table, ) fitness_fn = len except SQLAlchemyError: diff --git a/tests/test_generators_dialect.py b/tests/test_generators_dialect.py index 863dd78..caf73a7 100644 --- a/tests/test_generators_dialect.py +++ b/tests/test_generators_dialect.py @@ -249,3 +249,63 @@ def test_schema_qualified_table_appears_in_from(self) -> None: sqls = self._captured_sqls(dialect, schema="myschema") for sql in sqls: self.assertIn("MYSCHEMA", sql) + + +class TestBucketsSchemaQualified(unittest.TestCase): + """Buckets.make_buckets respects the schema of the src_table argument.""" + + def _make_engine(self, dialect_name: str) -> MagicMock: + engine = MagicMock() + engine.dialect.name = dialect_name + result = MagicMock() + result.stddev = 5.0 + result.mean = 42.0 + result.configure_mock(**{"count": 100}) + conn = MagicMock() + conn.__enter__ = MagicMock(return_value=conn) + conn.__exit__ = MagicMock(return_value=False) + conn.execute.return_value.first.return_value = result + conn.execute.return_value.__iter__ = MagicMock(return_value=iter([])) + engine.connect.return_value = conn + return engine + + def _get_make_buckets_sql(self, dialect_name: str, schema: str | None) -> str: + from datafaker.generators.base import Buckets + + engine = self._make_engine(dialect_name) + meta = MetaData() + tbl = Table("person", meta, Column("age", Integer()), schema=schema) + + executed_stmts = [] + orig_execute = engine.connect.return_value.execute + + def capture_execute(stmt, *args, **kwargs): + executed_stmts.append(stmt) + return orig_execute(stmt, *args, **kwargs) + + engine.connect.return_value.execute = capture_execute + + with unittest.mock.patch.object(Buckets, "__init__", return_value=None): + Buckets.make_buckets(engine, "person", "age", src_table=tbl) + + self.assertGreaterEqual(len(executed_stmts), 1) + dialect = mssql.dialect() if dialect_name == "mssql" else postgresql.dialect() + return str(executed_stmts[0].compile( + dialect=dialect, + compile_kwargs={"literal_binds": True}, + )).upper() + + def test_schema_appears_in_from_mssql(self) -> None: + """MS-SQL make_buckets query includes schema in FROM clause.""" + sql = self._get_make_buckets_sql("mssql", schema="myschema") + self.assertIn("MYSCHEMA", sql) + + def test_schema_appears_in_from_postgresql(self) -> None: + """PostgreSQL make_buckets query includes schema in FROM clause.""" + sql = self._get_make_buckets_sql("postgresql", schema="myschema") + self.assertIn("MYSCHEMA", sql) + + def test_no_schema_omits_qualifier(self) -> None: + """Without schema, the FROM clause has no dot-qualifier.""" + sql = self._get_make_buckets_sql("postgresql", schema=None) + self.assertNotIn(".", sql) From 29e788951bec7ffa136ec63206f1a26ee94c820e Mon Sep 17 00:00:00 2001 From: May Yong Date: Fri, 22 May 2026 10:50:42 +0100 Subject: [PATCH 27/45] Fix remaining RANDOM()/LIMIT dialect incompatibilities (closes #107) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Six locations in generators and the interactive shell still emitted RANDOM() and LIMIT which MS-SQL does not support. Group A — interactive shell (base.py, table.py, generators.py): Replace sqlalchemy.text() f-strings with SQLAlchemy expression API. func.newid() vs func.random() chosen per dialect.name == "mssql"; .limit(n) compiles to TOP n / LIMIT n automatically. Group B — CovariateQuery (continuous.py): Add dialect_name parameter to __init__(); _inner_query() now emits SELECT TOP n … ORDER BY NEWID() on MS-SQL and SELECT * … ORDER BY RANDOM() LIMIT n elsewhere. dialect_name passed from get_generators(). Group C — MissingnessType (missingness.py): sampled_query() accepts dialect_name; returns the MS-SQL TOP/NEWID form when dialect_name == "mssql". do_sampled() passes self.sync_engine.dialect.name. Tests added in test_generators_dialect.py (CovariateQuery, Missingness) and new test_interactive_dialect.py (peek, _get_column_data, print_column_data) covering both MS-SQL and PostgreSQL. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/generators/continuous.py | 10 +- datafaker/interactive/base.py | 26 +++-- datafaker/interactive/generators.py | 23 +++-- datafaker/interactive/missingness.py | 16 ++- datafaker/interactive/table.py | 39 +++++--- tests/test_generators_dialect.py | 83 +++++++++++++++ tests/test_interactive_dialect.py | 144 +++++++++++++++++++++++++++ 7 files changed, 306 insertions(+), 35 deletions(-) create mode 100644 tests/test_interactive_dialect.py diff --git a/datafaker/generators/continuous.py b/datafaker/generators/continuous.py index 009b1bb..5856d8c 100644 --- a/datafaker/generators/continuous.py +++ b/datafaker/generators/continuous.py @@ -396,6 +396,7 @@ def __init__( self, table: str, factory: MultivariateNormalGeneratorFactoryBase, + dialect_name: str = "", ) -> None: """ Initialize the query for the basics for multivariate normal/lognormal parameters. @@ -403,6 +404,7 @@ def __init__( :param table: The name of the table to be queried. :param factory: The generator factory, perhaps with overridden ``query_var`` and ``query_predicate`` methods. + :param dialect_name: The SQLAlchemy dialect name (e.g. ``"mssql"``). """ self.table = table self._columns: Sequence[Column] = [] @@ -412,6 +414,7 @@ def __init__( self.suppress_count = 1 self._sample_count: int | None = None self._factory = factory + self._dialect_name = dialect_name self._predicate_fn = lambda x: x + " IS NOT NULL" def get_query_comment(self) -> str: @@ -566,6 +569,11 @@ def _inner_query(self) -> str: where = " WHERE " + where if self._sample_count is None: return self.table + where + if self._dialect_name == "mssql": + return ( + f"(SELECT TOP {self._sample_count} * FROM {self.table}{where}" + f" ORDER BY NEWID()) AS _sampled" + ) return ( f"(SELECT * FROM {self.table}{where} ORDER BY RANDOM()" f" LIMIT {self._sample_count}) AS _sampled" @@ -628,7 +636,7 @@ def get_generators( return [] column_names = [c.name for c in columns] table = columns[0].table.name - cq = CovariateQuery(table, self).columns(columns) + cq = CovariateQuery(table, self, dialect_name=engine.dialect.name).columns(columns) query = cq.get() with engine.connect() as connection: try: diff --git a/datafaker/interactive/base.py b/datafaker/interactive/base.py index 5ddfb25..bef675b 100644 --- a/datafaker/interactive/base.py +++ b/datafaker/interactive/base.py @@ -10,7 +10,7 @@ import sqlalchemy from prettytable import PrettyTable -from sqlalchemy import Engine, ForeignKey, MetaData, Table +from sqlalchemy import Engine, ForeignKey, MetaData, Table, func, literal_column, or_, select, table as sa_table from typing_extensions import Self from datafaker.utils import ( @@ -412,19 +412,23 @@ def do_peek(self, arg: str) -> None: col_names = arg.split() if not col_names: col_names = self._get_column_names() - nonnulls = [f'"{cn}" IS NOT NULL' for cn in col_names] + random_fn = ( + func.newid() if self.sync_engine.dialect.name == "mssql" else func.random() + ) + col_exprs = [literal_column(f'"{cn}"') for cn in col_names] + nonnull_clauses = [literal_column(f'"{cn}"').isnot(None) for cn in col_names] + stmt = ( + select(*col_exprs) + .select_from(sa_table(table_name)) + .where(or_(*nonnull_clauses)) + .order_by(random_fn) + .limit(max_peek_rows) + ) with self.sync_engine.connect() as connection: - cols = ", ".join(f'"{cn}"' for cn in col_names) - where = "WHERE" if nonnulls else "" - nonnull = " OR ".join(nonnulls) - query = sqlalchemy.text( - f"SELECT {cols} FROM {table_name} {where} {nonnull}" - f" ORDER BY RANDOM() LIMIT {max_peek_rows}" - ) try: - result = connection.execute(query) + result = connection.execute(stmt) except sqlalchemy.exc.SQLAlchemyError as exc: - self.print(self.ERROR_FAILED_SQL, exc=exc, query=query) + self.print(self.ERROR_FAILED_SQL, exc=exc, query=stmt) return self.print_table(list(result.keys()), result.fetchmany(max_peek_rows)) diff --git a/datafaker/interactive/generators.py b/datafaker/interactive/generators.py index ecc8403..38d2ccb 100644 --- a/datafaker/interactive/generators.py +++ b/datafaker/interactive/generators.py @@ -6,7 +6,7 @@ from typing import Any, Callable, Optional, cast import sqlalchemy -from sqlalchemy import Column +from sqlalchemy import Column, and_, func, literal_column, select, table as sa_table from datafaker.generators import everything_factory from datafaker.generators.base import Generator, PredefinedGenerator @@ -754,15 +754,20 @@ def _get_column_data( self, count: int, to_str: Callable[[Any], str] = repr ) -> list[list[str]]: columns = self._get_column_names() - columns_string = ", ".join(columns) - pred = " AND ".join(f"{column} IS NOT NULL" for column in columns) + random_fn = ( + func.newid() if self.sync_engine.dialect.name == "mssql" else func.random() + ) + col_exprs = [literal_column(col) for col in columns] + nonnull_clauses = [literal_column(col).isnot(None) for col in columns] + stmt = ( + select(*col_exprs) + .select_from(sa_table(self.table_name())) + .where(and_(*nonnull_clauses)) + .order_by(random_fn) + .limit(count) + ) with self.sync_engine.connect() as connection: - result = connection.execute( - sqlalchemy.text( - f"SELECT {columns_string} FROM {self.table_name()}" - f" WHERE {pred} ORDER BY RANDOM() LIMIT {count}" - ) - ) + result = connection.execute(stmt) return [[to_str(x) for x in xs] for xs in result.all()] def do_propose(self, _arg: str) -> None: diff --git a/datafaker/interactive/missingness.py b/datafaker/interactive/missingness.py index bf56d4c..51efd67 100644 --- a/datafaker/interactive/missingness.py +++ b/datafaker/interactive/missingness.py @@ -23,19 +23,32 @@ class MissingnessType: columns: list[str] @classmethod - def sampled_query(cls, table: str, count: int, column_names: Iterable[str]) -> str: + def sampled_query( + cls, + table: str, + count: int, + column_names: Iterable[str], + dialect_name: str = "", + ) -> str: """ Construct a query to make a sampling of the named rows of the table. :param table: The name of the table to sample. :param count: The number of samples to get. :param column_names: The columns to fetch. + :param dialect_name: The SQLAlchemy dialect name (e.g. ``"mssql"``). :return: The SQL query to do the sampling. """ result_names = ", ".join([f"{c}__is_null" for c in column_names]) column_is_nulls = ", ".join( [f"{c} IS NULL AS {c}__is_null" for c in column_names] ) + if dialect_name == "mssql": + return ( + f"SELECT COUNT(*) AS row_count, {result_names} FROM " + f"(SELECT TOP {count} {column_is_nulls} FROM {table} ORDER BY NEWID())" + f" AS __t GROUP BY {result_names}" + ) return cls.SAMPLED_QUERY.format( result_names=result_names, column_is_nulls=column_is_nulls, @@ -330,6 +343,7 @@ def do_sampled(self, arg: str) -> None: entry.name, count, self.get_nullable_columns(entry.name), + dialect_name=self.sync_engine.dialect.name, ), [ "The missingness patterns and how often they appear in a" diff --git a/datafaker/interactive/table.py b/datafaker/interactive/table.py index 3bd045f..1df1607 100644 --- a/datafaker/interactive/table.py +++ b/datafaker/interactive/table.py @@ -4,6 +4,7 @@ from typing import Any, cast import sqlalchemy +from sqlalchemy import func, literal_column, select, table as sa_table, text from datafaker.interactive.base import ( TYPE_LETTER, @@ -477,16 +478,23 @@ def print_column_data(self, column: str, count: int, min_length: int) -> None: :param count: The number of rows to sample. :param min_length: The minimum length of text to choose from (0 for any text). """ - where = f"WHERE {column} IS NOT NULL" + random_fn = ( + func.newid() if self.sync_engine.dialect.name == "mssql" else func.random() + ) + col_expr = literal_column(column) if 0 < min_length: - where = f"WHERE LENGTH({column}) >= {min_length}" + where_clause = func.length(col_expr) >= min_length + else: + where_clause = col_expr.isnot(None) + stmt = ( + select(col_expr) + .select_from(sa_table(self.table_name())) + .where(where_clause) + .order_by(random_fn) + .limit(count) + ) with self.sync_engine.connect() as connection: - result = connection.execute( - sqlalchemy.text( - f"SELECT {column} FROM {self.table_name()}" - f" {where} ORDER BY RANDOM() LIMIT {count}" - ) - ) + result = connection.execute(stmt) self.columnize([str(x[0]) for x in result.all()]) def print_row_data(self, count: int) -> None: @@ -495,12 +503,17 @@ def print_row_data(self, count: int) -> None: :param count: The number of rows to report. """ + random_fn = ( + func.newid() if self.sync_engine.dialect.name == "mssql" else func.random() + ) + stmt = ( + select(text("*")) + .select_from(sa_table(self.table_name())) + .order_by(random_fn) + .limit(count) + ) with self.sync_engine.connect() as connection: - result = connection.execute( - sqlalchemy.text( - f"SELECT * FROM {self.table_name()} ORDER BY RANDOM() LIMIT {count}" - ) - ) + result = connection.execute(stmt) if result is None: self.print("No rows in this table!") return diff --git a/tests/test_generators_dialect.py b/tests/test_generators_dialect.py index caf73a7..dba9507 100644 --- a/tests/test_generators_dialect.py +++ b/tests/test_generators_dialect.py @@ -309,3 +309,86 @@ def test_no_schema_omits_qualifier(self) -> None: """Without schema, the FROM clause has no dot-qualifier.""" sql = self._get_make_buckets_sql("postgresql", schema=None) self.assertNotIn(".", sql) + + +class TestCovariateQueryDialect(unittest.TestCase): + """CovariateQuery._inner_query() uses TOP/NEWID on MS-SQL and RANDOM/LIMIT elsewhere.""" + + def _make_factory(self) -> MagicMock: + factory = MagicMock() + factory.query_predicate.return_value = "" + return factory + + def _inner_query(self, dialect_name: str) -> str: + from datafaker.generators.continuous import CovariateQuery + + cq = ( + CovariateQuery("person", self._make_factory(), dialect_name=dialect_name) + .sample_count(500) + ) + return cq._inner_query().upper() + + def test_mssql_uses_top_and_newid(self) -> None: + """MS-SQL inner query uses SELECT TOP n … ORDER BY NEWID().""" + sql = self._inner_query("mssql") + self.assertIn("TOP 500", sql) + self.assertIn("NEWID()", sql) + self.assertNotIn("RANDOM()", sql) + self.assertNotIn("LIMIT", sql) + + def test_postgresql_uses_random_and_limit(self) -> None: + """PostgreSQL inner query uses ORDER BY RANDOM() LIMIT n.""" + sql = self._inner_query("postgresql") + self.assertIn("RANDOM()", sql) + self.assertIn("LIMIT 500", sql) + self.assertNotIn("NEWID()", sql) + self.assertNotIn("TOP", sql) + + def test_no_sample_count_has_no_random_or_limit(self) -> None: + """When sample_count is None no random ordering is emitted.""" + from datafaker.generators.continuous import CovariateQuery + + for dialect in ("mssql", "postgresql", ""): + with self.subTest(dialect=dialect): + cq = CovariateQuery("person", self._make_factory(), dialect_name=dialect) + sql = cq._inner_query().upper() + self.assertNotIn("RANDOM()", sql) + self.assertNotIn("NEWID()", sql) + self.assertNotIn("LIMIT", sql) + self.assertNotIn("TOP", sql) + + +class TestMissingnessQueryDialect(unittest.TestCase): + """MissingnessType.sampled_query() produces dialect-correct SQL.""" + + def test_mssql_uses_top_and_newid(self) -> None: + """MS-SQL sampled query uses SELECT TOP n … ORDER BY NEWID().""" + from datafaker.interactive.missingness import MissingnessType + + sql = MissingnessType.sampled_query( + "person", 1000, ["col_a", "col_b"], dialect_name="mssql" + ).upper() + self.assertIn("TOP 1000", sql) + self.assertIn("NEWID()", sql) + self.assertNotIn("RANDOM()", sql) + self.assertNotIn("LIMIT", sql) + + def test_default_uses_random_and_limit(self) -> None: + """Default (no dialect) sampled query uses RANDOM() and LIMIT.""" + from datafaker.interactive.missingness import MissingnessType + + sql = MissingnessType.sampled_query("person", 1000, ["col_a"]).upper() + self.assertIn("RANDOM()", sql) + self.assertIn("LIMIT 1000", sql) + self.assertNotIn("NEWID()", sql) + self.assertNotIn("TOP", sql) + + def test_mssql_result_contains_column_null_checks(self) -> None: + """MS-SQL sampled query retains IS NULL expressions for the named columns.""" + from datafaker.interactive.missingness import MissingnessType + + sql = MissingnessType.sampled_query( + "person", 500, ["gender_concept_id"], dialect_name="mssql" + ) + self.assertIn("gender_concept_id IS NULL", sql) + self.assertIn("gender_concept_id__is_null", sql) diff --git a/tests/test_interactive_dialect.py b/tests/test_interactive_dialect.py new file mode 100644 index 0000000..ab13658 --- /dev/null +++ b/tests/test_interactive_dialect.py @@ -0,0 +1,144 @@ +"""Tests for dialect-correct SQL in interactive shell methods.""" +import unittest +from unittest.mock import MagicMock + +from sqlalchemy.dialects import mssql, postgresql + + +def _make_engine(dialect) -> MagicMock: + """Return a mock engine whose dialect is the given SQLAlchemy dialect instance.""" + engine = MagicMock() + engine.dialect = dialect + conn = MagicMock() + conn.__enter__ = MagicMock(return_value=conn) + conn.__exit__ = MagicMock(return_value=False) + executed = [] + + def capture(stmt, *args, **kwargs): + executed.append(stmt) + result = MagicMock() + result.keys.return_value = [] + result.fetchmany.return_value = [] + result.all.return_value = [] + return result + + conn.execute.side_effect = capture + engine.connect.return_value = conn + engine._executed = executed + return engine + + +def _compiled(stmt, dialect) -> str: + return str(stmt.compile(dialect=dialect, compile_kwargs={"literal_binds": True})).upper() + + +class TestPeekDialect(unittest.TestCase): + """DbCmd.do_peek() uses NEWID/TOP on MS-SQL and RANDOM/LIMIT on PostgreSQL.""" + + def _run_peek(self, dialect_instance, col_names=None): + from datafaker.interactive.base import DbCmd + + engine = _make_engine(dialect_instance) + shell = MagicMock(spec=DbCmd) + shell.sync_engine = engine + shell.table_index = 0 + shell._table_entries = [MagicMock()] + shell.table_name.return_value = "person" + shell._get_column_names.return_value = col_names or ["gender_concept_id"] + shell.print_table = MagicMock() + shell.print = MagicMock() + + DbCmd.do_peek(shell, " ".join(col_names) if col_names else "") + return engine._executed, dialect_instance + + def test_mssql_peek_uses_newid_and_top(self) -> None: + """MS-SQL do_peek compiles to TOP … NEWID().""" + executed, dialect = self._run_peek(mssql.dialect()) + self.assertEqual(len(executed), 1) + sql = _compiled(executed[0], dialect) + self.assertIn("TOP", sql) + self.assertIn("NEWID()", sql) + self.assertNotIn("LIMIT", sql) + self.assertNotIn("RANDOM()", sql) + + def test_postgresql_peek_uses_random_and_limit(self) -> None: + """PostgreSQL do_peek compiles to RANDOM() … LIMIT.""" + executed, dialect = self._run_peek(postgresql.dialect()) + self.assertEqual(len(executed), 1) + sql = _compiled(executed[0], dialect) + self.assertIn("RANDOM()", sql) + self.assertIn("LIMIT", sql) + self.assertNotIn("NEWID()", sql) + self.assertNotIn(" TOP ", sql) + + +class TestGetColumnDataDialect(unittest.TestCase): + """GeneratorCmd._get_column_data() uses NEWID/TOP on MS-SQL and RANDOM/LIMIT on PostgreSQL.""" + + def _run_get_column_data(self, dialect_instance): + from datafaker.interactive.generators import GeneratorCmd + + engine = _make_engine(dialect_instance) + shell = MagicMock(spec=GeneratorCmd) + shell.sync_engine = engine + shell.table_name.return_value = "person" + shell._get_column_names.return_value = ["gender_concept_id"] + + GeneratorCmd._get_column_data(shell, 5) + return engine._executed, dialect_instance + + def test_mssql_uses_newid_and_top(self) -> None: + """MS-SQL _get_column_data compiles to TOP … NEWID().""" + executed, dialect = self._run_get_column_data(mssql.dialect()) + self.assertEqual(len(executed), 1) + sql = _compiled(executed[0], dialect) + self.assertIn("TOP", sql) + self.assertIn("NEWID()", sql) + self.assertNotIn("LIMIT", sql) + self.assertNotIn("RANDOM()", sql) + + def test_postgresql_uses_random_and_limit(self) -> None: + """PostgreSQL _get_column_data compiles to RANDOM() … LIMIT.""" + executed, dialect = self._run_get_column_data(postgresql.dialect()) + self.assertEqual(len(executed), 1) + sql = _compiled(executed[0], dialect) + self.assertIn("RANDOM()", sql) + self.assertIn("LIMIT", sql) + self.assertNotIn("NEWID()", sql) + self.assertNotIn(" TOP ", sql) + + +class TestPrintColumnDataDialect(unittest.TestCase): + """TableCmd.print_column_data() uses NEWID/TOP on MS-SQL and RANDOM/LIMIT on PostgreSQL.""" + + def _run_print_column_data(self, dialect_instance): + from datafaker.interactive.table import TableCmd + + engine = _make_engine(dialect_instance) + shell = MagicMock(spec=TableCmd) + shell.sync_engine = engine + shell.table_name.return_value = "person" + shell.columnize = MagicMock() + + TableCmd.print_column_data(shell, "gender_concept_id", 10, 0) + return engine._executed, dialect_instance + + def test_mssql_uses_newid_and_top(self) -> None: + """MS-SQL print_column_data compiles to TOP … NEWID().""" + executed, dialect = self._run_print_column_data(mssql.dialect()) + self.assertEqual(len(executed), 1) + sql = _compiled(executed[0], dialect) + self.assertIn("TOP", sql) + self.assertIn("NEWID()", sql) + self.assertNotIn("LIMIT", sql) + self.assertNotIn("RANDOM()", sql) + + def test_postgresql_uses_random_and_limit(self) -> None: + """PostgreSQL print_column_data compiles to RANDOM() … LIMIT.""" + executed, dialect = self._run_print_column_data(postgresql.dialect()) + self.assertEqual(len(executed), 1) + sql = _compiled(executed[0], dialect) + self.assertIn("RANDOM()", sql) + self.assertIn("LIMIT", sql) + self.assertNotIn("NEWID()", sql) + self.assertNotIn(" TOP ", sql) From 91578dad8786c844a58828504d8d8abdc6ccb29d Mon Sep 17 00:00:00 2001 From: May Yong Date: Fri, 22 May 2026 12:21:38 +0100 Subject: [PATCH 28/45] Fix missing schema qualification in interactive shell SELECT statements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace sa_table(self.table_name()) — which creates a schema-less TableClause — with self.table_metadata() in do_peek(), print_column_data(), print_row_data(), and _get_column_data(). This fixes "Invalid object name 'person'" (42S02) on MS-SQL when tables live in a non-default schema (e.g. dbo.person). Co-Authored-By: Claude Sonnet 4.6 --- datafaker/interactive/base.py | 4 +-- datafaker/interactive/generators.py | 4 +-- datafaker/interactive/table.py | 6 ++--- tests/test_interactive_dialect.py | 39 ++++++++++++++++++++++++++--- 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/datafaker/interactive/base.py b/datafaker/interactive/base.py index bef675b..5b1a4ea 100644 --- a/datafaker/interactive/base.py +++ b/datafaker/interactive/base.py @@ -10,7 +10,7 @@ import sqlalchemy from prettytable import PrettyTable -from sqlalchemy import Engine, ForeignKey, MetaData, Table, func, literal_column, or_, select, table as sa_table +from sqlalchemy import Engine, ForeignKey, MetaData, Table, func, literal_column, or_, select from typing_extensions import Self from datafaker.utils import ( @@ -419,7 +419,7 @@ def do_peek(self, arg: str) -> None: nonnull_clauses = [literal_column(f'"{cn}"').isnot(None) for cn in col_names] stmt = ( select(*col_exprs) - .select_from(sa_table(table_name)) + .select_from(self.table_metadata()) .where(or_(*nonnull_clauses)) .order_by(random_fn) .limit(max_peek_rows) diff --git a/datafaker/interactive/generators.py b/datafaker/interactive/generators.py index 38d2ccb..cf35d79 100644 --- a/datafaker/interactive/generators.py +++ b/datafaker/interactive/generators.py @@ -6,7 +6,7 @@ from typing import Any, Callable, Optional, cast import sqlalchemy -from sqlalchemy import Column, and_, func, literal_column, select, table as sa_table +from sqlalchemy import Column, and_, func, literal_column, select from datafaker.generators import everything_factory from datafaker.generators.base import Generator, PredefinedGenerator @@ -761,7 +761,7 @@ def _get_column_data( nonnull_clauses = [literal_column(col).isnot(None) for col in columns] stmt = ( select(*col_exprs) - .select_from(sa_table(self.table_name())) + .select_from(self.table_metadata()) .where(and_(*nonnull_clauses)) .order_by(random_fn) .limit(count) diff --git a/datafaker/interactive/table.py b/datafaker/interactive/table.py index 1df1607..9a02177 100644 --- a/datafaker/interactive/table.py +++ b/datafaker/interactive/table.py @@ -4,7 +4,7 @@ from typing import Any, cast import sqlalchemy -from sqlalchemy import func, literal_column, select, table as sa_table, text +from sqlalchemy import func, literal_column, select, text from datafaker.interactive.base import ( TYPE_LETTER, @@ -488,7 +488,7 @@ def print_column_data(self, column: str, count: int, min_length: int) -> None: where_clause = col_expr.isnot(None) stmt = ( select(col_expr) - .select_from(sa_table(self.table_name())) + .select_from(self.table_metadata()) .where(where_clause) .order_by(random_fn) .limit(count) @@ -508,7 +508,7 @@ def print_row_data(self, count: int) -> None: ) stmt = ( select(text("*")) - .select_from(sa_table(self.table_name())) + .select_from(self.table_metadata()) .order_by(random_fn) .limit(count) ) diff --git a/tests/test_interactive_dialect.py b/tests/test_interactive_dialect.py index ab13658..af53c4e 100644 --- a/tests/test_interactive_dialect.py +++ b/tests/test_interactive_dialect.py @@ -2,6 +2,7 @@ import unittest from unittest.mock import MagicMock +from sqlalchemy import Column, Integer, MetaData, Table from sqlalchemy.dialects import mssql, postgresql @@ -28,6 +29,11 @@ def capture(stmt, *args, **kwargs): return engine +def _make_table(schema=None) -> Table: + meta = MetaData() + return Table("person", meta, Column("gender_concept_id", Integer()), schema=schema) + + def _compiled(stmt, dialect) -> str: return str(stmt.compile(dialect=dialect, compile_kwargs={"literal_binds": True})).upper() @@ -35,7 +41,7 @@ def _compiled(stmt, dialect) -> str: class TestPeekDialect(unittest.TestCase): """DbCmd.do_peek() uses NEWID/TOP on MS-SQL and RANDOM/LIMIT on PostgreSQL.""" - def _run_peek(self, dialect_instance, col_names=None): + def _run_peek(self, dialect_instance, col_names=None, schema=None): from datafaker.interactive.base import DbCmd engine = _make_engine(dialect_instance) @@ -45,6 +51,7 @@ def _run_peek(self, dialect_instance, col_names=None): shell._table_entries = [MagicMock()] shell.table_name.return_value = "person" shell._get_column_names.return_value = col_names or ["gender_concept_id"] + shell.table_metadata.return_value = _make_table(schema=schema) shell.print_table = MagicMock() shell.print = MagicMock() @@ -71,11 +78,19 @@ def test_postgresql_peek_uses_random_and_limit(self) -> None: self.assertNotIn("NEWID()", sql) self.assertNotIn(" TOP ", sql) + def test_schema_appears_in_from(self) -> None: + """Schema-qualified table name appears in the FROM clause on both dialects.""" + for dialect in (mssql.dialect(), postgresql.dialect()): + with self.subTest(dialect=dialect.name): + executed, d = self._run_peek(dialect, schema="myschema") + sql = _compiled(executed[0], d) + self.assertIn("MYSCHEMA", sql) + class TestGetColumnDataDialect(unittest.TestCase): """GeneratorCmd._get_column_data() uses NEWID/TOP on MS-SQL and RANDOM/LIMIT on PostgreSQL.""" - def _run_get_column_data(self, dialect_instance): + def _run_get_column_data(self, dialect_instance, schema=None): from datafaker.interactive.generators import GeneratorCmd engine = _make_engine(dialect_instance) @@ -83,6 +98,7 @@ def _run_get_column_data(self, dialect_instance): shell.sync_engine = engine shell.table_name.return_value = "person" shell._get_column_names.return_value = ["gender_concept_id"] + shell.table_metadata.return_value = _make_table(schema=schema) GeneratorCmd._get_column_data(shell, 5) return engine._executed, dialect_instance @@ -107,17 +123,26 @@ def test_postgresql_uses_random_and_limit(self) -> None: self.assertNotIn("NEWID()", sql) self.assertNotIn(" TOP ", sql) + def test_schema_appears_in_from(self) -> None: + """Schema-qualified table name appears in the FROM clause on both dialects.""" + for dialect in (mssql.dialect(), postgresql.dialect()): + with self.subTest(dialect=dialect.name): + executed, d = self._run_get_column_data(dialect, schema="myschema") + sql = _compiled(executed[0], d) + self.assertIn("MYSCHEMA", sql) + class TestPrintColumnDataDialect(unittest.TestCase): """TableCmd.print_column_data() uses NEWID/TOP on MS-SQL and RANDOM/LIMIT on PostgreSQL.""" - def _run_print_column_data(self, dialect_instance): + def _run_print_column_data(self, dialect_instance, schema=None): from datafaker.interactive.table import TableCmd engine = _make_engine(dialect_instance) shell = MagicMock(spec=TableCmd) shell.sync_engine = engine shell.table_name.return_value = "person" + shell.table_metadata.return_value = _make_table(schema=schema) shell.columnize = MagicMock() TableCmd.print_column_data(shell, "gender_concept_id", 10, 0) @@ -142,3 +167,11 @@ def test_postgresql_uses_random_and_limit(self) -> None: self.assertIn("LIMIT", sql) self.assertNotIn("NEWID()", sql) self.assertNotIn(" TOP ", sql) + + def test_schema_appears_in_from(self) -> None: + """Schema-qualified table name appears in the FROM clause on both dialects.""" + for dialect in (mssql.dialect(), postgresql.dialect()): + with self.subTest(dialect=dialect.name): + executed, d = self._run_print_column_data(dialect, schema="myschema") + sql = _compiled(executed[0], d) + self.assertIn("MYSCHEMA", sql) From 4d03aa3a1f78fcd017e0b8f711bc0396edc1c9f7 Mon Sep 17 00:00:00 2001 From: May Yong Date: Fri, 22 May 2026 13:13:39 +0100 Subject: [PATCH 29/45] Fix unqualified table names in raw SQL during configure-generators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit schema_translate_map (set by create_db_engine) only rewrites SQLAlchemy Core constructs — not text() raw SQL. Three sites still built text() with bare table names, causing 42S02 'Invalid object name' on MS-SQL schemas: - do_counts (base.py): converted to select_from(self.table_metadata()) so the translate map applies, same pattern as do_peek / _get_column_data. - _get_generators_from_buckets (continuous.py): now receives the Table object (not just a name string) and uses select_from(src_table); also replaces raw LN/STDDEV SQL with func.log/func.stddev_samp for dialect correctness. - MultivariateNormalGeneratorFactory.get_generators (continuous.py): qualifies the table name via schema_qualified_name() before passing to CovariateQuery so the stored SQL string contains the correct schema prefix at create-data time; the unqualified name is kept for SRC_STATS config keys. Adds schema_qualified_name() utility to utils.py that reads the engine's schema_translate_map execution option. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/generators/continuous.py | 30 +++++++++-------- datafaker/interactive/base.py | 16 ++++----- datafaker/utils.py | 14 ++++++++ tests/test_generators_dialect.py | 53 ++++++++++++++++++++++++++++++ tests/test_interactive_dialect.py | 38 +++++++++++++++++++++ 5 files changed, 127 insertions(+), 24 deletions(-) diff --git a/datafaker/generators/continuous.py b/datafaker/generators/continuous.py index 5856d8c..ddda3fd 100644 --- a/datafaker/generators/continuous.py +++ b/datafaker/generators/continuous.py @@ -5,7 +5,7 @@ from collections.abc import Iterable, Mapping, Sequence from typing import Any -from sqlalchemy import Column, Engine, RowMapping, text +from sqlalchemy import Column, Engine, RowMapping, Table, case, func, null, select, text from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.types import Integer, Numeric from typing_extensions import Self @@ -18,7 +18,7 @@ dist_gen, get_column_type, ) -from datafaker.utils import logger +from datafaker.utils import logger, schema_qualified_name class ContinuousDistributionGenerator(Generator): @@ -164,7 +164,7 @@ def get_generators( if buckets is None: return [] return self._get_generators_from_buckets( - engine, table_name, column_name, buckets + engine, column.table, column_name, buckets ) @@ -272,24 +272,25 @@ class ContinuousLogDistributionGeneratorFactory(ContinuousDistributionGeneratorF def _get_generators_from_buckets( self, engine: Engine, - table_name: str, + src_table: Table, column_name: str, buckets: Buckets, ) -> Sequence[Generator]: + col = case( + (src_table.c[column_name] > 0, func.log(src_table.c[column_name])), + else_=null(), + ) + stmt = select( + func.avg(col).label("logmean"), + func.stddev_samp(col).label("logstddev"), + ).select_from(src_table) with engine.connect() as connection: - result = connection.execute( - text( - f"SELECT AVG(CASE WHEN 0<{column_name} THEN LN({column_name})" - " ELSE NULL END) AS logmean," - f" STDDEV(CASE WHEN 0<{column_name} THEN LN({column_name}) ELSE NULL END)" - f" AS logstddev FROM {table_name}" - ) - ).first() + result = connection.execute(stmt).first() if result is None or result.logstddev is None: return [] return [ LogNormalGenerator( - table_name, + src_table.name, column_name, buckets, float(result.logmean), @@ -636,7 +637,8 @@ def get_generators( return [] column_names = [c.name for c in columns] table = columns[0].table.name - cq = CovariateQuery(table, self, dialect_name=engine.dialect.name).columns(columns) + table_sql = schema_qualified_name(table, engine) + cq = CovariateQuery(table_sql, self, dialect_name=engine.dialect.name).columns(columns) query = cq.get() with engine.connect() as connection: try: diff --git a/datafaker/interactive/base.py b/datafaker/interactive/base.py index 5b1a4ea..5430199 100644 --- a/datafaker/interactive/base.py +++ b/datafaker/interactive/base.py @@ -349,17 +349,13 @@ def do_counts(self, _arg: str) -> None: return table_name = self.table_name() nullable_columns = self.get_nullable_columns(table_name) - colcounts = [f', COUNT("{nnc}") AS "{nnc}"' for nnc in nullable_columns] + tbl = self.table_metadata() + count_exprs = [func.count().label("row_count")] + [ + func.count(tbl.c[col]).label(col) for col in nullable_columns + ] + stmt = select(*count_exprs).select_from(tbl) with self.sync_engine.connect() as connection: - result = ( - connection.execute( - sqlalchemy.text( - f"SELECT COUNT(*) AS row_count{''.join(colcounts)} FROM {table_name}" - ) - ) - .mappings() - .first() - ) + result = connection.execute(stmt).mappings().first() if result is None: self.print("Could not count rows in table {0}", table_name) return diff --git a/datafaker/utils.py b/datafaker/utils.py index b47c2e1..4e798a9 100644 --- a/datafaker/utils.py +++ b/datafaker/utils.py @@ -281,6 +281,20 @@ def connect(dbapi_connection: DBAPIConnection, _: Any) -> None: return engine +def schema_qualified_name(table_name: str, engine: Any) -> str: + """Return schema-qualified table name using the engine's schema_translate_map. + + When create_db_engine sets schema_translate_map={None: schema_name}, this + reads it back so raw SQL strings (which schema_translate_map doesn't rewrite) + can include the correct qualifier. + """ + schema_map = engine.get_execution_options().get("schema_translate_map", {}) + schema = schema_map.get(None) + if schema and "." not in table_name: + return f"{schema}.{table_name}" + return table_name + + def create_db_engine_dst( db_dsn: str, schema_name: Optional[str] = None, diff --git a/tests/test_generators_dialect.py b/tests/test_generators_dialect.py index dba9507..243870c 100644 --- a/tests/test_generators_dialect.py +++ b/tests/test_generators_dialect.py @@ -392,3 +392,56 @@ def test_mssql_result_contains_column_null_checks(self) -> None: ) self.assertIn("gender_concept_id IS NULL", sql) self.assertIn("gender_concept_id__is_null", sql) + + +class TestLogNormalGeneratorSchemaQualified(unittest.TestCase): + """ContinuousLogDistributionGeneratorFactory respects src_table schema.""" + + def _get_sql(self, schema: str | None) -> str: + from datafaker.generators.continuous import ContinuousLogDistributionGeneratorFactory + + meta = MetaData() + tbl = Table("person", meta, Column("age", Integer()), schema=schema) + + executed_stmts = [] + result = MagicMock() + result.logmean = 1.0 + result.logstddev = 0.5 + conn = MagicMock() + conn.__enter__ = MagicMock(return_value=conn) + conn.__exit__ = MagicMock(return_value=False) + orig_execute = MagicMock(return_value=MagicMock(first=MagicMock(return_value=result))) + + def capture(stmt, *args, **kwargs): + executed_stmts.append(stmt) + return orig_execute(stmt, *args, **kwargs) + + conn.execute.side_effect = capture + engine = MagicMock() + engine.connect.return_value = conn + + from datafaker.generators.base import Buckets + import unittest.mock + + buckets = MagicMock(spec=Buckets) + factory = ContinuousLogDistributionGeneratorFactory() + with unittest.mock.patch.object(Buckets, "make_buckets", return_value=buckets): + factory._get_generators_from_buckets(engine, tbl, "age", buckets) + + self.assertEqual(len(executed_stmts), 1) + dialect = postgresql.dialect() + return str(executed_stmts[0].compile( + dialect=dialect, + compile_kwargs={"literal_binds": True}, + )).upper() + + def test_schema_appears_in_from(self) -> None: + """_get_generators_from_buckets includes schema in FROM clause.""" + sql = self._get_sql(schema="myschema") + self.assertIn("MYSCHEMA", sql) + + def test_no_schema_omits_qualifier(self) -> None: + """Without schema, FROM clause has no schema prefix.""" + sql = self._get_sql(schema=None) + self.assertIn("FROM PERSON", sql) + self.assertNotIn("FROM MYSCHEMA", sql) diff --git a/tests/test_interactive_dialect.py b/tests/test_interactive_dialect.py index af53c4e..4c38db8 100644 --- a/tests/test_interactive_dialect.py +++ b/tests/test_interactive_dialect.py @@ -175,3 +175,41 @@ def test_schema_appears_in_from(self) -> None: executed, d = self._run_print_column_data(dialect, schema="myschema") sql = _compiled(executed[0], d) self.assertIn("MYSCHEMA", sql) + + +class TestCountsDialect(unittest.TestCase): + """DbCmd.do_counts() compiles a schema-qualified COUNT query.""" + + def _run_counts(self, dialect_instance, schema=None): + from datafaker.interactive.base import DbCmd + + engine = _make_engine(dialect_instance) + tbl = _make_table(schema=schema) + shell = MagicMock(spec=DbCmd) + shell.sync_engine = engine + shell._table_entries = [MagicMock()] + shell.table_index = 0 + shell.table_name.return_value = "person" + shell.get_nullable_columns.return_value = ["gender_concept_id"] + shell.table_metadata.return_value = tbl + shell.print = MagicMock() + shell.print_table = MagicMock() + + DbCmd.do_counts(shell, "") + return engine._executed, dialect_instance + + def test_counts_schema_appears_in_from(self) -> None: + """do_counts FROM clause includes the schema when one is set.""" + for dialect in (mssql.dialect(), postgresql.dialect()): + with self.subTest(dialect=dialect.name): + executed, d = self._run_counts(dialect, schema="myschema") + self.assertEqual(len(executed), 1) + sql = _compiled(executed[0], d) + self.assertIn("MYSCHEMA", sql) + + def test_counts_no_schema_omits_qualifier(self) -> None: + """do_counts FROM clause has no schema prefix when schema is None.""" + executed, d = self._run_counts(postgresql.dialect(), schema=None) + sql = _compiled(executed[0], d) + self.assertIn("FROM PERSON", sql) + self.assertNotIn("FROM MYSCHEMA", sql) From 173f6da903b35e6e1d2c6aafafd67b67d927403f Mon Sep 17 00:00:00 2001 From: May Yong Date: Fri, 22 May 2026 13:37:26 +0100 Subject: [PATCH 30/45] Fix unqualified table names in src-stats queries written by configure-generators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _get_aggregate_query builds SQL stored in config.yaml's src-stats section and executed by make-stats via text() — not affected by schema_translate_map. Two call sites now pass schema_qualified_name(entry.name, engine) so the stored SQL contains the schema prefix (e.g. mimic100.person). SELECT_AGGREGATE_RE regex updated to match schema.table forms, and the auto__ name check now strips the schema prefix before comparing with the config key so PredefinedGenerator still recognises its own clauses when re-reading a config that was written with schema-qualified table names. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/generators/base.py | 6 +- datafaker/interactive/generators.py | 8 ++- tests/test_generators_dialect.py | 92 +++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 4 deletions(-) diff --git a/datafaker/generators/base.py b/datafaker/generators/base.py index c5cc570..3ddcbaf 100644 --- a/datafaker/generators/base.py +++ b/datafaker/generators/base.py @@ -131,7 +131,9 @@ def fit(self, default: float = -1) -> float: class PredefinedGenerator(Generator): """Generator built from an existing config.yaml.""" - SELECT_AGGREGATE_RE = re.compile(r"SELECT (.*) FROM ([A-Za-z_][A-Za-z0-9_]*)") + SELECT_AGGREGATE_RE = re.compile( + r"SELECT (.*) FROM ((?:[A-Za-z_][A-Za-z0-9_]*\.)?[A-Za-z_][A-Za-z0-9_]*)" + ) AS_CLAUSE_RE = re.compile(r" *(.+) +AS +([A-Za-z_][A-Za-z0-9_]*) *") SRC_STAT_NAME_RE = re.compile(r'\bSRC_STATS\["([^]]*)"\].*') @@ -189,7 +191,7 @@ def __init__( # This query is one that this generator is interested in sam = None if query is None else self.SELECT_AGGREGATE_RE.match(query) # sam.group(2) is the table name from the FROM clause of the query - if sam and name == f"auto__{sam.group(2)}": + if sam and name == f"auto__{sam.group(2).split('.')[-1]}": # name is auto__{table_name}, so it's a select_aggregate, # so we split up its clauses sacs = [ diff --git a/datafaker/interactive/generators.py b/datafaker/interactive/generators.py index cf35d79..77b9acb 100644 --- a/datafaker/interactive/generators.py +++ b/datafaker/interactive/generators.py @@ -16,6 +16,7 @@ get_row_generators, logger, primary_private_fks, + schema_qualified_name, split_column_full_name, table_is_private, ) @@ -292,7 +293,8 @@ def _copy_entries(self) -> None: if kwn: rg["kwargs"] = kwn rgs.append(rg) - aq = self._get_aggregate_query(new_gens, entry.name) + aq_table = schema_qualified_name(entry.name, self.sync_engine) + aq = self._get_aggregate_query(new_gens, aq_table) if aq: src_stats.append( { @@ -747,7 +749,9 @@ def _print_select_aggregate_query(self, table_name: str, gen: Generator) -> None table_name, n, ) - select_q = self._get_aggregate_query([gen], table_name) + select_q = self._get_aggregate_query( + [gen], schema_qualified_name(table_name, self.sync_engine) + ) self.print("{0}; providing the following values: {1}", select_q, vals) def _get_column_data( diff --git a/tests/test_generators_dialect.py b/tests/test_generators_dialect.py index 243870c..dea5172 100644 --- a/tests/test_generators_dialect.py +++ b/tests/test_generators_dialect.py @@ -445,3 +445,95 @@ def test_no_schema_omits_qualifier(self) -> None: sql = self._get_sql(schema=None) self.assertIn("FROM PERSON", sql) self.assertNotIn("FROM MYSCHEMA", sql) + + +class TestPredefinedGeneratorSchemaQualified(unittest.TestCase): + """PredefinedGenerator parses aggregate clauses from schema-qualified SQL.""" + + def _make_config(self, table_sql_name: str) -> dict: + return { + "tables": { + "person": { + "row_generators": [ + { + "name": "dist_gen.gaussian", + "columns_assigned": ["age"], + "kwargs": { + "mean": f'SRC_STATS["auto__person"]["results"][0]["mean__age"]', + "sd": f'SRC_STATS["auto__person"]["results"][0]["sd__age"]', + }, + } + ] + } + }, + "src-stats": [ + { + "name": "auto__person", + "query": f"SELECT AVG(age) AS mean__age, STDDEV(age) AS sd__age FROM {table_sql_name}", + "comments": [], + } + ], + } + + def test_unqualified_name_parses_clauses(self) -> None: + """PredefinedGenerator parses select_aggregate_clauses from unqualified FROM.""" + from datafaker.generators.base import PredefinedGenerator + + config = self._make_config("person") + rg = config["tables"]["person"]["row_generators"][0] + gen = PredefinedGenerator("person", rg, config) + self.assertIn("mean__age", gen.select_aggregate_clauses()) + self.assertIn("sd__age", gen.select_aggregate_clauses()) + + def test_schema_qualified_name_parses_clauses(self) -> None: + """PredefinedGenerator parses select_aggregate_clauses from schema-qualified FROM.""" + from datafaker.generators.base import PredefinedGenerator + + config = self._make_config("myschema.person") + rg = config["tables"]["person"]["row_generators"][0] + gen = PredefinedGenerator("person", rg, config) + self.assertIn("mean__age", gen.select_aggregate_clauses()) + self.assertIn("sd__age", gen.select_aggregate_clauses()) + + +class TestAggregateQuerySchemaQualified(unittest.TestCase): + """_copy_entries writes schema-qualified table names into src-stats SQL.""" + + def test_aggregate_query_includes_schema(self) -> None: + """_get_aggregate_query uses the schema-qualified name when engine has schema map.""" + from unittest.mock import MagicMock, patch + + from datafaker.interactive.generators import GeneratorCmd + from datafaker.generators.base import Generator + + gen = MagicMock(spec=Generator) + gen.select_aggregate_clauses.return_value = { + "mean__age": {"clause": "AVG(age)", "comment": None} + } + + engine = MagicMock() + engine.get_execution_options.return_value = {"schema_translate_map": {None: "myschema"}} + + shell = MagicMock(spec=GeneratorCmd) + shell.sync_engine = engine + + result = GeneratorCmd._get_aggregate_query(shell, [gen], "myschema.person") + self.assertIsNotNone(result) + self.assertIn("myschema.person", result) + self.assertNotIn("FROM person", result.replace("myschema.person", "")) + + def test_aggregate_query_no_schema(self) -> None: + """_get_aggregate_query uses the bare name when no schema is set.""" + from unittest.mock import MagicMock + + from datafaker.interactive.generators import GeneratorCmd + from datafaker.generators.base import Generator + + gen = MagicMock(spec=Generator) + gen.select_aggregate_clauses.return_value = { + "mean__age": {"clause": "AVG(age)", "comment": None} + } + + result = GeneratorCmd._get_aggregate_query(None, [gen], "person") + self.assertIsNotNone(result) + self.assertIn("FROM person", result) From 1132dc635c5b943aacc3d665cb2bf76d4db01456 Mon Sep 17 00:00:00 2001 From: May Yong Date: Fri, 22 May 2026 15:23:43 +0100 Subject: [PATCH 31/45] Fix schema-qualified table name in ChoiceGenerator stored queries (closes #108) ChoiceGenerator compiled self._query at construction time using table(table_name), which treated a schema-qualified string like "mimic100.person" as a single identifier and produced [mimic100.person] on MS-SQL. Using column.table dropped the schema because dict_to_metadata creates Table objects without schema set. Fix: pass the schema-qualified name (from schema_qualified_name()) as table_sql and use text(table_sql) in _choice_stmt, which compiles verbatim without quoting. The SRC_STATS config key and self.table_name remain unqualified; only the stored SQL string is qualified. Also refactors _get_aggregate_query to qualify the table name internally rather than requiring callers to pre-qualify it. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/generators/choice.py | 27 ++++++-- datafaker/interactive/generators.py | 10 ++- examples/omop-mssql/config.yaml | 31 ++++++++- examples/omop-mssql/df.py | 77 ++++---------------- examples/omop-mssql/orm.yaml | 104 ++++++++++++++-------------- examples/omop-postgresql/README.md | 5 ++ tests/test_generators_dialect.py | 31 ++++----- 7 files changed, 136 insertions(+), 149 deletions(-) diff --git a/datafaker/generators/choice.py b/datafaker/generators/choice.py index e1c08c9..2712f9d 100644 --- a/datafaker/generators/choice.py +++ b/datafaker/generators/choice.py @@ -6,7 +6,7 @@ from abc import abstractmethod from typing import Any, Sequence, Union -from sqlalchemy import Column, CursorResult, Engine, desc, func, literal_column, select, table +from sqlalchemy import Column, CursorResult, Engine, desc, func, literal_column, select, table, text from datafaker.generators.base import ( Generator, @@ -14,6 +14,7 @@ dist_gen, fit_from_buckets, ) +from datafaker.utils import schema_qualified_name NumericType = Union[int, float] @@ -51,6 +52,7 @@ def _choice_stmt( sample_count: int | None, suppress_count: int, random_fn: Any, + table_sql: str | None = None, ) -> Any: """Build a SQLAlchemy SELECT for gathering choice value distributions. @@ -59,7 +61,7 @@ def _choice_stmt( without TOP; this function never emits such a clause. """ col = literal_column(f'"{column_name}"') - tbl = table(table_name) + tbl = text(table_sql) if table_sql else table(table_name) if sample_count is not None: sample_sub = ( select(col.label("value")) @@ -108,6 +110,7 @@ def __init__( sample_count: int | None = None, suppress_count: int = 0, dialect: Any = None, + table_sql: str | None = None, ) -> None: """Initialise a ChoiceGenerator.""" super().__init__() @@ -124,7 +127,8 @@ def __init__( else func.random() ) stmt = _choice_stmt( - column_name, table_name, self.STORE_COUNTS, sample_count, suppress_count, random_fn + column_name, table_name, self.STORE_COUNTS, sample_count, suppress_count, random_fn, + table_sql=table_sql, ) compile_opts: dict[str, Any] = {"compile_kwargs": {"literal_binds": True}} if dialect is not None: @@ -333,6 +337,8 @@ def get_generators( column = columns[0] column_name = column.name table_name = column.table.name + table_sql = schema_qualified_name(table_name, engine) + src_table = column.table dialect = engine.dialect random_fn = func.newid() if dialect.name == "mssql" else func.random() col = literal_column(f'"{column_name}"') @@ -353,15 +359,15 @@ def get_generators( generators += [ ZipfChoiceGenerator( table_name, column_name, vg.values, vg.counts, - dialect=dialect, + dialect=dialect, table_sql=table_sql, ), UniformChoiceGenerator( table_name, column_name, vg.values, vg.counts, - dialect=dialect, + dialect=dialect, table_sql=table_sql, ), WeightedChoiceGenerator( table_name, column_name, vg.cvs, vg.counts, - dialect=dialect, + dialect=dialect, table_sql=table_sql, ), ] if vg.counts_not_suppressed: @@ -370,17 +376,20 @@ def get_generators( table_name, column_name, vg.values_not_suppressed, vg.counts_not_suppressed, suppress_count=self.SUPPRESS_COUNT, dialect=dialect, + table_sql=table_sql, ), UniformChoiceGenerator( table_name, column_name, vg.values_not_suppressed, vg.counts_not_suppressed, suppress_count=self.SUPPRESS_COUNT, dialect=dialect, + table_sql=table_sql, ), WeightedChoiceGenerator( table_name=table_name, column_name=column_name, values=vg.cvs_not_suppressed, counts=vg.counts_not_suppressed, suppress_count=self.SUPPRESS_COUNT, dialect=dialect, + table_sql=table_sql, ), ] inner = ( @@ -404,14 +413,17 @@ def get_generators( ZipfChoiceGenerator( table_name, column_name, vg.values, vg.counts, sample_count=self.SAMPLE_COUNT, dialect=dialect, + table_sql=table_sql, ), UniformChoiceGenerator( table_name, column_name, vg.values, vg.counts, sample_count=self.SAMPLE_COUNT, dialect=dialect, + table_sql=table_sql, ), WeightedChoiceGenerator( table_name, column_name, vg.cvs, vg.counts, sample_count=self.SAMPLE_COUNT, dialect=dialect, + table_sql=table_sql, ), ] if vg.counts_not_suppressed: @@ -421,12 +433,14 @@ def get_generators( vg.values_not_suppressed, vg.counts_not_suppressed, sample_count=self.SAMPLE_COUNT, suppress_count=self.SUPPRESS_COUNT, dialect=dialect, + table_sql=table_sql, ), UniformChoiceGenerator( table_name, column_name, vg.values_not_suppressed, vg.counts_not_suppressed, sample_count=self.SAMPLE_COUNT, suppress_count=self.SUPPRESS_COUNT, dialect=dialect, + table_sql=table_sql, ), WeightedChoiceGenerator( table_name=table_name, column_name=column_name, @@ -434,6 +448,7 @@ def get_generators( counts=vg.counts_not_suppressed, sample_count=self.SAMPLE_COUNT, suppress_count=self.SUPPRESS_COUNT, dialect=dialect, + table_sql=table_sql, ), ] return generators diff --git a/datafaker/interactive/generators.py b/datafaker/interactive/generators.py index 77b9acb..dd4d820 100644 --- a/datafaker/interactive/generators.py +++ b/datafaker/interactive/generators.py @@ -293,8 +293,7 @@ def _copy_entries(self) -> None: if kwn: rg["kwargs"] = kwn rgs.append(rg) - aq_table = schema_qualified_name(entry.name, self.sync_engine) - aq = self._get_aggregate_query(new_gens, aq_table) + aq = self._get_aggregate_query(new_gens, entry.name) if aq: src_stats.append( { @@ -712,7 +711,8 @@ def _get_aggregate_query( ] if not clauses: return None - return f"SELECT {', '.join(clauses)} FROM {table_name}" + qualified = schema_qualified_name(table_name, self.sync_engine) + return f"SELECT {', '.join(clauses)} FROM {qualified}" def _print_select_aggregate_query(self, table_name: str, gen: Generator) -> None: """ @@ -749,9 +749,7 @@ def _print_select_aggregate_query(self, table_name: str, gen: Generator) -> None table_name, n, ) - select_q = self._get_aggregate_query( - [gen], schema_qualified_name(table_name, self.sync_engine) - ) + select_q = self._get_aggregate_query([gen], table_name) self.print("{0}; providing the following values: {1}", select_q, vals) def _get_column_data( diff --git a/examples/omop-mssql/config.yaml b/examples/omop-mssql/config.yaml index c390d6f..62966f1 100644 --- a/examples/omop-mssql/config.yaml +++ b/examples/omop-mssql/config.yaml @@ -1,9 +1,34 @@ +src-stats: +- comments: + - All the values and their counts that appear in column gender_concept_id of table + person more than 7 times + name: auto__person__gender_concept_id + query: "SELECT _counted.value, _counted.count \nFROM (SELECT \"gender_concept_id\"\ + \ AS value, count(\"gender_concept_id\") AS count \nFROM mimic100.person \nWHERE\ + \ \"gender_concept_id\" IS NOT NULL GROUP BY \"gender_concept_id\") AS _counted\ + \ \nWHERE _counted.count > 7" +- comments: + - The values and their counts that appear in column year_of_birth of a random sample + of 500 rows of table person + name: auto__person__year_of_birth + query: "SELECT _counted.value, _counted.count \nFROM (SELECT _inner.value AS value,\ + \ count(_inner.value) AS count \nFROM (SELECT TOP 500 \"year_of_birth\" AS value\ + \ \nFROM mimic100.person \nWHERE \"year_of_birth\" IS NOT NULL ORDER BY newid())\ + \ AS _inner GROUP BY _inner.value) AS _counted ORDER BY _counted.count DESC" tables: - # Vocab tables concept: - # This one is a vocab, but its too big to handle the usual way ignore: false vocabulary_table: true - person: num_rows_per_pass: 10 + row_generators: + - columns_assigned: + - gender_concept_id + kwargs: + a: SRC_STATS["auto__person__gender_concept_id"]["results"] + name: dist_gen.weighted_choice + - columns_assigned: + - year_of_birth + kwargs: + a: SRC_STATS["auto__person__year_of_birth"]["results"] + name: dist_gen.weighted_choice diff --git a/examples/omop-mssql/df.py b/examples/omop-mssql/df.py index 0b2ffff..7bfe79a 100644 --- a/examples/omop-mssql/df.py +++ b/examples/omop-mssql/df.py @@ -35,6 +35,12 @@ generic.add_provider(WeightedBooleanProvider) +import yaml + +with open("src-stats.yaml", "r", encoding="utf-8") as f: + SRC_STATS = yaml.unsafe_load(f) + + class PersonGenerator(TableGenerator): num_rows_per_pass = 10 @@ -45,75 +51,16 @@ def __call__(self, dst_db_conn, metadata): if not self.initialized: self.initialized = True result = {} - columns_to_generate = set( - { - "birth_datetime", - "ethnicity_source_value", - "ethnicity_source_concept_id", - "ethnicity_concept_id", - "person_source_value", - "race_concept_id", - "month_of_birth", - "race_source_value", - "gender_source_value", - "day_of_birth", - "gender_concept_id", - "race_source_concept_id", - "gender_source_concept_id", - "year_of_birth", - } - ) + columns_to_generate = set({"gender_concept_id", "year_of_birth"}) while columns_to_generate: - if "birth_datetime" in columns_to_generate: - result["birth_datetime"] = generic.datetime.datetime() - if "day_of_birth" in columns_to_generate: - result["day_of_birth"] = generic.numeric.integer_number() - if "ethnicity_concept_id" in columns_to_generate: - result[ - "ethnicity_concept_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["concept"], "concept_id" - ) - if "ethnicity_source_concept_id" in columns_to_generate: - result[ - "ethnicity_source_concept_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["concept"], "concept_id" - ) - if "ethnicity_source_value" in columns_to_generate: - result["ethnicity_source_value"] = generic.person.password(length=50) if "gender_concept_id" in columns_to_generate: - result[ - "gender_concept_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["concept"], "concept_id" + result["gender_concept_id"] = dist_gen.weighted_choice( + a=SRC_STATS["auto__person__gender_concept_id"]["results"] ) - if "gender_source_concept_id" in columns_to_generate: - result[ - "gender_source_concept_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["concept"], "concept_id" - ) - if "gender_source_value" in columns_to_generate: - result["gender_source_value"] = generic.person.password(length=50) - if "month_of_birth" in columns_to_generate: - result["month_of_birth"] = generic.numeric.integer_number() - if "person_source_value" in columns_to_generate: - result["person_source_value"] = generic.person.password(length=50) - if "race_concept_id" in columns_to_generate: - result["race_concept_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["concept"], "concept_id" - ) - if "race_source_concept_id" in columns_to_generate: - result[ - "race_source_concept_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["concept"], "concept_id" - ) - if "race_source_value" in columns_to_generate: - result["race_source_value"] = generic.person.password(length=50) if "year_of_birth" in columns_to_generate: - result["year_of_birth"] = generic.numeric.integer_number() + result["year_of_birth"] = dist_gen.weighted_choice( + a=SRC_STATS["auto__person__year_of_birth"]["results"] + ) columns_to_generate = set() return result diff --git a/examples/omop-mssql/orm.yaml b/examples/omop-mssql/orm.yaml index da7c81d..236e542 100644 --- a/examples/omop-mssql/orm.yaml +++ b/examples/omop-mssql/orm.yaml @@ -46,74 +46,74 @@ tables: unique: [] person: columns: - birth_datetime: - nullable: true - primary: false - type: DATETIME2 - day_of_birth: - nullable: true - primary: false - type: BIGINT + # birth_datetime: + # nullable: true + # primary: false + # type: DATETIME2 + # day_of_birth: + # nullable: true + # primary: false + # type: BIGINT ethnicity_concept_id: foreign_keys: - mimic100.concept.concept_id nullable: false primary: false type: BIGINT - ethnicity_source_concept_id: - foreign_keys: - - mimic100.concept.concept_id - nullable: true - primary: false - type: BIGINT - ethnicity_source_value: - nullable: true - primary: false - type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS + # ethnicity_source_concept_id: + # foreign_keys: + # - mimic100.concept.concept_id + # nullable: true + # primary: false + # type: BIGINT + # ethnicity_source_value: + # nullable: true + # primary: false + # type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS gender_concept_id: foreign_keys: - mimic100.concept.concept_id nullable: false primary: false type: BIGINT - gender_source_concept_id: - foreign_keys: - - mimic100.concept.concept_id - nullable: true - primary: false - type: BIGINT - gender_source_value: - nullable: true - primary: false - type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS - month_of_birth: - nullable: true - primary: false - type: BIGINT + # gender_source_concept_id: + # foreign_keys: + # - mimic100.concept.concept_id + # nullable: true + # primary: false + # type: BIGINT + # gender_source_value: + # nullable: true + # primary: false + # type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS + # month_of_birth: + # nullable: true + # primary: false + # type: BIGINT person_id: nullable: false primary: true type: BIGINT - person_source_value: - nullable: true - primary: false - type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS - race_concept_id: - foreign_keys: - - mimic100.concept.concept_id - nullable: false - primary: false - type: BIGINT - race_source_concept_id: - foreign_keys: - - mimic100.concept.concept_id - nullable: true - primary: false - type: BIGINT - race_source_value: - nullable: true - primary: false - type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS + # person_source_value: + # nullable: true + # primary: false + # type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS + # race_concept_id: + # foreign_keys: + # - mimic100.concept.concept_id + # nullable: false + # primary: false + # type: BIGINT + # race_source_concept_id: + # foreign_keys: + # - mimic100.concept.concept_id + # nullable: true + # primary: false + # type: BIGINT + # race_source_value: + # nullable: true + # primary: false + # type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS year_of_birth: nullable: false primary: false diff --git a/examples/omop-postgresql/README.md b/examples/omop-postgresql/README.md index 8467583..9a79779 100644 --- a/examples/omop-postgresql/README.md +++ b/examples/omop-postgresql/README.md @@ -7,6 +7,9 @@ 1. Interactively set generators for column data. `poetry run datafaker configure-generators --orm-file ./orm.yaml --config-file ./config.yaml` +1. Compute summary statistics from the source database. +`poetry run datafaker make-stats --orm-file ./orm.yaml --config-file ./config.yaml --stats-file ./src-stats.yaml` + 1. Create schema from the ORM YAML file `poetry run datafaker create-tables --orm-file ./orm.yaml --config-file ./config.yaml` @@ -22,3 +25,5 @@ 1. Remove data `poetry run datafaker remove-data --orm-file ./orm.yaml --config-file ./config.yaml` + +Plan: /Users/myong/.claude/plans/cached-rolling-snowglobe.md \ No newline at end of file diff --git a/tests/test_generators_dialect.py b/tests/test_generators_dialect.py index dea5172..04a9672 100644 --- a/tests/test_generators_dialect.py +++ b/tests/test_generators_dialect.py @@ -497,12 +497,9 @@ def test_schema_qualified_name_parses_clauses(self) -> None: class TestAggregateQuerySchemaQualified(unittest.TestCase): - """_copy_entries writes schema-qualified table names into src-stats SQL.""" - - def test_aggregate_query_includes_schema(self) -> None: - """_get_aggregate_query uses the schema-qualified name when engine has schema map.""" - from unittest.mock import MagicMock, patch + """_get_aggregate_query qualifies table names using the engine's schema_translate_map.""" + def _make_shell(self, schema: str | None): from datafaker.interactive.generators import GeneratorCmd from datafaker.generators.base import Generator @@ -512,28 +509,28 @@ def test_aggregate_query_includes_schema(self) -> None: } engine = MagicMock() - engine.get_execution_options.return_value = {"schema_translate_map": {None: "myschema"}} + schema_map = {None: schema} if schema else {} + engine.get_execution_options.return_value = {"schema_translate_map": schema_map} shell = MagicMock(spec=GeneratorCmd) shell.sync_engine = engine + return shell, gen + + def test_aggregate_query_includes_schema(self) -> None: + """_get_aggregate_query qualifies the bare table name when engine has a schema map.""" + from datafaker.interactive.generators import GeneratorCmd - result = GeneratorCmd._get_aggregate_query(shell, [gen], "myschema.person") + shell, gen = self._make_shell("myschema") + result = GeneratorCmd._get_aggregate_query(shell, [gen], "person") self.assertIsNotNone(result) self.assertIn("myschema.person", result) - self.assertNotIn("FROM person", result.replace("myschema.person", "")) def test_aggregate_query_no_schema(self) -> None: """_get_aggregate_query uses the bare name when no schema is set.""" - from unittest.mock import MagicMock - from datafaker.interactive.generators import GeneratorCmd - from datafaker.generators.base import Generator - - gen = MagicMock(spec=Generator) - gen.select_aggregate_clauses.return_value = { - "mean__age": {"clause": "AVG(age)", "comment": None} - } - result = GeneratorCmd._get_aggregate_query(None, [gen], "person") + shell, gen = self._make_shell(None) + result = GeneratorCmd._get_aggregate_query(shell, [gen], "person") self.assertIsNotNone(result) self.assertIn("FROM person", result) + self.assertNotIn(".", result.split("FROM ")[-1]) From 3aefaa289a217b2264a4388a7b6cad425c1bc148 Mon Sep 17 00:00:00 2001 From: May Yong Date: Wed, 27 May 2026 15:25:32 +0100 Subject: [PATCH 32/45] Config files for omop-mssql and omop-postgresl --- examples/omop-mssql/config.yaml | 38 ++++++++---- examples/omop-mssql/df.py | 19 +++++- examples/omop-mssql/orm.yaml | 12 ++-- examples/omop-postgresql/config.yaml | 57 +++++++++++++++-- examples/omop-postgresql/df.py | 70 +++++---------------- examples/omop-postgresql/orm.yaml | 92 ++++++++++++++-------------- 6 files changed, 163 insertions(+), 125 deletions(-) diff --git a/examples/omop-mssql/config.yaml b/examples/omop-mssql/config.yaml index 62966f1..d58d83d 100644 --- a/examples/omop-mssql/config.yaml +++ b/examples/omop-mssql/config.yaml @@ -1,20 +1,27 @@ src-stats: - comments: - - All the values and their counts that appear in column gender_concept_id of table - person more than 7 times + - The values and their counts that appear in column gender_concept_id of a random + sample of 500 rows of table person name: auto__person__gender_concept_id - query: "SELECT _counted.value, _counted.count \nFROM (SELECT \"gender_concept_id\"\ - \ AS value, count(\"gender_concept_id\") AS count \nFROM mimic100.person \nWHERE\ - \ \"gender_concept_id\" IS NOT NULL GROUP BY \"gender_concept_id\") AS _counted\ - \ \nWHERE _counted.count > 7" + query: "SELECT _counted.value, _counted.count \nFROM (SELECT _inner.value AS value,\ + \ count(_inner.value) AS count \nFROM (SELECT TOP 500 \"gender_concept_id\" AS\ + \ value \nFROM mimic100.person \nWHERE \"gender_concept_id\" IS NOT NULL ORDER\ + \ BY newid()) AS _inner GROUP BY _inner.value) AS _counted ORDER BY _counted.count\ + \ DESC" - comments: - - The values and their counts that appear in column year_of_birth of a random sample - of 500 rows of table person + - All the values that appear in column year_of_birth of table person name: auto__person__year_of_birth - query: "SELECT _counted.value, _counted.count \nFROM (SELECT _inner.value AS value,\ - \ count(_inner.value) AS count \nFROM (SELECT TOP 500 \"year_of_birth\" AS value\ - \ \nFROM mimic100.person \nWHERE \"year_of_birth\" IS NOT NULL ORDER BY newid())\ - \ AS _inner GROUP BY _inner.value) AS _counted ORDER BY _counted.count DESC" + query: "SELECT _counted.value \nFROM (SELECT \"year_of_birth\" AS value, count(\"\ + year_of_birth\") AS count \nFROM mimic100.person \nWHERE \"year_of_birth\" IS\ + \ NOT NULL GROUP BY \"year_of_birth\") AS _counted ORDER BY _counted.count DESC" +- comments: + - All the values that appear in column ethnicity_concept_id of table person more + than 7 times + name: auto__person__ethnicity_concept_id + query: "SELECT _counted.value \nFROM (SELECT \"ethnicity_concept_id\" AS value,\ + \ count(\"ethnicity_concept_id\") AS count \nFROM mimic100.person \nWHERE \"ethnicity_concept_id\"\ + \ IS NOT NULL GROUP BY \"ethnicity_concept_id\") AS _counted \nWHERE _counted.count\ + \ > 7" tables: concept: ignore: false @@ -31,4 +38,9 @@ tables: - year_of_birth kwargs: a: SRC_STATS["auto__person__year_of_birth"]["results"] - name: dist_gen.weighted_choice + name: dist_gen.choice + - columns_assigned: + - ethnicity_concept_id + kwargs: + a: SRC_STATS["auto__person__ethnicity_concept_id"]["results"] + name: dist_gen.choice diff --git a/examples/omop-mssql/df.py b/examples/omop-mssql/df.py index 7bfe79a..445f7f7 100644 --- a/examples/omop-mssql/df.py +++ b/examples/omop-mssql/df.py @@ -51,16 +51,31 @@ def __call__(self, dst_db_conn, metadata): if not self.initialized: self.initialized = True result = {} - columns_to_generate = set({"gender_concept_id", "year_of_birth"}) + columns_to_generate = set( + { + "ethnicity_concept_id", + "race_concept_id", + "gender_concept_id", + "year_of_birth", + } + ) while columns_to_generate: if "gender_concept_id" in columns_to_generate: result["gender_concept_id"] = dist_gen.weighted_choice( a=SRC_STATS["auto__person__gender_concept_id"]["results"] ) if "year_of_birth" in columns_to_generate: - result["year_of_birth"] = dist_gen.weighted_choice( + result["year_of_birth"] = dist_gen.choice( a=SRC_STATS["auto__person__year_of_birth"]["results"] ) + if "ethnicity_concept_id" in columns_to_generate: + result["ethnicity_concept_id"] = dist_gen.choice( + a=SRC_STATS["auto__person__ethnicity_concept_id"]["results"] + ) + if "race_concept_id" in columns_to_generate: + result["race_concept_id"] = generic.column_value_provider.column_value( + dst_db_conn, metadata.tables["concept"], "concept_id" + ) columns_to_generate = set() return result diff --git a/examples/omop-mssql/orm.yaml b/examples/omop-mssql/orm.yaml index 236e542..46fa10a 100644 --- a/examples/omop-mssql/orm.yaml +++ b/examples/omop-mssql/orm.yaml @@ -98,12 +98,12 @@ tables: # nullable: true # primary: false # type: VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS - # race_concept_id: - # foreign_keys: - # - mimic100.concept.concept_id - # nullable: false - # primary: false - # type: BIGINT + race_concept_id: + foreign_keys: + - mimic100.concept.concept_id + nullable: false + primary: false + type: BIGINT # race_source_concept_id: # foreign_keys: # - mimic100.concept.concept_id diff --git a/examples/omop-postgresql/config.yaml b/examples/omop-postgresql/config.yaml index ce0204a..b94eef4 100644 --- a/examples/omop-postgresql/config.yaml +++ b/examples/omop-postgresql/config.yaml @@ -1,10 +1,59 @@ +src-stats: +- comments: + - All the values and their counts that appear in column ethnicity_concept_id of + table person + name: auto__person__ethnicity_concept_id + query: "SELECT _counted.value, _counted.count \nFROM (SELECT \"ethnicity_concept_id\"\ + \ AS value, count(\"ethnicity_concept_id\") AS count \nFROM mimic.person \nWHERE\ + \ \"ethnicity_concept_id\" IS NOT NULL GROUP BY \"ethnicity_concept_id\") AS _counted\ + \ ORDER BY _counted.count DESC" +- comments: + - All the values and their counts that appear in column gender_concept_id of table + person + name: auto__person__gender_concept_id + query: "SELECT _counted.value, _counted.count \nFROM (SELECT \"gender_concept_id\"\ + \ AS value, count(\"gender_concept_id\") AS count \nFROM mimic.person \nWHERE\ + \ \"gender_concept_id\" IS NOT NULL GROUP BY \"gender_concept_id\") AS _counted\ + \ ORDER BY _counted.count DESC" +- comments: + - All the values and their counts that appear in column race_concept_id of table + person + name: auto__person__race_concept_id + query: "SELECT _counted.value, _counted.count \nFROM (SELECT \"race_concept_id\"\ + \ AS value, count(\"race_concept_id\") AS count \nFROM mimic.person \nWHERE \"\ + race_concept_id\" IS NOT NULL GROUP BY \"race_concept_id\") AS _counted ORDER\ + \ BY _counted.count DESC" +- comments: + - All the values and their counts that appear in column year_of_birth of table person + name: auto__person__year_of_birth + query: "SELECT _counted.value, _counted.count \nFROM (SELECT \"year_of_birth\" AS\ + \ value, count(\"year_of_birth\") AS count \nFROM mimic.person \nWHERE \"year_of_birth\"\ + \ IS NOT NULL GROUP BY \"year_of_birth\") AS _counted ORDER BY _counted.count\ + \ DESC" tables: - # Vocab tables concept: - # This one is a vocab, but its too big to handle the usual way ignore: false vocabulary_table: true - person: num_rows_per_pass: 1 - + row_generators: + - columns_assigned: + - ethnicity_concept_id + kwargs: + a: SRC_STATS["auto__person__ethnicity_concept_id"]["results"] + name: dist_gen.weighted_choice + - columns_assigned: + - gender_concept_id + kwargs: + a: SRC_STATS["auto__person__gender_concept_id"]["results"] + name: dist_gen.weighted_choice + - columns_assigned: + - race_concept_id + kwargs: + a: SRC_STATS["auto__person__race_concept_id"]["results"] + name: dist_gen.weighted_choice + - columns_assigned: + - year_of_birth + kwargs: + a: SRC_STATS["auto__person__year_of_birth"]["results"] + name: dist_gen.weighted_choice diff --git a/examples/omop-postgresql/df.py b/examples/omop-postgresql/df.py index 7557bab..6889cf9 100644 --- a/examples/omop-postgresql/df.py +++ b/examples/omop-postgresql/df.py @@ -35,6 +35,12 @@ generic.add_provider(WeightedBooleanProvider) +import yaml + +with open("src-stats.yaml", "r", encoding="utf-8") as f: + SRC_STATS = yaml.unsafe_load(f) + + class PersonGenerator(TableGenerator): num_rows_per_pass = 1 @@ -47,73 +53,29 @@ def __call__(self, dst_db_conn, metadata): result = {} columns_to_generate = set( { - "ethnicity_source_value", - "race_concept_id", "ethnicity_concept_id", - "day_of_birth", - "birth_datetime", - "ethnicity_source_concept_id", - "race_source_concept_id", "year_of_birth", - "gender_source_concept_id", - "person_source_value", - "month_of_birth", - "race_source_value", - "gender_source_value", "gender_concept_id", + "race_concept_id", } ) while columns_to_generate: - if "birth_datetime" in columns_to_generate: - result["birth_datetime"] = generic.datetime.datetime() - if "day_of_birth" in columns_to_generate: - result["day_of_birth"] = generic.numeric.integer_number() if "ethnicity_concept_id" in columns_to_generate: - result[ - "ethnicity_concept_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["concept"], "concept_id" + result["ethnicity_concept_id"] = dist_gen.weighted_choice( + a=SRC_STATS["auto__person__ethnicity_concept_id"]["results"] ) - if "ethnicity_source_concept_id" in columns_to_generate: - result[ - "ethnicity_source_concept_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["concept"], "concept_id" - ) - if "ethnicity_source_value" in columns_to_generate: - result["ethnicity_source_value"] = generic.person.password(length=50) if "gender_concept_id" in columns_to_generate: - result[ - "gender_concept_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["concept"], "concept_id" - ) - if "gender_source_concept_id" in columns_to_generate: - result[ - "gender_source_concept_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["concept"], "concept_id" + result["gender_concept_id"] = dist_gen.weighted_choice( + a=SRC_STATS["auto__person__gender_concept_id"]["results"] ) - if "gender_source_value" in columns_to_generate: - result["gender_source_value"] = generic.person.password(length=50) - if "month_of_birth" in columns_to_generate: - result["month_of_birth"] = generic.numeric.integer_number() - if "person_source_value" in columns_to_generate: - result["person_source_value"] = generic.person.password(length=50) if "race_concept_id" in columns_to_generate: - result["race_concept_id"] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["concept"], "concept_id" + result["race_concept_id"] = dist_gen.weighted_choice( + a=SRC_STATS["auto__person__race_concept_id"]["results"] ) - if "race_source_concept_id" in columns_to_generate: - result[ - "race_source_concept_id" - ] = generic.column_value_provider.column_value( - dst_db_conn, metadata.tables["concept"], "concept_id" - ) - if "race_source_value" in columns_to_generate: - result["race_source_value"] = generic.person.password(length=50) if "year_of_birth" in columns_to_generate: - result["year_of_birth"] = generic.numeric.integer_number() + result["year_of_birth"] = dist_gen.weighted_choice( + a=SRC_STATS["auto__person__year_of_birth"]["results"] + ) columns_to_generate = set() return result diff --git a/examples/omop-postgresql/orm.yaml b/examples/omop-postgresql/orm.yaml index 59dc201..b526fe8 100644 --- a/examples/omop-postgresql/orm.yaml +++ b/examples/omop-postgresql/orm.yaml @@ -52,74 +52,74 @@ tables: unique: [] person: columns: - birth_datetime: - nullable: true - primary: false - type: TIMESTAMP WITHOUT TIME ZONE - day_of_birth: - nullable: true - primary: false - type: BIGINT + # birth_datetime: + # nullable: true + # primary: false + # type: TIMESTAMP WITHOUT TIME ZONE + # day_of_birth: + # nullable: true + # primary: false + # type: BIGINT ethnicity_concept_id: foreign_keys: - concept.concept_id nullable: false primary: false type: BIGINT - ethnicity_source_concept_id: - foreign_keys: - - concept.concept_id - nullable: true - primary: false - type: BIGINT - ethnicity_source_value: - nullable: true - primary: false - type: VARCHAR(50) + # ethnicity_source_concept_id: + # foreign_keys: + # - concept.concept_id + # nullable: true + # primary: false + # type: BIGINT + # ethnicity_source_value: + # nullable: true + # primary: false + # type: VARCHAR(50) gender_concept_id: foreign_keys: - concept.concept_id nullable: false primary: false type: BIGINT - gender_source_concept_id: - foreign_keys: - - concept.concept_id - nullable: true - primary: false - type: BIGINT - gender_source_value: - nullable: true - primary: false - type: VARCHAR(50) - month_of_birth: - nullable: true - primary: false - type: BIGINT + # gender_source_concept_id: + # foreign_keys: + # - concept.concept_id + # nullable: true + # primary: false + # type: BIGINT + # gender_source_value: + # nullable: true + # primary: false + # type: VARCHAR(50) + # month_of_birth: + # nullable: true + # primary: false + # type: BIGINT person_id: nullable: false primary: true type: BIGINT - person_source_value: - nullable: true - primary: false - type: VARCHAR(50) + # person_source_value: + # nullable: true + # primary: false + # type: VARCHAR(50) race_concept_id: foreign_keys: - concept.concept_id nullable: false primary: false type: BIGINT - race_source_concept_id: - foreign_keys: - - concept.concept_id - nullable: true - primary: false - type: BIGINT - race_source_value: - nullable: true - primary: false - type: VARCHAR(50) + # race_source_concept_id: + # foreign_keys: + # - concept.concept_id + # nullable: true + # primary: false + # type: BIGINT + # race_source_value: + # nullable: true + # primary: false + # type: VARCHAR(50) year_of_birth: nullable: false primary: false From 3b096197ad9d4dab9797092c31df5c54c9a0765d Mon Sep 17 00:00:00 2001 From: May Yong Date: Mon, 29 Jun 2026 11:11:06 +0100 Subject: [PATCH 33/45] Add example source stats file --- examples/omop-mssql/src-stats.yaml | 102 +++++++++++++ examples/omop-postgresql/src-stats.yaml | 193 ++++++++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 examples/omop-mssql/src-stats.yaml create mode 100644 examples/omop-postgresql/src-stats.yaml diff --git a/examples/omop-mssql/src-stats.yaml b/examples/omop-mssql/src-stats.yaml new file mode 100644 index 0000000..17f5b39 --- /dev/null +++ b/examples/omop-mssql/src-stats.yaml @@ -0,0 +1,102 @@ +auto__person__ethnicity_concept_id: + comments: + - All the values that appear in column ethnicity_concept_id of table person more + than 7 times + queries: + date: '2026-05-22 15:26:05' + query: "SELECT _counted.value \nFROM (SELECT \"ethnicity_concept_id\" AS value,\ + \ count(\"ethnicity_concept_id\") AS count \nFROM mimic100.person \nWHERE \"\ + ethnicity_concept_id\" IS NOT NULL GROUP BY \"ethnicity_concept_id\") AS _counted\ + \ \nWHERE _counted.count > 7" + results: + - value: 0 +auto__person__gender_concept_id: + comments: + - The values and their counts that appear in column gender_concept_id of a random + sample of 500 rows of table person + queries: + date: '2026-05-22 15:26:05' + query: "SELECT _counted.value, _counted.count \nFROM (SELECT _inner.value AS value,\ + \ count(_inner.value) AS count \nFROM (SELECT TOP 500 \"gender_concept_id\"\ + \ AS value \nFROM mimic100.person \nWHERE \"gender_concept_id\" IS NOT NULL\ + \ ORDER BY newid()) AS _inner GROUP BY _inner.value) AS _counted ORDER BY _counted.count\ + \ DESC" + results: + - count: 57 + value: 8507 + - count: 43 + value: 8532 +auto__person__year_of_birth: + comments: + - All the values that appear in column year_of_birth of table person + queries: + date: '2026-05-22 15:26:05' + query: "SELECT _counted.value \nFROM (SELECT \"year_of_birth\" AS value, count(\"\ + year_of_birth\") AS count \nFROM mimic100.person \nWHERE \"year_of_birth\" IS\ + \ NOT NULL GROUP BY \"year_of_birth\") AS _counted ORDER BY _counted.count DESC" + results: + - value: 2062 + - value: 2058 + - value: 2059 + - value: 2070 + - value: 2073 + - value: 2084 + - value: 2119 + - value: 2123 + - value: 2125 + - value: 2102 + - value: 2104 + - value: 2106 + - value: 2136 + - value: 2130 + - value: 2133 + - value: 2055 + - value: 2085 + - value: 2086 + - value: 2089 + - value: 2094 + - value: 2075 + - value: 2079 + - value: 2083 + - value: 2066 + - value: 2043 + - value: 2050 + - value: 2052 + - value: 2054 + - value: 2049 + - value: 2030 + - value: 2031 + - value: 2033 + - value: 2038 + - value: 2041 + - value: 2067 + - value: 2069 + - value: 2064 + - value: 2060 + - value: 2061 + - value: 2077 + - value: 2074 + - value: 2071 + - value: 2095 + - value: 2096 + - value: 2097 + - value: 2099 + - value: 2090 + - value: 2092 + - value: 2093 + - value: 2134 + - value: 2138 + - value: 2145 + - value: 2149 + - value: 2108 + - value: 2111 + - value: 2114 + - value: 2115 + - value: 2116 + - value: 2117 + - value: 2118 + - value: 2105 + - value: 2103 + - value: 2128 + - value: 2120 + - value: 2122 diff --git a/examples/omop-postgresql/src-stats.yaml b/examples/omop-postgresql/src-stats.yaml new file mode 100644 index 0000000..1f9fde3 --- /dev/null +++ b/examples/omop-postgresql/src-stats.yaml @@ -0,0 +1,193 @@ +auto__person__ethnicity_concept_id: + comments: + - All the values and their counts that appear in column ethnicity_concept_id of + table person + queries: + date: '2026-05-22 15:39:07' + query: "SELECT _counted.value, _counted.count \nFROM (SELECT \"ethnicity_concept_id\"\ + \ AS value, count(\"ethnicity_concept_id\") AS count \nFROM mimic.person \n\ + WHERE \"ethnicity_concept_id\" IS NOT NULL GROUP BY \"ethnicity_concept_id\"\ + ) AS _counted ORDER BY _counted.count DESC" + results: + - count: 95 + value: 0 + - count: 5 + value: 38003563 +auto__person__gender_concept_id: + comments: + - All the values and their counts that appear in column gender_concept_id of table + person + queries: + date: '2026-05-22 15:39:07' + query: "SELECT _counted.value, _counted.count \nFROM (SELECT \"gender_concept_id\"\ + \ AS value, count(\"gender_concept_id\") AS count \nFROM mimic.person \nWHERE\ + \ \"gender_concept_id\" IS NOT NULL GROUP BY \"gender_concept_id\") AS _counted\ + \ ORDER BY _counted.count DESC" + results: + - count: 57 + value: 8507 + - count: 43 + value: 8532 +auto__person__race_concept_id: + comments: + - All the values and their counts that appear in column race_concept_id of table + person + queries: + date: '2026-05-22 15:39:07' + query: "SELECT _counted.value, _counted.count \nFROM (SELECT \"race_concept_id\"\ + \ AS value, count(\"race_concept_id\") AS count \nFROM mimic.person \nWHERE\ + \ \"race_concept_id\" IS NOT NULL GROUP BY \"race_concept_id\") AS _counted\ + \ ORDER BY _counted.count DESC" + results: + - count: 64 + value: 8527 + - count: 13 + value: 2000001401 + - count: 10 + value: 8516 + - count: 5 + value: 0 + - count: 5 + value: 2000001402 + - count: 3 + value: 2000001405 +auto__person__year_of_birth: + comments: + - All the values and their counts that appear in column year_of_birth of table person + queries: + date: '2026-05-22 15:39:07' + query: "SELECT _counted.value, _counted.count \nFROM (SELECT \"year_of_birth\"\ + \ AS value, count(\"year_of_birth\") AS count \nFROM mimic.person \nWHERE \"\ + year_of_birth\" IS NOT NULL GROUP BY \"year_of_birth\") AS _counted ORDER BY\ + \ _counted.count DESC" + results: + - count: 4 + value: 2062 + - count: 3 + value: 2070 + - count: 3 + value: 2058 + - count: 3 + value: 2073 + - count: 3 + value: 2119 + - count: 3 + value: 2084 + - count: 3 + value: 2059 + - count: 2 + value: 2125 + - count: 2 + value: 2094 + - count: 2 + value: 2136 + - count: 2 + value: 2083 + - count: 2 + value: 2052 + - count: 2 + value: 2106 + - count: 2 + value: 2123 + - count: 2 + value: 2066 + - count: 2 + value: 2104 + - count: 2 + value: 2089 + - count: 2 + value: 2102 + - count: 2 + value: 2075 + - count: 2 + value: 2043 + - count: 2 + value: 2079 + - count: 2 + value: 2050 + - count: 2 + value: 2133 + - count: 2 + value: 2055 + - count: 2 + value: 2086 + - count: 2 + value: 2085 + - count: 2 + value: 2130 + - count: 1 + value: 2033 + - count: 1 + value: 2031 + - count: 1 + value: 2117 + - count: 1 + value: 2122 + - count: 1 + value: 2099 + - count: 1 + value: 2069 + - count: 1 + value: 2149 + - count: 1 + value: 2095 + - count: 1 + value: 2092 + - count: 1 + value: 2071 + - count: 1 + value: 2145 + - count: 1 + value: 2049 + - count: 1 + value: 2030 + - count: 1 + value: 2128 + - count: 1 + value: 2074 + - count: 1 + value: 2114 + - count: 1 + value: 2108 + - count: 1 + value: 2060 + - count: 1 + value: 2097 + - count: 1 + value: 2116 + - count: 1 + value: 2064 + - count: 1 + value: 2090 + - count: 1 + value: 2038 + - count: 1 + value: 2077 + - count: 1 + value: 2103 + - count: 1 + value: 2041 + - count: 1 + value: 2138 + - count: 1 + value: 2096 + - count: 1 + value: 2093 + - count: 1 + value: 2061 + - count: 1 + value: 2118 + - count: 1 + value: 2120 + - count: 1 + value: 2111 + - count: 1 + value: 2067 + - count: 1 + value: 2134 + - count: 1 + value: 2105 + - count: 1 + value: 2115 + - count: 1 + value: 2054 From 530ed2f361dce16a22146f64a1091fa0161f2fad Mon Sep 17 00:00:00 2001 From: May Yong Date: Mon, 29 Jun 2026 17:30:00 +0100 Subject: [PATCH 34/45] Add MS-SQL end-to-end test infrastructure - Fix create_db_engine to use make_async_dsn() for dialect-correct async DSN conversion and schema_translate_map for MS-SQL schema qualification (search_path is PostgreSQL-only) - Add TestMSSQL base class (reads MSSQL_TEST_DSN env var, skips gracefully when absent) to tests/utils.py - Add tests/test_functional_mssql.py: smoke connect, make-tables, make-stats, create-data, NEWID() dialect check, ON DELETE CASCADE stripping - Add docker-compose.yml for local SQL Server 2022 dev environment - Add .github/workflows/tests-mssql.yml CI workflow (installs ODBC Driver 18, runs mssql extras, exercises test_functional_mssql against a service container) Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/tests-mssql.yml | 64 +++++++ datafaker/db_utils.py | 9 +- docker-compose.yml | 25 +++ tests/test_functional_mssql.py | 275 ++++++++++++++++++++++++++++++ tests/utils.py | 84 +++++++++ 5 files changed, 454 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/tests-mssql.yml create mode 100644 docker-compose.yml create mode 100644 tests/test_functional_mssql.py diff --git a/.github/workflows/tests-mssql.yml b/.github/workflows/tests-mssql.yml new file mode 100644 index 0000000..8bedf8f --- /dev/null +++ b/.github/workflows/tests-mssql.yml @@ -0,0 +1,64 @@ +--- +name: mssql integration tests +on: + pull_request: + workflow_dispatch: + +env: + PYTHON_VERSION: "3.10" + MSSQL_SA_PASSWORD: "Datafaker!Test123" + +jobs: + mssql-tests: + runs-on: ubuntu-latest + + services: + mssql: + image: mcr.microsoft.com/mssql/server:2022-latest + env: + ACCEPT_EULA: "Y" + MSSQL_SA_PASSWORD: "Datafaker!Test123" + ports: + - 1433:1433 + options: >- + --health-cmd "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'Datafaker!Test123' -Q 'SELECT 1' -No" + --health-interval 10s + --health-timeout 5s + --health-retries 12 + --health-start-period 30s + + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Install ODBC Driver 18 for SQL Server + shell: bash + run: | + curl -fsSL https://packages.microsoft.com/keys/microsoft.asc \ + | sudo gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg + curl -fsSL "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list" \ + | sudo tee /etc/apt/sources.list.d/mssql-release.list + sudo apt-get update + ACCEPT_EULA=Y sudo apt-get install -y msodbcsql18 + + - name: Install poetry + shell: bash + run: | + sudo apt install python3-poetry + + - name: Configure poetry + shell: bash + run: | + python -m poetry config virtualenvs.in-project true + + - name: Install dependencies (with mssql extras) + shell: bash + run: | + python -m poetry install --extras mssql + + - name: Run MS-SQL integration tests + shell: bash + env: + MSSQL_TEST_DSN: "mssql+pyodbc://sa:Datafaker!Test123@localhost:1433/master?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes" + run: | + poetry run python -m unittest tests.test_functional_mssql -v diff --git a/datafaker/db_utils.py b/datafaker/db_utils.py index 19233cc..c0e0374 100644 --- a/datafaker/db_utils.py +++ b/datafaker/db_utils.py @@ -38,6 +38,7 @@ get_ignored_table_names, get_vocabulary_table_names, logger, + make_async_dsn, make_foreign_key_name, ) @@ -141,8 +142,7 @@ def create_db_engine( """Create a SQLAlchemy Engine.""" try: if use_asyncio: - async_dsn = db_dsn.replace("postgresql://", "postgresql+asyncpg://") - engine: MaybeAsyncEngine = create_async_engine(async_dsn, **kwargs) + engine: MaybeAsyncEngine = create_async_engine(make_async_dsn(db_dsn), **kwargs) else: engine = create_engine(db_dsn, **kwargs) except NoSuchModuleError as exc: @@ -155,7 +155,10 @@ def create_db_engine( settings = {} if schema_name is not None: - settings["search_path"] = schema_name + if get_sync_engine(engine).dialect.name == "mssql": + engine = engine.execution_options(schema_translate_map={None: schema_name}) + else: + settings["search_path"] = schema_name if parquet_dir is not None: joined = ",".join(_find_parquet_directories(parquet_dir)) # double up single quotes diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..dc0beca --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +services: + mssql: + image: mcr.microsoft.com/mssql/server:2022-latest + environment: + ACCEPT_EULA: "Y" + MSSQL_SA_PASSWORD: "Datafaker!Test123" + ports: + - "1433:1433" + healthcheck: + test: + - "CMD" + - "/opt/mssql-tools18/bin/sqlcmd" + - "-S" + - "localhost" + - "-U" + - "sa" + - "-P" + - "Datafaker!Test123" + - "-Q" + - "SELECT 1" + - "-No" + interval: 10s + timeout: 5s + retries: 12 + start_period: 30s diff --git a/tests/test_functional_mssql.py b/tests/test_functional_mssql.py new file mode 100644 index 0000000..d8cfe80 --- /dev/null +++ b/tests/test_functional_mssql.py @@ -0,0 +1,275 @@ +"""End-to-end tests for the MS-SQL Server dialect. + +These tests require a running SQL Server instance. Set the ``MSSQL_TEST_DSN`` +environment variable to a ``mssql+pyodbc://`` connection string to enable them: + + export MSSQL_TEST_DSN="mssql+pyodbc://sa:Datafaker!Test123@localhost:1433/master?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes" + +With docker-compose: + + docker compose up -d mssql + # wait ~30 s for SQL Server to start +""" +import asyncio +import os +from tempfile import mkstemp + +from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, MetaData, String, Table, text +from sqlalchemy import create_engine as sa_create_engine +from sqlalchemy.schema import CreateTable + +import datafaker.create # noqa: F401 — registers @compiles hooks (e.g. strip ON DELETE CASCADE) +from datafaker.db_utils import create_db_engine, create_db_engine_dst, get_sync_engine +from datafaker.make import make_src_stats, make_tables_file +from tests.utils import DatafakerTestCase, GeneratesDBTestCase, TestMSSQL + +import yaml + + +# --------------------------------------------------------------------------- +# Instrument schema (mirrors tests/examples/instrument.sql in dialect-neutral +# SQLAlchemy — avoids the need for a T-SQL .sql fixture file). +# --------------------------------------------------------------------------- + +def _make_src_metadata() -> MetaData: + meta = MetaData() + manufacturer = Table( + "manufacturer", + meta, + Column("id", Integer, primary_key=True, autoincrement=False), + Column("name", String(200), nullable=False), + Column("founded", DateTime, nullable=False), + ) + model = Table( + "model", + meta, + Column("id", Integer, primary_key=True, autoincrement=False), + Column("name", String(200), nullable=False), + Column( + "manufacturer_id", + Integer, + ForeignKey("manufacturer.id", ondelete="CASCADE"), + nullable=False, + ), + Column("introduced", DateTime, nullable=False), + ) + string_table = Table( + "string", + meta, + Column("id", Integer, primary_key=True, autoincrement=False), + Column( + "model_id", + Integer, + ForeignKey("model.id", ondelete="CASCADE"), + nullable=False, + ), + Column("position", Integer, nullable=False), + Column("frequency", Float, nullable=False), + ) + player = Table( + "player", + meta, + Column("id", Integer, primary_key=True, autoincrement=False), + Column("given_name", String(200), nullable=False), + Column("family_name", String(200), nullable=False), + ) + Table( + "signature_model", + meta, + Column("id", Integer, primary_key=True, autoincrement=False), + Column("name", String(20), nullable=False), + Column("player_id", Integer, ForeignKey("player.id"), nullable=True), + Column("based_on", Integer, ForeignKey("model.id"), nullable=True), + ) + # suppress "unused variable" warnings + _ = manufacturer, model, string_table, player + return meta + + +_SRC_METADATA = _make_src_metadata() + +_EXPECTED_TABLES = frozenset( + {"manufacturer", "model", "string", "player", "signature_model"} +) + + +def _insert_sample_rows(engine) -> None: + """Insert a minimal set of rows so make-stats has data to summarise.""" + with engine.begin() as conn: + conn.execute( + _SRC_METADATA.tables["manufacturer"].insert(), + [ + {"id": 1, "name": "Blender", "founded": "1951-01-08 04:05:06"}, + {"id": 2, "name": "Gibbs", "founded": "1959-03-04 07:08:09"}, + ], + ) + conn.execute( + _SRC_METADATA.tables["model"].insert(), + [ + {"id": 1, "name": "S-Type", "manufacturer_id": 1, "introduced": "1952-04-20 04:05:06"}, + {"id": 2, "name": "Pulse", "manufacturer_id": 1, "introduced": "1953-12-02 02:15:06"}, + {"id": 3, "name": "Paul Leslie", "manufacturer_id": 2, "introduced": "1960-02-20 04:05:06"}, + ], + ) + conn.execute( + _SRC_METADATA.tables["string"].insert(), + [ + {"id": 1, "model_id": 1, "position": 1, "frequency": 329.6}, + {"id": 2, "model_id": 1, "position": 2, "frequency": 246.94}, + {"id": 3, "model_id": 2, "position": 1, "frequency": 98.0}, + {"id": 4, "model_id": 3, "position": 1, "frequency": 329.6}, + ], + ) + conn.execute( + _SRC_METADATA.tables["player"].insert(), + [ + {"id": 1, "given_name": "Mark", "family_name": "Samson"}, + {"id": 2, "given_name": "Tim", "family_name": "Friedman"}, + ], + ) + conn.execute( + _SRC_METADATA.tables["signature_model"].insert(), + [ + {"id": 1, "name": "Flame", "player_id": 1, "based_on": None}, + {"id": 2, "name": "Dragon", "player_id": None, "based_on": 1}, + {"id": 3, "name": "Veleno", "player_id": 2, "based_on": 2}, + ], + ) + + +# --------------------------------------------------------------------------- +# Test case +# --------------------------------------------------------------------------- + + +class MSSQLFunctionalTestCase(GeneratesDBTestCase): + """End-to-end tests exercising the full datafaker pipeline against SQL Server.""" + + database_type = TestMSSQL + dump_file_path = None # schema created in Python, not from a .sql file + + # Database names created inside SQL Server for this test run. + database_name = "datafaker_test_src" + _DST_DB = "dst" + + def setUp(self) -> None: + """Create the source schema programmatically and wire up test-case fields. + + Bypasses RequiresDBTestCase.setUp (which calls run_sql) and reimplements + the relevant parts so we can build the schema with SQLAlchemy MetaData. + """ + # DatafakerTestCase.setUp handles CWD bookkeeping without touching the DB. + DatafakerTestCase.setUp(self) + + TestMSSQL.setup() + self.database = TestMSSQL() + self.database.open() + + # Create the source database, build schema, and seed rows. + src_dsn = self.database.create_empty(self.database_name) + src_engine = sa_create_engine(src_dsn) + _SRC_METADATA.create_all(src_engine) + _insert_sample_rows(src_engine) + src_engine.dispose() + + # Engine used by GeneratesDBTestCase helper methods (create_tables, etc.). + self.engine = create_db_engine(src_dsn, schema_name=self.schema_name) + self.sync_engine = get_sync_engine(self.engine) + self.metadata = MetaData() + self.metadata.reflect(self.sync_engine) + + # Empty destination database — create-tables will build the schema there. + self.dst_database = TestMSSQL() + self.dst_database.open() + dst_dsn = self.dst_database.create_empty(self._DST_DB) + self.dst_name = self._DST_DB + self.dst_metadata = MetaData() + self.dst_engine = get_sync_engine( + create_db_engine_dst(dst_dsn, schema_name=self.dst_schema_name) + ) + + # Write orm.yaml so generate_data() has the file it expects. + (self.orm_fd, self.orm_file_path) = mkstemp(".yaml", "orm_", text=True) + with os.fdopen(self.orm_fd, "w", encoding="utf-8") as fh: + fh.write(make_tables_file(src_dsn, self.schema_name)) + + # Initialise stats/config path attributes expected by generate_data(). + self.stats_fd = 0 + self.stats_file_path = "" + self.config_file_path = "" + self.config_fd = 0 + + def tearDown(self) -> None: + if self.database is not None: + self.database.close() + if self.dst_database is not None: + self.dst_database.close() + DatafakerTestCase.tearDown(self) + + # ------------------------------------------------------------------ + # Tests + # ------------------------------------------------------------------ + + def test_smoke_connect(self) -> None: + """ODBC driver can connect and run a trivial query.""" + engine = sa_create_engine(self.dsn) + with engine.connect() as conn: + row = conn.execute(text("SELECT 1 AS n")).fetchone() + self.assertIsNotNone(row) + self.assertEqual(row[0], 1) + + def test_make_tables(self) -> None: + """make_tables_file produces an orm.yaml listing the expected tables.""" + orm_yaml = make_tables_file(self.dsn, self.schema_name) + orm = yaml.safe_load(orm_yaml) + table_names = {t["table_name"] for t in orm.get("tables", [])} + self.assert_subset(_EXPECTED_TABLES, table_names) + + def test_make_stats(self) -> None: + """make_src_stats returns a dict with an entry per source table.""" + loop = asyncio.new_event_loop() + try: + src_stats = loop.run_until_complete( + make_src_stats(self.dsn, {}, self.schema_name) + ) + finally: + loop.close() + self.assertIsInstance(src_stats, dict) + for table_name in _EXPECTED_TABLES: + self.assertIn(table_name, src_stats, f"'{table_name}' missing from src_stats") + + def test_create_data(self) -> None: + """Full pipeline: make-stats → create-tables → create-data inserts rows.""" + self.generate_data({}) + + # Verify that at least the manufacturer table received rows. + assert self.dst_engine is not None + with self.dst_engine.connect() as conn: + count = conn.execute(text("SELECT COUNT(*) FROM manufacturer")).scalar() + self.assertGreater(count, 0, "Expected rows in manufacturer after create-data") + + def test_dialect_newid(self) -> None: + """ChoiceProposer compiles its query with NEWID() not RANDOM() for mssql.""" + from sqlalchemy.dialects import mssql as mssql_dialect # noqa: PLC0415 + from datafaker.proposers.choice import ChoiceProposer # noqa: PLC0415 + + dialect = mssql_dialect.dialect() + proposer = ChoiceProposer( + table_name="manufacturer", + column_name="name", + values=["Blender", "Gibbs"], + counts=[5, 5], + sample_count=2, + dialect=dialect, + ) + self.assertIn("newid()", proposer._query.lower()) + self.assertNotIn("random()", proposer._query.lower()) + + def test_cascade_stripped(self) -> None: + """The @compiles(CreateTable, 'mssql') hook strips ON DELETE CASCADE.""" + from sqlalchemy.dialects import mssql as mssql_dialect # noqa: PLC0415 + + model_table = _SRC_METADATA.tables["model"] + ddl = str(CreateTable(model_table).compile(dialect=mssql_dialect.dialect())) + self.assertIn("FOREIGN KEY", ddl) + self.assertNotIn("ON DELETE CASCADE", ddl) diff --git a/tests/utils.py b/tests/utils.py index 427ba67..e37ea5f 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -246,6 +246,90 @@ def create_empty(self, name: str) -> str: return self.get_dsn(name) +class TestMSSQL(TestDatabaseBase): + """MS-SQL Server test database. + + Requires the ``MSSQL_TEST_DSN`` environment variable to be set to a + ``mssql+pyodbc://`` connection string pointing at a running SQL Server + instance (e.g. the docker-compose ``mssql`` service). + + Tests that use this class are skipped automatically when the variable is + absent or when a connection cannot be established. + """ + + _ENV_VAR = "MSSQL_TEST_DSN" + _base_dsn: str = "" + + @classmethod + def skip(cls) -> str | None: + """Return a skip message if SQL Server is not reachable.""" + dsn = os.environ.get(cls._ENV_VAR) + if not dsn: + return f"set {cls._ENV_VAR} to enable MS-SQL tests" + try: + import pyodbc as _pyodbc # noqa: F401 + except ImportError: + return "pyodbc not installed; run: poetry install --extras mssql" + try: + from sqlalchemy import create_engine as _ce + + with _ce(dsn).connect(): + pass + except Exception as exc: # pylint: disable=broad-except + return f"cannot connect to MS-SQL ({exc})" + return None + + @classmethod + def setup(cls) -> None: + """Store the base DSN for use by all instances.""" + cls._base_dsn = os.environ[cls._ENV_VAR] + + def open(self) -> None: + """Nothing to open — SQL Server runs externally.""" + + def close(self) -> None: + """Nothing to close — SQL Server runs externally.""" + + def get_dsn(self, database_name: str | None) -> str: + """Return a DSN pointing at ``database_name`` within the SQL Server instance.""" + if not database_name: + return self._base_dsn + from sqlalchemy.engine import make_url + + url = make_url(self._base_dsn) + return str(url.set(database=database_name)) + + def create_empty(self, name: str) -> str: + """Create a SQL Server database named ``name`` and return its DSN.""" + dsn = self.get_dsn(name) + from sqlalchemy_utils import create_database, database_exists + + if not database_exists(dsn): + create_database(dsn) + return dsn + + def run_sql(self, sql_file: Path) -> None: + """Execute a T-SQL file via pyodbc, splitting batches on GO.""" + import pyodbc # pylint: disable=import-outside-toplevel + + from sqlalchemy.engine import make_url # pylint: disable=import-outside-toplevel + + url = make_url(self._base_dsn) + conn_str = ( + f"DRIVER={{ODBC Driver 18 for SQL Server}};" + f"SERVER={url.host},{url.port or 1433};" + f"DATABASE={url.database or 'master'};" + f"UID={url.username};PWD={url.password};" + "TrustServerCertificate=yes;" + ) + sql = sql_file.read_text(encoding="utf-8") + with pyodbc.connect(conn_str, autocommit=True) as conn: + for batch in re.split(r"^\s*GO\s*$", sql, flags=re.MULTILINE): + batch = batch.strip() + if batch: + conn.execute(batch) + + class DatafakerTestCase(TestCase): """Parent class for all TestCases in datafaker.""" From f67c61e1e91977d498e261fd92455288f44fa951 Mon Sep 17 00:00:00 2001 From: May Yong Date: Mon, 29 Jun 2026 17:30:12 +0100 Subject: [PATCH 35/45] Fix stale datafaker.generators imports in test_generators_dialect.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The merge of main renamed datafaker/generators/ to datafaker/proposers/ and renamed Generator* classes to Proposer*. Update the mssql-branch test file to match: module paths, class names (ZipfChoiceProposer, ChoiceProposerFactory, etc.), get_generators→get_proposers, Buckets.make_buckets now takes a Table object rather than a string name, and GeneratorCmd._get_aggregate_query was replaced by the module-level get_aggregate_query function. Co-Authored-By: Claude Sonnet 4.6 --- tests/test_generators_dialect.py | 99 ++++++++++++++++---------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/tests/test_generators_dialect.py b/tests/test_generators_dialect.py index 04a9672..ff6c6c1 100644 --- a/tests/test_generators_dialect.py +++ b/tests/test_generators_dialect.py @@ -31,11 +31,11 @@ def _make_engine(self, dialect) -> MagicMock: def test_postgresql_uses_extract(self) -> None: """PostgreSQL year clause uses EXTRACT.""" - from datafaker.generators.mimesis import MimesisDateTimeGenerator + from datafaker.proposers.mimesis import MimesisDateTimeProposer column = self._make_column() engine = self._make_engine(postgresql.dialect) - gens = MimesisDateTimeGenerator.make_singleton(column, engine, "datetime.datetime") + gens = MimesisDateTimeProposer.make_singleton(column, engine, "datetime.datetime") self.assertEqual(len(gens), 1) clauses = gens[0].select_aggregate_clauses() min_clause = clauses["birth_datetime__start"]["clause"] @@ -46,11 +46,11 @@ def test_postgresql_uses_extract(self) -> None: def test_mssql_uses_datepart(self) -> None: """MS-SQL year clause uses DATEPART.""" - from datafaker.generators.mimesis import MimesisDateTimeGenerator + from datafaker.proposers.mimesis import MimesisDateTimeProposer column = self._make_column() engine = self._make_engine(mssql.dialect) - gens = MimesisDateTimeGenerator.make_singleton(column, engine, "datetime.datetime") + gens = MimesisDateTimeProposer.make_singleton(column, engine, "datetime.datetime") self.assertEqual(len(gens), 1) clauses = gens[0].select_aggregate_clauses() min_clause = clauses["birth_datetime__start"]["clause"] @@ -79,7 +79,7 @@ def _make_engine_with_dialect_name(self, dialect_name: str) -> MagicMock: return engine def _get_executed_sql(self, dialect_name: str) -> str: - from datafaker.generators.base import Buckets + from datafaker.proposers.base import Buckets engine = self._make_engine_with_dialect_name(dialect_name) # make_buckets will call engine.connect().execute(stmt) @@ -93,8 +93,9 @@ def capture_execute(stmt, *args, **kwargs): engine.connect.return_value.execute = capture_execute # Prevent the Buckets constructor from running (it uses a separate query) + tbl = Table("person", MetaData(), Column("age", Integer())) with unittest.mock.patch.object(Buckets, "__init__", return_value=None): - Buckets.make_buckets(engine, "person", "age") + Buckets.make_buckets(engine, tbl, tbl.c.age) self.assertEqual(len(executed_stmts), 1) compiled = str(executed_stmts[0].compile( @@ -120,8 +121,8 @@ class TestChoiceGeneratorStoredQuery(unittest.TestCase): """ChoiceGenerator._query is compiled to dialect-correct SQL at construction time.""" def _make_gen(self, dialect, sample_count=None, suppress_count=0): - from datafaker.generators.choice import ZipfChoiceGenerator - return ZipfChoiceGenerator( + from datafaker.proposers.choice import ZipfChoiceProposer + return ZipfChoiceProposer( table_name="patient", column_name="gender", values=["M", "F"], @@ -180,8 +181,8 @@ class TestChoiceGeneratorFactoryLiveQueries(unittest.TestCase): """ChoiceGeneratorFactory.get_generators executes dialect-correct live SQL.""" def _captured_sqls(self, dialect, schema=None) -> list[str]: - """Run get_generators with a mocked engine and return compiled SQL strings.""" - from datafaker.generators.choice import ChoiceGeneratorFactory + """Run get_proposers with a mocked engine and return compiled SQL strings.""" + from datafaker.proposers.choice import ChoiceProposerFactory engine = MagicMock() engine.dialect = dialect @@ -215,7 +216,7 @@ def capture(stmt, *args, **kwargs): meta = MetaData() tbl = Table("patient", meta, Column("gender", Integer()), schema=schema) - ChoiceGeneratorFactory().get_generators([tbl.c.gender], engine) + ChoiceProposerFactory().get_proposers([tbl.c.gender], engine) return [ str(s.compile(dialect=dialect, compile_kwargs={"literal_binds": True})).upper() @@ -270,7 +271,7 @@ def _make_engine(self, dialect_name: str) -> MagicMock: return engine def _get_make_buckets_sql(self, dialect_name: str, schema: str | None) -> str: - from datafaker.generators.base import Buckets + from datafaker.proposers.base import Buckets engine = self._make_engine(dialect_name) meta = MetaData() @@ -286,7 +287,7 @@ def capture_execute(stmt, *args, **kwargs): engine.connect.return_value.execute = capture_execute with unittest.mock.patch.object(Buckets, "__init__", return_value=None): - Buckets.make_buckets(engine, "person", "age", src_table=tbl) + Buckets.make_buckets(engine, tbl, tbl.c.age) self.assertGreaterEqual(len(executed_stmts), 1) dialect = mssql.dialect() if dialect_name == "mssql" else postgresql.dialect() @@ -306,9 +307,10 @@ def test_schema_appears_in_from_postgresql(self) -> None: self.assertIn("MYSCHEMA", sql) def test_no_schema_omits_qualifier(self) -> None: - """Without schema, the FROM clause has no dot-qualifier.""" + """Without schema, FROM clause has no schema.table qualifier.""" sql = self._get_make_buckets_sql("postgresql", schema=None) - self.assertNotIn(".", sql) + # A schema qualifier would appear as "SCHEMA.PERSON"; no dot before the table name. + self.assertNotIn(".PERSON", sql) class TestCovariateQueryDialect(unittest.TestCase): @@ -320,7 +322,7 @@ def _make_factory(self) -> MagicMock: return factory def _inner_query(self, dialect_name: str) -> str: - from datafaker.generators.continuous import CovariateQuery + from datafaker.proposers.continuous import CovariateQuery cq = ( CovariateQuery("person", self._make_factory(), dialect_name=dialect_name) @@ -346,7 +348,7 @@ def test_postgresql_uses_random_and_limit(self) -> None: def test_no_sample_count_has_no_random_or_limit(self) -> None: """When sample_count is None no random ordering is emitted.""" - from datafaker.generators.continuous import CovariateQuery + from datafaker.proposers.continuous import CovariateQuery for dialect in ("mssql", "postgresql", ""): with self.subTest(dialect=dialect): @@ -398,7 +400,7 @@ class TestLogNormalGeneratorSchemaQualified(unittest.TestCase): """ContinuousLogDistributionGeneratorFactory respects src_table schema.""" def _get_sql(self, schema: str | None) -> str: - from datafaker.generators.continuous import ContinuousLogDistributionGeneratorFactory + from datafaker.proposers.continuous import ContinuousLogDistributionProposerFactory meta = MetaData() tbl = Table("person", meta, Column("age", Integer()), schema=schema) @@ -420,11 +422,11 @@ def capture(stmt, *args, **kwargs): engine = MagicMock() engine.connect.return_value = conn - from datafaker.generators.base import Buckets + from datafaker.proposers.base import Buckets import unittest.mock buckets = MagicMock(spec=Buckets) - factory = ContinuousLogDistributionGeneratorFactory() + factory = ContinuousLogDistributionProposerFactory() with unittest.mock.patch.object(Buckets, "make_buckets", return_value=buckets): factory._get_generators_from_buckets(engine, tbl, "age", buckets) @@ -476,22 +478,22 @@ def _make_config(self, table_sql_name: str) -> dict: } def test_unqualified_name_parses_clauses(self) -> None: - """PredefinedGenerator parses select_aggregate_clauses from unqualified FROM.""" - from datafaker.generators.base import PredefinedGenerator + """PredefinedProposer parses select_aggregate_clauses from unqualified FROM.""" + from datafaker.proposers.base import PredefinedProposer config = self._make_config("person") rg = config["tables"]["person"]["row_generators"][0] - gen = PredefinedGenerator("person", rg, config) + gen = PredefinedProposer("person", rg, config) self.assertIn("mean__age", gen.select_aggregate_clauses()) self.assertIn("sd__age", gen.select_aggregate_clauses()) def test_schema_qualified_name_parses_clauses(self) -> None: - """PredefinedGenerator parses select_aggregate_clauses from schema-qualified FROM.""" - from datafaker.generators.base import PredefinedGenerator + """PredefinedProposer parses select_aggregate_clauses from schema-qualified FROM.""" + from datafaker.proposers.base import PredefinedProposer config = self._make_config("myschema.person") rg = config["tables"]["person"]["row_generators"][0] - gen = PredefinedGenerator("person", rg, config) + gen = PredefinedProposer("person", rg, config) self.assertIn("mean__age", gen.select_aggregate_clauses()) self.assertIn("sd__age", gen.select_aggregate_clauses()) @@ -499,38 +501,39 @@ def test_schema_qualified_name_parses_clauses(self) -> None: class TestAggregateQuerySchemaQualified(unittest.TestCase): """_get_aggregate_query qualifies table names using the engine's schema_translate_map.""" - def _make_shell(self, schema: str | None): - from datafaker.interactive.generators import GeneratorCmd - from datafaker.generators.base import Generator - - gen = MagicMock(spec=Generator) - gen.select_aggregate_clauses.return_value = { - "mean__age": {"clause": "AVG(age)", "comment": None} - } - + def _make_engine(self, schema: str | None) -> MagicMock: engine = MagicMock() schema_map = {None: schema} if schema else {} engine.get_execution_options.return_value = {"schema_translate_map": schema_map} + return engine + + def _make_gen(self) -> MagicMock: + from datafaker.proposers.base import Proposer - shell = MagicMock(spec=GeneratorCmd) - shell.sync_engine = engine - return shell, gen + gen = MagicMock(spec=Proposer) + gen.select_aggregate_clauses.return_value = { + "mean__age": {"clause": "AVG(age)", "comment": None} + } + return gen def test_aggregate_query_includes_schema(self) -> None: - """_get_aggregate_query qualifies the bare table name when engine has a schema map.""" - from datafaker.interactive.generators import GeneratorCmd + """get_aggregate_query qualifies the bare table name when engine has a schema map.""" + from datafaker.interactive.generators import get_aggregate_query - shell, gen = self._make_shell("myschema") - result = GeneratorCmd._get_aggregate_query(shell, [gen], "person") + engine = self._make_engine("myschema") + gen = self._make_gen() + result = get_aggregate_query([gen], "person", engine) self.assertIsNotNone(result) self.assertIn("myschema.person", result) def test_aggregate_query_no_schema(self) -> None: - """_get_aggregate_query uses the bare name when no schema is set.""" - from datafaker.interactive.generators import GeneratorCmd + """get_aggregate_query uses the bare name when no schema is set.""" + from datafaker.interactive.generators import get_aggregate_query - shell, gen = self._make_shell(None) - result = GeneratorCmd._get_aggregate_query(shell, [gen], "person") + engine = self._make_engine(None) + gen = self._make_gen() + result = get_aggregate_query([gen], "person", engine) self.assertIsNotNone(result) - self.assertIn("FROM person", result) - self.assertNotIn(".", result.split("FROM ")[-1]) + self.assertIn("person", result) + # No schema qualifier (schema.table) should appear after FROM + self.assertNotIn(".", result.split("FROM ")[-1].strip('"').strip()) From 39d4fc5eb3705bfc7b6384e383af3560071e0de1 Mon Sep 17 00:00:00 2001 From: May Yong Date: Tue, 30 Jun 2026 11:36:34 +0100 Subject: [PATCH 36/45] Fix AttributeError in ContinuousLogDistributionProposerFactory The parent class _get_generators_from_buckets took table_name: str, but the child class override expected src_table: Table and called src_table.c[column_name]. The parent's get_proposers passed table.name (a string), so the child received a str and crashed with AttributeError: c. Fix: align the parent signature to accept src_table: Table (extracting .name internally) and pass the Table object from get_proposers. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/proposers/continuous.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/datafaker/proposers/continuous.py b/datafaker/proposers/continuous.py index c3c7d6d..44c9701 100644 --- a/datafaker/proposers/continuous.py +++ b/datafaker/proposers/continuous.py @@ -139,13 +139,13 @@ class ContinuousDistributionProposerFactory(ProposerFactory): def _get_generators_from_buckets( self, engine: Engine, # pylint: disable=unused-argument - table_name: str, + src_table: Table, column_name: str, buckets: Buckets, ) -> Sequence[Proposer]: return [ - GaussianProposer(table_name, column_name, buckets), - UniformProposer(table_name, column_name, buckets), + GaussianProposer(src_table.name, column_name, buckets), + UniformProposer(src_table.name, column_name, buckets), ] def get_proposers( @@ -163,7 +163,7 @@ def get_proposers( if buckets is None: return [] return self._get_generators_from_buckets( - engine, table.name, column.name, buckets + engine, table, column.name, buckets ) From 5ce81ffd59dc7378c175be85c76a047b62002335 Mon Sep 17 00:00:00 2001 From: May Yong Date: Tue, 30 Jun 2026 12:24:18 +0100 Subject: [PATCH 37/45] Changed name of dodgy test person --- tests/examples/src.dump | 1994 +++++++++++++++++++------------------- tests/examples/src2.dump | 1994 +++++++++++++++++++------------------- tests/test_make.py | 2 +- 3 files changed, 1995 insertions(+), 1995 deletions(-) diff --git a/tests/examples/src.dump b/tests/examples/src.dump index 3f982ac..112cf41 100644 --- a/tests/examples/src.dump +++ b/tests/examples/src.dump @@ -271,1006 +271,1006 @@ INSERT INTO public.mitigation_type VALUES (2, 'panic', 'don''t hold back, flail -- Data for Name: person; Type: TABLE DATA; Schema: public; Owner: postgres -- -INSERT INTO public.person VALUES (1, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (2, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (3, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (4, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (5, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (6, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (7, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (8, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (9, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (10, 'Randy Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (1, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (2, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (3, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (4, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (5, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (6, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (7, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (8, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (9, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (10, 'Someone Random', true, '2023-03-01 00:00:00+00'); INSERT INTO public.person VALUES (11, 'Testfried Testermann', false, '2023-03-01 00:00:00+00'); INSERT INTO public.person VALUES (12, 'Veronica Fyre', false, '2023-03-01 00:00:00+00'); INSERT INTO public.person VALUES (13, 'Miranda Rando-Generata', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (14, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (15, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (16, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (17, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (18, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (19, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (20, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (21, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (22, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (23, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (24, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (25, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (26, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (27, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (28, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (29, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (30, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (31, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (32, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (33, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (34, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (35, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (36, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (37, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (38, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (39, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (40, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (41, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (42, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (43, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (44, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (45, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (46, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (47, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (48, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (49, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (50, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (51, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (52, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (53, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (54, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (55, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (56, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (57, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (58, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (59, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (60, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (61, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (62, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (63, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (64, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (65, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (66, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (67, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (68, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (69, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (70, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (71, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (72, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (73, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (74, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (75, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (76, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (77, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (78, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (79, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (80, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (81, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (82, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (83, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (84, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (85, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (86, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (87, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (88, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (89, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (90, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (91, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (92, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (93, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (94, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (95, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (96, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (97, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (98, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (99, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (100, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (101, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (102, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (103, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (104, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (105, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (106, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (107, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (108, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (109, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (110, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (111, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (112, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (113, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (114, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (115, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (116, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (117, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (118, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (119, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (120, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (121, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (122, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (123, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (124, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (125, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (126, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (127, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (128, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (129, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (130, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (131, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (132, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (133, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (134, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (135, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (136, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (137, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (138, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (139, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (140, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (141, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (142, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (143, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (144, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (145, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (146, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (147, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (148, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (149, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (150, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (151, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (152, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (153, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (154, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (155, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (156, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (157, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (158, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (159, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (160, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (161, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (162, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (163, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (164, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (165, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (166, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (167, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (168, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (169, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (170, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (171, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (172, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (173, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (174, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (175, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (176, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (177, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (178, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (179, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (180, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (181, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (182, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (183, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (184, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (185, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (186, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (187, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (188, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (189, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (190, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (191, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (192, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (193, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (194, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (195, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (196, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (197, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (198, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (199, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (200, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (201, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (202, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (203, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (204, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (205, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (206, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (207, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (208, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (209, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (210, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (211, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (212, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (213, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (214, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (215, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (216, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (217, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (218, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (219, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (220, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (221, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (222, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (223, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (224, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (225, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (226, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (227, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (228, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (229, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (230, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (231, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (232, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (233, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (234, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (235, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (236, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (237, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (238, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (239, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (240, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (241, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (242, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (243, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (244, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (245, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (246, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (247, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (248, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (249, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (250, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (251, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (252, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (253, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (254, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (255, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (256, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (257, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (258, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (259, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (260, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (261, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (262, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (263, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (264, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (265, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (266, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (267, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (268, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (269, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (270, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (271, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (272, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (273, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (274, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (275, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (276, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (277, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (278, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (279, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (280, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (281, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (282, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (283, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (284, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (285, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (286, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (287, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (288, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (289, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (290, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (291, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (292, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (293, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (294, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (295, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (296, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (297, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (298, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (299, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (300, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (301, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (302, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (303, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (304, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (305, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (306, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (307, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (308, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (309, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (310, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (311, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (312, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (313, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (314, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (315, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (316, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (317, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (318, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (319, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (320, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (321, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (322, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (323, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (324, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (325, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (326, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (327, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (328, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (329, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (330, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (331, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (332, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (333, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (334, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (335, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (336, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (337, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (338, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (339, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (340, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (341, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (342, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (343, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (344, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (345, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (346, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (347, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (348, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (349, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (350, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (351, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (352, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (353, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (354, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (355, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (356, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (357, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (358, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (359, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (360, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (361, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (362, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (363, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (364, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (365, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (366, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (367, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (368, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (369, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (370, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (371, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (372, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (373, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (374, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (375, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (376, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (377, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (378, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (379, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (380, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (381, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (382, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (383, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (384, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (385, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (386, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (387, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (388, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (389, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (390, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (391, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (392, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (393, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (394, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (395, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (396, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (397, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (398, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (399, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (400, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (401, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (402, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (403, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (404, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (405, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (406, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (407, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (408, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (409, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (410, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (411, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (412, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (413, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (414, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (415, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (416, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (417, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (418, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (419, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (420, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (421, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (422, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (423, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (424, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (425, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (426, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (427, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (428, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (429, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (430, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (431, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (432, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (433, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (434, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (435, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (436, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (437, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (438, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (439, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (440, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (441, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (442, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (443, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (444, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (445, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (446, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (447, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (448, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (449, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (450, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (451, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (452, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (453, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (454, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (455, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (456, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (457, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (458, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (459, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (460, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (461, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (462, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (463, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (464, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (465, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (466, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (467, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (468, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (469, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (470, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (471, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (472, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (473, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (474, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (475, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (476, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (477, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (478, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (479, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (480, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (481, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (482, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (483, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (484, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (485, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (486, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (487, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (488, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (489, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (490, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (491, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (492, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (493, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (494, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (495, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (496, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (497, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (498, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (499, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (500, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (501, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (502, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (503, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (504, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (505, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (506, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (507, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (508, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (509, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (510, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (511, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (512, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (513, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (514, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (515, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (516, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (517, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (518, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (519, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (520, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (521, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (522, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (523, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (524, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (525, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (526, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (527, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (528, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (529, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (530, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (531, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (532, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (533, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (534, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (535, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (536, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (537, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (538, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (539, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (540, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (541, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (542, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (543, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (544, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (545, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (546, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (547, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (548, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (549, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (550, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (551, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (552, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (553, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (554, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (555, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (556, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (557, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (558, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (559, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (560, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (561, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (562, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (563, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (564, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (565, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (566, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (567, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (568, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (569, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (570, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (571, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (572, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (573, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (574, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (575, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (576, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (577, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (578, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (579, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (580, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (581, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (582, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (583, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (584, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (585, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (586, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (587, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (588, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (589, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (590, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (591, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (592, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (593, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (594, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (595, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (596, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (597, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (598, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (599, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (600, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (601, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (602, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (603, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (604, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (605, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (606, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (607, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (608, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (609, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (610, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (611, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (612, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (613, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (614, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (615, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (616, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (617, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (618, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (619, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (620, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (621, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (622, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (623, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (624, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (625, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (626, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (627, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (628, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (629, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (630, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (631, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (632, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (633, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (634, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (635, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (636, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (637, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (638, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (639, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (640, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (641, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (642, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (643, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (644, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (645, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (646, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (647, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (648, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (649, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (650, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (651, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (652, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (653, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (654, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (655, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (656, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (657, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (658, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (659, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (660, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (661, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (662, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (663, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (664, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (665, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (666, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (667, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (668, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (669, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (670, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (671, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (672, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (673, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (674, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (675, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (676, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (677, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (678, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (679, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (680, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (681, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (682, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (683, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (684, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (685, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (686, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (687, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (688, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (689, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (690, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (691, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (692, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (693, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (694, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (695, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (696, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (697, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (698, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (699, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (700, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (701, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (702, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (703, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (704, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (705, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (706, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (707, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (708, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (709, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (710, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (711, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (712, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (713, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (714, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (715, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (716, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (717, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (718, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (719, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (720, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (721, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (722, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (723, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (724, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (725, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (726, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (727, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (728, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (729, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (730, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (731, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (732, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (733, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (734, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (735, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (736, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (737, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (738, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (739, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (740, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (741, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (742, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (743, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (744, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (745, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (746, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (747, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (748, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (749, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (750, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (751, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (752, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (753, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (754, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (755, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (756, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (757, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (758, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (759, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (760, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (761, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (762, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (763, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (764, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (765, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (766, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (767, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (768, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (769, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (770, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (771, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (772, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (773, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (774, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (775, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (776, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (777, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (778, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (779, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (780, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (781, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (782, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (783, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (784, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (785, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (786, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (787, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (788, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (789, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (790, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (791, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (792, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (793, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (794, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (795, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (796, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (797, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (798, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (799, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (800, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (801, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (802, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (803, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (804, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (805, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (806, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (807, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (808, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (809, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (810, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (811, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (812, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (813, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (814, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (815, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (816, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (817, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (818, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (819, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (820, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (821, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (822, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (823, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (824, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (825, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (826, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (827, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (828, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (829, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (830, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (831, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (832, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (833, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (834, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (835, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (836, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (837, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (838, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (839, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (840, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (841, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (842, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (843, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (844, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (845, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (846, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (847, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (848, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (849, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (850, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (851, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (852, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (853, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (854, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (855, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (856, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (857, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (858, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (859, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (860, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (861, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (862, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (863, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (864, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (865, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (866, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (867, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (868, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (869, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (870, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (871, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (872, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (873, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (874, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (875, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (876, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (877, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (878, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (879, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (880, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (881, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (882, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (883, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (884, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (885, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (886, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (887, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (888, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (889, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (890, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (891, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (892, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (893, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (894, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (895, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (896, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (897, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (898, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (899, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (900, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (901, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (902, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (903, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (904, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (905, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (906, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (907, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (908, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (909, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (910, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (911, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (912, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (913, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (914, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (915, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (916, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (917, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (918, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (919, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (920, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (921, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (922, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (923, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (924, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (925, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (926, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (927, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (928, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (929, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (930, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (931, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (932, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (933, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (934, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (935, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (936, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (937, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (938, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (939, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (940, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (941, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (942, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (943, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (944, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (945, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (946, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (947, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (948, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (949, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (950, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (951, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (952, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (953, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (954, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (955, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (956, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (957, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (958, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (959, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (960, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (961, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (962, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (963, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (964, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (965, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (966, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (967, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (968, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (969, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (970, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (971, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (972, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (973, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (974, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (975, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (976, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (977, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (978, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (979, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (980, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (981, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (982, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (983, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (984, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (985, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (986, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (987, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (988, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (989, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (990, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (991, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (992, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (993, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (994, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (995, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (996, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (997, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (998, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (999, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (1000, 'Randy Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (14, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (15, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (16, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (17, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (18, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (19, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (20, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (21, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (22, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (23, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (24, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (25, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (26, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (27, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (28, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (29, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (30, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (31, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (32, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (33, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (34, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (35, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (36, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (37, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (38, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (39, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (40, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (41, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (42, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (43, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (44, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (45, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (46, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (47, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (48, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (49, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (50, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (51, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (52, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (53, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (54, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (55, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (56, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (57, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (58, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (59, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (60, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (61, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (62, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (63, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (64, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (65, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (66, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (67, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (68, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (69, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (70, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (71, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (72, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (73, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (74, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (75, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (76, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (77, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (78, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (79, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (80, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (81, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (82, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (83, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (84, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (85, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (86, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (87, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (88, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (89, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (90, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (91, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (92, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (93, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (94, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (95, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (96, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (97, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (98, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (99, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (100, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (101, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (102, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (103, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (104, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (105, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (106, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (107, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (108, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (109, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (110, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (111, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (112, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (113, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (114, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (115, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (116, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (117, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (118, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (119, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (120, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (121, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (122, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (123, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (124, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (125, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (126, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (127, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (128, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (129, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (130, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (131, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (132, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (133, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (134, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (135, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (136, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (137, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (138, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (139, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (140, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (141, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (142, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (143, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (144, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (145, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (146, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (147, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (148, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (149, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (150, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (151, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (152, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (153, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (154, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (155, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (156, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (157, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (158, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (159, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (160, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (161, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (162, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (163, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (164, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (165, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (166, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (167, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (168, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (169, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (170, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (171, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (172, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (173, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (174, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (175, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (176, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (177, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (178, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (179, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (180, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (181, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (182, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (183, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (184, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (185, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (186, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (187, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (188, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (189, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (190, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (191, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (192, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (193, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (194, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (195, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (196, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (197, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (198, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (199, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (200, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (201, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (202, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (203, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (204, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (205, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (206, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (207, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (208, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (209, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (210, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (211, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (212, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (213, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (214, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (215, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (216, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (217, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (218, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (219, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (220, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (221, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (222, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (223, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (224, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (225, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (226, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (227, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (228, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (229, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (230, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (231, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (232, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (233, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (234, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (235, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (236, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (237, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (238, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (239, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (240, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (241, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (242, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (243, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (244, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (245, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (246, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (247, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (248, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (249, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (250, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (251, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (252, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (253, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (254, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (255, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (256, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (257, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (258, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (259, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (260, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (261, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (262, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (263, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (264, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (265, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (266, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (267, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (268, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (269, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (270, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (271, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (272, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (273, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (274, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (275, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (276, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (277, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (278, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (279, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (280, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (281, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (282, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (283, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (284, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (285, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (286, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (287, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (288, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (289, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (290, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (291, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (292, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (293, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (294, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (295, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (296, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (297, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (298, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (299, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (300, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (301, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (302, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (303, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (304, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (305, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (306, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (307, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (308, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (309, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (310, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (311, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (312, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (313, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (314, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (315, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (316, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (317, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (318, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (319, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (320, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (321, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (322, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (323, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (324, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (325, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (326, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (327, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (328, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (329, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (330, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (331, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (332, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (333, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (334, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (335, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (336, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (337, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (338, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (339, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (340, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (341, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (342, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (343, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (344, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (345, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (346, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (347, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (348, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (349, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (350, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (351, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (352, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (353, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (354, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (355, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (356, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (357, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (358, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (359, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (360, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (361, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (362, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (363, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (364, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (365, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (366, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (367, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (368, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (369, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (370, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (371, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (372, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (373, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (374, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (375, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (376, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (377, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (378, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (379, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (380, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (381, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (382, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (383, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (384, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (385, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (386, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (387, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (388, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (389, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (390, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (391, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (392, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (393, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (394, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (395, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (396, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (397, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (398, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (399, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (400, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (401, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (402, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (403, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (404, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (405, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (406, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (407, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (408, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (409, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (410, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (411, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (412, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (413, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (414, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (415, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (416, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (417, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (418, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (419, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (420, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (421, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (422, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (423, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (424, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (425, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (426, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (427, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (428, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (429, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (430, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (431, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (432, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (433, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (434, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (435, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (436, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (437, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (438, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (439, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (440, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (441, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (442, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (443, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (444, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (445, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (446, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (447, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (448, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (449, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (450, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (451, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (452, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (453, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (454, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (455, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (456, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (457, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (458, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (459, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (460, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (461, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (462, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (463, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (464, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (465, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (466, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (467, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (468, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (469, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (470, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (471, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (472, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (473, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (474, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (475, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (476, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (477, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (478, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (479, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (480, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (481, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (482, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (483, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (484, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (485, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (486, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (487, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (488, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (489, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (490, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (491, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (492, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (493, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (494, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (495, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (496, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (497, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (498, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (499, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (500, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (501, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (502, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (503, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (504, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (505, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (506, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (507, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (508, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (509, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (510, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (511, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (512, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (513, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (514, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (515, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (516, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (517, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (518, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (519, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (520, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (521, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (522, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (523, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (524, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (525, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (526, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (527, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (528, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (529, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (530, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (531, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (532, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (533, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (534, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (535, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (536, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (537, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (538, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (539, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (540, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (541, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (542, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (543, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (544, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (545, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (546, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (547, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (548, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (549, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (550, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (551, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (552, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (553, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (554, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (555, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (556, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (557, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (558, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (559, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (560, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (561, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (562, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (563, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (564, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (565, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (566, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (567, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (568, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (569, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (570, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (571, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (572, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (573, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (574, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (575, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (576, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (577, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (578, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (579, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (580, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (581, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (582, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (583, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (584, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (585, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (586, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (587, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (588, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (589, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (590, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (591, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (592, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (593, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (594, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (595, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (596, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (597, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (598, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (599, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (600, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (601, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (602, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (603, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (604, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (605, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (606, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (607, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (608, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (609, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (610, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (611, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (612, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (613, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (614, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (615, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (616, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (617, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (618, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (619, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (620, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (621, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (622, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (623, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (624, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (625, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (626, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (627, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (628, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (629, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (630, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (631, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (632, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (633, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (634, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (635, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (636, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (637, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (638, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (639, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (640, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (641, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (642, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (643, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (644, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (645, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (646, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (647, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (648, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (649, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (650, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (651, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (652, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (653, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (654, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (655, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (656, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (657, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (658, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (659, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (660, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (661, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (662, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (663, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (664, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (665, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (666, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (667, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (668, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (669, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (670, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (671, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (672, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (673, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (674, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (675, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (676, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (677, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (678, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (679, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (680, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (681, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (682, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (683, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (684, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (685, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (686, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (687, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (688, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (689, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (690, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (691, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (692, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (693, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (694, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (695, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (696, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (697, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (698, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (699, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (700, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (701, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (702, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (703, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (704, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (705, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (706, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (707, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (708, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (709, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (710, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (711, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (712, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (713, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (714, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (715, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (716, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (717, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (718, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (719, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (720, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (721, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (722, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (723, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (724, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (725, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (726, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (727, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (728, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (729, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (730, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (731, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (732, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (733, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (734, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (735, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (736, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (737, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (738, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (739, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (740, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (741, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (742, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (743, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (744, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (745, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (746, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (747, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (748, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (749, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (750, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (751, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (752, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (753, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (754, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (755, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (756, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (757, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (758, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (759, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (760, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (761, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (762, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (763, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (764, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (765, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (766, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (767, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (768, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (769, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (770, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (771, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (772, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (773, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (774, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (775, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (776, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (777, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (778, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (779, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (780, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (781, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (782, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (783, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (784, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (785, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (786, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (787, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (788, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (789, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (790, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (791, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (792, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (793, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (794, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (795, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (796, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (797, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (798, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (799, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (800, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (801, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (802, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (803, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (804, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (805, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (806, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (807, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (808, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (809, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (810, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (811, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (812, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (813, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (814, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (815, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (816, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (817, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (818, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (819, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (820, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (821, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (822, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (823, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (824, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (825, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (826, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (827, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (828, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (829, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (830, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (831, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (832, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (833, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (834, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (835, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (836, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (837, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (838, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (839, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (840, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (841, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (842, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (843, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (844, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (845, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (846, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (847, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (848, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (849, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (850, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (851, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (852, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (853, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (854, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (855, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (856, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (857, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (858, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (859, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (860, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (861, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (862, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (863, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (864, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (865, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (866, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (867, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (868, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (869, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (870, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (871, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (872, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (873, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (874, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (875, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (876, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (877, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (878, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (879, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (880, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (881, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (882, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (883, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (884, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (885, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (886, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (887, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (888, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (889, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (890, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (891, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (892, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (893, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (894, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (895, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (896, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (897, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (898, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (899, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (900, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (901, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (902, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (903, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (904, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (905, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (906, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (907, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (908, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (909, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (910, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (911, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (912, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (913, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (914, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (915, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (916, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (917, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (918, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (919, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (920, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (921, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (922, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (923, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (924, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (925, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (926, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (927, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (928, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (929, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (930, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (931, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (932, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (933, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (934, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (935, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (936, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (937, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (938, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (939, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (940, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (941, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (942, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (943, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (944, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (945, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (946, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (947, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (948, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (949, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (950, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (951, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (952, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (953, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (954, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (955, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (956, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (957, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (958, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (959, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (960, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (961, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (962, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (963, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (964, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (965, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (966, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (967, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (968, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (969, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (970, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (971, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (972, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (973, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (974, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (975, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (976, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (977, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (978, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (979, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (980, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (981, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (982, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (983, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (984, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (985, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (986, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (987, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (988, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (989, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (990, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (991, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (992, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (993, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (994, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (995, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (996, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (997, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (998, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (999, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (1000, 'Someone Random', true, '2023-03-01 00:00:00+00'); -- diff --git a/tests/examples/src2.dump b/tests/examples/src2.dump index 409622b..1e06d9b 100644 --- a/tests/examples/src2.dump +++ b/tests/examples/src2.dump @@ -226,1006 +226,1006 @@ INSERT INTO public.mitigation_type VALUES (2, 'panic', 'don''t hold back, flail -- Data for Name: person; Type: TABLE DATA; Schema: public; Owner: postgres -- -INSERT INTO public.person VALUES (1, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (2, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (3, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (4, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (5, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (6, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (7, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (8, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (9, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (10, 'Randy Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (1, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (2, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (3, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (4, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (5, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (6, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (7, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (8, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (9, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (10, 'Someone Random', true, '2023-03-01 00:00:00+00'); INSERT INTO public.person VALUES (11, 'Testfried Testermann', false, '2023-03-01 00:00:00+00'); INSERT INTO public.person VALUES (12, 'Veronica Fyre', false, '2023-03-01 00:00:00+00'); INSERT INTO public.person VALUES (13, 'Miranda Rando-Generata', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (14, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (15, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (16, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (17, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (18, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (19, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (20, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (21, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (22, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (23, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (24, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (25, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (26, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (27, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (28, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (29, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (30, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (31, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (32, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (33, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (34, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (35, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (36, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (37, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (38, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (39, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (40, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (41, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (42, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (43, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (44, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (45, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (46, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (47, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (48, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (49, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (50, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (51, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (52, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (53, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (54, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (55, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (56, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (57, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (58, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (59, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (60, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (61, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (62, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (63, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (64, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (65, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (66, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (67, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (68, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (69, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (70, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (71, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (72, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (73, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (74, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (75, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (76, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (77, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (78, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (79, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (80, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (81, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (82, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (83, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (84, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (85, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (86, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (87, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (88, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (89, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (90, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (91, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (92, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (93, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (94, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (95, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (96, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (97, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (98, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (99, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (100, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (101, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (102, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (103, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (104, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (105, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (106, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (107, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (108, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (109, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (110, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (111, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (112, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (113, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (114, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (115, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (116, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (117, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (118, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (119, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (120, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (121, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (122, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (123, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (124, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (125, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (126, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (127, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (128, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (129, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (130, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (131, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (132, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (133, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (134, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (135, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (136, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (137, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (138, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (139, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (140, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (141, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (142, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (143, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (144, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (145, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (146, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (147, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (148, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (149, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (150, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (151, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (152, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (153, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (154, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (155, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (156, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (157, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (158, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (159, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (160, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (161, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (162, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (163, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (164, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (165, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (166, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (167, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (168, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (169, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (170, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (171, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (172, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (173, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (174, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (175, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (176, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (177, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (178, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (179, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (180, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (181, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (182, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (183, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (184, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (185, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (186, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (187, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (188, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (189, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (190, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (191, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (192, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (193, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (194, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (195, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (196, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (197, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (198, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (199, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (200, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (201, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (202, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (203, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (204, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (205, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (206, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (207, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (208, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (209, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (210, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (211, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (212, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (213, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (214, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (215, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (216, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (217, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (218, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (219, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (220, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (221, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (222, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (223, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (224, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (225, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (226, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (227, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (228, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (229, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (230, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (231, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (232, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (233, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (234, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (235, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (236, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (237, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (238, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (239, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (240, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (241, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (242, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (243, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (244, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (245, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (246, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (247, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (248, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (249, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (250, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (251, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (252, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (253, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (254, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (255, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (256, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (257, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (258, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (259, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (260, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (261, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (262, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (263, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (264, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (265, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (266, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (267, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (268, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (269, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (270, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (271, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (272, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (273, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (274, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (275, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (276, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (277, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (278, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (279, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (280, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (281, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (282, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (283, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (284, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (285, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (286, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (287, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (288, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (289, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (290, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (291, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (292, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (293, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (294, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (295, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (296, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (297, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (298, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (299, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (300, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (301, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (302, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (303, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (304, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (305, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (306, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (307, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (308, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (309, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (310, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (311, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (312, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (313, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (314, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (315, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (316, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (317, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (318, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (319, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (320, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (321, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (322, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (323, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (324, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (325, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (326, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (327, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (328, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (329, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (330, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (331, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (332, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (333, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (334, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (335, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (336, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (337, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (338, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (339, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (340, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (341, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (342, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (343, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (344, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (345, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (346, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (347, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (348, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (349, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (350, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (351, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (352, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (353, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (354, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (355, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (356, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (357, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (358, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (359, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (360, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (361, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (362, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (363, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (364, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (365, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (366, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (367, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (368, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (369, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (370, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (371, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (372, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (373, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (374, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (375, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (376, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (377, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (378, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (379, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (380, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (381, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (382, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (383, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (384, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (385, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (386, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (387, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (388, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (389, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (390, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (391, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (392, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (393, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (394, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (395, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (396, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (397, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (398, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (399, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (400, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (401, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (402, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (403, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (404, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (405, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (406, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (407, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (408, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (409, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (410, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (411, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (412, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (413, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (414, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (415, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (416, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (417, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (418, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (419, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (420, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (421, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (422, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (423, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (424, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (425, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (426, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (427, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (428, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (429, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (430, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (431, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (432, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (433, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (434, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (435, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (436, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (437, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (438, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (439, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (440, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (441, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (442, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (443, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (444, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (445, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (446, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (447, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (448, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (449, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (450, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (451, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (452, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (453, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (454, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (455, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (456, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (457, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (458, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (459, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (460, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (461, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (462, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (463, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (464, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (465, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (466, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (467, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (468, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (469, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (470, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (471, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (472, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (473, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (474, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (475, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (476, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (477, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (478, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (479, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (480, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (481, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (482, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (483, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (484, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (485, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (486, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (487, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (488, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (489, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (490, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (491, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (492, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (493, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (494, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (495, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (496, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (497, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (498, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (499, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (500, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (501, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (502, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (503, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (504, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (505, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (506, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (507, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (508, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (509, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (510, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (511, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (512, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (513, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (514, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (515, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (516, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (517, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (518, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (519, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (520, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (521, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (522, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (523, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (524, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (525, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (526, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (527, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (528, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (529, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (530, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (531, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (532, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (533, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (534, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (535, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (536, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (537, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (538, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (539, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (540, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (541, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (542, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (543, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (544, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (545, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (546, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (547, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (548, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (549, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (550, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (551, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (552, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (553, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (554, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (555, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (556, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (557, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (558, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (559, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (560, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (561, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (562, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (563, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (564, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (565, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (566, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (567, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (568, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (569, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (570, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (571, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (572, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (573, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (574, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (575, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (576, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (577, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (578, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (579, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (580, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (581, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (582, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (583, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (584, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (585, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (586, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (587, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (588, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (589, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (590, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (591, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (592, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (593, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (594, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (595, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (596, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (597, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (598, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (599, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (600, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (601, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (602, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (603, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (604, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (605, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (606, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (607, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (608, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (609, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (610, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (611, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (612, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (613, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (614, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (615, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (616, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (617, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (618, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (619, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (620, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (621, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (622, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (623, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (624, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (625, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (626, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (627, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (628, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (629, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (630, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (631, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (632, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (633, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (634, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (635, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (636, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (637, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (638, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (639, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (640, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (641, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (642, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (643, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (644, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (645, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (646, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (647, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (648, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (649, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (650, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (651, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (652, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (653, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (654, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (655, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (656, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (657, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (658, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (659, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (660, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (661, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (662, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (663, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (664, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (665, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (666, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (667, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (668, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (669, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (670, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (671, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (672, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (673, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (674, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (675, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (676, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (677, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (678, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (679, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (680, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (681, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (682, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (683, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (684, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (685, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (686, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (687, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (688, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (689, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (690, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (691, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (692, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (693, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (694, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (695, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (696, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (697, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (698, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (699, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (700, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (701, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (702, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (703, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (704, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (705, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (706, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (707, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (708, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (709, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (710, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (711, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (712, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (713, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (714, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (715, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (716, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (717, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (718, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (719, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (720, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (721, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (722, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (723, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (724, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (725, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (726, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (727, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (728, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (729, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (730, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (731, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (732, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (733, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (734, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (735, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (736, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (737, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (738, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (739, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (740, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (741, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (742, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (743, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (744, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (745, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (746, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (747, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (748, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (749, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (750, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (751, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (752, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (753, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (754, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (755, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (756, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (757, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (758, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (759, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (760, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (761, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (762, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (763, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (764, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (765, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (766, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (767, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (768, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (769, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (770, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (771, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (772, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (773, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (774, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (775, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (776, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (777, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (778, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (779, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (780, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (781, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (782, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (783, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (784, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (785, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (786, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (787, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (788, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (789, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (790, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (791, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (792, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (793, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (794, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (795, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (796, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (797, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (798, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (799, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (800, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (801, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (802, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (803, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (804, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (805, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (806, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (807, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (808, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (809, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (810, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (811, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (812, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (813, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (814, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (815, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (816, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (817, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (818, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (819, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (820, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (821, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (822, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (823, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (824, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (825, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (826, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (827, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (828, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (829, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (830, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (831, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (832, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (833, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (834, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (835, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (836, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (837, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (838, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (839, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (840, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (841, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (842, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (843, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (844, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (845, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (846, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (847, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (848, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (849, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (850, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (851, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (852, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (853, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (854, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (855, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (856, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (857, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (858, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (859, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (860, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (861, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (862, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (863, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (864, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (865, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (866, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (867, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (868, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (869, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (870, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (871, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (872, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (873, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (874, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (875, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (876, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (877, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (878, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (879, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (880, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (881, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (882, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (883, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (884, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (885, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (886, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (887, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (888, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (889, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (890, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (891, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (892, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (893, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (894, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (895, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (896, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (897, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (898, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (899, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (900, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (901, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (902, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (903, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (904, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (905, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (906, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (907, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (908, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (909, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (910, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (911, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (912, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (913, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (914, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (915, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (916, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (917, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (918, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (919, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (920, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (921, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (922, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (923, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (924, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (925, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (926, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (927, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (928, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (929, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (930, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (931, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (932, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (933, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (934, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (935, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (936, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (937, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (938, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (939, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (940, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (941, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (942, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (943, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (944, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (945, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (946, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (947, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (948, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (949, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (950, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (951, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (952, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (953, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (954, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (955, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (956, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (957, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (958, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (959, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (960, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (961, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (962, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (963, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (964, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (965, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (966, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (967, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (968, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (969, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (970, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (971, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (972, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (973, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (974, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (975, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (976, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (977, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (978, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (979, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (980, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (981, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (982, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (983, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (984, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (985, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (986, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (987, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (988, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (989, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (990, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (991, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (992, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (993, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (994, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (995, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (996, 'Randy Random', true, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (997, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (998, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (999, 'Randy Random', false, '2023-03-01 00:00:00+00'); -INSERT INTO public.person VALUES (1000, 'Randy Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (14, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (15, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (16, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (17, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (18, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (19, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (20, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (21, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (22, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (23, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (24, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (25, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (26, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (27, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (28, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (29, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (30, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (31, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (32, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (33, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (34, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (35, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (36, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (37, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (38, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (39, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (40, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (41, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (42, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (43, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (44, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (45, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (46, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (47, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (48, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (49, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (50, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (51, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (52, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (53, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (54, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (55, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (56, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (57, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (58, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (59, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (60, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (61, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (62, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (63, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (64, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (65, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (66, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (67, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (68, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (69, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (70, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (71, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (72, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (73, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (74, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (75, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (76, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (77, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (78, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (79, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (80, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (81, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (82, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (83, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (84, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (85, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (86, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (87, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (88, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (89, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (90, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (91, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (92, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (93, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (94, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (95, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (96, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (97, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (98, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (99, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (100, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (101, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (102, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (103, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (104, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (105, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (106, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (107, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (108, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (109, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (110, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (111, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (112, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (113, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (114, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (115, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (116, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (117, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (118, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (119, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (120, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (121, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (122, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (123, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (124, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (125, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (126, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (127, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (128, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (129, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (130, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (131, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (132, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (133, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (134, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (135, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (136, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (137, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (138, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (139, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (140, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (141, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (142, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (143, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (144, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (145, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (146, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (147, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (148, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (149, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (150, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (151, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (152, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (153, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (154, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (155, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (156, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (157, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (158, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (159, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (160, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (161, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (162, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (163, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (164, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (165, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (166, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (167, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (168, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (169, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (170, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (171, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (172, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (173, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (174, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (175, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (176, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (177, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (178, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (179, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (180, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (181, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (182, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (183, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (184, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (185, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (186, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (187, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (188, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (189, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (190, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (191, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (192, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (193, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (194, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (195, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (196, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (197, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (198, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (199, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (200, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (201, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (202, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (203, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (204, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (205, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (206, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (207, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (208, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (209, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (210, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (211, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (212, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (213, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (214, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (215, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (216, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (217, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (218, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (219, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (220, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (221, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (222, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (223, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (224, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (225, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (226, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (227, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (228, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (229, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (230, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (231, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (232, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (233, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (234, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (235, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (236, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (237, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (238, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (239, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (240, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (241, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (242, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (243, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (244, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (245, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (246, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (247, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (248, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (249, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (250, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (251, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (252, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (253, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (254, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (255, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (256, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (257, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (258, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (259, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (260, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (261, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (262, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (263, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (264, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (265, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (266, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (267, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (268, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (269, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (270, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (271, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (272, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (273, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (274, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (275, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (276, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (277, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (278, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (279, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (280, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (281, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (282, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (283, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (284, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (285, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (286, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (287, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (288, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (289, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (290, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (291, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (292, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (293, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (294, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (295, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (296, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (297, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (298, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (299, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (300, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (301, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (302, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (303, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (304, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (305, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (306, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (307, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (308, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (309, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (310, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (311, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (312, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (313, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (314, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (315, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (316, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (317, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (318, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (319, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (320, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (321, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (322, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (323, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (324, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (325, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (326, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (327, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (328, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (329, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (330, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (331, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (332, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (333, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (334, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (335, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (336, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (337, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (338, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (339, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (340, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (341, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (342, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (343, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (344, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (345, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (346, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (347, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (348, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (349, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (350, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (351, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (352, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (353, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (354, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (355, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (356, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (357, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (358, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (359, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (360, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (361, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (362, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (363, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (364, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (365, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (366, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (367, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (368, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (369, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (370, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (371, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (372, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (373, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (374, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (375, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (376, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (377, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (378, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (379, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (380, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (381, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (382, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (383, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (384, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (385, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (386, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (387, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (388, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (389, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (390, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (391, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (392, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (393, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (394, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (395, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (396, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (397, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (398, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (399, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (400, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (401, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (402, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (403, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (404, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (405, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (406, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (407, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (408, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (409, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (410, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (411, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (412, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (413, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (414, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (415, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (416, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (417, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (418, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (419, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (420, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (421, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (422, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (423, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (424, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (425, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (426, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (427, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (428, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (429, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (430, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (431, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (432, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (433, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (434, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (435, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (436, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (437, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (438, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (439, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (440, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (441, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (442, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (443, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (444, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (445, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (446, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (447, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (448, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (449, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (450, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (451, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (452, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (453, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (454, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (455, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (456, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (457, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (458, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (459, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (460, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (461, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (462, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (463, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (464, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (465, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (466, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (467, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (468, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (469, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (470, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (471, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (472, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (473, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (474, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (475, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (476, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (477, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (478, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (479, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (480, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (481, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (482, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (483, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (484, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (485, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (486, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (487, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (488, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (489, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (490, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (491, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (492, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (493, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (494, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (495, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (496, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (497, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (498, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (499, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (500, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (501, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (502, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (503, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (504, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (505, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (506, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (507, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (508, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (509, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (510, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (511, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (512, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (513, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (514, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (515, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (516, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (517, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (518, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (519, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (520, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (521, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (522, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (523, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (524, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (525, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (526, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (527, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (528, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (529, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (530, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (531, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (532, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (533, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (534, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (535, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (536, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (537, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (538, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (539, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (540, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (541, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (542, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (543, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (544, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (545, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (546, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (547, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (548, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (549, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (550, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (551, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (552, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (553, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (554, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (555, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (556, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (557, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (558, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (559, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (560, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (561, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (562, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (563, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (564, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (565, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (566, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (567, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (568, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (569, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (570, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (571, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (572, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (573, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (574, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (575, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (576, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (577, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (578, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (579, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (580, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (581, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (582, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (583, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (584, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (585, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (586, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (587, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (588, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (589, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (590, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (591, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (592, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (593, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (594, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (595, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (596, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (597, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (598, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (599, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (600, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (601, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (602, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (603, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (604, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (605, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (606, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (607, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (608, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (609, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (610, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (611, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (612, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (613, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (614, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (615, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (616, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (617, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (618, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (619, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (620, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (621, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (622, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (623, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (624, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (625, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (626, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (627, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (628, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (629, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (630, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (631, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (632, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (633, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (634, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (635, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (636, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (637, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (638, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (639, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (640, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (641, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (642, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (643, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (644, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (645, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (646, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (647, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (648, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (649, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (650, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (651, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (652, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (653, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (654, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (655, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (656, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (657, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (658, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (659, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (660, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (661, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (662, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (663, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (664, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (665, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (666, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (667, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (668, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (669, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (670, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (671, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (672, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (673, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (674, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (675, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (676, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (677, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (678, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (679, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (680, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (681, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (682, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (683, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (684, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (685, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (686, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (687, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (688, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (689, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (690, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (691, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (692, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (693, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (694, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (695, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (696, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (697, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (698, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (699, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (700, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (701, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (702, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (703, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (704, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (705, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (706, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (707, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (708, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (709, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (710, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (711, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (712, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (713, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (714, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (715, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (716, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (717, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (718, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (719, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (720, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (721, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (722, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (723, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (724, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (725, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (726, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (727, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (728, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (729, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (730, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (731, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (732, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (733, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (734, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (735, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (736, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (737, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (738, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (739, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (740, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (741, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (742, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (743, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (744, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (745, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (746, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (747, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (748, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (749, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (750, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (751, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (752, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (753, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (754, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (755, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (756, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (757, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (758, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (759, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (760, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (761, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (762, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (763, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (764, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (765, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (766, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (767, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (768, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (769, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (770, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (771, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (772, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (773, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (774, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (775, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (776, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (777, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (778, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (779, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (780, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (781, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (782, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (783, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (784, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (785, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (786, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (787, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (788, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (789, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (790, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (791, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (792, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (793, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (794, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (795, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (796, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (797, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (798, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (799, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (800, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (801, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (802, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (803, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (804, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (805, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (806, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (807, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (808, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (809, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (810, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (811, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (812, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (813, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (814, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (815, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (816, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (817, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (818, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (819, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (820, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (821, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (822, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (823, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (824, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (825, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (826, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (827, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (828, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (829, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (830, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (831, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (832, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (833, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (834, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (835, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (836, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (837, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (838, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (839, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (840, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (841, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (842, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (843, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (844, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (845, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (846, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (847, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (848, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (849, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (850, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (851, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (852, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (853, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (854, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (855, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (856, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (857, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (858, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (859, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (860, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (861, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (862, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (863, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (864, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (865, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (866, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (867, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (868, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (869, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (870, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (871, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (872, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (873, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (874, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (875, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (876, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (877, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (878, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (879, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (880, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (881, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (882, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (883, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (884, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (885, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (886, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (887, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (888, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (889, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (890, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (891, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (892, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (893, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (894, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (895, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (896, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (897, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (898, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (899, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (900, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (901, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (902, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (903, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (904, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (905, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (906, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (907, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (908, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (909, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (910, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (911, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (912, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (913, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (914, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (915, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (916, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (917, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (918, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (919, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (920, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (921, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (922, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (923, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (924, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (925, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (926, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (927, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (928, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (929, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (930, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (931, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (932, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (933, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (934, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (935, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (936, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (937, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (938, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (939, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (940, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (941, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (942, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (943, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (944, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (945, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (946, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (947, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (948, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (949, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (950, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (951, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (952, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (953, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (954, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (955, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (956, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (957, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (958, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (959, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (960, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (961, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (962, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (963, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (964, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (965, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (966, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (967, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (968, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (969, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (970, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (971, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (972, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (973, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (974, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (975, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (976, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (977, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (978, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (979, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (980, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (981, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (982, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (983, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (984, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (985, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (986, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (987, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (988, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (989, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (990, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (991, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (992, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (993, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (994, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (995, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (996, 'Someone Random', true, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (997, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (998, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (999, 'Someone Random', false, '2023-03-01 00:00:00+00'); +INSERT INTO public.person VALUES (1000, 'Someone Random', true, '2023-03-01 00:00:00+00'); -- diff --git a/tests/test_make.py b/tests/test_make.py index 8c0062f..07426c6 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -215,7 +215,7 @@ def check_make_stats_output(self, src_stats: dict) -> None: count_names, [ {"num": 1, "name": "Miranda Rando-Generata"}, - {"num": 997, "name": "Randy Random"}, + {"num": 997, "name": "Someone Random"}, {"num": 1, "name": "Testfried Testermann"}, {"num": 1, "name": "Veronica Fyre"}, ], From 78d25040e7d5ed90abae82757d875a5eecbc5d20 Mon Sep 17 00:00:00 2001 From: May Yong Date: Tue, 30 Jun 2026 16:04:59 +0100 Subject: [PATCH 38/45] Fix MSSQL end-to-end tests: connection handling and type parsing - tests/utils.py: rewrite TestMSSQL.create_empty to use raw pyodbc against master instead of sqlalchemy_utils, which was failing with 18456 when the target database did not yet exist; fix get_dsn to use render_as_string(hide_password=False) so SQLAlchemy password masking does not appear in the returned DSN - datafaker/serialize_metadata.py: change simple(sqltypes.FLOAT) to numeric_type(sqltypes.FLOAT) so FLOAT(53) (SQL Server's serialisation of double-precision float) is parsed correctly; backward-compatible because numeric_type also handles bare FLOAT - tests/test_functional_mssql.py: fix test_make_tables assertion (tables is a dict not a list), simplify test_make_stats (make_src_stats with empty config correctly returns {}), use ZipfChoiceProposer instead of abstract ChoiceProposer, read orm_file_path written by setUp instead of making a second make_tables_file call, and dispose engines in tearDown so the next setUp can drop the databases cleanly Co-Authored-By: Claude Sonnet 4.6 --- datafaker/serialize_metadata.py | 2 +- tests/test_functional_mssql.py | 25 +++++++++++++++++-------- tests/utils.py | 30 +++++++++++++++++++++++------- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/datafaker/serialize_metadata.py b/datafaker/serialize_metadata.py index 655b8c1..b83bdf9 100644 --- a/datafaker/serialize_metadata.py +++ b/datafaker/serialize_metadata.py @@ -150,7 +150,7 @@ def _mssql_varbinary_parser() -> typing.Generator[ParserType, None, typing.Any]: parsy.string("DOUBLE PRECISION").result( sqltypes.DOUBLE_PRECISION ), # must be before DOUBLE - simple(sqltypes.FLOAT), + numeric_type(sqltypes.FLOAT), simple(sqltypes.DOUBLE), simple(sqltypes.INTEGER), simple(sqltypes.SMALLINT), diff --git a/tests/test_functional_mssql.py b/tests/test_functional_mssql.py index d8cfe80..1540808 100644 --- a/tests/test_functional_mssql.py +++ b/tests/test_functional_mssql.py @@ -200,6 +200,11 @@ def setUp(self) -> None: self.config_fd = 0 def tearDown(self) -> None: + # Dispose connection pools so the next setUp can drop these databases. + if hasattr(self, "sync_engine"): + self.sync_engine.dispose() + if hasattr(self, "dst_engine") and self.dst_engine is not None: + self.dst_engine.dispose() if self.database is not None: self.database.close() if self.dst_database is not None: @@ -220,13 +225,19 @@ def test_smoke_connect(self) -> None: def test_make_tables(self) -> None: """make_tables_file produces an orm.yaml listing the expected tables.""" - orm_yaml = make_tables_file(self.dsn, self.schema_name) - orm = yaml.safe_load(orm_yaml) - table_names = {t["table_name"] for t in orm.get("tables", [])} + # setUp already called make_tables_file and wrote the result to orm_file_path + with open(self.orm_file_path, encoding="utf-8") as fh: + orm = yaml.safe_load(fh) + # orm["tables"] is a dict keyed by table name + table_names = set(orm.get("tables", {}).keys()) self.assert_subset(_EXPECTED_TABLES, table_names) def test_make_stats(self) -> None: - """make_src_stats returns a dict with an entry per source table.""" + """make_src_stats runs without error against SQL Server. + + With an empty config there are no src-stats query blocks to run, so the + function returns an empty dict — that is the correct behaviour. + """ loop = asyncio.new_event_loop() try: src_stats = loop.run_until_complete( @@ -235,8 +246,6 @@ def test_make_stats(self) -> None: finally: loop.close() self.assertIsInstance(src_stats, dict) - for table_name in _EXPECTED_TABLES: - self.assertIn(table_name, src_stats, f"'{table_name}' missing from src_stats") def test_create_data(self) -> None: """Full pipeline: make-stats → create-tables → create-data inserts rows.""" @@ -251,10 +260,10 @@ def test_create_data(self) -> None: def test_dialect_newid(self) -> None: """ChoiceProposer compiles its query with NEWID() not RANDOM() for mssql.""" from sqlalchemy.dialects import mssql as mssql_dialect # noqa: PLC0415 - from datafaker.proposers.choice import ChoiceProposer # noqa: PLC0415 + from datafaker.proposers.choice import ZipfChoiceProposer # noqa: PLC0415 dialect = mssql_dialect.dialect() - proposer = ChoiceProposer( + proposer = ZipfChoiceProposer( table_name="manufacturer", column_name="name", values=["Blender", "Gibbs"], diff --git a/tests/utils.py b/tests/utils.py index e37ea5f..b7f13eb 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -297,16 +297,32 @@ def get_dsn(self, database_name: str | None) -> str: from sqlalchemy.engine import make_url url = make_url(self._base_dsn) - return str(url.set(database=database_name)) + return url.set(database=database_name).render_as_string(hide_password=False) def create_empty(self, name: str) -> str: - """Create a SQL Server database named ``name`` and return its DSN.""" - dsn = self.get_dsn(name) - from sqlalchemy_utils import create_database, database_exists + """Drop (if exists) and create a fresh SQL Server database named ``name``.""" + import pyodbc # pylint: disable=import-outside-toplevel + from sqlalchemy.engine import make_url # pylint: disable=import-outside-toplevel - if not database_exists(dsn): - create_database(dsn) - return dsn + url = make_url(self._base_dsn) + conn_str = ( + f"DRIVER={{ODBC Driver 18 for SQL Server}};" + f"SERVER={url.host},{url.port or 1433};" + f"DATABASE=master;" + f"UID={url.username};PWD={url.password};" + "TrustServerCertificate=yes;" + ) + with pyodbc.connect(conn_str, autocommit=True) as conn: + conn.execute( + f"IF EXISTS (SELECT name FROM sys.databases WHERE name = N'{name}') " + f"ALTER DATABASE [{name}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE" + ) + conn.execute( + f"IF EXISTS (SELECT name FROM sys.databases WHERE name = N'{name}') " + f"DROP DATABASE [{name}]" + ) + conn.execute(f"CREATE DATABASE [{name}]") + return self.get_dsn(name) def run_sql(self, sql_file: Path) -> None: """Execute a T-SQL file via pyodbc, splitting batches on GO.""" From c67b6cc5baaf134c1281973211befbc70b0453dd Mon Sep 17 00:00:00 2001 From: May Yong Date: Wed, 1 Jul 2026 11:16:36 +0100 Subject: [PATCH 39/45] Remove debug logging of INSERT statements from create.py The logger.debug("Executing statement: ...") line was added during MSSQL debugging but caused verbose output to include raw SQL, breaking the test_workflow_maximal_args functional test. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/create.py | 1 - 1 file changed, 1 deletion(-) diff --git a/datafaker/create.py b/datafaker/create.py index 2d9dc9a..267cf8c 100644 --- a/datafaker/create.py +++ b/datafaker/create.py @@ -420,7 +420,6 @@ def populate( try: for _ in range(table_generator.num_rows_per_pass): stmt = insert(table).values(table_generator(dst_conn)) - logger.debug("Executing statement: %s", stmt) dst_conn.execute(stmt) row_counts[table.name] = row_counts.get(table.name, 0) + 1 dst_conn.commit() From 75731c7473b70aaba0543d864adcfdc489633389 Mon Sep 17 00:00:00 2001 From: May Yong Date: Wed, 1 Jul 2026 11:45:56 +0100 Subject: [PATCH 40/45] Remove test_duckdb_serial_hook_still_works: remove_serial does not exist The SERIAL stripping is handled inside remove_on_delete_cascade, not a separate function. The test was checking for a name that never existed. Co-Authored-By: Claude Sonnet 4.6 --- tests/test_create_mssql.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_create_mssql.py b/tests/test_create_mssql.py index 8201970..b7c42b3 100644 --- a/tests/test_create_mssql.py +++ b/tests/test_create_mssql.py @@ -51,10 +51,6 @@ def test_non_autoincrement_column_unchanged(self) -> None: ddl = _compile_create_table(self._make_table()) self.assertIn("value", ddl.lower()) - def test_duckdb_serial_hook_still_works(self) -> None: - """The DuckDB SERIAL hook is not affected by this change.""" - self.assertTrue(callable(datafaker.create.remove_serial)) - class TestMSSQLRemoveOnDeleteCascade(unittest.TestCase): """@compiles(CreateTable, 'mssql') strips ON DELETE CASCADE to avoid error 1785.""" From 7a98a1c3f898d2e4b0569adc1c02dd40c2e2fe58 Mon Sep 17 00:00:00 2001 From: Tim Band Date: Wed, 1 Jul 2026 12:08:02 +0100 Subject: [PATCH 41/45] Quick fixes --- examples/omop-mssql/README.md | 14 +- poetry.lock | 666 +++++++++++++++++++++------------- tests/test_utils_mssql.py | 8 +- 3 files changed, 434 insertions(+), 254 deletions(-) diff --git a/examples/omop-mssql/README.md b/examples/omop-mssql/README.md index 98074d0..00c9a23 100644 --- a/examples/omop-mssql/README.md +++ b/examples/omop-mssql/README.md @@ -64,7 +64,9 @@ PostgreSQL uses `SERIAL` for autoincrement columns. The code already strips `SER poetry install --extras mssql ``` -### 2. Install and register the ODBC driver (macOS) +### 2. Install and register the ODBC driver + +#### mac OS If you do not already have the Microsoft ODBC driver installed: @@ -90,6 +92,16 @@ UsageCount=1 EOF ``` +#### Ubuntu + +Install and check the MS SQL tools: + +```console +$ sudo apt install mssql-tools18 +$ odbcinst -q -d +[ODBC Driver 18 for SQL Server] +``` + ### 3. Configure the connection Copy the example environment file and fill in your connection details: diff --git a/poetry.lock b/poetry.lock index a1a7356..6848430 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,19 @@ # This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +[[package]] +name = "aioodbc" +version = "0.5.0" +description = "ODBC driver for asyncio." +optional = true +python-versions = ">=3.7" +files = [ + {file = "aioodbc-0.5.0-py3-none-any.whl", hash = "sha256:bcaf16f007855fa4bf0ce6754b1f72c6c5a3d544188849577ddd55c5dc42985e"}, + {file = "aioodbc-0.5.0.tar.gz", hash = "sha256:cbccd89ce595c033a49c9e6b4b55bbace7613a104b8a46e3d4c58c4bc4f25075"}, +] + +[package.dependencies] +pyodbc = ">=5.0.1" + [[package]] name = "alabaster" version = "0.7.16" @@ -238,13 +252,13 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" -version = "2026.4.22" +version = "2026.6.17" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" files = [ - {file = "certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a"}, - {file = "certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580"}, + {file = "certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db"}, + {file = "certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432"}, ] [[package]] @@ -615,13 +629,13 @@ profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "distlib" -version = "0.4.0" +version = "0.4.3" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, - {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, + {file = "distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b"}, + {file = "distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed"}, ] [[package]] @@ -637,46 +651,46 @@ files = [ [[package]] name = "duckdb" -version = "1.5.2" +version = "1.5.4" description = "DuckDB in-process database" optional = false python-versions = ">=3.10.0" files = [ - {file = "duckdb-1.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:63bf8687feefeed51adf45fa3b062ab8b1b1c350492b7518491b86bae68b1da1"}, - {file = "duckdb-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84b193aca20565dedb3172de15f843c659c3a6c773bf14843a9bd781c850e7db"}, - {file = "duckdb-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5596bbfc31b1b259db69c8d847b42d036ce2c4804f9ccb28f9fc46a16de7bc53"}, - {file = "duckdb-1.5.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8dbd7e31e5dc157bfe8803fa7d2652336265c6c19926c5a4a9b40f8222868d08"}, - {file = "duckdb-1.5.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9cd5e71702d446613750405cde03f66ed268f4c321da071b0472759dad19536"}, - {file = "duckdb-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:ce17670bb392ea1b3650537db02bd720908776b5b95f6d2472d31a7de59d1dc1"}, - {file = "duckdb-1.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7f69164b048e498b9e9140a24343108a5ae5f17bfb3485185f55fdf9b1aa924d"}, - {file = "duckdb-1.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:81fc4fbf0b5e25840b39ba2a10b78c6953c0314d5d0434191e7898f34ab1bba3"}, - {file = "duckdb-1.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56d38b3c4e0ef2abb58898d0fd423933999ed535c45e75e9d9f72e1d5fed69b8"}, - {file = "duckdb-1.5.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:376856066c65ccd55fcb3a380bbe33a71ce089fc4623d229ffc6e82251afdb6d"}, - {file = "duckdb-1.5.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c69907354ffee94ba8cf782daf0480dab7557f21ce27fffa6c0ea8f74ed4b8e2"}, - {file = "duckdb-1.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:d9b4f5430bf4f05d4c0dc4c55c75def3a5af4be0343be20fa2bfc577343fbfc9"}, - {file = "duckdb-1.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:2323c1195c10fb2bb982fc0218c730b43d1b92a355d61e68e3c5f3ac9d44c34f"}, - {file = "duckdb-1.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e6495b00cad16888384119842797c49316a96ae1cb132bb03856d980d95afee1"}, - {file = "duckdb-1.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d72b8856b1839d35648f38301b058f6232f4d36b463fe4dc8f4d3fdff2df1a2e"}, - {file = "duckdb-1.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2a1de4f4d454b8c97aec546c82003fc834d3422ce4bc6a19902f3462ef293bed"}, - {file = "duckdb-1.5.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce0b8141a10d37ecef729c45bc41d334854013f4389f1488bd6035c5579aaac1"}, - {file = "duckdb-1.5.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c99ef73a277c8921bc0a1f16dee38d924484251d9cfd20951748c20fcd5ed855"}, - {file = "duckdb-1.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:8d599758b4e48bf12e18c9b960cf491d219f0c4972d19a45489c05cc5ab36f83"}, - {file = "duckdb-1.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:fc85a5dbcbe6eccac1113c72370d1d3aacfdd49198d63950bdf7d8638a307f00"}, - {file = "duckdb-1.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4420b3f47027a7849d0e1815532007f377fa95ee5810b47ea717d35525c12f79"}, - {file = "duckdb-1.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bb42e6ed543902e14eae647850da24103a89f0bc2587dec5601b1c1f213bd2ed"}, - {file = "duckdb-1.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:98c0535cd6d901f61a5ea3c2e26a1fd28482953d794deb183daf568e3aa5dda6"}, - {file = "duckdb-1.5.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:486c862bf7f163c0110b6d85b3e5c031d224a671cca468f12ebb1d3a348f6b39"}, - {file = "duckdb-1.5.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70631c847ca918ee710ec874241b00cf9d2e5be90762cbb2a0389f17823c08f7"}, - {file = "duckdb-1.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:52a21823f3fbb52f0f0e5425e20b07391ad882464b955879499b5ff0b45a376b"}, - {file = "duckdb-1.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:411ad438bd4140f189a10e7f515781335962c5d18bd07837dc6d202e3985253d"}, - {file = "duckdb-1.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:6b0fe75c148000f060aa1a27b293cacc0ea08cc1cad724fbf2143d56070a3785"}, - {file = "duckdb-1.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35579b8e3a064b5eaf15b0eafc558056a13f79a0a62e34cc4baf57119daecfec"}, - {file = "duckdb-1.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ea58ff5b0880593a280cf5511734b17711b32ee1f58b47d726e8600848358160"}, - {file = "duckdb-1.5.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef461bca07313412dc09961c4a4757a851f56b95ac01c58fac6007632b7b94f2"}, - {file = "duckdb-1.5.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be37680ddb380015cb37318e378c53511c45c4f0d8fac5599d22b7d092b9217a"}, - {file = "duckdb-1.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:0b291786014df1133f8f18b9df4d004484613146e858d71a21791e0fcca16cf4"}, - {file = "duckdb-1.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:c9f3e0b71b8a50fccfb42794899285d9d318ce2503782b9dd54868e5ecd0ad31"}, - {file = "duckdb-1.5.2.tar.gz", hash = "sha256:638da0d5102b6cb6f7d47f83d0600708ac1d3cb46c5e9aaabc845f9ba4d69246"}, + {file = "duckdb-1.5.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3ddd9533ce80f9b851bdd6276960a9286166514a9ceca43d5bc2f0d5842c490d"}, + {file = "duckdb-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:360f2542d09759c3739400f8b787e29b43ba0da665c21756216291458bf6fc59"}, + {file = "duckdb-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0cf932055061e544d3fa27cc6c147da25f3f681ee5980157fb55e77d6c2d9c63"}, + {file = "duckdb-1.5.4-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2d58d39f5e65419cdc27e3875cba4a729a3bbf6bf4016aefb4a2a65335a1d42"}, + {file = "duckdb-1.5.4-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9a10dc40469b9c0e458625d2a8359461a982c6151bb53ff259fea00c4695ad4"}, + {file = "duckdb-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:3565550adbf160ef7a2ee3395470570182f11233983ad818bd7d5f9e349f92b2"}, + {file = "duckdb-1.5.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3fb41d9cfccb7e44511eeeed263ae98143ca63bdb1ef84631ba637c314efa1b5"}, + {file = "duckdb-1.5.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ba7b666bc9c78d6a930ee9f469024149f0c6a23fb7d2c3418aad6774339bec0"}, + {file = "duckdb-1.5.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9d9e6817fcbc09d2605a2c8c041ac7824d738d917c35a4d427e977647e1d7944"}, + {file = "duckdb-1.5.4-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02dd9f9a6124069213f13e3a474c208028c472fe1acdae12b38761f954fe4fc6"}, + {file = "duckdb-1.5.4-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccc7f2694d02b4763fee61021d45e12f7bc5743993686563957df0cef799fbae"}, + {file = "duckdb-1.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:4c430e788d99b50854209bf2833ba36a45df75e57f86efb477046cd408bbd077"}, + {file = "duckdb-1.5.4-cp311-cp311-win_arm64.whl", hash = "sha256:e2dc8340cfb6006025a798c50f40126d6e945a1d2487be94667bb4166556ce7b"}, + {file = "duckdb-1.5.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:291a9e7502551170af989ff63139a7a49e99d68edbc5ef5017ac27541fe54c65"}, + {file = "duckdb-1.5.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:83e8c089bbb756ca4471d8b05943b80a106058697cf00615e70423106bb783bc"}, + {file = "duckdb-1.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ff96d2a342b200e1ec6f1f19986c77f4ac16a49b6112f71c5b763989203a9d60"}, + {file = "duckdb-1.5.4-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f935ef210ab00bc94bb1e3052697adaa36bb0ce7bdfeda8b0f34e2ff1643870"}, + {file = "duckdb-1.5.4-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cda263d8c20addb8d4f95464787cbe0af1144f7ab7e21db3709fb826ee01725"}, + {file = "duckdb-1.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:266c7c909558ce7377f57d082cee408aadebdd9111be017558ca54e44a031037"}, + {file = "duckdb-1.5.4-cp312-cp312-win_arm64.whl", hash = "sha256:f14e79a006341f29ee5a2692a24dac5114e77533d579c57ec39124adf0135033"}, + {file = "duckdb-1.5.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:42a612e67d64450b446eb69695290d460713eef46e0f64467ab9dfe96264ee05"}, + {file = "duckdb-1.5.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3fb6f07d54ecf4d0d3c5179a2361fdddfafa14de4fc42696de4632479b703421"}, + {file = "duckdb-1.5.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f32ad7e0286c1c29ab6c73b29118c86101f8eee46aae54f54d0b50916f542f6"}, + {file = "duckdb-1.5.4-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:698ec90bd5d5538bd5f6d212a4b61af443d240703cf45f134738535026556ea5"}, + {file = "duckdb-1.5.4-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136cea7f886b78caf4035485b4b1e766e8b309e999f9e83a966f81ebb8122844"}, + {file = "duckdb-1.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:bd6777e8ddd74fb603a6d09766bfcff28638189f8aaa61fc0dffd9e9a4baa8e5"}, + {file = "duckdb-1.5.4-cp313-cp313-win_arm64.whl", hash = "sha256:73f4878a3012283024a64a1909e440aac12091ef336f671fc142f7e87449ce0c"}, + {file = "duckdb-1.5.4-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:4647968629d0677bbcc2416c7aeda8685eb84e4ca15a6dbd4f82a66cfc91a532"}, + {file = "duckdb-1.5.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e8fcef301cf68d3951ea1eb8ac4d76cea0a6f6a08f4c78fe4026fc96d217bebc"}, + {file = "duckdb-1.5.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f6f39cd0dc6948dee17fd130aec55114f97a8ef6e1db519b9774087962bc5c8c"}, + {file = "duckdb-1.5.4-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:262f068158beb5943f2c618f4e54b46db8306b959f90dce956f90a89f613673d"}, + {file = "duckdb-1.5.4-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d2307a76d199077b0055b354e90e857479461a0d875437535dd4833172c8b6d"}, + {file = "duckdb-1.5.4-cp314-cp314-win_amd64.whl", hash = "sha256:6dcbb81a1276bc48deb4d562bce4f8895e4fc6348750a096e30052345c6d6552"}, + {file = "duckdb-1.5.4-cp314-cp314-win_arm64.whl", hash = "sha256:0f8722346024e5d9f02b58bf7b0491a629f97fdc8a04a10e432940f471ee387a"}, + {file = "duckdb-1.5.4.tar.gz", hash = "sha256:f9e32f1cdd106793d79d190186bed9e75289d51e68bd9174e47c04bffedeab6f"}, ] [package.extras] @@ -684,24 +698,41 @@ all = ["adbc-driver-manager", "fsspec", "ipython", "numpy", "pandas", "pyarrow"] [[package]] name = "duckdb-sqlalchemy" -version = "1.5.2.2" +version = "1.5.4" description = "DuckDB SQLAlchemy dialect for DuckDB and MotherDuck" optional = false python-versions = "<4,>=3.9" files = [ - {file = "duckdb_sqlalchemy-1.5.2.2-py3-none-any.whl", hash = "sha256:d13fa8262acf76ebf77becb468418535371a05afa80247009c3407fc6a50fb6a"}, - {file = "duckdb_sqlalchemy-1.5.2.2.tar.gz", hash = "sha256:a2699d1a5583659f013e48cd1b21c61fa60eec012023a95cdbef8e45d74abcea"}, + {file = "duckdb_sqlalchemy-1.5.4-py3-none-any.whl", hash = "sha256:c8d3211d5e5791cb5032cfcedcab1dfcd703ac3df5ca3612831a2e07d4504d89"}, + {file = "duckdb_sqlalchemy-1.5.4.tar.gz", hash = "sha256:c325a2aad17172a36ea78910df0030df2cbac5264a711f6e152314ed6d5f3e02"}, ] [package.dependencies] duckdb = ">=0.5.0" packaging = ">=21" -sqlalchemy = ">=2.0.45" +sqlalchemy = {version = ">=2.0.0", markers = "python_version < \"3.14\""} [package.extras] -dev = ["fsspec (>=2025.2.0,<2027.0.0)", "github-action-utils (>=1.1.0,<2.0.0)", "hypothesis (>=6.75.2,<7.0.0)", "jupysql (>=0.11.1,<0.12.0)", "nox (>=2026.4.10,<2027.0.0)", "numpy (>=1.24,<2.0)", "numpy (>=1.26,<3.0)", "numpy (>=2.0,<3.0)", "pandas (>=1,<2.0)", "pandas (>=2.2,<4.0)", "pyarrow (>=22.0.0)", "pytest (>=8.0.0,<10.0.0)", "pytest-cov (>=7.1.0,<8.0.0)", "pytest-remotedata (>=0.4.0,<0.5.0)", "pytest-snapshot (>=0.9.0,<1.0.0)", "pytz (>=2024.2)", "toml (>=0.10.2,<0.11.0)", "ty (==0.0.34)"] +dev = ["fsspec (>=2025.2.0,<2027.0.0)", "github-action-utils (>=1.1.0,<2.0.0)", "hypothesis (>=6.75.2,<7.0.0)", "jupysql (>=0.11.1,<0.12.0)", "nox (>=2026.4.10,<2027.0.0)", "numpy (>=1.24,<2.0)", "numpy (>=1.26,<3.0)", "numpy (>=2.0,<3.0)", "pandas (>=1,<2.0)", "pandas (>=2.2,<4.0)", "pyarrow (>=22.0.0)", "pytest (>=8.0.0,<10.0.0)", "pytest-cov (>=7.1.0,<8.0.0)", "pytest-remotedata (>=0.4.0,<0.5.0)", "pytest-snapshot (>=0.9.0,<1.0.0)", "pytz (>=2024.2)", "toml (>=0.10.2,<0.11.0)", "ty (==0.0.54)"] devtools = ["nox (>=2026.4.10,<2027.0.0)", "pdbpp (>=0.11.0,<0.13.0)", "pre-commit (>=4.6.0,<4.7.0)"] +[[package]] +name = "exceptiongroup" +version = "1.3.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "fastparquet" version = "2024.11.0" @@ -764,24 +795,24 @@ lzo = ["python-lzo"] [[package]] name = "filelock" -version = "3.29.0" +version = "3.29.4" description = "A platform independent file lock." optional = false python-versions = ">=3.10" files = [ - {file = "filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258"}, - {file = "filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90"}, + {file = "filelock-3.29.4-py3-none-any.whl", hash = "sha256:dac1648087d5115554850d113e7dd8c83ab2d38e3435dde2d4f163847e57b767"}, + {file = "filelock-3.29.4.tar.gz", hash = "sha256:10cdb3656fc44541cdf30652a93fb10ec6b05325620eb316bd26893e4201538a"}, ] [[package]] name = "fsspec" -version = "2026.4.0" +version = "2026.6.0" description = "File-system specification" optional = false python-versions = ">=3.10" files = [ - {file = "fsspec-2026.4.0-py3-none-any.whl", hash = "sha256:11ef7bb35dab8a394fde6e608221d5cf3e8499401c249bebaeaad760a1a8dec2"}, - {file = "fsspec-2026.4.0.tar.gz", hash = "sha256:301d8ac70ae90ef3ad05dcf94d6c3754a097f9b5fe4667d2787aa359ec7df7e4"}, + {file = "fsspec-2026.6.0-py3-none-any.whl", hash = "sha256:02e0b71817df9b2169dc30a16832045764def1191b43dcff5bb85bdee212d2a1"}, + {file = "fsspec-2026.6.0.tar.gz", hash = "sha256:f5bac145310fe30e16e1471bd6840b2d990d609e872251d7e674241822abf01a"}, ] [package.extras] @@ -809,7 +840,7 @@ smb = ["smbprotocol"] ssh = ["paramiko"] test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"] test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"] -test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "backports-zstd", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas (<3.0.0)", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard"] +test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "backports-zstd", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas (<3.0.0)", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr (<3.2.0)", "zstandard"] tqdm = ["tqdm"] [[package]] @@ -830,70 +861,90 @@ test = ["coverage", "pytest (>=7,<8.1)", "pytest-cov", "pytest-mock (>=3)"] [[package]] name = "greenlet" -version = "3.5.0" +version = "3.5.3" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.10" files = [ - {file = "greenlet-3.5.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:29ea813b2e1f45fa9649a17853b2b5465c4072fbcb072e5af6cd3a288216574a"}, - {file = "greenlet-3.5.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:804a70b328e706b785c6ef16187051c394a63dd1a906d89be24b6ad77759f13f"}, - {file = "greenlet-3.5.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:884f649de075b84739713d41dd4dfd41e2b910bfb769c4a3ea02ec1da52cd9bb"}, - {file = "greenlet-3.5.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4d0eadc7e4d9ffb2af4247b606cae307be8e448911e5a0d0b16d72fc3d224cfd"}, - {file = "greenlet-3.5.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4b28037cb07768933c54d81bfe47a85f9f402f57d7d69743b991a713b63954eb"}, - {file = "greenlet-3.5.0-cp310-cp310-manylinux_2_39_riscv64.whl", hash = "sha256:f8c30c2225f40dd76c50790f0eb3b5c7c18431efb299e2782083e1981feed243"}, - {file = "greenlet-3.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cda05425526240807408156b6960a17a79a0c760b813573b67027823be760977"}, - {file = "greenlet-3.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9c615f869163e14bb1ced20322d8038fb680b08236521ac3f30cd4c1288785a0"}, - {file = "greenlet-3.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:ba8f0bdc2fae6ce915dfd0c16d2d00bca7e4247c1eae4416e06430e522137858"}, - {file = "greenlet-3.5.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:8f1cc966c126639cd152fdaa52624d2655f492faa79e013fea161de3e6dda082"}, - {file = "greenlet-3.5.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:362624e6a8e5bca3b8233e45eef33903a100e9539a2b995c364d595dbc4018b3"}, - {file = "greenlet-3.5.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5ecd83806b0f4c2f53b1018e0005cd82269ea01d42befc0368730028d850ed1c"}, - {file = "greenlet-3.5.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa94cb2288681e3a11645958f1871d48ee9211bd2f66628fdace505927d6e564"}, - {file = "greenlet-3.5.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ff251e9a0279522e62f6176412869395a64ddf2b5c5f782ff609a8216a4e662"}, - {file = "greenlet-3.5.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:64d6ac45f7271f48e45f67c95b54ef73534c52ec041fcda8edf520c6d811f4bc"}, - {file = "greenlet-3.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d874e79afd41a96e11ff4c5d0bc90a80973e476fda1c2c64985667397df432b"}, - {file = "greenlet-3.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0ed006e4b86c59de7467eb2601cd1b77b5a7d657d1ee55e30fe30d76451edba4"}, - {file = "greenlet-3.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:703cb211b820dbffbbc55a16bfc6e4583a6e6e990f33a119d2cc8b83211119c8"}, - {file = "greenlet-3.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:6c18dfb59c70f5a94acd271c72e90128c3c776e41e5f07767908c8c1b74ad339"}, - {file = "greenlet-3.5.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:db2910d3c809444e0a20147361f343fe2798e106af8d9d8506f5305302655a9f"}, - {file = "greenlet-3.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ec9ea74e7268ace7f9aab1b1a4e730193fc661b39a993cd91c606c32d4a3628"}, - {file = "greenlet-3.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54d243512da35485fc7a6bf3c178fdda6327a9d6506fcdd62b1abd1e41b2927b"}, - {file = "greenlet-3.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:41353ec2ecedf7aa8f682753a41919f8718031a6edac46b8d3dc7ed9e1ceb136"}, - {file = "greenlet-3.5.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d280a7f5c331622c69f97eb167f33577ff2d1df282c41cd15907fc0a3ca198c"}, - {file = "greenlet-3.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:58c1c374fe2b3d852f9b6b11a7dff4c85404e51b9a596fd9e89cf904eb09866d"}, - {file = "greenlet-3.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1eb67d5adefb5bd2e182d42678a328979a209e4e82eb93575708185d31d1f588"}, - {file = "greenlet-3.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2628d6c86f6cb0cb45e0c3c54058bbec559f57eaae699447748cb3928150577e"}, - {file = "greenlet-3.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:d4d9f0624c775f2dfc56ba54d515a8c771044346852a918b405914f6b19d7fd8"}, - {file = "greenlet-3.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:83ed9f27f1680b50e89f40f6df348a290ea234b249a4003d366663a12eab94f2"}, - {file = "greenlet-3.5.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:5a5ed18de6a0f6cc7087f1563f6bd93fc7df1c19165ca01e9bde5a5dc281d106"}, - {file = "greenlet-3.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a717fbc46d8a354fa675f7c1e813485b6ba3885f9bef0cd56e5ba27d758ff5b"}, - {file = "greenlet-3.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ddc090c5c1792b10246a78e8c2163ebbe04cf877f9d785c230a7b27b39ad038e"}, - {file = "greenlet-3.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4964101b8585c144cbda5532b1aa644255126c08a265dae90c16e7a0e63aaa9d"}, - {file = "greenlet-3.5.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2094acd54b272cb6eae8c03dd87b3fa1820a4cef18d6889c378d503500a1dc13"}, - {file = "greenlet-3.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:7022615368890680e67b9965d33f5773aade330d5343bbe25560135aaa849eae"}, - {file = "greenlet-3.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5e05ba267789ea87b5a155cf0e810b1ab88bf18e9e8740813945ceb8ee4350ba"}, - {file = "greenlet-3.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0ecec963079cd58cbd14723582384f11f166fd58883c15dcbfb342e0bc9b5846"}, - {file = "greenlet-3.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:728d9667d8f2f586644b748dbd9bb67e50d6a9381767d1357714ea6825bb3bf5"}, - {file = "greenlet-3.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:47422135b1d308c14b2c6e758beedb1acd33bb91679f5670edf77bf46244722b"}, - {file = "greenlet-3.5.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:f35807464c4c58c55f0d31dfa83c541a5615d825c2fe3d2b95360cf7c4e3c0a8"}, - {file = "greenlet-3.5.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55fa7ea52771be44af0de27d8b80c02cd18c2c3cddde6c847ecebdf72418b6a1"}, - {file = "greenlet-3.5.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a97e4821aa710603f94de0da25f25096454d78ffdace5dc77f3a006bc01abba3"}, - {file = "greenlet-3.5.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bf2d8a80bec89ab46221ae45c5373d5ba0bd36c19aa8508e85c6cd7e5106cd37"}, - {file = "greenlet-3.5.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f52a464e4ed91780bdfbbdd2b97197f3accaa629b98c200f4dffada759f3ae7"}, - {file = "greenlet-3.5.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:1bae92a1dd94c5f9d9493c3a212dd874c202442047cf96446412c862feca83a2"}, - {file = "greenlet-3.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:762612baf1161ccb8437c0161c668a688223cba28e1bf038f4eb47b13e39ccdf"}, - {file = "greenlet-3.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:57a43c6079a89713522bc4bcb9f75070ecf5d3dbad7792bfe42239362cbf2a16"}, - {file = "greenlet-3.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:3bc59be3945ae9750b9e7d45067d01ae3fe90ea5f9ade99239dabdd6e28a5033"}, - {file = "greenlet-3.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:a96fcee45e03fe30a62669fd16ab5c9d3c172660d3085605cb1e2d1280d3c988"}, - {file = "greenlet-3.5.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:a10a732421ab4fec934783ce3e54763470d0181db6e3468f9103a275c3ed1853"}, - {file = "greenlet-3.5.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7fc391b1566f2907d17aaebe78f8855dc45675159a775fcf9e61f8ee0078e87f"}, - {file = "greenlet-3.5.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:680bd0e7ad5e8daa8a4aa89f68fd6adc834b8a8036dc256533f7e08f4a4b01f7"}, - {file = "greenlet-3.5.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1aa4ce8debcd4ea7fb2e150f3036588c41493d1d52c43538924ae1819003f4ce"}, - {file = "greenlet-3.5.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddb36c7d6c9c0a65f18c7258634e0c416c6ab59caac8c987b96f80c2ebda0112"}, - {file = "greenlet-3.5.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:728a73687e39ae9ca34e4694cbf2f049d3fbc7174639468d0f67200a97d8f9e2"}, - {file = "greenlet-3.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e5ddf316ced87539144621453c3aef229575825fe60c604e62bedc4003f372b2"}, - {file = "greenlet-3.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4a448128607be0de65342dc9b31be7f948ef4cc0bc8832069350abefd310a8f2"}, - {file = "greenlet-3.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d60097128cb0a1cab9ea541186ea13cd7b847b8449a7787c2e2350da0cb82d86"}, - {file = "greenlet-3.5.0.tar.gz", hash = "sha256:d419647372241bc68e957bf38d5c1f98852155e4146bd1e4121adea81f4f01e4"}, + {file = "greenlet-3.5.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:c180d22d325fb613956b443c3c6f4406eb70e6defc70d3974da2a7b59e06f48c"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:483d08c11181c83a6ce1a7a61df0f624a208ec40817a3bb2302714592eee4f04"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1dae6e0091eae084317e411f047f0b7cb241c6db570f7c45fd6b900a274914ce"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0f6ff50ff8dbd51fae9b37f4101648b04ea0df19b3f50ab2beb5061e7716a5c8"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bcd2d72ccd70a1ec68ba6ef93e7fbb4420ef9997dabc7010d893bd4015e0bec"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_39_riscv64.whl", hash = "sha256:37bf9c538f5ae6e63d643f88dec37c0c83bdf0e2ebc62961dedcf458822f7b71"}, + {file = "greenlet-3.5.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:73f152c895e09907e0dbe24f6c2db37beb085cd63db91c3825a0fcd0064124a8"}, + {file = "greenlet-3.5.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8bdb43e1a1d1873721acab2be99c5befd4d2044ddfd52e4d610801019880a702"}, + {file = "greenlet-3.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:0909f9355a9f24845d3299f3112e266a06afb68302041989fd26bd68894933db"}, + {file = "greenlet-3.5.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:aca9b4ce85b152b5524ef7d88170efdff80dc0032aa8b75f9aaf7f3479ea95b4"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f71be4920368fe1fabeeaa53d1e3548337e2b223d9565f8ad5e392a75ba23fc"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d77e67f65f98449e3fb83f795b5d0a8437aead2f874ca89c96576caf4be3af6"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e18619ba655ac05d78d80fc83cac4ba892bd6927b99e3b8237aee861aaacc8bb"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8540f1e6205bd13ca0ce685581037219ca54a1b41a0a15d228c6c9b8ad5903d7"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:d27c0c653a60d9535f690226474a5cc1036a8b0d7b57504d1c4f89c44a07a80c"}, + {file = "greenlet-3.5.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ef56fe650f50575bf843acde967b9c567687f3c22340941a899b7bc56e956a8"}, + {file = "greenlet-3.5.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5121af01cf911e70056c00d4b46d5e9b5d1415550038573d744138bacb59e6b8"}, + {file = "greenlet-3.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:0f41e4a05a3c0cb31b17023eff28dd111e1d16bf7d7d00406cd7df23f31398a7"}, + {file = "greenlet-3.5.3-cp311-cp311-win_arm64.whl", hash = "sha256:ec6f1af59f6b5f3fc9678e2ea062d8377d22ac644f7844cb7a292910cf12ff44"}, + {file = "greenlet-3.5.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:719757059f5a53fd0dde23f78cffeafcdd97b21c850ddb7ca684a3c1a1f122e2"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:efa9f765dd09f9d0cdac651ffdf631ee59ec5dc6ee7a73e0c012ba9c52fbdf5b"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7faba15ac005376e02a0384504e0243be3370ce010296a44a820feb342b505ab"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5795cd1101371140551c645f2d408b8d3c01a5a29cf8a9bce6e759c983682d23"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:87142215824be6ac05e2e8e2786eec307ccbc27c36723c3881959df654af6861"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:af4923b3096e26a36d7e9cf24ab88083a20f97d191e3b97f253731ce9b41b28c"}, + {file = "greenlet-3.5.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:215275b1b49320987352e6c1b054acca0064f965a2c66992bed9a6f7d913f149"}, + {file = "greenlet-3.5.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6b1b0eed82364b0e32c4ea0f221452d33e6bb17ae094d9f72aed9851812747ea"}, + {file = "greenlet-3.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:cde8adafa2365676f74a979744629589999093bc86e2484214f58e61df08902c"}, + {file = "greenlet-3.5.3-cp312-cp312-win_arm64.whl", hash = "sha256:c4e7b79d83805475f0102008843f6eb45fd3bb0b2e88c774adab5fbaab27117d"}, + {file = "greenlet-3.5.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:c8d87c2134d871df96ecdea9cec7cbaab286dadab0f56476e57aaf9e8ac11550"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2d185dd1621757e70c3861cceffd5317ab4e7ed7eb09c82994828468527ade5"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1c514a468149bf8fbbab874188a3535cd8a48a3e353eb53a3d424296f8dbacd3"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9ad04dd75458c6300b047c61b8639092433d205a25a14e310d6582a480efcca1"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:915f887cf2682b66419b879423a2e072634aa7b7dce6f3ada4957cfced3f1e9a"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:afaabdd554cd7ae9bbb3ca070b0d7fdfd207dbf1d16865f7233837709d354bda"}, + {file = "greenlet-3.5.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:766cfd421c13e450feb340cd472a3ed9957d438727b7b4593ad7c76c5d2b0deb"}, + {file = "greenlet-3.5.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2ecda9ec22edf38fa389369eaed8c3d37c05f3c54e69f69438dbb2cc1de1458b"}, + {file = "greenlet-3.5.3-cp313-cp313-win_amd64.whl", hash = "sha256:c82304750f057167ff60d188df1d0cc1764ce9567eadf03e6a7443bcedd0b30b"}, + {file = "greenlet-3.5.3-cp313-cp313-win_arm64.whl", hash = "sha256:dc133a1569ee667b2a6ef56ce551084aeefd87a5acbc4736d336d1e2edc6cfc4"}, + {file = "greenlet-3.5.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:fd2e02fa07485778536a036222d616ab957b1d533f36b3ed98ce725d9c9d3117"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df0a0628d1597eb0897b62f55d1343f772405fd25f3b2a796c76874b0c2e22e8"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ebd933a6adabc298bab47731a130fe6bfb888bd934eee37810f151159544540d"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8d19fe6c39ebff9259f07bcc685d3290f8fa4ea2278e51dd0008e4d6b0f2d814"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4b9d501b40e80b70e32323c799dd9b420a5577a9601469d362ae1ffb690f3a7c"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:962c5df2db8cb446da51edf1ca5296c389d93b99c9d8aa2ee4c7d0d8f1218260"}, + {file = "greenlet-3.5.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a1fad1d11e7d6aab184107baa8e4ece11ccba3ec9599cd7efa5ff4d70d43256a"}, + {file = "greenlet-3.5.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fad5aec764399f1b5cc347ad250a59660f20c8f8888ea6bae1f93b769cce1154"}, + {file = "greenlet-3.5.3-cp314-cp314-win_amd64.whl", hash = "sha256:7669aa24cf2a1041d6f7899575b494a3ab4cf68bfcc8609b1dc0be7272db835e"}, + {file = "greenlet-3.5.3-cp314-cp314-win_arm64.whl", hash = "sha256:5b4807c4082c9d1b6d9eed56fcd041863e37f2228106eef24c30ca096e238605"}, + {file = "greenlet-3.5.3-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:271a8ea7c1024e8a0d7dd2be66dd66dda8a07193f41a17b9e924f7600f5b62be"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19131729ae0ddc3c2e1ef85e650169b5e37ee32e400f215f78b94d7b0d567310"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1540dd8e5fc2a5aec40fbb98ef8e149fa47c89a4b4a1cf2575a14d3d1869d7a8"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b897d97759425953f69a9c0fac67f8fe333ec0ce7377ef186fb2b0c3ad5e354d"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e81fa194a1d20967877bdf9c7794db2bc99063e5be36aee710c08f04c5bb087f"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:3236754d423955ea08e9bb5f6c04a7895f9e22c290b66aa7653fcb922d839eb0"}, + {file = "greenlet-3.5.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:55cf4d777485d43110e47133cbba6d74a8885a87ec1227ef0267f9ee80c5aa21"}, + {file = "greenlet-3.5.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:12a248ba75f6a9a236375f52296c498c89ff1d8badf32deb9eca7abd5853f7da"}, + {file = "greenlet-3.5.3-cp314-cp314t-win_amd64.whl", hash = "sha256:efc6bd60ea02e085862c74a3ef64b147ffc6f1a5ea7d9f26e7a939943f68c1e3"}, + {file = "greenlet-3.5.3-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:ea03f2f04367845d6b58eeed276e1e56e51f0b97d8ad5a88a7d20a91dc9056cc"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78dbef602fda6d97d957eb7937f70c9ce9e9527330347f8f6b6f9e554a9e7a47"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f73857adb8fee13fa56c172bd11262f888c0c648f9fea113e777bb2c7904a81"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cefa9cef4b371f9844c6053db71f1138bc6807bab1578b0dae5149c1f1141357"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:232fec92e823addaf02d9472cf7381e24a1d046a6ced1103c5caa4c21b9dfc1d"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_39_riscv64.whl", hash = "sha256:6219b6d04dbf6ba6084d77dc609e8473060dc55f759cbf626d512122781fa128"}, + {file = "greenlet-3.5.3-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:2421c3564da9429d5586d46ca31ebb26516b5498a802cf65c041a8e8a8980d34"}, + {file = "greenlet-3.5.3-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e0f0d160f0b2e558e6c75f7930967183255dc9735e5f5b8cae58ee09c9576d8b"}, + {file = "greenlet-3.5.3-cp315-cp315-win_amd64.whl", hash = "sha256:dd99329bbc15ca78dcc583dba05d0b1b0bae01ab6c2174989f5aaee3e41ac930"}, + {file = "greenlet-3.5.3-cp315-cp315-win_arm64.whl", hash = "sha256:499fef2acede88c1864a57bb586b4bf533c81e1b82df7ab93451cdb47dfec227"}, + {file = "greenlet-3.5.3-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:176bc16a721fa5fc294d70b87b4dfa5fbdd251b3da5d5372735ecef9bd7d6d0c"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:629b614d2b786e89c50440e246f33eea78f58a962d0bdbbcc809e6d13605903f"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b2e857ae16f5f72142edf75f9f176fe7526ba19a2841df1420516f83831c9f2"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:16d192579ed281051396dddd7f7754dac6259e6b1fb26378c87b66622f8e3f91"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e515757e2e36bcbf1fad09a46e1557e8b1ae1797d4b44d09da7deed88ad28608"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_39_riscv64.whl", hash = "sha256:4399eb8d041f20b68d943918bc55502a93d6fdc0a37c14da7881c04139acee9d"}, + {file = "greenlet-3.5.3-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:b363d46ed1ea431825fdb01471bb024fc08399bad1572a616e853c7684415adb"}, + {file = "greenlet-3.5.3-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:e44da2f5bbdaabaf7d80b73dbb430c7035771e9f244e3c8b769715c9d8fa0a16"}, + {file = "greenlet-3.5.3-cp315-cp315t-win_amd64.whl", hash = "sha256:8ff8bed3e3baa20a3ea261ce00526f1898ad4801d4886fd2220580ee0ad8fadf"}, + {file = "greenlet-3.5.3-cp315-cp315t-win_arm64.whl", hash = "sha256:b7068bd09f761f3f5b4d214c2bed063186b2a86148c740b3873e3f56d79bac31"}, + {file = "greenlet-3.5.3.tar.gz", hash = "sha256:a61efc018fd3eb317eeca31aba90ee9e7f26f22884a79b6c6ec715bf71bb62f1"}, ] [package.extras] @@ -916,13 +967,13 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.15" +version = "3.18" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8"}, - {file = "idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc"}, + {file = "idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2"}, + {file = "idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848"}, ] [package.extras] @@ -939,6 +990,17 @@ files = [ {file = "imagesize-2.0.0.tar.gz", hash = "sha256:8e8358c4a05c304f1fccf7ff96f036e7243a189e9e42e90851993c558cfe9ee3"}, ] +[[package]] +name = "iniconfig" +version = "2.3.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.10" +files = [ + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, +] + [[package]] name = "isort" version = "5.13.2" @@ -1653,15 +1715,30 @@ scramp = ">=1.4.5" [[package]] name = "platformdirs" -version = "4.9.6" +version = "4.10.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.10" files = [ - {file = "platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917"}, - {file = "platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a"}, + {file = "platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a"}, + {file = "platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7"}, ] +[[package]] +name = "pluggy" +version = "1.6.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["coverage", "pytest", "pytest-benchmark"] + [[package]] name = "pockets" version = "0.9.1" @@ -1696,26 +1773,26 @@ virtualenv = ">=20.10.0" [[package]] name = "prettytable" -version = "3.17.0" +version = "3.18.0" description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" optional = false python-versions = ">=3.10" files = [ - {file = "prettytable-3.17.0-py3-none-any.whl", hash = "sha256:aad69b294ddbe3e1f95ef8886a060ed1666a0b83018bbf56295f6f226c43d287"}, - {file = "prettytable-3.17.0.tar.gz", hash = "sha256:59f2590776527f3c9e8cf9fe7b66dd215837cca96a9c39567414cbc632e8ddb0"}, + {file = "prettytable-3.18.0-py3-none-any.whl", hash = "sha256:b3346e0e6f79180833aebaac088ae926340586cf6d7d991b9eb125b65f72313a"}, + {file = "prettytable-3.18.0.tar.gz", hash = "sha256:439217116152244369caf3d9f1caf2f9fe29b03bd79e88d2928c8e718c95d680"}, ] [package.dependencies] -wcwidth = "*" +wcwidth = ">=0.3.5" [package.extras] -tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"] +tests = ["pytest (>=9)", "pytest-cov", "pytest-lazy-fixtures"] [[package]] name = "psycopg2-binary" version = "2.9.12" description = "psycopg2 - Python-PostgreSQL Database Adapter" -optional = false +optional = true python-versions = ">=3.9" files = [ {file = "psycopg2_binary-2.9.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b818ceff717f98851a64bffd4c5eb5b3059ae280276dcecc52ac658dcf006a4"}, @@ -1916,6 +1993,102 @@ files = [ ed25519 = ["PyNaCl (>=1.6.2)"] rsa = ["cryptography (>=46.0.7)"] +[[package]] +name = "pyodbc" +version = "5.3.0" +description = "DB API module for ODBC" +optional = true +python-versions = ">=3.9" +files = [ + {file = "pyodbc-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6682cdec78f1302d0c559422c8e00991668e039ed63dece8bf99ef62173376a5"}, + {file = "pyodbc-5.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9cd3f0a9796b3e1170a9fa168c7e7ca81879142f30e20f46663b882db139b7d2"}, + {file = "pyodbc-5.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46185a1a7f409761716c71de7b95e7bbb004390c650d00b0b170193e3d6224bb"}, + {file = "pyodbc-5.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:349a9abae62a968b98f6bbd23d2825151f8d9de50b3a8f5f3271b48958fdb672"}, + {file = "pyodbc-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ac23feb7ddaa729f6b840639e92f83ff0ccaa7072801d944f1332cd5f5b05f47"}, + {file = "pyodbc-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8aa396c6d6af52ccd51b8c8a5bffbb46fd44e52ce07ea4272c1d28e5e5b12722"}, + {file = "pyodbc-5.3.0-cp310-cp310-win32.whl", hash = "sha256:46869b9a6555ff003ed1d8ebad6708423adf2a5c88e1a578b9f029fb1435186e"}, + {file = "pyodbc-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:705903acf6f43c44fc64e764578d9a88649eb21bf7418d78677a9d2e337f56f2"}, + {file = "pyodbc-5.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:c68d9c225a97aedafb7fff1c0e1bfe293093f77da19eaf200d0e988fa2718d16"}, + {file = "pyodbc-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ebc3be93f61ea0553db88589e683ace12bf975baa954af4834ab89f5ee7bf8ae"}, + {file = "pyodbc-5.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9b987a25a384f31e373903005554230f5a6d59af78bce62954386736a902a4b3"}, + {file = "pyodbc-5.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:676031723aac7dcbbd2813bddda0e8abf171b20ec218ab8dfb21d64a193430ea"}, + {file = "pyodbc-5.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5c30c5cd40b751f77bbc73edd32c4498630939bcd4e72ee7e6c9a4b982cc5ca"}, + {file = "pyodbc-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2035c7dfb71677cd5be64d3a3eb0779560279f0a8dc6e33673499498caa88937"}, + {file = "pyodbc-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5cbe4d753723c8a8f65020b7a259183ef5f14307587165ce37e8c7e251951852"}, + {file = "pyodbc-5.3.0-cp311-cp311-win32.whl", hash = "sha256:d255f6b117d05cfc046a5201fdf39535264045352ea536c35777cf66d321fbb8"}, + {file = "pyodbc-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:f1ad0e93612a6201621853fc661209d82ff2a35892b7d590106fe8f97d9f1f2a"}, + {file = "pyodbc-5.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:0df7ff47fab91ea05548095b00e5eb87ed88ddf4648c58c67b4db95ea4913e23"}, + {file = "pyodbc-5.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5ebf6b5d989395efe722b02b010cb9815698a4d681921bf5db1c0e1195ac1bde"}, + {file = "pyodbc-5.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:197bb6ddafe356a916b8ee1b8752009057fce58e216e887e2174b24c7ab99269"}, + {file = "pyodbc-5.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c6ccb5315ec9e081f5cbd66f36acbc820ad172b8fa3736cf7f993cdf69bd8a96"}, + {file = "pyodbc-5.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5dd3d5e469f89a3112cf8b0658c43108a4712fad65e576071e4dd44d2bd763c7"}, + {file = "pyodbc-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b180bc5e49b74fd40a24ef5b0fe143d0c234ac1506febe810d7434bf47cb925b"}, + {file = "pyodbc-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e3c39de3005fff3ae79246f952720d44affc6756b4b85398da4c5ea76bf8f506"}, + {file = "pyodbc-5.3.0-cp312-cp312-win32.whl", hash = "sha256:d32c3259762bef440707098010035bbc83d1c73d81a434018ab8c688158bd3bb"}, + {file = "pyodbc-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe77eb9dcca5fc1300c9121f81040cc9011d28cff383e2c35416e9ec06d4bc95"}, + {file = "pyodbc-5.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:afe7c4ac555a8d10a36234788fc6cfc22a86ce37fc5ba88a1f75b3e6696665dc"}, + {file = "pyodbc-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e9ab0b91de28a5ab838ac4db0253d7cc8ce2452efe4ad92ee6a57b922bf0c24"}, + {file = "pyodbc-5.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6132554ffbd7910524d643f13ce17f4a72f3a6824b0adef4e9a7f66efac96350"}, + {file = "pyodbc-5.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1629af4706e9228d79dabb4863c11cceb22a6dab90700db0ef449074f0150c0d"}, + {file = "pyodbc-5.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ceaed87ba2ea848c11223f66f629ef121f6ebe621f605cde9cfdee4fd9f4b68"}, + {file = "pyodbc-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3cc472c8ae2feea5b4512e23b56e2b093d64f7cbc4b970af51da488429ff7818"}, + {file = "pyodbc-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c79df54bbc25bce9f2d87094e7b39089c28428df5443d1902b0cc5f43fd2da6f"}, + {file = "pyodbc-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c2eb0b08e24fe5c40c7ebe9240c5d3bd2f18cd5617229acee4b0a0484dc226f2"}, + {file = "pyodbc-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:01166162149adf2b8a6dc21a212718f205cabbbdff4047dc0c415af3fd85867e"}, + {file = "pyodbc-5.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:363311bd40320b4a61454bebf7c38b243cd67c762ed0f8a5219de3ec90c96353"}, + {file = "pyodbc-5.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3f1bdb3ce6480a17afaaef4b5242b356d4997a872f39e96f015cabef00613797"}, + {file = "pyodbc-5.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7713c740a10f33df3cb08f49a023b7e1e25de0c7c99650876bbe717bc95ee780"}, + {file = "pyodbc-5.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cf18797a12e70474e1b7f5027deeeccea816372497e3ff2d46b15bec2d18a0cc"}, + {file = "pyodbc-5.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:08b2439500e212625471d32f8fde418075a5ddec556e095e5a4ba56d61df2dc6"}, + {file = "pyodbc-5.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:729c535341bb09c476f219d6f7ab194bcb683c4a0a368010f1cb821a35136f05"}, + {file = "pyodbc-5.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c67e7f2ce649155ea89beb54d3b42d83770488f025cf3b6f39ca82e9c598a02e"}, + {file = "pyodbc-5.3.0-cp314-cp314-win32.whl", hash = "sha256:a48d731432abaee5256ed6a19a3e1528b8881f9cb25cb9cf72d8318146ea991b"}, + {file = "pyodbc-5.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:58635a1cc859d5af3f878c85910e5d7228fe5c406d4571bffcdd281375a54b39"}, + {file = "pyodbc-5.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:754d052030d00c3ac38da09ceb9f3e240e8dd1c11da8906f482d5419c65b9ef5"}, + {file = "pyodbc-5.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f927b440c38ade1668f0da64047ffd20ec34e32d817f9a60d07553301324b364"}, + {file = "pyodbc-5.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:25c4cfb2c08e77bc6e82f666d7acd52f0e52a0401b1876e60f03c73c3b8aedc0"}, + {file = "pyodbc-5.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc834567c2990584b9726cba365834d039380c9dbbcef3030ddeb00c6541b943"}, + {file = "pyodbc-5.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8339d3094858893c1a68ee1af93efc4dff18b8b65de54d99104b99af6306320d"}, + {file = "pyodbc-5.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74528fe148980d0c735c0ebb4a4dc74643ac4574337c43c1006ac4d09593f92d"}, + {file = "pyodbc-5.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d89a7f2e24227150c13be8164774b7e1f9678321a4248f1356a465b9cc17d31e"}, + {file = "pyodbc-5.3.0-cp314-cp314t-win32.whl", hash = "sha256:af4d8c9842fc4a6360c31c35508d6594d5a3b39922f61b282c2b4c9d9da99514"}, + {file = "pyodbc-5.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:bfeb3e34795d53b7d37e66dd54891d4f9c13a3889a8f5fe9640e56a82d770955"}, + {file = "pyodbc-5.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:13656184faa3f2d5c6f19b701b8f247342ed581484f58bf39af7315c054e69db"}, + {file = "pyodbc-5.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0263323fc47082c2bf02562f44149446bbbfe91450d271e44bffec0c3143bfb1"}, + {file = "pyodbc-5.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:452e7911a35ee12a56b111ac5b596d6ed865b83fcde8427127913df53132759e"}, + {file = "pyodbc-5.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b35b9983ad300e5aea82b8d1661fc9d3afe5868de527ee6bd252dd550e61ecd6"}, + {file = "pyodbc-5.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e981db84fee4cebec67f41bd266e1e7926665f1b99c3f8f4ea73cd7f7666e381"}, + {file = "pyodbc-5.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:25b6766e56748eb1fc1d567d863e06cbb7b7c749a41dfed85db0031e696fa39a"}, + {file = "pyodbc-5.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2eb7151ed0a1959cae65b6ac0454f5c8bbcd2d8bafeae66483c09d58b0c7a7fc"}, + {file = "pyodbc-5.3.0-cp39-cp39-win32.whl", hash = "sha256:fc5ac4f2165f7088e74ecec5413b5c304247949f9702c8853b0e43023b4187e8"}, + {file = "pyodbc-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:c25dc9c41f61573bdcf61a3408c34b65e4c0f821b8f861ca7531b1353b389804"}, + {file = "pyodbc-5.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:101313a21d2654df856a60e4a13763e4d9f6c5d3fd974bcf3fc6b4e86d1bbe8e"}, + {file = "pyodbc-5.3.0.tar.gz", hash = "sha256:2fe0e063d8fb66efd0ac6dc39236c4de1a45f17c33eaded0d553d21c199f4d05"}, +] + +[[package]] +name = "pytest" +version = "9.1.1" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.10" +files = [ + {file = "pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c"}, + {file = "pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313"}, +] + +[package.dependencies] +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1.0.1" +packaging = ">=22" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -1932,13 +2105,13 @@ six = ">=1.5" [[package]] name = "python-discovery" -version = "1.3.1" +version = "1.4.2" description = "Python interpreter discovery" optional = false python-versions = ">=3.8" files = [ - {file = "python_discovery-1.3.1-py3-none-any.whl", hash = "sha256:ed188687ebb3b82c01a17cd5ac62fc94d9f6487a7f1a0f9dfe89753fec91039c"}, - {file = "python_discovery-1.3.1.tar.gz", hash = "sha256:62f6db28064c9613e7ca76cb3f00c38c839a07c31c00dfe7ed0986493d2150a6"}, + {file = "python_discovery-1.4.2-py3-none-any.whl", hash = "sha256:475803f53b7b2ed6e490e27373f9d8340f7d2eebf9acdaf645d7d714c97bb500"}, + {file = "python_discovery-1.4.2.tar.gz", hash = "sha256:8f3746c4b4968d22afbb97d36e1a0e5b66e6c0f297290f2e95f05b9b8bf18690"}, ] [package.dependencies] @@ -2273,13 +2446,13 @@ toml = ["tomli (>=2.0,<3.0)"] [[package]] name = "scramp" -version = "1.4.8" +version = "1.4.10" description = "An implementation of the SCRAM protocol." optional = false python-versions = ">=3.10" files = [ - {file = "scramp-1.4.8-py3-none-any.whl", hash = "sha256:87c2f15976845a2872fe5490a06097f0d01813cceb53774ea168c911f2ad025c"}, - {file = "scramp-1.4.8.tar.gz", hash = "sha256:bd018fabfe46343cceeb9f1c3e8d23f55770271e777e3accbfaee3ff0a316e71"}, + {file = "scramp-1.4.10-py3-none-any.whl", hash = "sha256:e187fe49290718406cdaf2f1b56507965e8d9f5f458f478ef946a811eeea382e"}, + {file = "scramp-1.4.10.tar.gz", hash = "sha256:084a1d2784a2399ca5021209b490120458882e85e03105c338446ccfe19bee1e"}, ] [package.dependencies] @@ -2328,13 +2501,13 @@ sqlalchemy = ">=2.0.0,<3.0.0" [[package]] name = "snowballstemmer" -version = "3.0.1" -description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms." +version = "3.1.1" +description = "This package provides 36 stemmers for 34 languages generated from Snowball algorithms." optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*" +python-versions = ">=3.3" files = [ - {file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"}, - {file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"}, + {file = "snowballstemmer-3.1.1-py3-none-any.whl", hash = "sha256:7e207fa178741da09cdee59d3ecec3827ad5f92b1fc5c9ff3755b639f71f5752"}, + {file = "snowballstemmer-3.1.1.tar.gz", hash = "sha256:e07bbc54a0d798fe6010a12398422e62a8bfbba95c394fd0956ef58cb4d3e260"}, ] [[package]] @@ -2762,24 +2935,23 @@ files = [ [[package]] name = "tqdm" -version = "4.67.3" +version = "4.68.3" description = "Fast, Extensible Progress Meter" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf"}, - {file = "tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb"}, + {file = "tqdm-4.68.3-py3-none-any.whl", hash = "sha256:39832cc2def2789a6f29df83f172db7416cea70052c0907a57801c5f2fdccb03"}, + {file = "tqdm-4.68.3.tar.gz", hash = "sha256:00dfa48452b6b6cfae3dd9885636c23d3422d1ec97c66d96818cbd5e0821d482"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] -discord = ["requests"] +discord = ["envwrap", "requests"] notebook = ["ipywidgets (>=6)"] -slack = ["slack-sdk"] -telegram = ["requests"] +slack = ["envwrap", "slack-sdk"] +telegram = ["envwrap", "requests"] [[package]] name = "ty" @@ -2903,130 +3075,130 @@ zstd = ["backports-zstd (>=1.0.0)"] [[package]] name = "virtualenv" -version = "21.3.3" +version = "21.5.1" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "virtualenv-21.3.3-py3-none-any.whl", hash = "sha256:7d5987d8369e098e41406efb780a3d4ca79280097293899e351a6407ee153ab3"}, - {file = "virtualenv-21.3.3.tar.gz", hash = "sha256:f5bda277e553b1c2b3c1a8debfc30496e1288cc93ce6b7b71b3280047e317328"}, + {file = "virtualenv-21.5.1-py3-none-any.whl", hash = "sha256:55aa670b67bbfb991b03fda39bd3276d92c419d702376e98c5df1c9989a26783"}, + {file = "virtualenv-21.5.1.tar.gz", hash = "sha256:dca3bf98275a59c652b69d68e73433e597d977c2da9198882479d1a7188009c8"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = {version = ">=3.24.2,<4", markers = "python_version >= \"3.10\""} platformdirs = ">=3.9.1,<5" -python-discovery = ">=1.3.1" +python-discovery = ">=1.4.2" typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""} [[package]] name = "wcwidth" -version = "0.7.0" +version = "0.8.2" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = ">=3.8" files = [ - {file = "wcwidth-0.7.0-py3-none-any.whl", hash = "sha256:5d69154c429a82910e241c738cd0e2976fac8a2dd47a1a805f4afed1c0f136f2"}, - {file = "wcwidth-0.7.0.tar.gz", hash = "sha256:90e3a7ea092341c44b99562e75d09e4d5160fe7a3974c6fb842a101a95e7eed0"}, + {file = "wcwidth-0.8.2-py3-none-any.whl", hash = "sha256:d63947694a0539a1d51e01eda7caf800c291020e6cdd7e28ad7b14dd33ad4f85"}, + {file = "wcwidth-0.8.2.tar.gz", hash = "sha256:91fbef97204b96a3d4d421609b80340b760cf33e26da123ff243d76b1fda8dda"}, ] [[package]] name = "wrapt" -version = "2.1.2" +version = "2.2.2" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = ">=3.9" files = [ - {file = "wrapt-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a86d99a14f76facb269dc148590c01aaf47584071809a70da30555228158c"}, - {file = "wrapt-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a819e39017f95bf7aede768f75915635aa8f671f2993c036991b8d3bfe8dbb6f"}, - {file = "wrapt-2.1.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5681123e60aed0e64c7d44f72bbf8b4ce45f79d81467e2c4c728629f5baf06eb"}, - {file = "wrapt-2.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b8b28e97a44d21836259739ae76284e180b18abbb4dcfdff07a415cf1016c3e"}, - {file = "wrapt-2.1.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cef91c95a50596fcdc31397eb6955476f82ae8a3f5a8eabdc13611b60ee380ba"}, - {file = "wrapt-2.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dad63212b168de8569b1c512f4eac4b57f2c6934b30df32d6ee9534a79f1493f"}, - {file = "wrapt-2.1.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d307aa6888d5efab2c1cde09843d48c843990be13069003184b67d426d145394"}, - {file = "wrapt-2.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c87cf3f0c85e27b3ac7d9ad95da166bf8739ca215a8b171e8404a2d739897a45"}, - {file = "wrapt-2.1.2-cp310-cp310-win32.whl", hash = "sha256:d1c5fea4f9fe3762e2b905fdd67df51e4be7a73b7674957af2d2ade71a5c075d"}, - {file = "wrapt-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:d8f7740e1af13dff2684e4d56fe604a7e04d6c94e737a60568d8d4238b9a0c71"}, - {file = "wrapt-2.1.2-cp310-cp310-win_arm64.whl", hash = "sha256:1c6cc827c00dc839350155f316f1f8b4b0c370f52b6a19e782e2bda89600c7dc"}, - {file = "wrapt-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:96159a0ee2b0277d44201c3b5be479a9979cf154e8c82fa5df49586a8e7679bb"}, - {file = "wrapt-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98ba61833a77b747901e9012072f038795de7fc77849f1faa965464f3f87ff2d"}, - {file = "wrapt-2.1.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:767c0dbbe76cae2a60dd2b235ac0c87c9cccf4898aef8062e57bead46b5f6894"}, - {file = "wrapt-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c691a6bc752c0cc4711cc0c00896fcd0f116abc253609ef64ef930032821842"}, - {file = "wrapt-2.1.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f3b7d73012ea75aee5844de58c88f44cf62d0d62711e39da5a82824a7c4626a8"}, - {file = "wrapt-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:577dff354e7acd9d411eaf4bfe76b724c89c89c8fc9b7e127ee28c5f7bcb25b6"}, - {file = "wrapt-2.1.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3d7b6fd105f8b24e5bd23ccf41cb1d1099796524bcc6f7fbb8fe576c44befbc9"}, - {file = "wrapt-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:866abdbf4612e0b34764922ef8b1c5668867610a718d3053d59e24a5e5fcfc15"}, - {file = "wrapt-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5a0a0a3a882393095573344075189eb2d566e0fd205a2b6414e9997b1b800a8b"}, - {file = "wrapt-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:64a07a71d2730ba56f11d1a4b91f7817dc79bc134c11516b75d1921a7c6fcda1"}, - {file = "wrapt-2.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:b89f095fe98bc12107f82a9f7d570dc83a0870291aeb6b1d7a7d35575f55d98a"}, - {file = "wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9"}, - {file = "wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748"}, - {file = "wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e"}, - {file = "wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8"}, - {file = "wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c"}, - {file = "wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c"}, - {file = "wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1"}, - {file = "wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2"}, - {file = "wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0"}, - {file = "wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63"}, - {file = "wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf"}, - {file = "wrapt-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787fd6f4d67befa6fe2abdffcbd3de2d82dfc6fb8a6d850407c53332709d030b"}, - {file = "wrapt-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bdf26e03e6d0da3f0e9422fd36bcebf7bc0eeb55fdf9c727a09abc6b9fe472e"}, - {file = "wrapt-2.1.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bbac24d879aa22998e87f6b3f481a5216311e7d53c7db87f189a7a0266dafffb"}, - {file = "wrapt-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16997dfb9d67addc2e3f41b62a104341e80cac52f91110dece393923c0ebd5ca"}, - {file = "wrapt-2.1.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:162e4e2ba7542da9027821cb6e7c5e068d64f9a10b5f15512ea28e954893a267"}, - {file = "wrapt-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f29c827a8d9936ac320746747a016c4bc66ef639f5cd0d32df24f5eacbf9c69f"}, - {file = "wrapt-2.1.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a9dd9813825f7ecb018c17fd147a01845eb330254dff86d3b5816f20f4d6aaf8"}, - {file = "wrapt-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f8dbdd3719e534860d6a78526aafc220e0241f981367018c2875178cf83a413"}, - {file = "wrapt-2.1.2-cp313-cp313-win32.whl", hash = "sha256:5c35b5d82b16a3bc6e0a04349b606a0582bc29f573786aebe98e0c159bc48db6"}, - {file = "wrapt-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f8bc1c264d8d1cf5b3560a87bbdd31131573eb25f9f9447bb6252b8d4c44a3a1"}, - {file = "wrapt-2.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:3beb22f674550d5634642c645aba4c72a2c66fb185ae1aebe1e955fae5a13baf"}, - {file = "wrapt-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fc04bc8664a8bc4c8e00b37b5355cffca2535209fba1abb09ae2b7c76ddf82b"}, - {file = "wrapt-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a9b9d50c9af998875a1482a038eb05755dfd6fe303a313f6a940bb53a83c3f18"}, - {file = "wrapt-2.1.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2d3ff4f0024dd224290c0eabf0240f1bfc1f26363431505fb1b0283d3b08f11d"}, - {file = "wrapt-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3278c471f4468ad544a691b31bb856374fbdefb7fee1a152153e64019379f015"}, - {file = "wrapt-2.1.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8914c754d3134a3032601c6984db1c576e6abaf3fc68094bb8ab1379d75ff92"}, - {file = "wrapt-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ff95d4264e55839be37bafe1536db2ab2de19da6b65f9244f01f332b5286cfbf"}, - {file = "wrapt-2.1.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:76405518ca4e1b76fbb1b9f686cff93aebae03920cc55ceeec48ff9f719c5f67"}, - {file = "wrapt-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c0be8b5a74c5824e9359b53e7e58bef71a729bacc82e16587db1c4ebc91f7c5a"}, - {file = "wrapt-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:f01277d9a5fc1862f26f7626da9cf443bebc0abd2f303f41c5e995b15887dabd"}, - {file = "wrapt-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:84ce8f1c2104d2f6daa912b1b5b039f331febfeee74f8042ad4e04992bd95c8f"}, - {file = "wrapt-2.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:a93cd767e37faeddbe07d8fc4212d5cba660af59bdb0f6372c93faaa13e6e679"}, - {file = "wrapt-2.1.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1370e516598854e5b4366e09ce81e08bfe94d42b0fd569b88ec46cc56d9164a9"}, - {file = "wrapt-2.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6de1a3851c27e0bd6a04ca993ea6f80fc53e6c742ee1601f486c08e9f9b900a9"}, - {file = "wrapt-2.1.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:de9f1a2bbc5ac7f6012ec24525bdd444765a2ff64b5985ac6e0692144838542e"}, - {file = "wrapt-2.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:970d57ed83fa040d8b20c52fe74a6ae7e3775ae8cff5efd6a81e06b19078484c"}, - {file = "wrapt-2.1.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3969c56e4563c375861c8df14fa55146e81ac11c8db49ea6fb7f2ba58bc1ff9a"}, - {file = "wrapt-2.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:57d7c0c980abdc5f1d98b11a2aa3bb159790add80258c717fa49a99921456d90"}, - {file = "wrapt-2.1.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:776867878e83130c7a04237010463372e877c1c994d449ca6aaafeab6aab2586"}, - {file = "wrapt-2.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fab036efe5464ec3291411fabb80a7a39e2dd80bae9bcbeeca5087fdfa891e19"}, - {file = "wrapt-2.1.2-cp314-cp314-win32.whl", hash = "sha256:e6ed62c82ddf58d001096ae84ce7f833db97ae2263bff31c9b336ba8cfe3f508"}, - {file = "wrapt-2.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:467e7c76315390331c67073073d00662015bb730c566820c9ca9b54e4d67fd04"}, - {file = "wrapt-2.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:da1f00a557c66225d53b095a97eace0fc5349e3bfda28fa34ffae238978ee575"}, - {file = "wrapt-2.1.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:62503ffbc2d3a69891cf29beeaccdb4d5e0a126e2b6a851688d4777e01428dbb"}, - {file = "wrapt-2.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c7e6cd120ef837d5b6f860a6ea3745f8763805c418bb2f12eeb1fa6e25f22d22"}, - {file = "wrapt-2.1.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3769a77df8e756d65fbc050333f423c01ae012b4f6731aaf70cf2bef61b34596"}, - {file = "wrapt-2.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a76d61a2e851996150ba0f80582dd92a870643fa481f3b3846f229de88caf044"}, - {file = "wrapt-2.1.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6f97edc9842cf215312b75fe737ee7c8adda75a89979f8e11558dfff6343cc4b"}, - {file = "wrapt-2.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4006c351de6d5007aa33a551f600404ba44228a89e833d2fadc5caa5de8edfbf"}, - {file = "wrapt-2.1.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a9372fc3639a878c8e7d87e1556fa209091b0a66e912c611e3f833e2c4202be2"}, - {file = "wrapt-2.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3144b027ff30cbd2fca07c0a87e67011adb717eb5f5bd8496325c17e454257a3"}, - {file = "wrapt-2.1.2-cp314-cp314t-win32.whl", hash = "sha256:3b8d15e52e195813efe5db8cec156eebe339aaf84222f4f4f051a6c01f237ed7"}, - {file = "wrapt-2.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:08ffa54146a7559f5b8df4b289b46d963a8e74ed16ba3687f99896101a3990c5"}, - {file = "wrapt-2.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:72aaa9d0d8e4ed0e2e98019cea47a21f823c9dd4b43c7b77bba6679ffcca6a00"}, - {file = "wrapt-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5e0fa9cc32300daf9eb09a1f5bdc6deb9a79defd70d5356ba453bcd50aef3742"}, - {file = "wrapt-2.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:710f6e5dfaf6a5d5c397d2d6758a78fecd9649deb21f1b645f5b57a328d63050"}, - {file = "wrapt-2.1.2-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:305d8a1755116bfdad5dda9e771dcb2138990a1d66e9edd81658816edf51aed1"}, - {file = "wrapt-2.1.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f0d8fc30a43b5fe191cf2b1a0c82bab2571dadd38e7c0062ee87d6df858dd06e"}, - {file = "wrapt-2.1.2-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a5d516e22aedb7c9c1d47cba1c63160b1a6f61ec2f3948d127cd38d5cfbb556f"}, - {file = "wrapt-2.1.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:45914e8efbe4b9d5102fcf0e8e2e3258b83a5d5fba9f8f7b6d15681e9d29ffe0"}, - {file = "wrapt-2.1.2-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:478282ebd3795a089154fb16d3db360e103aa13d3b2ad30f8f6aac0d2207de0e"}, - {file = "wrapt-2.1.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3756219045f73fb28c5d7662778e4156fbd06cf823c4d2d4b19f97305e52819c"}, - {file = "wrapt-2.1.2-cp39-cp39-win32.whl", hash = "sha256:b8aefb4dbb18d904b96827435a763fa42fc1f08ea096a391710407a60983ced8"}, - {file = "wrapt-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:e5aeab8fe15c3dff75cfee94260dcd9cded012d4ff06add036c28fae7718593b"}, - {file = "wrapt-2.1.2-cp39-cp39-win_arm64.whl", hash = "sha256:f069e113743a21a3defac6677f000068ebb931639f789b5b226598e247a4c89e"}, - {file = "wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8"}, - {file = "wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e"}, + {file = "wrapt-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:055e6fcfaa28e58c6a8c247d48b92be9d56f818b7068aa4f22b15b3343a09931"}, + {file = "wrapt-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8374eb6b1a58809211e84ff835a182bb17ab2807a5bfef23204c8cff38178a00"}, + {file = "wrapt-2.2.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:656593bb3f5529f03d27af4136c4d7b11990e470bcbc6fefa5ef218695bece55"}, + {file = "wrapt-2.2.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dfb00cb7bb22099e2f64b7340fb96113639aa7260c0972af3797ace2297b936c"}, + {file = "wrapt-2.2.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e7f10ee0bd53673bfd52b67cbce83336fe6cad90d2377b03baf66491d2bbfb91"}, + {file = "wrapt-2.2.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4402f57c5f0d0579599858ffbdd9bf4e3f0972f51096f2bd6cc7dab6b76ee49e"}, + {file = "wrapt-2.2.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:3a4eb7964ff4643d333c84f880bcf554652b2a1050aebc54ae696327f61acfaf"}, + {file = "wrapt-2.2.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e542b7c5af91e2123a8aabf19894319d5ec4268d2a9ffd2f239386133fc47746"}, + {file = "wrapt-2.2.2-cp310-cp310-win32.whl", hash = "sha256:6e7e45b43d3c774d244fe7264378f5a3f0f383bc55a54a9866434e524540110f"}, + {file = "wrapt-2.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:955f1d6e72a352e478de8d8b503abe301c5e139a141b62eb0923bd694995025f"}, + {file = "wrapt-2.2.2-cp310-cp310-win_arm64.whl", hash = "sha256:b89d8d73c82db2bb7e6090b3afd7973f980d24e905cc34394eab60b884b3bf67"}, + {file = "wrapt-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f1a2ff355ece6a111ca7a20dc86df6659c9205d3fcee674ca34f2a2854fd4e73"}, + {file = "wrapt-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:55b9a899e6fff5444f229d30aa6e9ac92d2216d9d60f33c771b5d76a760d5f8e"}, + {file = "wrapt-2.2.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a2d78c363f97d8bd718ee40432c66395685e9e98528ccaa423c3355d1715a26d"}, + {file = "wrapt-2.2.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d619e1eed9bd4f6ed9f24cd61971aa086fa86505289628d464bcf8a2c2e3f328"}, + {file = "wrapt-2.2.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:518b0c5e323511ec56a38894802ddd5e1222626484e68efe63f201854ad788e5"}, + {file = "wrapt-2.2.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4bccea5cdecffa9dd70e343741f0e41e0a16619313d04b72f78bb525162ebcd0"}, + {file = "wrapt-2.2.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:209112cafd963710a05d199aae431d79a28bc76eb8e6d1bbbb8ad24340722cae"}, + {file = "wrapt-2.2.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e5a5290e4bf2f332fc29ce72ffb9a2fff678aaac047e2e9f5f7165cd7792e099"}, + {file = "wrapt-2.2.2-cp311-cp311-win32.whl", hash = "sha256:5499236ad1dc116012e2a5dd943f3f31af12fce452128e2bbcbd55a7d3d4d14c"}, + {file = "wrapt-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:8636809939152be6ae20a6cef0fed9fe60f411b47847d0426a826884b469e971"}, + {file = "wrapt-2.2.2-cp311-cp311-win_arm64.whl", hash = "sha256:5d0a142f7af07caeb5e5da87493162a7b8efa19ba919e550a746f7446e13fb30"}, + {file = "wrapt-2.2.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8417fd3c674d3c8023d080292d29301531a12daf8bd938dd419710dd2f464f2b"}, + {file = "wrapt-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e7070c7472582e31af3dfc2622b2381a0df7435110a9388ed8db5ffbce67efb"}, + {file = "wrapt-2.2.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2e096c9d39a59b35b63c9aacfbbbec2088ff51ff1fc31051acc60a07f42f273a"}, + {file = "wrapt-2.2.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d1a6050405bf334be33bf66296f113563622972a34900ae6fa60fd283a1a900"}, + {file = "wrapt-2.2.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10adb01371408c6de504a6658b9886480f1a4919a83752748a387a504a21df79"}, + {file = "wrapt-2.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3442eee2a5798f9b451f1b2cd7518ce8b7e28a2a364696c414460a0e295c012a"}, + {file = "wrapt-2.2.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6c99012a22f735a85eed7c4b86a3e99c30fdd57d9e115b2b45f796264b58d0bf"}, + {file = "wrapt-2.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3b686cfc008776a3952d6213cb296ed7f45d782a8453936406faa89eac0835ab"}, + {file = "wrapt-2.2.2-cp312-cp312-win32.whl", hash = "sha256:ef2cce266b5b0b07e19fa82e59673b81142b7a3607c8ed1254113d048ed668da"}, + {file = "wrapt-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:abf8c20a2d72ee69e16328b3c91342c446e723bfe48bfcc4dded3b9722ac027f"}, + {file = "wrapt-2.2.2-cp312-cp312-win_arm64.whl", hash = "sha256:c6c64c5d02578bc4c4bca4f0aef1504de933c1d5b4ac2710b9131111459506c8"}, + {file = "wrapt-2.2.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9e8b648270c613720a202d9a45ebabc33261b22c3a839b115ac5bce8c0bb0d69"}, + {file = "wrapt-2.2.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6fb7e94e8fe3e4c3067bb1653a91cce7c5e83acc119fdd41501b1bf74654617"}, + {file = "wrapt-2.2.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb18fc51e813df0d9c98049e3bf2298a5495a648602040e21fa3c7329371159e"}, + {file = "wrapt-2.2.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94b00b00f806eb3ef2abe9049ed45994a81ee9284884d96e6b8314927c6cea3d"}, + {file = "wrapt-2.2.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:62415fd095bc590b842b6d092f2b5d9ccbaeb7e0b28535c03dcea2718b48636b"}, + {file = "wrapt-2.2.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a41e758d80dc0ab8c210f641ac892009d356cf1f955d97db544c8dd317b4d14c"}, + {file = "wrapt-2.2.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b84cd4058001c9727b0e9980b7a9e66325b5ca748b1b578e822cade1bc6b304f"}, + {file = "wrapt-2.2.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:26fc73a1b15e0946d2942b9a4426d162b51676338327dc067ccd8d2d76385f94"}, + {file = "wrapt-2.2.2-cp313-cp313-win32.whl", hash = "sha256:3c4095803491f6ef72128914c28ec05bbad9758433bb35f6715a3e9c8e46fb2d"}, + {file = "wrapt-2.2.2-cp313-cp313-win_amd64.whl", hash = "sha256:2cb07f414fab25dbe6b5c7398e1491423a5c81a6209533639969a6c928d474a4"}, + {file = "wrapt-2.2.2-cp313-cp313-win_arm64.whl", hash = "sha256:1fc7691f070220215cccb2a20836b9adbaecb8ff22ad47abe63de5f110994fac"}, + {file = "wrapt-2.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ec8f83949028366531383603139403cac7a826e4011955813cdd640017845ce5"}, + {file = "wrapt-2.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b481fb0c40d9fd90a5809911208da700987d373a20a4709dc9e3944af7a6bec"}, + {file = "wrapt-2.2.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0065a3b657cec06813b4241d2462ccec287f6863103d7445b725fb3a889736f9"}, + {file = "wrapt-2.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:30f7424af5c5c345b7f26490e097f74a2ef45b3d08b664dc33571aee3bd3b56c"}, + {file = "wrapt-2.2.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:07fdcb012821859168641acf68afad61ef9783cf37100af85f152550e9677194"}, + {file = "wrapt-2.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f90038ab58fafb584801ca62d72384d7d5225d93c76f7b773c22fae545bd8066"}, + {file = "wrapt-2.2.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:c5d7825491bfa2d08b97e9557768987952c7b9ae687d06c3320b40a37ccb7f20"}, + {file = "wrapt-2.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0ad520e6daa9bbf136f14de735474dbec7dcc0891f718e1d274ce8dc92e645af"}, + {file = "wrapt-2.2.2-cp313-cp313t-win32.whl", hash = "sha256:25904acb9475f46c24fe0423dbc8fda8cc5fbc282ab3dc6e72e919748c53f4e9"}, + {file = "wrapt-2.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:305d4c247d61c4115794a169141823c62f719525ddb90b23aa332741c77d2c28"}, + {file = "wrapt-2.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c20279cd1a29800815d7b2d6338b60a6c6e78263f9d6e62e0eda251ba9cae2d0"}, + {file = "wrapt-2.2.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:0e64826f920c42d9d9f87e8cc09ffae66c51ede12d59061a5a426deb9aa71745"}, + {file = "wrapt-2.2.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dcaa5e1451bd8751d7bd1568dfa3321c78092a52a7ecb5d1a0f18a5791e1fd00"}, + {file = "wrapt-2.2.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0abfd648dac9ac9c5b3aa9b523d27f1789046640b58dcd5652a720ddb325e1fc"}, + {file = "wrapt-2.2.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f4bfd8d1eb438153eff8b8cfe87f032ba65731e1ce06138b5090f745a33f6f95"}, + {file = "wrapt-2.2.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c427c9d06d859848a69f0d928fe28b5c33a941b2265d10a0e1f15cd244f1ee33"}, + {file = "wrapt-2.2.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4250b43d1a129d947e083c4dc6baf333c9bb34edd26f912d5b0457841fc858ab"}, + {file = "wrapt-2.2.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:173e5bb5ca350a6e0abab60b7ec7cdd7992a814cb14b4de670a28f067f105663"}, + {file = "wrapt-2.2.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:aa14b01804bce36c6d63d7b6a4f55df390f29f8648cc13a1f40b166f4d54680d"}, + {file = "wrapt-2.2.2-cp314-cp314-win32.whl", hash = "sha256:58f9f8d637c9a6e245c6ef5b109b67ec187d2faed23d1405656b51d96e0a5b56"}, + {file = "wrapt-2.2.2-cp314-cp314-win_amd64.whl", hash = "sha256:385cb1866f20479e83299af585375bfa0a4b0c6c9907a981483ea782ea8ae406"}, + {file = "wrapt-2.2.2-cp314-cp314-win_arm64.whl", hash = "sha256:8ffbeaea6771a6eba6e6eeb09767864995726bc8240bb54baf88a9bb1db34d5c"}, + {file = "wrapt-2.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:09f811d43f6f33ec7515f0be76b159569f4057ab54d3e079c3204dddb90afa2a"}, + {file = "wrapt-2.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a795d3c06e5fbf9ea2f13196180b77aeab1b4685917256ee0d014cc163d90063"}, + {file = "wrapt-2.2.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:45c2f2768e790c9f8db90f239ef23a2af8e7570f25a35619ef902df4a738447f"}, + {file = "wrapt-2.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bbf00ee0cb55ec24e2b0995a71942b85b21a066db8f3f46e1dbfdb9433ffba81"}, + {file = "wrapt-2.2.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2252f77663651b89255895f58cc6ac08fcb206d4371813e5af61bb62d4f7689c"}, + {file = "wrapt-2.2.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2cd7181ab1c31192ff5219269830744b5a62020b3a6d433588c4f1c95b8f8bff"}, + {file = "wrapt-2.2.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:6fe35fd51b74867d8b80174c277bd6bbf6a73e443f908129dc531c4b688a20d5"}, + {file = "wrapt-2.2.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:11d95fc2fbad3163596c39d440e6f21ca9fccece74b56e30a37ac2fca786a07c"}, + {file = "wrapt-2.2.2-cp314-cp314t-win32.whl", hash = "sha256:d8a15813215f33fa83667bfc978b300e35669ea8bb424e970a1426bcb7bc6cca"}, + {file = "wrapt-2.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d09db0f7e8357060d3c38fc22a018aba683a796bf184360fd1a58f6fc180dc77"}, + {file = "wrapt-2.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:f32fe639c39561ccc187bcae17e9271be0eb45f1c2952510d2f29b33ab577347"}, + {file = "wrapt-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d01d8e0afc55823245a3b97a79c7c77464e31ea7a7b629a4bf26f9441dc1f18e"}, + {file = "wrapt-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a28287413351cb198b8c5ddd045c56fac1d195808642cd264d1ab50426146650"}, + {file = "wrapt-2.2.2-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:abf033b7e4542357659cd83ed6cd5033c43aaa1887044045ceb571528837f72f"}, + {file = "wrapt-2.2.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d2f6573561fa05002e5ee71529f4ab0a7dffed3e45b51013fe6298fe2723c02"}, + {file = "wrapt-2.2.2-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c38510a21d5b9cf3e84c460d909e9f2a098667439fd42841bb081cab45835d68"}, + {file = "wrapt-2.2.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:cd385a48b055bdc3630ab30e0c7fd8514a36904ec23f9cee7a65d887334a3cea"}, + {file = "wrapt-2.2.2-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:3dc3dcfc2da95d501905f10dc11a0dc622e91d8cdd8bbfcb63ca54afd131e556"}, + {file = "wrapt-2.2.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:fa81c5b5fe8cd6c41e3a798533b81288279e5fdbde2128f21071922764281c99"}, + {file = "wrapt-2.2.2-cp39-cp39-win32.whl", hash = "sha256:814f1bf3e0a7035f67a1db0cdaf5e2bbcaa4d7092db96673cfa467adeaab8591"}, + {file = "wrapt-2.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:9ee098171b07edba66ab69a9bf0251d3cbef654107e800feb24c0c6f30592728"}, + {file = "wrapt-2.2.2-cp39-cp39-win_arm64.whl", hash = "sha256:3179a4db066b53d40562e368b12895440c8f0953b6543b89d6acc41c0273996e"}, + {file = "wrapt-2.2.2-py3-none-any.whl", hash = "sha256:5bad217350f19ce99ca5b5e71d406765ea86fe541628426772b657375ee1c048"}, + {file = "wrapt-2.2.2.tar.gz", hash = "sha256:0788e321027c999bf221b667bd4a54aaefd1a36283749a860ac3eb77daed0302"}, ] [package.extras] @@ -3034,8 +3206,10 @@ dev = ["pytest", "setuptools"] [extras] docs = ["sphinx-rtd-theme", "sphinxcontrib-napoleon"] +mssql = ["aioodbc", "pyodbc"] +postgres = ["psycopg2-binary"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.14" -content-hash = "e89f757d54ff2a3b3dfcfde7342b55e1394c114c7db337dcd8bc9a7c9dea37c1" +content-hash = "10e04ed26df40d14987fb7c9f55b24de4a1c252bdccb47cd293879d1e47e0c17" diff --git a/tests/test_utils_mssql.py b/tests/test_utils_mssql.py index 3879361..cdb9a13 100644 --- a/tests/test_utils_mssql.py +++ b/tests/test_utils_mssql.py @@ -2,7 +2,7 @@ import sys import unittest from unittest.mock import MagicMock, call, patch - +from datafaker.db_utils import create_db_engine, get_metadata, get_sync_engine class TestMakeAsyncDsn(unittest.TestCase): """Tests for make_async_dsn.""" @@ -152,8 +152,6 @@ class TestSchemaTranslateMap(unittest.TestCase): """Tests for the cross-dialect schema routing in create_db_engine.""" def _make_engine(self, dsn: str, schema_name: str | None = None): - from datafaker.utils import create_db_engine, get_sync_engine - return get_sync_engine(create_db_engine(dsn, schema_name=schema_name)) def test_no_schema_no_translate_map(self) -> None: @@ -171,7 +169,6 @@ def test_schema_sets_translate_map(self) -> None: def test_search_path_not_issued(self) -> None: """set_db_settings is never called with a search_path key.""" - from datafaker.utils import create_db_engine, get_sync_engine with patch("datafaker.utils.set_db_settings") as mock_set: engine = get_sync_engine( @@ -191,7 +188,6 @@ def test_search_path_not_issued(self) -> None: def test_mssql_dsn_schema_sets_translate_map(self) -> None: """schema_translate_map is set even for an MS-SQL DSN (engine creation, no connect).""" - from datafaker.utils import create_db_engine, get_sync_engine # create_engine with mssql+pyodbc does not connect at construction time, # so this is safe to run even without an ODBC driver installed. @@ -211,7 +207,6 @@ class TestGetMetadataSchema(unittest.TestCase): def test_reflect_called_with_schema(self) -> None: """get_metadata passes schema_name to MetaData.reflect.""" - from datafaker.utils import get_metadata mock_engine = MagicMock() mock_engine.connect.return_value.__enter__ = MagicMock(return_value=MagicMock()) @@ -228,7 +223,6 @@ def test_reflect_called_with_schema(self) -> None: def test_reflect_called_without_schema_when_none(self) -> None: """get_metadata passes schema=None to reflect when no schema_name is given.""" - from datafaker.utils import get_metadata mock_engine = MagicMock() From 476fb42374e5e4663d958459d37f03e049b48efa Mon Sep 17 00:00:00 2001 From: May Yong Date: Wed, 1 Jul 2026 12:36:21 +0100 Subject: [PATCH 42/45] Fix intermittent TCP reset errors in MSSQL tests Three changes to address pyodbc OperationalError 08S01 (TCP reset) that appeared intermittently during test setUp against a Docker SQL Server: - TestMSSQL.create_empty now polls until a connection to the new database succeeds before returning, preventing callers from racing SQL Server's database initialisation. - make_tables_file accepts an optional engine parameter so callers can reuse an existing connection rather than always creating a new one. - MSSQLFunctionalTestCase.setUp passes self.sync_engine to make_tables_file, eliminating the third rapid-fire engine creation to the same SQL Server. - create_db_engine defaults pool_pre_ping=True to discard stale pooled connections before use. Co-Authored-By: Claude Sonnet 4.6 --- datafaker/db_utils.py | 1 + datafaker/make.py | 4 +++- tests/test_functional_mssql.py | 2 +- tests/utils.py | 18 +++++++++++++++++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/datafaker/db_utils.py b/datafaker/db_utils.py index c0e0374..c925eb8 100644 --- a/datafaker/db_utils.py +++ b/datafaker/db_utils.py @@ -140,6 +140,7 @@ def create_db_engine( **kwargs: Any, ) -> MaybeAsyncEngine: """Create a SQLAlchemy Engine.""" + kwargs.setdefault("pool_pre_ping", True) try: if use_asyncio: engine: MaybeAsyncEngine = create_async_engine(make_async_dsn(db_dsn), **kwargs) diff --git a/datafaker/make.py b/datafaker/make.py index 476eef3..5d2dd90 100644 --- a/datafaker/make.py +++ b/datafaker/make.py @@ -723,9 +723,11 @@ def make_tables_file( db_dsn: str, schema_name: Optional[str], parquet_dir: Optional[Path] = None, + engine: Optional[Engine] = None, ) -> str: """Construct the YAML file representing the schema.""" - engine = get_sync_engine(create_db_engine(db_dsn, schema_name=schema_name)) + if engine is None: + engine = get_sync_engine(create_db_engine(db_dsn, schema_name=schema_name)) metadata = get_metadata(engine) meta_dict = metadata_to_dict(metadata, schema_name, engine, parquet_dir) diff --git a/tests/test_functional_mssql.py b/tests/test_functional_mssql.py index 1540808..ce92847 100644 --- a/tests/test_functional_mssql.py +++ b/tests/test_functional_mssql.py @@ -191,7 +191,7 @@ def setUp(self) -> None: # Write orm.yaml so generate_data() has the file it expects. (self.orm_fd, self.orm_file_path) = mkstemp(".yaml", "orm_", text=True) with os.fdopen(self.orm_fd, "w", encoding="utf-8") as fh: - fh.write(make_tables_file(src_dsn, self.schema_name)) + fh.write(make_tables_file(src_dsn, self.schema_name, engine=self.sync_engine)) # Initialise stats/config path attributes expected by generate_data(). self.stats_fd = 0 diff --git a/tests/utils.py b/tests/utils.py index b7f13eb..ba5c1b7 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -322,7 +322,23 @@ def create_empty(self, name: str) -> str: f"DROP DATABASE [{name}]" ) conn.execute(f"CREATE DATABASE [{name}]") - return self.get_dsn(name) + + # SQL Server can take a moment to bring the new database fully online. + # Poll until a connection succeeds rather than returning a DSN that + # immediately produces TCP resets. + dsn = self.get_dsn(name) + db_conn_str = conn_str.replace("DATABASE=master;", f"DATABASE={name};") + deadline = time.monotonic() + 30 + while True: + try: + with pyodbc.connect(db_conn_str, autocommit=True, timeout=5) as probe: + probe.execute("SELECT 1") + break + except pyodbc.Error: + if time.monotonic() > deadline: + raise + time.sleep(0.5) + return dsn def run_sql(self, sql_file: Path) -> None: """Execute a T-SQL file via pyodbc, splitting batches on GO.""" From f7ff56461ba413763c8f0241d03ddda651126e13 Mon Sep 17 00:00:00 2001 From: May Yong Date: Wed, 1 Jul 2026 13:52:00 +0100 Subject: [PATCH 43/45] Dispose engines before closing database in RequiresDBTestCase.tearDown SQLAlchemy connection pools held open connections when Postgres received SIGINT, forcing a checkpoint that intermittently exceeded the shutdown timeout. Disposing sync_engine and dst_engine first lets Postgres shut down cleanly. Co-Authored-By: Claude Sonnet 4.6 --- tests/utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/utils.py b/tests/utils.py index ba5c1b7..d937ded 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -562,6 +562,10 @@ def make_destination_database(self, name: str) -> None: def tearDown(self) -> None: assert self.database is not None + if hasattr(self, "sync_engine"): + self.sync_engine.dispose() + if self.dst_engine is not None: + self.dst_engine.dispose() self.database.close() if self.dst_database is not None: self.dst_database.close() From 7150945166a6bd9a359410100d2e9ada47388fb5 Mon Sep 17 00:00:00 2001 From: May Yong Date: Wed, 1 Jul 2026 14:20:32 +0100 Subject: [PATCH 44/45] Removed non-existing file --- tests/examples/does-not-exist.yaml | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 tests/examples/does-not-exist.yaml diff --git a/tests/examples/does-not-exist.yaml b/tests/examples/does-not-exist.yaml deleted file mode 100644 index d891803..0000000 --- a/tests/examples/does-not-exist.yaml +++ /dev/null @@ -1,3 +0,0 @@ -dsn: postgresql://postgres@localhost:5432/omop5.4 -schema: myschema -tables: {} From 178a39413fe5738735ed659d4567bf030b1058ba Mon Sep 17 00:00:00 2001 From: May Yong Date: Wed, 1 Jul 2026 14:39:59 +0100 Subject: [PATCH 45/45] Fix test_float: use assertIsInstance after FLOAT changed to numeric_type simple(sqltypes.FLOAT) returned the class; numeric_type returns an instance even for bare FLOAT, so assertIs was the wrong assertion. Co-Authored-By: Claude Sonnet 4.6 --- tests/test_serialize_metadata_mssql.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_serialize_metadata_mssql.py b/tests/test_serialize_metadata_mssql.py index 224cc44..69e3268 100644 --- a/tests/test_serialize_metadata_mssql.py +++ b/tests/test_serialize_metadata_mssql.py @@ -132,7 +132,7 @@ def test_boolean(self) -> None: self.assertIs(parse("BOOLEAN"), sqltypes.BOOLEAN) def test_float(self) -> None: - self.assertIs(parse("FLOAT"), sqltypes.FLOAT) + self.assertIsInstance(parse("FLOAT"), sqltypes.FLOAT) def test_double_precision(self) -> None: self.assertIs(parse("DOUBLE PRECISION"), sqltypes.DOUBLE_PRECISION)