{"id":35560691,"url":"https://github.com/hizzle-co/datastore","last_synced_at":"2026-03-06T07:07:40.293Z","repository":{"id":39482787,"uuid":"492851239","full_name":"hizzle-co/datastore","owner":"hizzle-co","description":null,"archived":false,"fork":false,"pushed_at":"2026-02-23T10:57:36.000Z","size":318,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-23T19:37:38.789Z","etag":null,"topics":["database","datastore","wordpress"],"latest_commit_sha":null,"homepage":"https://hizzle-co.github.io/datastore/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hizzle-co.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-05-16T13:38:23.000Z","updated_at":"2026-02-23T10:51:50.000Z","dependencies_parsed_at":"2024-03-29T04:25:21.969Z","dependency_job_id":"1f2e80ad-b7b2-46de-ab3a-51b661138818","html_url":"https://github.com/hizzle-co/datastore","commit_stats":{"total_commits":40,"total_committers":2,"mean_commits":20.0,"dds":"0.025000000000000022","last_synced_commit":"4ad1d628348e1f09f9aafa89cd11280db07bf674"},"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"purl":"pkg:github/hizzle-co/datastore","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hizzle-co%2Fdatastore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hizzle-co%2Fdatastore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hizzle-co%2Fdatastore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hizzle-co%2Fdatastore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hizzle-co","download_url":"https://codeload.github.com/hizzle-co/datastore/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hizzle-co%2Fdatastore/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30164955,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T04:43:31.446Z","status":"ssl_error","status_checked_at":"2026-03-06T04:40:30.133Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","datastore","wordpress"],"created_at":"2026-01-04T11:15:19.950Z","updated_at":"2026-03-06T07:07:40.269Z","avatar_url":"https://github.com/hizzle-co.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# datastore\n\nThis is currently in Beta so expect the API to change alot.\n\n## Installation\n\nInstall via Composer:\n\n```bash\ncomposer require hizzle/store\n```\n\n## Features\n\n- **CRUD Operations**: Create, read, update, and delete records\n- **Query Builder**: Powerful query builder with filtering, sorting, and pagination\n- **Aggregate Functions**: Support for SUM, AVG, COUNT, MIN, MAX with grouping\n- **JOIN Queries**: Relate collections together for complex data analysis\n- **REST API**: Automatic REST API endpoints for all collections\n- **Meta Fields**: Support for custom meta fields with multiple values\n- **Custom Post Types**: Integrate with WordPress custom post types\n\n## Quick Start\n\n### Recommended: Using Main Class\n\nThe `Main` class provides a simplified API for interacting with your store:\n\n```php\nuse Hizzle\\Store\\Main;\n\n// Get or create store instance\n$db = Main::instance('my_store');\n\n// Initialize store with collections\n$db-\u003einit_store(\n    array(\n        'orders' =\u003e array(\n            'object'        =\u003e 'Order',\n            'singular_name' =\u003e 'order',\n            'props'         =\u003e array(\n                'id'          =\u003e array(\n                    'type'        =\u003e 'BIGINT',\n                    'length'      =\u003e 20,\n                    'nullable'    =\u003e false,\n                    'extra'       =\u003e 'AUTO_INCREMENT',\n                    'description' =\u003e 'Order ID',\n                ),\n                'customer_id' =\u003e array(\n                    'type'        =\u003e 'BIGINT',\n                    'length'      =\u003e 20,\n                    'nullable'    =\u003e false,\n                    'description' =\u003e 'Customer ID',\n                ),\n                'total'       =\u003e array(\n                    'type'        =\u003e 'DECIMAL',\n                    'length'      =\u003e '10,2',\n                    'nullable'    =\u003e false,\n                    'description' =\u003e 'Order total',\n                ),\n                'status'      =\u003e array(\n                    'type'        =\u003e 'VARCHAR',\n                    'length'      =\u003e 20,\n                    'default'     =\u003e 'pending',\n                    'description' =\u003e 'Order status',\n                ),\n            ),\n            'keys'          =\u003e array(\n                'primary'     =\u003e array( 'id' ),\n                'customer_id' =\u003e array( 'customer_id' ),\n                'status'      =\u003e array( 'status' ),\n            ),\n            'labels'        =\u003e array(\n                'name'          =\u003e __( 'Orders', 'textdomain' ),\n                'singular_name' =\u003e __( 'Order', 'textdomain' ),\n            ),\n        ),\n    )\n);\n\n// Work with records\n$order = $db-\u003eget('orders', 123);\n$orders = $db-\u003equery('orders', array('status' =\u003e 'completed'));\n```\n\n### Alternative: Using Store Class Directly\n\n```php\nuse Hizzle\\Store\\Store;\n\n// Initialize a store\n$store = new Store(\n    'my_store',\n    array(\n        'payments' =\u003e array(\n            // This object must extend Hizzle\\Store\\Record\n            'object'        =\u003e 'Payment',\n            'singular_name' =\u003e 'payment',\n            'props'         =\u003e array(\n                'id'                  =\u003e array(\n                    'type'        =\u003e 'BIGINT',\n                    'length'      =\u003e 20,\n                    'nullable'    =\u003e false,\n                    'extra'       =\u003e 'AUTO_INCREMENT',\n                    'description' =\u003e 'Payment ID',\n                ),\n                'customer_id'       =\u003e array(\n                    'type'        =\u003e 'BIGINT',\n                    'length'      =\u003e 20,\n                    'nullable'    =\u003e false,\n                    'description' =\u003e 'Customer ID',\n                ),\n                /* ... */\n            ),\n            'joins'         =\u003e array(\n                'customers' =\u003e array(\n                    'collection' =\u003e 'my_store_customers',\n                    'on'         =\u003e 'customer_id',\n                    'type'       =\u003e 'LEFT',\n                ),\n                'plans'     =\u003e array(\n                    'collection' =\u003e 'my_store_plans',\n                    'on'         =\u003e 'plan_id',\n                    'type'       =\u003e 'LEFT',\n                ),\n                'products'  =\u003e array(\n                    'collection' =\u003e 'my_store_products',\n                    // We are assuming that the above payments schema has\n                    // No 'plan_id' property, so we join via plans table\n                    // Which is already joined above\n                    'on'         =\u003e 'plans.product_id',\n                    'type'       =\u003e 'LEFT',\n                ),\n            ),\n            'keys'          =\u003e array(\n                'primary'             =\u003e array( 'id' ),\n                'customer_id'         =\u003e array( 'customer_id' ),\n                'subscription_id'     =\u003e array( 'subscription_id' ),\n                'status'              =\u003e array( 'status' ),\n                'date_created_status' =\u003e array( 'date_created', 'status' ),\n                'unique'              =\u003e array( 'uuid', 'transaction_id' ),\n            ),\n            'labels'        =\u003e array(\n                'name'          =\u003e __( 'Payments', 'textdomain' ),\n                'singular_name' =\u003e __( 'Payment', 'textdomain' ),\n                'add_new'       =\u003e __( 'Add New', 'textdomain' ),\n                'add_new_item'  =\u003e __( 'Add New Payment', 'textdomain' ),\n                'edit_item'     =\u003e __( 'Overview', 'textdomain' ),\n                'new_item'      =\u003e __( 'Add Payment', 'textdomain' ),\n                'view_item'     =\u003e __( 'View Payment', 'textdomain' ),\n                'view_items'    =\u003e __( 'View Payments', 'textdomain' ),\n                'search_items'  =\u003e __( 'Search payments', 'textdomain' ),\n                'not_found'     =\u003e __( 'No payments found.', 'textdomain' ),\n                'import'        =\u003e __( 'Import Payments', 'textdomain' ),\n            ),\n        ),\n        'customers' =\u003e array( /* ... */ ),\n        /** Other collections **/\n    )\n);\n```\n\n### Working with Records\n\n#### Create Records\n\n```php\n// Using Main class (recommended)\n$db = Main::instance('my_store');\n\n// Get the collection first\n$collection = Store::instance('my_store')-\u003eget('payments');\n\n// Create a new payment\n$payment = $collection-\u003ecreate(array(\n    'customer_id' =\u003e 123,\n    'amount' =\u003e 99.99,\n    'status' =\u003e 'completed',\n));\n\n// Get the payment ID\n$payment_id = $payment-\u003eget_id();\n```\n\n#### Read Records\n\n```php\n// Using Main class (recommended)\n$db = Main::instance('my_store');\n\n// Get a single record by ID\n$payment = $db-\u003eget('payments', $payment_id);\n\nif ($payment \u0026\u0026 !is_wp_error($payment)) {\n    echo $payment-\u003eget('amount'); // 99.99\n    echo $payment-\u003eget('status'); // completed\n}\n\n// Get ID by a specific property\n$payment_id = $db-\u003eget_id_by_prop('transaction_id', 'txn_abc123', 'payments');\n\n// Using Collection directly\n// Throws \\Hizzle\\Store\\Store_Exception on failure\n$collection = Store::instance('my_store')-\u003eget('payments');\n$payment = $collection-\u003eget($payment_id);\n\n// Check if a record exists\nif ($collection-\u003eexists($payment_id)) {\n    // Record exists\n}\n```\n\n#### Update Records\n\n```php\n// Get the record using Main class\n$db = Main::instance('my_store');\n$payment = $db-\u003eget('payments', $payment_id);\n\nif ($payment \u0026\u0026 !is_wp_error($payment)) {\n    $payment-\u003eset('status', 'refunded');\n    $payment-\u003eset('refund_date', current_time('mysql'));\n    $payment-\u003esave();\n}\n\n// Or update via collection\n// Throws \\Hizzle\\Store\\Store_Exception on failure\n$collection = Store::instance('my_store')-\u003eget('payments');\n$collection-\u003eupdate($payment_id, array(\n    'status' =\u003e 'refunded',\n    'refund_date' =\u003e current_time('mysql'),\n));\n```\n\n#### Delete Records\n\n```php\n// Using Main class (recommended)\n$db = Main::instance('my_store');\n\n// Delete records matching criteria\n$deleted = $db-\u003edelete_where(\n    array(\n        'status' =\u003e 'pending',\n        'customer_id' =\u003e 123,\n    ),\n    'payments'\n);\n\n// Delete all records (use with caution!)\n$db-\u003edelete_all('payments');\n\n// Or delete via record object\n$payment = $db-\u003eget('payments', $payment_id);\nif ($payment \u0026\u0026 !is_wp_error($payment)) {\n    $payment-\u003edelete();\n}\n```\n\n### Querying Records\n\n```php\n// Using Main class (recommended)\n$db = Main::instance('my_store');\n\n// Basic query - returns results\n$payments = $db-\u003equery('payments', array(\n    'status' =\u003e 'completed',\n    'customer_id' =\u003e 123,\n    'per_page' =\u003e 10,\n    'page' =\u003e 1,\n));\n\n// Count records\n$count = $db-\u003equery('payments', array(\n    'status' =\u003e 'completed',\n), 'count');\n\n// Aggregate query\n$results = $db-\u003equery('payments', array(\n    'aggregate' =\u003e array(\n        'amount' =\u003e array('SUM', 'AVG', 'COUNT'),\n    ),\n    'groupby' =\u003e 'status',\n), 'aggregate');\n\n// Get Query object for more control\n$query = $db-\u003equery('payments', array(\n    'status' =\u003e 'completed',\n), 'query');\n\n$payments = $query-\u003eget_results();\n$total = $query-\u003eget_total();\n\n// Using Collection directly\n$collection = Store::instance('my_store')-\u003eget('payments');\n$query = $collection-\u003equery(array(\n    'status' =\u003e 'completed',\n    'customer_id' =\u003e 123,\n    'per_page' =\u003e 10,\n    'page' =\u003e 1,\n));\n\n$payments = $query-\u003eget_results();\n$total = $query-\u003eget_total();\n\n// Complex query with date filters\n$payments = $db-\u003equery('payments', array(\n    'status' =\u003e array('completed', 'pending'),\n    'amount_min' =\u003e 50,\n    'date_created_after' =\u003e '2026-01-01',\n    'orderby' =\u003e 'date_created',\n    'order' =\u003e 'DESC',\n));\n```\n\n### Working with Metadata\n\n```php\n// Using Main class (recommended)\n$db = Main::instance('my_store');\n\n// Add meta data\n$db-\u003eadd_record_meta($payment_id, 'gateway', 'stripe', false, 'payments');\n\n// Get meta data\n$gateway = $db-\u003eget_record_meta($payment_id, 'gateway', true, 'payments');\n\n// Update meta data\n$db-\u003eupdate_record_meta($payment_id, 'gateway', 'paypal', '', 'payments');\n\n// Delete meta data\n$db-\u003edelete_record_meta($payment_id, 'gateway', '', 'payments');\n\n// Delete all metadata for a record\n$db-\u003edelete_all_record_meta($payment_id, 'payments');\n\n// Delete all metadata by key across all records\n$db-\u003edelete_all_meta_by_key('old_field', 'payments');\n\n// Check if meta exists\nif ($db-\u003erecord_meta_exists($payment_id, 'gateway', 'payments')) {\n    // Meta exists\n}\n\n// Using Collection directly\n$collection = Store::instance('my_store')-\u003eget('payments');\n$collection-\u003eadd_record_meta($payment_id, 'gateway', 'stripe');\n$gateway = $collection-\u003eget_record_meta($payment_id, 'gateway', true);\n$collection-\u003eupdate_record_meta($payment_id, 'gateway', 'paypal');\n$collection-\u003edelete_record_meta($payment_id, 'gateway');\n```\n\n### Error Handling\n\n```php\nuse Hizzle\\Store\\Main;\n\n// Main class automatically converts exceptions to WP_Error\n$db = Main::instance('my_store');\n$payment = $db-\u003eget('payments', $payment_id);\n\nif (is_wp_error($payment)) {\n    error_log($payment-\u003eget_error_message());\n} else {\n    // Work with the payment\n    echo $payment-\u003eget('amount');\n}\n\n// When using Store/Collection directly, use try/catch\ntry {\n    $collection = Store::instance('my_store')-\u003eget('payments');\n    $payment = $collection-\u003eget($payment_id);\n    \n    // Do something with the payment\n    \n} catch (\\Hizzle\\Store\\Store_Exception $e) {\n    error_log($e-\u003egetMessage());\n    \n    // Or convert to WP_Error\n    $error = new WP_Error(\n        $e-\u003egetErrorCode(),\n        $e-\u003egetMessage(),\n        $e-\u003egetErrorData()\n    );\n}\n```\n\n### JOIN Queries\n\nDefine relationships between collections:\n\n```php\n'customers' =\u003e array(\n    'status' =\u003e 'complete',\n    // ... other config\n    'joins' =\u003e array(\n        'payments' =\u003e array(\n            'collection' =\u003e 'my_store_payments',\n            'on' =\u003e 'id',\n            'foreign_key' =\u003e 'customer_id',\n            'type' =\u003e 'LEFT',\n        ),\n    ),\n)\n```\n\nUse JOINs in aggregate queries:\n\n```php\n$query = $collection-\u003equery(array(\n    'join' =\u003e array('payments'),\n    'aggregate' =\u003e array(\n        'payments.amount' =\u003e array('SUM', 'COUNT'),\n    ),\n    'groupby' =\u003e 'id',\n));\n```\n\n## Documentation\n\n### API Reference\n\nComplete documentation for all components is available in the [docs](docs/) folder:\n\n- **Core Classes**\n  - [Store](docs/store.md) - Main store management\n  - [Collection](docs/collection.md) - Collection CRUD operations\n  - [Record](docs/record.md) - Individual record operations\n  - [Query](docs/query.md) - Query builder and filtering\n\n- **Supporting Classes**\n  - [Prop](docs/prop.md) - Property definitions\n  - [REST_Controller](docs/rest-controller.md) - REST API endpoints\n  - [List_Table](docs/list-table.md) - WordPress admin tables\n  - [Webhooks](docs/webhooks.md) - Event-driven webhooks\n\n- **Utilities**\n  - [Date_Time](docs/date-time.md) - Date/time handling\n  - [Store_Exception](docs/store-exception.md) - Exception handling\n\n### Guides\n\n- [JOIN Queries Guide](docs/joins.md) - Comprehensive guide to using JOINs\n- [Example Code](example-joins.php) - Working examples with JOINs\n\n## Requirements\n\n- PHP \u003e= 5.3.0\n- WordPress \u003e= 4.7.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhizzle-co%2Fdatastore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhizzle-co%2Fdatastore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhizzle-co%2Fdatastore/lists"}