Coverage for mindsdb / integrations / handlers / shopify_handler / shopify_tables.py: 0%

218 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-21 00:36 +0000

1import json 

2from typing import List, Dict 

3 

4import shopify 

5import pandas as pd 

6 

7from mindsdb.integrations.libs.api_handler import MetaAPIResource 

8from mindsdb.integrations.utilities.sql_utils import FilterCondition, FilterOperator, SortColumn 

9from mindsdb.utilities import log 

10 

11from .utils import query_graphql_nodes, get_graphql_columns, _format_error 

12from .models.products import Products, columns as products_columns 

13from .models.product_variants import ProductVariants, columns as product_variants_columns 

14from .models.customers import Customers, columns as customers_columns 

15from .models.orders import Orders, columns as orders_columns 

16from .models.marketing_events import MarketingEvents, columns as marketing_events_columns 

17from .models.inventory_items import InventoryItems, columns as inventory_items_columns 

18from .models.staff_members import StaffMembers, columns as staff_members_columns 

19from .models.gift_cards import GiftCards, columns as gift_cards_columns 

20 

21logger = log.getLogger(__name__) 

22 

23 

24class ShopifyMetaAPIResource(MetaAPIResource): 

25 """A class to represent a Shopify Meta API resource.""" 

26 

27 def list( 

28 self, 

29 conditions: list[FilterCondition] | None = None, 

30 limit: int | None = None, 

31 sort: list[SortColumn] | None = None, 

32 targets: list[str] | None = None, 

33 **kwargs, 

34 ): 

35 """Query the Shopify API to get the resources data. 

36 

37 Args: 

38 conditions: The conditions to apply to the query. 

39 limit: The limit of the resources to return. 

40 sort: The sort to apply to the query. 

41 targets: The columns to include in the query. 

42 

43 Returns: 

44 pd.DataFrame: The data of the resources. 

45 """ 

46 sort_key, sort_reverse = self._get_sort(sort) 

47 query_conditions = self._get_query_conditions(conditions) 

48 

49 api_session = self.handler.connect() 

50 shopify.ShopifyResource.activate_session(api_session) 

51 

52 columns = get_graphql_columns(self.model, targets) 

53 data = query_graphql_nodes( 

54 self.model_name, 

55 self.model, 

56 columns, 

57 sort_key=sort_key, 

58 sort_reverse=sort_reverse, 

59 query=query_conditions, 

60 limit=limit, 

61 ) 

62 

63 if len(data) == 0: 

64 df_columns = targets 

65 if targets is None or len(targets) == 0: 

66 df_columns = [column.name for column in self.model] 

67 products_df = pd.DataFrame(data, columns=df_columns) 

68 else: 

69 products_df = pd.DataFrame(data) 

70 

71 return products_df 

72 

73 def _get_sort(self, sort: List[SortColumn] | None) -> tuple[str, bool]: 

74 """Get the sort key and reverse from the sort list. 

75 

76 Args: 

77 sort: The sort list. 

78 

79 Returns: 

80 tuple[str, bool]: The sort key and reverse flag. 

81 """ 

82 sort_key = None 

83 sort_reverse = None 

84 sort_map = self.sort_map or {} 

85 if sort: 

86 order_by = sort[0].column.lower() 

87 asc = sort[0].ascending 

88 if order_by not in sort_map: 

89 logger.info( 

90 f"Used unsupported column for order by: {order_by}, available columns are: {list(self.sort_map.keys())}." 

91 ) 

92 return None, None 

93 

94 sort_key = sort_map[order_by] 

95 sort_reverse = not asc 

96 sort[0].applied = True 

97 return sort_key, sort_reverse 

98 

99 def _get_query_conditions(self, conditions: List[FilterCondition] | None) -> str: 

100 """Get the GraphQL query conditions from the conditions list. 

101 

102 Args: 

103 conditions: The conditions list. 

104 

105 Returns: 

106 str: The query conditions. 

107 """ 

108 query_conditions = [] 

109 conditions_op_map = self.conditions_op_map or {} 

110 for condition in conditions or []: 

111 op = condition.op 

112 column = condition.column.lower() 

113 mapped_op = conditions_op_map.get((column, op)) 

114 if mapped_op: 

115 value = condition.value 

116 if isinstance(value, list): 

117 value = ",".join(value) 

118 elif isinstance(value, bool): 

119 value = f"{value}".lower() 

120 query_conditions.append(f"{mapped_op}{value}") 

121 condition.applied = True 

122 query_conditions = " AND ".join(query_conditions) 

123 return query_conditions 

124 

125 def get_columns(self) -> List[str]: 

126 """Get the table columns names. 

127 

128 Returns: 

129 List[str]: The columns names. 

130 """ 

131 return [column["COLUMN_NAME"] for column in self.columns] 

132 

133 def meta_get_columns(self, *args, **kwargs) -> List[dict]: 

134 """Get the table columns metadata. 

135 

136 Returns: 

137 List[dict]: The columns metadata. 

138 """ 

139 return self.columns 

140 

141 def query_graphql(self, query: str) -> dict: 

142 """Query the GraphQL API. 

143 

144 Args: 

145 query: The GraphQL query to execute. 

146 

147 Returns: 

148 dict: The result of the GraphQL query. 

149 """ 

150 api_session = self.handler.connect() 

151 shopify.ShopifyResource.activate_session(api_session) 

152 result = shopify.GraphQL().execute(query) 

153 result = json.loads(result) 

154 if "errors" in result: 

155 raise Exception(_format_error(result["errors"])) 

156 return result 

157 

158 

159class ProductsTable(ShopifyMetaAPIResource): 

160 """The Shopify Products Table implementation 

161 Reference: https://shopify.dev/docs/api/admin-graphql/latest/queries/products 

162 """ 

163 

164 def __init__(self, *args, **kwargs): 

165 self.name = "products" 

166 self.model = Products 

167 self.model_name = "products" 

168 self.columns = products_columns 

169 

170 sort_map = { 

171 Products.createdAt: "CREATED_AT", 

172 Products.id: "ID", 

173 Products.totalInventory: "INVENTORY_TOTAL", 

174 Products.productType: "PRODUCT_TYPE", 

175 Products.publishedAt: "PUBLISHED_AT", 

176 Products.title: "TITLE", 

177 Products.updatedAt: "UPDATED_AT", 

178 Products.vendor: "VENDOR", 

179 } 

180 self.sort_map = {key.name.lower(): value for key, value in sort_map.items()} 

181 

182 self.conditions_op_map = { 

183 ("createdat", FilterOperator.GREATER_THAN): "created_at:>", 

184 ("createdat", FilterOperator.GREATER_THAN_OR_EQUAL): "created_at:>=", 

185 ("createdat", FilterOperator.LESS_THAN): "created_at:<", 

186 ("createdat", FilterOperator.LESS_THAN_OR_EQUAL): "created_at:<=", 

187 ("createdat", FilterOperator.EQUAL): "created_at:", 

188 ("id", FilterOperator.GREATER_THAN): "id:>", 

189 ("id", FilterOperator.GREATER_THAN_OR_EQUAL): "id:>=", 

190 ("id", FilterOperator.LESS_THAN): "id:<", 

191 ("id", FilterOperator.LESS_THAN_OR_EQUAL): "id:<=", 

192 ("id", FilterOperator.EQUAL): "id:", 

193 ("isgiftcard", FilterOperator.EQUAL): "gift_card:", 

194 ("handle", FilterOperator.EQUAL): "handle:", 

195 ("handle", FilterOperator.IN): "handle:", 

196 ("totalinventory", FilterOperator.EQUAL): "inventory_total:", 

197 ("producttype", FilterOperator.EQUAL): "product_type:", 

198 ("producttype", FilterOperator.IN): "product_type:", 

199 ("publishedat", FilterOperator.GREATER_THAN): "published_at:>", 

200 ("publishedat", FilterOperator.GREATER_THAN_OR_EQUAL): "published_at:>=", 

201 ("publishedat", FilterOperator.LESS_THAN): "published_at:<", 

202 ("publishedat", FilterOperator.LESS_THAN_OR_EQUAL): "published_at:<=", 

203 ("publishedat", FilterOperator.EQUAL): "published_at:", 

204 ("status", FilterOperator.EQUAL): "status:", 

205 ("status", FilterOperator.IN): "status:", 

206 ("title", FilterOperator.EQUAL): "title:", 

207 ("updatedat", FilterOperator.GREATER_THAN): "updated_at:>", 

208 ("updatedat", FilterOperator.GREATER_THAN_OR_EQUAL): "updated_at:>=", 

209 ("updatedat", FilterOperator.LESS_THAN): "updated_at:<", 

210 ("updatedat", FilterOperator.LESS_THAN_OR_EQUAL): "updated_at:<=", 

211 ("updatedat", FilterOperator.EQUAL): "updated_at:", 

212 ("vendor", FilterOperator.EQUAL): "vendor:", 

213 } 

214 super().__init__(*args, **kwargs) 

215 

216 def meta_get_tables(self, *args, **kwargs) -> dict: 

217 response = self.query_graphql("""{ 

218 productsCount(limit:null) { 

219 count 

220 } }""") 

221 row_count = response["data"]["productsCount"]["count"] 

222 

223 return { 

224 "table_name": self.name, 

225 "table_type": "BASE TABLE", 

226 "table_description": "List of products. Products are the items that merchants can sell in their store.", 

227 "row_count": row_count, 

228 } 

229 

230 def meta_get_primary_keys(self, table_name: str) -> list[Dict]: 

231 return [ 

232 { 

233 "table_name": table_name, 

234 "column_name": "id", 

235 } 

236 ] 

237 

238 def meta_get_foreign_keys(self, table_name: str, all_tables: list[str]) -> list[Dict]: 

239 return [] 

240 

241 

242class ProductVariantsTable(ShopifyMetaAPIResource): 

243 """The Shopify Product Variants Table implementation 

244 Reference: https://shopify.dev/docs/api/admin-graphql/latest/queries/productvariants 

245 """ 

246 

247 def __init__(self, *args, **kwargs): 

248 self.name = "product_variants" 

249 self.model = ProductVariants 

250 self.model_name = "productVariants" 

251 self.columns = product_variants_columns 

252 

253 sort_map = { 

254 ProductVariants.id: "ID", 

255 ProductVariants.inventoryQuantity: "INVENTORY_QUANTITY", 

256 ProductVariants.displayName: "NAME", 

257 ProductVariants.position: "POSITION", 

258 ProductVariants.sku: "SKU", 

259 ProductVariants.title: "TITLE", 

260 } 

261 self.sort_map = {key.name.lower(): value for key, value in sort_map.items()} 

262 

263 self.conditions_op_map = { 

264 ("barcode", FilterOperator.EQUAL): "barcode:", 

265 ("id", FilterOperator.GREATER_THAN): "id:>", 

266 ("id", FilterOperator.GREATER_THAN_OR_EQUAL): "id:>=", 

267 ("id", FilterOperator.LESS_THAN): "id:<", 

268 ("id", FilterOperator.LESS_THAN_OR_EQUAL): "id:<=", 

269 ("id", FilterOperator.EQUAL): "id:", 

270 ("inventoryquantity", FilterOperator.GREATER_THAN): "inventoryquantity:>", 

271 ("inventoryquantity", FilterOperator.GREATER_THAN_OR_EQUAL): "inventoryquantity:>=", 

272 ("inventoryquantity", FilterOperator.LESS_THAN): "inventoryquantity:<", 

273 ("inventoryquantity", FilterOperator.LESS_THAN_OR_EQUAL): "inventoryquantity:<=", 

274 ("inventoryquantity", FilterOperator.EQUAL): "inventoryquantity:", 

275 ("productid", FilterOperator.GREATER_THAN): "product_id:>", 

276 ("productid", FilterOperator.GREATER_THAN_OR_EQUAL): "product_id:>=", 

277 ("productid", FilterOperator.LESS_THAN): "product_id:<", 

278 ("productid", FilterOperator.LESS_THAN_OR_EQUAL): "product_id:<=", 

279 ("productid", FilterOperator.EQUAL): "product_id:", 

280 ("productid", FilterOperator.IN): "toproduct_ids:", 

281 ("sku", FilterOperator.EQUAL): "sku:", 

282 ("title", FilterOperator.EQUAL): "title:", 

283 ("updatedat", FilterOperator.GREATER_THAN): "updated_at:>", 

284 ("updatedat", FilterOperator.GREATER_THAN_OR_EQUAL): "updated_at:>=", 

285 ("updatedat", FilterOperator.LESS_THAN): "updated_at:<", 

286 ("updatedat", FilterOperator.LESS_THAN_OR_EQUAL): "updated_at:<=", 

287 ("updatedat", FilterOperator.EQUAL): "updated_at:", 

288 } 

289 super().__init__(*args, **kwargs) 

290 

291 def meta_get_tables(self, *args, **kwargs) -> dict: 

292 response = self.query_graphql("""{ 

293 productVariantsCount(limit:null) { 

294 count 

295 } }""") 

296 row_count = response["data"]["productVariantsCount"]["count"] 

297 

298 return { 

299 "table_name": self.name, 

300 "table_type": "BASE TABLE", 

301 "table_description": "List of product variants. A product variant is a specific version of a product that comes in more than one option, such as size or color.", 

302 "row_count": row_count, 

303 } 

304 

305 def meta_get_primary_keys(self, table_name: str) -> list[Dict]: 

306 return [ 

307 { 

308 "table_name": table_name, 

309 "column_name": "id", 

310 } 

311 ] 

312 

313 def meta_get_foreign_keys(self, table_name: str, all_tables: list[str]) -> list[Dict]: 

314 return [ 

315 { 

316 "PARENT_TABLE_NAME": table_name, 

317 "PARENT_COLUMN_NAME": "productId", 

318 "CHILD_TABLE_NAME": "products", 

319 "CHILD_COLUMN_NAME": "id", 

320 } 

321 ] 

322 

323 

324class CustomersTable(ShopifyMetaAPIResource): 

325 """The Shopify Customers Table implementation 

326 Reference: https://shopify.dev/docs/api/admin-graphql/latest/queries/customers 

327 """ 

328 

329 def __init__(self, *args, **kwargs): 

330 self.name = "customers" 

331 self.model = Customers 

332 self.model_name = "customers" 

333 self.columns = customers_columns 

334 

335 sort_map = { 

336 Customers.createdAt: "CREATED_AT", 

337 Customers.id: "ID", 

338 Customers.updatedAt: "UPDATED_AT", 

339 } 

340 self.sort_map = {key.name.lower(): value for key, value in sort_map.items()} 

341 

342 self.conditions_op_map = { 

343 ("country", FilterOperator.EQUAL): "country:", 

344 ("createdat", FilterOperator.GREATER_THAN): "customer_date:>", 

345 ("createdat", FilterOperator.GREATER_THAN_OR_EQUAL): "customer_date:>=", 

346 ("createdat", FilterOperator.LESS_THAN): "customer_date:<", 

347 ("createdat", FilterOperator.LESS_THAN_OR_EQUAL): "customer_date:<=", 

348 ("createdat", FilterOperator.EQUAL): "customer_date:", 

349 ("email", FilterOperator.EQUAL): "email:", 

350 ("firstname", FilterOperator.EQUAL): "first_name:", 

351 ("id", FilterOperator.GREATER_THAN): "id:>", 

352 ("id", FilterOperator.GREATER_THAN_OR_EQUAL): "id:>=", 

353 ("id", FilterOperator.LESS_THAN): "id:<", 

354 ("id", FilterOperator.LESS_THAN_OR_EQUAL): "id:<=", 

355 ("id", FilterOperator.EQUAL): "id:", 

356 ("lastname", FilterOperator.EQUAL): "last_name:", 

357 ("phonenumber", FilterOperator.EQUAL): "phone:", 

358 ("updatedat", FilterOperator.GREATER_THAN): "updated_at:>", 

359 ("updatedat", FilterOperator.GREATER_THAN_OR_EQUAL): "updated_at:>=", 

360 ("updatedat", FilterOperator.LESS_THAN): "updated_at:<", 

361 ("updatedat", FilterOperator.LESS_THAN_OR_EQUAL): "updated_at:<=", 

362 ("updatedat", FilterOperator.EQUAL): "updated_at:", 

363 } 

364 super().__init__(*args, **kwargs) 

365 

366 def meta_get_tables(self, *args, **kwargs) -> dict: 

367 response = self.query_graphql("""{ 

368 customersCount(limit:null) { 

369 count 

370 } }""") 

371 row_count = response["data"]["customersCount"]["count"] 

372 

373 return { 

374 "table_name": self.name, 

375 "table_type": "BASE TABLE", 

376 "table_description": "List of customers in your Shopify store, including key information such as name, email, location, and purchase history", 

377 "row_count": row_count, 

378 } 

379 

380 def meta_get_primary_keys(self, table_name: str) -> List[Dict]: 

381 return [ 

382 { 

383 "table_name": table_name, 

384 "column_name": "id", 

385 } 

386 ] 

387 

388 def meta_get_foreign_keys(self, table_name: str, all_tables: List[str]) -> List[Dict]: 

389 return [] 

390 

391 

392class OrdersTable(ShopifyMetaAPIResource): 

393 """The Shopify Orders Table implementation 

394 Reference: https://shopify.dev/docs/api/admin-graphql/latest/queries/orders 

395 """ 

396 

397 def __init__(self, *args, **kwargs): 

398 self.name = "orders" 

399 self.model = Orders 

400 self.model_name = "orders" 

401 self.columns = orders_columns 

402 

403 sort_map = { 

404 Orders.createdAt: "CREATED_AT", 

405 Orders.id: "ID", 

406 Orders.number: "ORDER_NUMBER", 

407 Orders.poNumber: "PO_NUMBER", 

408 Orders.processedAt: "PROCESSED_AT", 

409 Orders.updatedAt: "UPDATED_AT", 

410 } 

411 self.sort_map = {key.name.lower(): value for key, value in sort_map.items()} 

412 

413 self.conditions_op_map = { 

414 ("confirmationnumber", FilterOperator.EQUAL): "confirmation_number:", 

415 ("createdat", FilterOperator.GREATER_THAN): "created_at:>", 

416 ("createdat", FilterOperator.GREATER_THAN_OR_EQUAL): "created_at:>=", 

417 ("createdat", FilterOperator.LESS_THAN): "created_at:<", 

418 ("createdat", FilterOperator.LESS_THAN_OR_EQUAL): "created_at:<=", 

419 ("createdat", FilterOperator.EQUAL): "created_at:", 

420 ("customerid", FilterOperator.EQUAL): "customer_id:", 

421 ("discountcode", FilterOperator.EQUAL): "discount_code:", 

422 ("email", FilterOperator.EQUAL): "email:", 

423 ("id", FilterOperator.GREATER_THAN): "id:>", 

424 ("id", FilterOperator.GREATER_THAN_OR_EQUAL): "id:>=", 

425 ("id", FilterOperator.LESS_THAN): "id:<", 

426 ("id", FilterOperator.LESS_THAN_OR_EQUAL): "id:<=", 

427 ("id", FilterOperator.EQUAL): "id:", 

428 ("name", FilterOperator.EQUAL): "name:", 

429 ("ponumber", FilterOperator.EQUAL): "po_number:", 

430 ("processedat", FilterOperator.GREATER_THAN): "processed_at:>", 

431 ("processedat", FilterOperator.GREATER_THAN_OR_EQUAL): "processed_at:>=", 

432 ("processedat", FilterOperator.LESS_THAN): "processed_at:<", 

433 ("processedat", FilterOperator.LESS_THAN_OR_EQUAL): "processed_at:<=", 

434 ("processedat", FilterOperator.EQUAL): "processed_at:", 

435 ("returnstatus", FilterOperator.EQUAL): "return_status:", 

436 ("sourceidentifier", FilterOperator.EQUAL): "source_identifier:", 

437 ("sourcename", FilterOperator.EQUAL): "source_name:", 

438 ("test", FilterOperator.EQUAL): "test:", 

439 ("totalweight", FilterOperator.GREATER_THAN): "total_weight:>", 

440 ("totalweight", FilterOperator.GREATER_THAN_OR_EQUAL): "total_weight:>=", 

441 ("totalweight", FilterOperator.LESS_THAN): "total_weight:<", 

442 ("totalweight", FilterOperator.LESS_THAN_OR_EQUAL): "total_weight:<=", 

443 ("totalweight", FilterOperator.EQUAL): "total_weight:", 

444 ("updatedat", FilterOperator.GREATER_THAN): "updated_at:>", 

445 ("updatedat", FilterOperator.GREATER_THAN_OR_EQUAL): "updated_at:>=", 

446 ("updatedat", FilterOperator.LESS_THAN): "updated_at:<", 

447 ("updatedat", FilterOperator.LESS_THAN_OR_EQUAL): "updated_at:<=", 

448 ("updatedat", FilterOperator.EQUAL): "updated_at:", 

449 } 

450 super().__init__(*args, **kwargs) 

451 

452 def meta_get_tables(self, *args, **kwargs) -> dict: 

453 response = self.query_graphql("""{ 

454 ordersCount(limit:null) { 

455 count 

456 } }""") 

457 row_count = response["data"]["ordersCount"]["count"] 

458 

459 return { 

460 "table_name": self.name, 

461 "table_type": "BASE TABLE", 

462 "table_description": "List of orders placed in the store, including data such as order status, customer, and line item details.", 

463 "row_count": row_count, 

464 } 

465 

466 def meta_get_primary_keys(self, table_name: str) -> List[Dict]: 

467 return [ 

468 { 

469 "table_name": table_name, 

470 "column_name": "id", 

471 } 

472 ] 

473 

474 def meta_get_foreign_keys(self, table_name: str, all_tables: List[str]) -> List[Dict]: 

475 return [ 

476 { 

477 "PARENT_TABLE_NAME": table_name, 

478 "PARENT_COLUMN_NAME": "customerId", 

479 "CHILD_TABLE_NAME": "customers", 

480 "CHILD_COLUMN_NAME": "id", 

481 } 

482 ] 

483 

484 

485class MarketingEventsTable(ShopifyMetaAPIResource): 

486 """The Shopify MarketingEvents table implementation 

487 Reference: https://shopify.dev/docs/api/admin-graphql/latest/queries/marketingevents 

488 """ 

489 

490 def __init__(self, *args, **kwargs): 

491 self.name = "marketing_events" 

492 self.model = MarketingEvents 

493 self.model_name = "marketingEvents" 

494 self.columns = marketing_events_columns 

495 

496 sort_map = { 

497 MarketingEvents.id: "ID", 

498 MarketingEvents.startedAt: "STARTED_AT", 

499 } 

500 self.sort_map = {key.name.lower(): value for key, value in sort_map.items()} 

501 

502 self.conditions_op_map = { 

503 ("id", FilterOperator.GREATER_THAN): "id:>", 

504 ("id", FilterOperator.GREATER_THAN_OR_EQUAL): "id:>=", 

505 ("id", FilterOperator.LESS_THAN): "id:<", 

506 ("id", FilterOperator.LESS_THAN_OR_EQUAL): "id:<=", 

507 ("id", FilterOperator.EQUAL): "id:", 

508 ("startedat", FilterOperator.GREATER_THAN): "started_at:>", 

509 ("startedat", FilterOperator.GREATER_THAN_OR_EQUAL): "started_at:>=", 

510 ("startedat", FilterOperator.LESS_THAN): "started_at:<", 

511 ("startedat", FilterOperator.LESS_THAN_OR_EQUAL): "started_at:<=", 

512 ("startedat", FilterOperator.EQUAL): "started_at:", 

513 ("description", FilterOperator.EQUAL): "description:", 

514 ("description", FilterOperator.LIKE): "description:", 

515 ("type", FilterOperator.EQUAL): "type:", 

516 ("type", FilterOperator.LIKE): "type:", 

517 } 

518 super().__init__(*args, **kwargs) 

519 

520 def meta_get_tables(self, *args, **kwargs) -> dict: 

521 data = query_graphql_nodes( 

522 self.model_name, 

523 self.model, 

524 "id", 

525 ) 

526 row_count = len(data) 

527 

528 return { 

529 "table_name": self.name, 

530 "table_type": "BASE TABLE", 

531 "table_description": "A list of marketing events.", 

532 "row_count": row_count, 

533 } 

534 

535 def meta_get_primary_keys(self, table_name: str) -> List[Dict]: 

536 return [ 

537 { 

538 "table_name": table_name, 

539 "column_name": "id", 

540 } 

541 ] 

542 

543 def meta_get_foreign_keys(self, table_name: str, all_tables: List[str]) -> List[Dict]: 

544 return [] 

545 

546 

547class InventoryItemsTable(ShopifyMetaAPIResource): 

548 """The Shopify InventoryItems table implementation 

549 Reference: https://shopify.dev/docs/api/admin-graphql/latest/queries/inventoryitems 

550 """ 

551 

552 def __init__(self, *args, **kwargs): 

553 self.name = "inventory_items" 

554 self.model = InventoryItems 

555 self.model_name = "inventoryItems" 

556 self.columns = inventory_items_columns 

557 

558 self.sort_map = {} 

559 

560 self.conditions_op_map = { 

561 ("id", FilterOperator.GREATER_THAN): "id:>", 

562 ("id", FilterOperator.GREATER_THAN_OR_EQUAL): "id:>=", 

563 ("id", FilterOperator.LESS_THAN): "id:<", 

564 ("id", FilterOperator.LESS_THAN_OR_EQUAL): "id:<=", 

565 ("id", FilterOperator.EQUAL): "id:", 

566 ("createdat", FilterOperator.GREATER_THAN): "created_at:>", 

567 ("createdat", FilterOperator.GREATER_THAN_OR_EQUAL): "created_at:>=", 

568 ("createdat", FilterOperator.LESS_THAN): "created_at:<", 

569 ("createdat", FilterOperator.LESS_THAN_OR_EQUAL): "created_at:<=", 

570 ("createdat", FilterOperator.EQUAL): "created_at:", 

571 ("sku", FilterOperator.EQUAL): "sku:", 

572 ("updatedat", FilterOperator.GREATER_THAN): "updated_at:>", 

573 ("updatedat", FilterOperator.GREATER_THAN_OR_EQUAL): "updated_at:>=", 

574 ("updatedat", FilterOperator.LESS_THAN): "updated_at:<", 

575 ("updatedat", FilterOperator.LESS_THAN_OR_EQUAL): "updated_at:<=", 

576 ("updatedat", FilterOperator.EQUAL): "updated_at:", 

577 } 

578 super().__init__(*args, **kwargs) 

579 

580 def meta_get_tables(self, *args, **kwargs) -> dict: 

581 data = query_graphql_nodes( 

582 self.model_name, 

583 self.model, 

584 "id", 

585 ) 

586 row_count = len(data) 

587 

588 return { 

589 "table_name": self.name, 

590 "table_type": "BASE TABLE", 

591 "table_description": "A list of inventory items.", 

592 "row_count": row_count, 

593 } 

594 

595 def meta_get_primary_keys(self, table_name: str) -> List[Dict]: 

596 return [ 

597 { 

598 "table_name": table_name, 

599 "column_name": "id", 

600 } 

601 ] 

602 

603 def meta_get_foreign_keys(self, table_name: str, all_tables: List[str]) -> List[Dict]: 

604 return [] 

605 

606 

607class StaffMembersTable(ShopifyMetaAPIResource): 

608 """The Shopify StaffMembers table implementation 

609 Reference: https://shopify.dev/docs/api/admin-graphql/latest/queries/staffmembers 

610 """ 

611 

612 def __init__(self, *args, **kwargs): 

613 self.name = "staff_members" 

614 self.model = StaffMembers 

615 self.model_name = "staffMembers" 

616 self.columns = staff_members_columns 

617 

618 sort_map = { 

619 StaffMembers.id: "ID", 

620 StaffMembers.email: "EMAIL", 

621 StaffMembers.firstName: "FIRST_NAME", 

622 StaffMembers.lastName: "LAST_NAME", 

623 } 

624 self.sort_map = {key.name.lower(): value for key, value in sort_map.items()} 

625 

626 self.conditions_op_map = { 

627 ("accounttype", FilterOperator.EQUAL): "account_type:", 

628 ("email", FilterOperator.EQUAL): "email:", 

629 ("firstname", FilterOperator.EQUAL): "first_name:", 

630 ("firstname", FilterOperator.LIKE): "first_name:", 

631 ("lastname", FilterOperator.EQUAL): "last_name:", 

632 ("lastname", FilterOperator.LIKE): "last_name:", 

633 ("id", FilterOperator.GREATER_THAN): "id:>", 

634 ("id", FilterOperator.GREATER_THAN_OR_EQUAL): "id:>=", 

635 ("id", FilterOperator.LESS_THAN): "id:<", 

636 ("id", FilterOperator.LESS_THAN_OR_EQUAL): "id:<=", 

637 ("id", FilterOperator.EQUAL): "id:", 

638 } 

639 super().__init__(*args, **kwargs) 

640 

641 def meta_get_tables(self, *args, **kwargs) -> dict: 

642 data = query_graphql_nodes( 

643 self.model_name, 

644 self.model, 

645 "id", 

646 ) 

647 row_count = len(data) 

648 

649 return { 

650 "table_name": self.name, 

651 "table_type": "BASE TABLE", 

652 "table_description": "The shop staff members.", 

653 "row_count": row_count, 

654 } 

655 

656 def meta_get_primary_keys(self, table_name: str) -> List[Dict]: 

657 return [ 

658 { 

659 "table_name": table_name, 

660 "column_name": "id", 

661 } 

662 ] 

663 

664 def meta_get_foreign_keys(self, table_name: str, all_tables: List[str]) -> List[Dict]: 

665 return [] 

666 

667 

668class GiftCardsTable(ShopifyMetaAPIResource): 

669 """The Shopify GiftCards table implementation 

670 Reference: https://shopify.dev/docs/api/admin-graphql/latest/queries/giftcards 

671 """ 

672 

673 def __init__(self, *args, **kwargs): 

674 self.name = "gift_cards" 

675 self.model = GiftCards 

676 self.model_name = "giftCards" 

677 self.columns = gift_cards_columns 

678 

679 sort_map = { 

680 GiftCards.balance: "BALANCE", 

681 GiftCards.createdAt: "CREATED_AT", 

682 GiftCards.deactivatedAt: "DISABLED_AT", 

683 GiftCards.expiresOn: "EXPIRES_ON", 

684 GiftCards.id: "ID", 

685 GiftCards.initialValue: "INITIAL_VALUE", 

686 GiftCards.updatedAt: "UPDATED_AT", 

687 } 

688 self.sort_map = {key.name.lower(): value for key, value in sort_map.items()} 

689 

690 self.conditions_op_map = { 

691 ("createdat", FilterOperator.GREATER_THAN): "created_at:>", 

692 ("createdat", FilterOperator.GREATER_THAN_OR_EQUAL): "created_at:>=", 

693 ("createdat", FilterOperator.LESS_THAN): "created_at:<", 

694 ("createdat", FilterOperator.LESS_THAN_OR_EQUAL): "created_at:<=", 

695 ("createdat", FilterOperator.EQUAL): "created_at:", 

696 ("expireson", FilterOperator.GREATER_THAN): "expires_on:>", 

697 ("expireson", FilterOperator.GREATER_THAN_OR_EQUAL): "expires_on:>=", 

698 ("expireson", FilterOperator.LESS_THAN): "expires_on:<", 

699 ("expireson", FilterOperator.LESS_THAN_OR_EQUAL): "expires_on:<=", 

700 ("expireson", FilterOperator.EQUAL): "expires_on:", 

701 ("id", FilterOperator.GREATER_THAN): "id:>", 

702 ("id", FilterOperator.GREATER_THAN_OR_EQUAL): "id:>=", 

703 ("id", FilterOperator.LESS_THAN): "id:<", 

704 ("id", FilterOperator.LESS_THAN_OR_EQUAL): "id:<=", 

705 ("id", FilterOperator.EQUAL): "id:", 

706 } 

707 super().__init__(*args, **kwargs) 

708 

709 def meta_get_tables(self, *args, **kwargs) -> dict: 

710 response = self.query_graphql("""{ 

711 giftCardsCount(limit:null) { 

712 count 

713 } }""") 

714 row_count = response["data"]["giftCardsCount"]["count"] 

715 

716 return { 

717 "table_name": self.name, 

718 "table_type": "BASE TABLE", 

719 "table_description": "List of gift cards.", 

720 "row_count": row_count, 

721 } 

722 

723 def meta_get_primary_keys(self, table_name: str) -> List[Dict]: 

724 return [ 

725 { 

726 "table_name": table_name, 

727 "column_name": "id", 

728 } 

729 ] 

730 

731 def meta_get_foreign_keys(self, table_name: str, all_tables: List[str]) -> List[Dict]: 

732 return [ 

733 { 

734 "PARENT_TABLE_NAME": table_name, 

735 "PARENT_COLUMN_NAME": "customerId", 

736 "CHILD_TABLE_NAME": "customers", 

737 "CHILD_COLUMN_NAME": "id", 

738 }, 

739 { 

740 "PARENT_TABLE_NAME": table_name, 

741 "PARENT_COLUMN_NAME": "orderId", 

742 "CHILD_TABLE_NAME": "orders", 

743 "CHILD_COLUMN_NAME": "id", 

744 }, 

745 ]